capitalex hat die Gist bearbeitet . Zu Änderung gehen
1 file changed, 71 insertions, 23 deletions
february.lua
@@ -1,31 +1,47 @@ | |||
1 | + | local pprint = require "pprint" | |
1 | 2 | local program = [[ | |
2 | - | = [What is] February = | |
3 | - | [February is] a syntax front end for nova , designed around streaming tokens . | |
4 | - | = = = | |
3 | + | = = @rpn \\ [3] [4] dup * swap dup * swap + sqrt print | |
5 | 4 | ||
6 | - | ~ [Many Rules] Many Delimiter ~ | |
7 | - | [February can] let you switch between them on the fly . | |
8 | - | ~ ~ ~ | |
5 | + | = @rpn dup . @rpn.data $ = | |
6 | + | @rpn.data \\ $ $ | |
9 | 7 | ||
10 | - | *** [A note] *** | |
11 | - | SAYS you don't need those [backets] . | |
12 | - | BUT they might help with clarity | |
13 | - | ||
14 | - | *** *** [What is] February | |
15 | - | *** *** *** | |
8 | + | = @rpn swap . @rpn.data \\ $x $y = | |
9 | + | @rpn.data \\ $y $x | |
10 | + | ||
11 | + | = @rpn * . @rpn.data \\ $y $x = | |
12 | + | @rpn.data $z . @code [$z = $x * $y] | |
13 | + | ||
14 | + | = @rpn + . @rpn.data \\ $y $x = | |
15 | + | @rpn.data $z . @code [$z = $x + $y] | |
16 | + | ||
17 | + | = @rpn sqrt . @rpn.data $x = | |
18 | + | @rpn.data $y . @code [$y = math.sqrt(tonumber($x))] | |
19 | + | ||
20 | + | = @rpn print . @rpn.data $x = | |
21 | + | @code [print($x)] | |
22 | + | ||
23 | + | = @rpn $x = | |
24 | + | @rpn.data $x | |
16 | 25 | ]] | |
26 | + | -- [TODO] make parser module | |
27 | + | -- - add symbol parsing hooks (for `[` and `"`) | |
28 | + | -- - add symbol stream hooks (for things like `( a b c )`) | |
29 | + | -- - add rule steam hooks (for things like `?`) | |
30 | + | -- - add post-parsing hooks (for full rule set transformation) | |
17 | 31 | local stream = program:gmatch(".") | |
18 | - | local char, rule, rule_symbol, label_symbol, depth, symbol, side | |
32 | + | local char, rule, rule_symbol, label_symbol, depth, symbol, side, striding | |
19 | 33 | local tuple, rules, LEFT, RIGHT = {}, {}, 1, 2 | |
20 | 34 | repeat | |
21 | 35 | rule_symbol, char = "", stream() | |
22 | 36 | side, rule = LEFT, {{}, {}} | |
23 | 37 | while char and char:match("[%s%.,]") do | |
38 | + | -- skip all characters that can't be bound | |
24 | 39 | char = stream() | |
25 | 40 | end | |
26 | 41 | if char == nil then | |
27 | 42 | break | |
28 | 43 | elseif char == "[" then | |
44 | + | -- rule delimiter is multibyte | |
29 | 45 | depth, char = 1, stream() | |
30 | 46 | while char do | |
31 | 47 | if char == "[" then depth = depth + 1 end | |
@@ -34,26 +50,31 @@ repeat | |||
34 | 50 | rule_symbol, char = rule_symbol .. char, stream() | |
35 | 51 | end | |
36 | 52 | else | |
53 | + | -- rule delimiter is a single character | |
37 | 54 | rule_symbol = "" while char and not char:match("%s") do | |
38 | 55 | rule_symbol, char = rule_symbol .. char, stream() if char == "[" then | |
39 | 56 | io.stderr:write "Warning: symbol contains `[`. A space may be missing?" | |
40 | 57 | end | |
41 | 58 | end | |
42 | 59 | end | |
43 | - | repeat | |
60 | + | repeat -- consume rules from this set | |
44 | 61 | char = stream() | |
45 | 62 | while char and (char:match("[%s]") or not label_symbol and char:match("[%.,]")) do | |
63 | + | -- skip whitespace or [.,] if a label hasn't been selected | |
46 | 64 | char = stream() | |
47 | 65 | end | |
48 | 66 | if not char then | |
49 | - | if label_symbol then | |
67 | + | if label_symbol and not striding then | |
50 | 68 | table.insert(rule[side], {label_symbol, tuple}) | |
51 | 69 | end | |
52 | 70 | break | |
53 | 71 | end | |
72 | + | -- read a symbol from the stream | |
54 | 73 | if char:match("[%.,]") then | |
74 | + | -- we've hit a tuple related delimiter | |
55 | 75 | symbol = char | |
56 | 76 | elseif char == "[" then | |
77 | + | -- parse a boxed symbol | |
57 | 78 | symbol, depth, char = "", 1, stream() while char do | |
58 | 79 | if char == "[" then depth = depth + 1 end | |
59 | 80 | if char == "]" then depth = depth - 1 end | |
@@ -61,20 +82,33 @@ repeat | |||
61 | 82 | symbol, char = symbol .. char, stream() | |
62 | 83 | end | |
63 | 84 | else | |
85 | + | -- parse a symbol seperated by spaces | |
86 | + | -- this segment warns if a symbol contains `[` | |
64 | 87 | symbol = "" while char and not char:match("%s") do | |
65 | 88 | symbol, char = symbol .. char, stream() if char == "[" then | |
66 | 89 | io.stderr:write "Warning: symbol contains `[`. A space may be missing?" | |
67 | 90 | end | |
68 | 91 | end | |
69 | 92 | end | |
93 | + | -- process that symbol | |
70 | 94 | if symbol == "," then | |
95 | + | -- push a tuple | |
71 | 96 | table.insert(rule[side], {label_symbol, tuple}) | |
72 | - | tuple = {} | |
97 | + | striding, tuple = false, {} | |
73 | 98 | elseif symbol == "." then | |
74 | - | table.insert(rule[side], {label_symbol, tuple}) | |
75 | - | tuple, label_symbol = {}, nil | |
99 | + | -- push a tuple, clear label symbol | |
100 | + | if not (striding and #tuple == 0) then | |
101 | + | table.insert(rule[side], {label_symbol, tuple}) | |
102 | + | end | |
103 | + | striding, tuple, label_symbol = false, {}, nil | |
104 | + | elseif symbol == [[\\]] then | |
105 | + | if #tuple ~= 0 then | |
106 | + | table.insert(rule[side], {label_symbol, tuple}) | |
107 | + | tuple = {} | |
108 | + | end | |
109 | + | striding = true | |
76 | 110 | elseif symbol == rule_symbol and side == RIGHT then | |
77 | - | if label_symbol then | |
111 | + | if label_symbol and not (striding and #tuple == 0) then | |
78 | 112 | table.insert(rule[side], {label_symbol, tuple}) | |
79 | 113 | tuple = {} | |
80 | 114 | end | |
@@ -82,20 +116,34 @@ repeat | |||
82 | 116 | break | |
83 | 117 | else | |
84 | 118 | table.insert(rules, rule) | |
85 | - | side, rule, label_symbol = LEFT, {{}, {}}, nil | |
119 | + | striding, side, rule, label_symbol = false, LEFT, {{}, {}}, nil | |
86 | 120 | end | |
87 | 121 | elseif symbol == rule_symbol and side == LEFT then | |
88 | - | if label_symbol then | |
122 | + | -- a rule dilimiter | |
123 | + | if label_symbol and not (striding and #tuple == 0) then | |
89 | 124 | table.insert(rule[side], {label_symbol, tuple}) | |
90 | 125 | end | |
91 | - | tuple, side, label_symbol = {}, RIGHT, nil | |
126 | + | striding, tuple, side, label_symbol = false, {}, RIGHT, nil | |
92 | 127 | elseif not label_symbol then | |
128 | + | -- a label s symbol | |
93 | 129 | label_symbol = symbol | |
130 | + | elseif striding then | |
131 | + | table.insert(rule[side], {label_symbol, {symbol}}) | |
94 | 132 | else | |
133 | + | -- a symbol in a tuple | |
95 | 134 | table.insert(tuple, symbol) | |
96 | 135 | end | |
97 | 136 | until not char | |
98 | 137 | if #rule[LEFT] ~= 0 or #rule[RIGHT] ~= 0 then | |
99 | 138 | table.insert(rules, rule) | |
100 | 139 | end | |
101 | - | until not char | |
140 | + | until not char | |
141 | + | ||
142 | + | local compile = require "compiler" | |
143 | + | ||
144 | + | print(compile(rules, { | |
145 | + | mode = "main", | |
146 | + | state_every_rewrite = false, | |
147 | + | state_at_start = true, | |
148 | + | state_at_end = true, | |
149 | + | })) |
capitalex hat die Gist bearbeitet . Zu Änderung gehen
1 file changed, 101 insertions
february.lua(Datei erstellt)
@@ -0,0 +1,101 @@ | |||
1 | + | local program = [[ | |
2 | + | = [What is] February = | |
3 | + | [February is] a syntax front end for nova , designed around streaming tokens . | |
4 | + | = = = | |
5 | + | ||
6 | + | ~ [Many Rules] Many Delimiter ~ | |
7 | + | [February can] let you switch between them on the fly . | |
8 | + | ~ ~ ~ | |
9 | + | ||
10 | + | *** [A note] *** | |
11 | + | SAYS you don't need those [backets] . | |
12 | + | BUT they might help with clarity | |
13 | + | ||
14 | + | *** *** [What is] February | |
15 | + | *** *** *** | |
16 | + | ]] | |
17 | + | local stream = program:gmatch(".") | |
18 | + | local char, rule, rule_symbol, label_symbol, depth, symbol, side | |
19 | + | local tuple, rules, LEFT, RIGHT = {}, {}, 1, 2 | |
20 | + | repeat | |
21 | + | rule_symbol, char = "", stream() | |
22 | + | side, rule = LEFT, {{}, {}} | |
23 | + | while char and char:match("[%s%.,]") do | |
24 | + | char = stream() | |
25 | + | end | |
26 | + | if char == nil then | |
27 | + | break | |
28 | + | elseif char == "[" then | |
29 | + | depth, char = 1, stream() | |
30 | + | while char do | |
31 | + | if char == "[" then depth = depth + 1 end | |
32 | + | if char == "]" then depth = depth - 1 end | |
33 | + | if depth == 0 then break end | |
34 | + | rule_symbol, char = rule_symbol .. char, stream() | |
35 | + | end | |
36 | + | else | |
37 | + | rule_symbol = "" while char and not char:match("%s") do | |
38 | + | rule_symbol, char = rule_symbol .. char, stream() if char == "[" then | |
39 | + | io.stderr:write "Warning: symbol contains `[`. A space may be missing?" | |
40 | + | end | |
41 | + | end | |
42 | + | end | |
43 | + | repeat | |
44 | + | char = stream() | |
45 | + | while char and (char:match("[%s]") or not label_symbol and char:match("[%.,]")) do | |
46 | + | char = stream() | |
47 | + | end | |
48 | + | if not char then | |
49 | + | if label_symbol then | |
50 | + | table.insert(rule[side], {label_symbol, tuple}) | |
51 | + | end | |
52 | + | break | |
53 | + | end | |
54 | + | if char:match("[%.,]") then | |
55 | + | symbol = char | |
56 | + | elseif char == "[" then | |
57 | + | symbol, depth, char = "", 1, stream() while char do | |
58 | + | if char == "[" then depth = depth + 1 end | |
59 | + | if char == "]" then depth = depth - 1 end | |
60 | + | if depth == 0 then break end | |
61 | + | symbol, char = symbol .. char, stream() | |
62 | + | end | |
63 | + | else | |
64 | + | symbol = "" while char and not char:match("%s") do | |
65 | + | symbol, char = symbol .. char, stream() if char == "[" then | |
66 | + | io.stderr:write "Warning: symbol contains `[`. A space may be missing?" | |
67 | + | end | |
68 | + | end | |
69 | + | end | |
70 | + | if symbol == "," then | |
71 | + | table.insert(rule[side], {label_symbol, tuple}) | |
72 | + | tuple = {} | |
73 | + | elseif symbol == "." then | |
74 | + | table.insert(rule[side], {label_symbol, tuple}) | |
75 | + | tuple, label_symbol = {}, nil | |
76 | + | elseif symbol == rule_symbol and side == RIGHT then | |
77 | + | if label_symbol then | |
78 | + | table.insert(rule[side], {label_symbol, tuple}) | |
79 | + | tuple = {} | |
80 | + | end | |
81 | + | if #rule[LEFT] == 0 and #rule[RIGHT] == 0 then | |
82 | + | break | |
83 | + | else | |
84 | + | table.insert(rules, rule) | |
85 | + | side, rule, label_symbol = LEFT, {{}, {}}, nil | |
86 | + | end | |
87 | + | elseif symbol == rule_symbol and side == LEFT then | |
88 | + | if label_symbol then | |
89 | + | table.insert(rule[side], {label_symbol, tuple}) | |
90 | + | end | |
91 | + | tuple, side, label_symbol = {}, RIGHT, nil | |
92 | + | elseif not label_symbol then | |
93 | + | label_symbol = symbol | |
94 | + | else | |
95 | + | table.insert(tuple, symbol) | |
96 | + | end | |
97 | + | until not char | |
98 | + | if #rule[LEFT] ~= 0 or #rule[RIGHT] ~= 0 then | |
99 | + | table.insert(rules, rule) | |
100 | + | end | |
101 | + | until not char |