aboutsummaryrefslogtreecommitdiff
path: root/parser2.moon
diff options
context:
space:
mode:
Diffstat (limited to 'parser2.moon')
-rw-r--r--parser2.moon64
1 files changed, 64 insertions, 0 deletions
diff --git a/parser2.moon b/parser2.moon
new file mode 100644
index 0000000..9a2e2ff
--- /dev/null
+++ b/parser2.moon
@@ -0,0 +1,64 @@
+-- This file contains the parser, which converts text into abstract syntax trees
+lpeg = require 'lpeg'
+re = require 're'
+lpeg.setmaxstack 20000
+{:P,:R,:S,:C,:Cmt,:Carg,:Cc} = lpeg
+{:repr} = require 'utils'
+
+DEFS = with {}
+ -- Newline supports either windows-style CR+LF or unix-style LF
+ .nl = P("\r")^-1 * P("\n")
+ .tab = P("\t")
+ .tonumber = tonumber
+ .tochar = string.char
+ .unpack = unpack or table.unpack
+ .nil = Cc(nil)
+ .userdata = Carg(1)
+ .utf8_char = (
+ R("\194\223")*R("\128\191") +
+ R("\224\239")*R("\128\191")*R("\128\191") +
+ R("\240\244")*R("\128\191")*R("\128\191")*R("\128\191"))
+ .Tree = (t, userdata)-> userdata.make_tree(t, userdata)
+
+setmetatable(DEFS, {__index:(key)=>
+ if i = key\match("^ascii_(%d+)$")
+ c = string.char(tonumber(i))
+ self[key] = c
+ return c
+ elseif i = key\match("^number_(%d+)$")
+ p = Cc(tonumber(i))
+ self[key] = p
+ return p
+})
+
+-- Just for cleanliness, I put the language spec in its own file using a slightly modified
+-- version of the lpeg.re syntax.
+peg_tidier = re.compile [[
+file <- %nl* {~ (def/comment) (%nl+ (def/comment))* %nl* ~}
+def <- anon_def / captured_def
+anon_def <-
+ ({ident} (" "*) ":" {[^%nl]* (%nl+ " "+ [^%nl]*)*})
+ -> "%1 <- %2"
+captured_def <-
+ ({ident} (" "*) "(" {ident} ")" (" "*) ":" {[^%nl]* (%nl+ " "+ [^%nl]*)*})
+ -> "%1 <- ({| {:start:{}:} %3 {:stop:{}:} {:type: (''->'%2') :} |} %%userdata) -> Tree"
+ident <- [a-zA-Z_][a-zA-Z0-9_]*
+comment <- "--" [^%nl]*
+]]
+
+make_parser = (peg, make_tree=nil)->
+ peg = assert(peg_tidier\match(peg))
+ peg = assert(re.compile(peg, DEFS))
+ return (input, filename='???')->
+ input = tostring(input)
+ tree_mt = {__index: {source:input, filename:filename}}
+ userdata = {
+ make_tree: make_tree or ((t)->setmetatable(t, tree_mt))
+ :filename, source:input
+ }
+ tree = peg\match(input, nil, userdata)
+ if not tree
+ error "File #{filename} failed to parse:\n#{input}"
+ return tree
+
+return make_parser