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 | + | })) | |
february.lua(文件已创建)
| @@ -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 | |
上一页
下一页