shadytrees / Zoetrope
Portable short tags for PHP.
Clone this repository (size: 9.1 KB): HTTPS / SSH
$ hg clone http://bitbucket.org/shadytrees/zoetrope/
| commit 3: | 8c035d290800 |
| parent 2: | 84a16f6ccacc |
| branch: | default |
Refactor: Less work to mark unparsed text, more work to coagulate. Now handling strings.
Changed (Δ523 bytes):
raw changeset »
lib/zoetrope/dfa.php (30 lines added, 34 lines removed)
tests/expressions.php (6 lines added, 1 lines removed)
Up to file-list lib/zoetrope/dfa.php:
| … | … | @@ -8,21 +8,27 @@ class ZoeTropeException extends Exceptio |
8 |
8 |
|
9 |
9 |
class ZoeTropeDFA { |
10 |
10 |
function __construct($str) { |
11 |
/* Unprocessed string. */ |
|
12 |
11 |
$this->str = $str; |
13 |
12 |
/* Line number for error handling. */ |
14 |
13 |
$this->line = 0; |
14 |
/* Are we in a string literal? */ |
|
15 |
$this->stringy = false; |
|
15 |
16 |
/* Where the last expression began. */ |
16 |
17 |
$this->last_expr = -1; |
17 |
18 |
/* Where the last echo began. */ |
18 |
19 |
$this->last_echo = -1; |
19 |
/* Where the text begins have the last {expr, echo} ends. */ |
|
20 |
$this->text_begins = -1; |
|
20 |
} |
|
21 |
||
22 |
/* Stores a token of parser output. |
|
23 |
||
24 |
* $text: Text to add. */ |
|
25 |
function add($text) { |
|
26 |
$this->swaths[] = array($this->pos, $this->token_size, $text); |
|
21 |
27 |
} |
22 |
28 |
|
23 |
29 |
/* Advances the DFA based on the current token. Raises a |
24 |
30 |
ZoeException for delimiter mismatches. Appends the resulting |
25 |
swaths of transformed text |
|
31 |
swaths of transformed text by calling $this->add(). |
|
26 |
32 |
|
27 |
33 |
* $token: "left-expr", "right-expr", and so forth. |
28 |
34 |
* $pos: Location of DFA in $this->str. |
| … | … | @@ -37,34 +43,31 @@ class ZoeTropeDFA { |
37 |
43 |
elseif (strpos($token, '-echo') > 0) { |
38 |
44 |
if ($this->last_expr != -1) return; |
39 |
45 |
} |
40 |
/* Output text not captured by my literals. */ |
|
41 |
if (strpos($token, 'left') === 0) { |
|
42 |
/* If {{, I want $pos to point to the place after it, |
|
43 |
not before. */ |
|
44 |
$this->pos += $this->token_size; |
|
45 |
$this->push_text(); |
|
46 |
$this->text_begins = -1; |
|
47 |
} |
|
48 |
elseif (strpos($token, 'right') === 0) { |
|
49 |
$this->text_begins = $pos + $this->token_size; |
|
46 |
/* Don't parse anything in a string literal. */ |
|
47 |
if ($this->stringy) { |
|
48 |
if ($token != 'squote') return; |
|
49 |
/* TODO: backslash escapes. One pan into another. */ |
|
50 |
50 |
} |
51 |
51 |
|
52 |
52 |
switch($token) { |
53 |
53 |
case 'left-expr': |
54 |
54 |
$this->left_expr(); |
55 |
$this-> |
|
55 |
$this->add('<?php'); |
|
56 |
56 |
break; |
57 |
57 |
case 'right-expr': |
58 |
58 |
$this->right_expr(); |
59 |
$this-> |
|
59 |
$this->add('?>'); |
|
60 |
60 |
break; |
61 |
61 |
case 'left-echo': |
62 |
62 |
$this->left_echo(); |
63 |
$this-> |
|
63 |
$this->add('<?php echo('); |
|
64 |
64 |
break; |
65 |
65 |
case 'right-echo': |
66 |
66 |
$this->right_echo(); |
67 |
$this-> |
|
67 |
$this->add(')?>'); |
|
68 |
break; |
|
69 |
case 'squote': |
|
70 |
$this->stringy = !$this->stringy; |
|
68 |
71 |
break; |
69 |
72 |
case 'newline': |
70 |
73 |
$this->line++; |
| … | … | @@ -72,17 +75,6 @@ class ZoeTropeDFA { |
72 |
75 |
} |
73 |
76 |
} |
74 |
77 |
|
75 |
/* Pushes from $this->text_begins to now, respecting token literal |
|
76 |
sizes. */ |
|
77 |
function push_text() { |
|
78 |
if ($this->text_begins == -1) return; |
|
79 |
// The length from the *end* of the last }}, computed by |
|
80 |
// strlen, to the current location. |
|
81 |
$pos = $this->pos - $this->token_size; |
|
82 |
$this->swaths[] = _zo_splice($this->str, |
|
83 |
$this->text_begins, $pos); |
|
84 |
} |
|
85 |
||
86 |
78 |
function left_expr() { |
87 |
79 |
if ($this->last_expr != -1) { |
88 |
80 |
$e = 'Line %s: Opening an expression within an expression'; |
| … | … | @@ -104,8 +96,6 @@ class ZoeTropeDFA { |
104 |
96 |
$e = 'Line %s: Closing an unopened expression'; |
105 |
97 |
throw new ZoeTropeException(sprintf($e, $this->line)); |
106 |
98 |
} |
107 |
$this->swaths[] = _zo_splice($this->str, |
|
108 |
$this->last_expr, $this->pos); |
|
109 |
99 |
$this->last_expr = -1; |
110 |
100 |
} |
111 |
101 |
|
| … | … | @@ -114,13 +104,19 @@ class ZoeTropeDFA { |
114 |
104 |
$e = 'Line %s: Closing an unopened echo'; |
115 |
105 |
throw new ZoeTropeException(sprintf($e, $this->line)); |
116 |
106 |
} |
117 |
$this->swaths[] = _zo_splice($this->str, |
|
118 |
$this->last_echo, $this->pos); |
|
119 |
107 |
$this->last_echo = -1; |
120 |
108 |
} |
121 |
109 |
|
122 |
110 |
/* Returns the result of the DFA preprocessing. */ |
123 |
111 |
function coagulate() { |
124 |
|
|
112 |
$last_pos = -1; |
|
113 |
foreach ($this->swaths as $swath) { |
|
114 |
list($pos, $token_size, $text) = $swath; |
|
115 |
if ($last_pos != -1) { |
|
116 |
echo _zo_splice($this->str, $last_pos, $pos); |
|
117 |
} |
|
118 |
echo $text; |
|
119 |
$last_pos = $pos + $token_size; |
|
120 |
} |
|
125 |
121 |
} |
126 |
122 |
} |
Up to file-list tests/expressions.php:
| … | … | @@ -4,7 +4,8 @@ require_once 'testutil.php'; |
4 |
4 |
require_once ABSDIR . '/zoetrope.php'; |
5 |
5 |
|
6 |
6 |
$str = <<<EOD |
7 |
{{ |
|
7 |
{{ \$three = 3; |
|
8 |
if ('{[' === ']}'): }} |
|
8 |
9 |
<div>Hello, world.</div> |
9 |
10 |
{{ elseif ('{[' == ']}'): }} |
10 |
11 |
<div>Goodbye, world.</div> |
| … | … | @@ -12,6 +13,10 @@ require_once ABSDIR . '/zoetrope.php'; |
12 |
13 |
|
13 |
14 |
{[ '1 + 2{{}}' ]} |
14 |
15 |
|
16 |
{[ '1 + 2{[]}' ]} |
|
17 |
||
18 |
{{ print('1 + 2{{}}'); }} |
|
19 |
||
15 |
20 |
EOD; |
16 |
21 |
|
17 |
22 |
say(zoetrope_render($str)); |
