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.
Hao Lian / shadytrees
13 months ago

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 into array $this->swaths.
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->swaths[] = '<?php';
55
            $this->add('<?php');
56
56
            break;
57
57
        case 'right-expr':
58
58
            $this->right_expr();
59
            $this->swaths[] = '?>';
59
            $this->add('?>');
60
60
            break;
61
61
        case 'left-echo':
62
62
            $this->left_echo();
63
            $this->swaths[] = '<?php echo(';
63
            $this->add('<?php echo(');
64
64
            break;
65
65
        case 'right-echo':
66
66
            $this->right_echo();
67
            $this->swaths[] = ')?>';
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
        return implode('', $this->swaths);
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
{{ if ('{[' === ']}'): }}
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));