diff options
| author | s-ol <s-ol@users.noreply.github.com> | 2020-01-29 21:49:09 +0000 |
|---|---|---|
| committer | s-ol <s-ol@users.noreply.github.com> | 2020-01-29 21:49:39 +0000 |
| commit | 3d4b6213c1e37c695ca3f33347b8b041825ca471 (patch) | |
| tree | ccf52664d6397a11bdcc8b9c81c8da759d50b8c3 | |
| download | alive-3d4b6213c1e37c695ca3f33347b8b041825ca471.tar.gz alive-3d4b6213c1e37c695ca3f33347b8b041825ca471.zip | |
initial commit
| -rw-r--r-- | parsing.moon | 76 | ||||
| -rw-r--r-- | spec/peg_spec.moon | 71 |
2 files changed, 147 insertions, 0 deletions
diff --git a/parsing.moon b/parsing.moon new file mode 100644 index 0000000..f9efef4 --- /dev/null +++ b/parsing.moon @@ -0,0 +1,76 @@ +lpeg = require 'lpeg' + +class Atom + new: (@raw, @style='', @value) => + + stringify: => + switch @style + when '' + @raw + when '"' + "\"#{@raw}\"" + else + error! + + @make_num: (match) -> Atom match, '', tonumber match + @make_sym: (match) -> Atom match, '', match + @make_str: (match) -> Atom match, '"', match + +class Xpr + new: (parts, @style='(') => + @white = {} + @white[0] = parts[1] + + for i = 2,#parts,2 + @[i/2] = parts[i] + @white[i/2] = parts[i+1] + + stringify: => + buf = '' + buf ..= @white[0] + for i, frag in ipairs @ + buf ..= frag\stringify! + buf ..= @white[i] + + switch @style + when 'naked' + buf + else + '(' .. buf .. ')' + + make_sexpr: (parts) -> Xpr parts, '(' + make_nexpr: (parts) -> Xpr parts, 'naked' + +space = (lpeg.S ' \t\r\n') ^ 1 / 1 +mspace = (lpeg.S ' \t\r\n') ^ 0 / 1 + +sym = ((lpeg.R 'az', 'AZ') + (lpeg.S '-_+*')) ^ 1 / Atom.make_sym +str = '"' * (lpeg.C (1 - lpeg.P '"') ^ 0) * '"' / Atom.make_str +num = (lpeg.R '09', 'AZ') ^ 1 / Atom.make_num +atom = sym + num + str + +expr = (lpeg.V 'sexpr') + atom +explist = lpeg.Ct mspace * (lpeg.V 'expr') * (space * atom) ^ 0 * mspace +sexpr = (lpeg.P '(') * (lpeg.V 'explist') * (lpeg.P ')') / Xpr.make_sexpr + +nexpr = lpeg.P { + (lpeg.V 'explist') / Xpr.make_nexpr + :expr, :explist, :sexpr +} + +sexpr = lpeg.P { + 'sexpr' + :expr, :explist, :sexpr +} + +program = nexpr + +{ + :space + :atom + :expr + :explist + :sexpr + :nexpr + :program +} diff --git a/spec/peg_spec.moon b/spec/peg_spec.moon new file mode 100644 index 0000000..1b25406 --- /dev/null +++ b/spec/peg_spec.moon @@ -0,0 +1,71 @@ +import space, atom, expr, explist, sexpr, nexpr, program from require 'parsing' + +describe 'atom parsing', -> + test 'symbols', -> + sym = atom\match 'some-toast help' + assert.is.equal 'some-toast', sym.raw + assert.is.equal 'some-toast', sym.value + assert.is.equal 'some-toast', sym\stringify! + + test 'numbers', -> + num = atom\match '1234 nope' + assert.is.equal '1234', num.raw + assert.is.equal 1234, num.value + assert.is.equal '1234', num\stringify! + + test 'strings', -> + str = atom\match '"help some stuff!" nope' + assert.is.equal 'help some stuff!', str.raw + assert.is.equal 'help some stuff!', str.value + assert.is.equal '"help some stuff!"', str\stringify! + +test 'whitespace parsing', -> + assert.is.equal ' ', space\match ' ' + assert.is.equal '\n\t ', space\match '\n\t ' + +describe 'nexpr parsing', -> + it 'handles leading whitespace', -> + node = nexpr\match ' 3\tok-yes' + + assert.is.equal 2, #node + assert.is.equal 3, node[1].value + assert.is.equal 'ok-yes', node[2].value + + assert.is.equal ' 3\tok-yes', node\stringify! + + it 'handles trailing whitespace', -> + node = nexpr\match '3\tok-yes\n' + + assert.is.equal 2, #node + assert.is.equal 3, node[1].value + assert.is.equal 'ok-yes', node[2].value + + assert.is.equal '3\tok-yes\n', node\stringify! + + it 'handles whitespace everywhere', -> + node = nexpr\match ' 3\tok-yes\n' + + assert.is.equal 2, #node + assert.is.equal 3, node[1].value + assert.is.equal 'ok-yes', node[2].value + + assert.is.equal ' 3\tok-yes\n', node\stringify! + +test 'sexpr parsing', -> + str = '( 3 ok-yes + "friend" )' + node = sexpr\match str + + assert.is.equal '(', node.style + assert.is.equal 3, #node + assert.is.equal 3, node[1].value + assert.is.equal 'ok-yes', node[2].value + assert.is.equal 'friend', node[3].value + + assert.is.equal str, node\stringify! + +test 'mixed parsing', -> + str = '( 3 ok-yes + "friend" )' + node = program\match str + assert.is.equal str, node\stringify! |
