aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBruce Hill <bitbucket@bruce-hill.com>2018-09-14 14:00:48 -0700
committerBruce Hill <bitbucket@bruce-hill.com>2018-09-14 14:01:07 -0700
commit7c1f2dfd69afe119322e19b3a4061876b3dd1033 (patch)
treeee540007cdad2681b03a208c657811591da58cc9
parent4d48bf359df98512a2a741d48ea222d055b733c0 (diff)
Fixes and improvements, and ported nomsu.3.peg to new tidier syntax.
-rw-r--r--nomsu.3.peg168
-rw-r--r--nomsu.4.peg25
-rw-r--r--nomsu_compiler.lua71
-rw-r--r--nomsu_compiler.moon34
-rw-r--r--parser.lua119
-rw-r--r--parser.moon68
-rw-r--r--pretty_errors.lua1
-rw-r--r--pretty_errors.moon1
8 files changed, 168 insertions, 319 deletions
diff --git a/nomsu.3.peg b/nomsu.3.peg
index 244a621..21fa86c 100644
--- a/nomsu.3.peg
+++ b/nomsu.3.peg
@@ -3,69 +3,94 @@ file:
{:curr_indent: ' '* :}
(((action / expression / inline_block / indented_block) eol !.)
/ file_chunks / empty_block)
- %ws* (!! .+ -> "Parse error" !!)?
+ {:curr_indent: %nil :}
+ !.
-shebang: "#!" (!"nomsu" [^%nl])* "nomsu" %ws+ "-V" %ws* {:version: [0-9.]+ :} [^%nl]*
+shebang: "#!" (!"nomsu" [^%nl])* "nomsu" ws+ "-V" ws* {:version: [0-9.]+ :} [^%nl]*
file_chunks (FileChunks):
{:curr_indent: ' '* :}
shebang? comment? blank_lines?
(top_block (nl_nodent section_division top_block)*)
blank_lines?
+ ws* unexpected_chunk?
+ {:curr_indent: %nil :}
top_block (Block):
{:curr_indent: ' '* :}
comment? blank_lines? statement (nl_nodent statement)*
+ {:curr_indent: %nil :}
empty_block (Block):
{:curr_indent: ' '* :}
comment? blank_lines?
+ {:curr_indent: %nil :}
-nodent: =curr_indent !(" ")
+nodent: (unexpected_indent [^%nl]* / =curr_indent)
indent: =curr_indent " "
-blank_lines: %nl ((nodent comment / %ws*) %nl)*
-eol: %ws* eol_comment? (!. / &%nl)
+blank_lines: %nl ((nodent comment / ws*) %nl)*
+eol: ws* eol_comment? (!. / &%nl)
nl_nodent: blank_lines nodent
-nl_indent: blank_lines {:curr_indent: indent :} (comment nl_nodent)?
-
-comment:
- "#" (({} {~ [^%nl]* (%nl+ (indent -> '') [^%nl]*)* ~} %userdata) => add_comment)
-eol_comment:
- "#" (({} {[^%nl]*} %userdata) => add_comment)
+nl_indent: blank_lines {:curr_indent: indent :} (comment nl_nodent)*
+
+comment (Comment):
+ "#" {~ [^%nl]* (%nl+ (indent -> '') [^%nl]*)* ~}
+eol_comment (Comment):
+ "#" {[^%nl]*}
+
+unexpected_code: ws* _unexpected_code
+_unexpected_code (Error):
+ {:error: {~ [^%nl]+ -> "Couldn't parse this code" ~} :}
+unexpected_chunk (Error):
+ {:error: {~ .+ -> "Couldn't parse this code" ~} :}
+unexpected_indent (Error):
+ {:error: {~ (=curr_indent ws+) -> "Messed up indentation" ~} :}
+ {:hint: {~ '' -> 'Either make sure this line is aligned with the one above it, or make sure the previous line ends with something that uses indentation, like ":" or "(..)"' ~} :}
+missing_paren_err (Error):
+ {:error: {~ eol -> 'Line ended without finding a closing )-parenthesis' ~} :}
+ {:hint: {~ '' -> 'Put a ")" here' ~} :}
+missing_quote_err (Error):
+ {:error: {~ eol -> 'Line ended before finding a closing double quotation mark' ~} :}
+ {:hint: {~ "" -> "Put a quotation mark here" ~} :}
+missing_bracket_error (Error):
+ {:error: {~ eol -> "Line ended before finding a closing ]-bracket" ~} :}
+ {:hint: {~ '' -> 'Put a "]" here' ~} :}
+missing_brace_error (Error):
+ {:error: {~ eol -> "Line ended before finding a closing }-brace" ~} :}
+ {:hint: {~ '' -> 'Put a "}" here' ~} :}
section_division: ("~")^+3 eol
inline_block:
- "(" %ws* inline_block %ws* ")" / raw_inline_block
+ "(" ws* inline_block ws* ")" / raw_inline_block
raw_inline_block (Block):
- (!"::") ":" %ws* ((inline_statement (%ws* ";" %ws* inline_statement)*) / !(eol nl_indent))
+ (!"::") ":" ws* ((inline_statement (ws* ";" ws* inline_statement)*) / !(eol nl_indent))
indented_block (Block):
- ":" eol nl_indent statement (nl_nodent statement)* (%nl (%ws* %nl)* nodent comment)*
+ ":" eol nl_indent statement (nl_nodent statement)*
+ (%nl (ws* %nl)* nodent (comment / eol / unexpected_code))*
+ {:curr_indent: %nil :}
statement:
- (action / expression) (eol / (!! [^%nl]+ -> "Unexpected code while parsing line" !!))
+ (action / expression) (eol / unexpected_code)
inline_statement: (inline_action / inline_expression)
noindex_inline_expression:
number / variable / inline_text / inline_list / inline_dict / inline_nomsu
/ ( "("
- %ws* (inline_action / inline_expression) %ws*
- (%ws* ',' %ws* (inline_action / inline_expression) %ws*)*
- (")"
- / (!! eol -> 'Line ended without finding a closing )-parenthesis' !!)
- / (!! [^%nl]+ -> 'Unexpected code while parsing subexpression' !!)
- )
+ ws* (inline_action / inline_expression) ws*
+ (ws* ',' ws* (inline_action / inline_expression) ws*)*
+ (")" / missing_paren_err / unexpected_code)
)
inline_expression: index_chain / noindex_inline_expression
indented_expression:
indented_text / indented_nomsu / indented_list / indented_dict / ({|
"(..)" nl_indent
- (action / expression) (nl_nodent comment)*
- (eol / (!! [^%nl]+ -> "Unexpected code while parsing indented expression" !!))
+ (action / expression) (eol / unexpected_code)
+ (%nl (ws* %nl)* nodent (comment / eol / unexpected_code))*
+ {:curr_indent: %nil :}
|} -> unpack)
- / (nl_indent (!! [^%nl]* -> "Unexpected indentation. Perhaps you meant to put a ':' or '(..)' on the previous line?" !!) (nl_nodent [^%nl]*)*)
expression:
inline_expression / indented_expression
@@ -79,45 +104,42 @@ index_chain (IndexChain):
-- Actions need either at least 1 word, or at least 2 tokens
inline_action (Action):
!section_division
- ({:target: inline_arg :} %ws* "::" %ws*)?
- ( (inline_arg (%ws* (inline_arg / word))+)
- / (word (%ws* (inline_arg / word))*))
- (%ws* inline_block)?
+ ({:target: inline_arg :} ws* "::" ws*)?
+ ( (inline_arg (ws* (inline_arg / word))+)
+ / (word (ws* (inline_arg / word))*))
+ (ws* inline_block)?
inline_arg: inline_expression / inline_block
action (Action):
!section_division
- ({:target: arg :} (nl_nodent "..")? %ws* "::" (nl_nodent "..")? %ws*)?
- ( (arg ((nl_nodent "..")? %ws* (arg / word))+)
- / (word ((nl_nodent "..")? %ws* (arg / word))*))
+ ({:target: arg :} (nl_nodent "..")? ws* "::" (nl_nodent "..")? ws*)?
+ ( (arg ((nl_nodent "..")? ws* (arg / word))+)
+ / (word ((nl_nodent "..")? ws* (arg / word))*))
arg: expression / inline_block / indented_block
-word: !number { %operator_char+ / %ident_char+ }
+word: !number { operator_char+ / ident_char+ }
text_word (Text): word
inline_text (Text):
- !('".."' eol)
- '"'
- ({~ (('\"' -> '"') / ('\\' -> '\') / %escaped_char / [^%nl\"])+ ~}
- / inline_text_interpolation)*
- ('"'
- / (!! eol -> 'Line ended before finding a closing double quotation mark' !!)
- / (!! [^%nl]+ -> 'Unexpected code while parsing Text' !!))
+ !(indented_text)
+ ('"' _inline_text* ('"' / missing_quote_err / unexpected_code))
+_inline_text:
+ {~ (('\"' -> '"') / ('\\' -> '\') / escaped_char / [^%nl\"]+)+ ~}
+ / inline_text_interpolation
inline_text_interpolation:
"\" (
variable / inline_list / inline_dict / inline_text
/ ("("
- %ws* (inline_action / inline_expression) %ws*
- (%ws* ',' %ws* (inline_action / inline_expression) %ws*)*
- (")"
- / (!! eol -> 'Line ended without finding a closing )-parenthesis' !!)
- / (!! [^%nl]+ -> 'Unexpected code while parsing Text interpolation' !!)))
+ ws* (inline_action / inline_expression) ws*
+ (ws* ',' ws* (inline_action / inline_expression) ws*)*
+ (")" / missing_paren_err / unexpected_code))
)
indented_text (Text):
- '".."' eol %nl {%nl*} {:curr_indent: indent :}
+ '".."' eol %nl {%nl+}? {:curr_indent: indent :}
(indented_plain_text / text_interpolation / {~ %nl+ (=curr_indent -> "") ~})*
- (!! [^%nl]+ -> "Unexpected code while parsing Text" !!)?
+ unexpected_code?
+ {:curr_indent: %nil :}
-- Tracking text-lines-within-indented-text as separate objects allows for better debugging line info
indented_plain_text (Text):
{~ (("\\" -> "\") / (("\" blank_lines =curr_indent "..") -> "") / (!text_interpolation "\") / [^%nl\]+)+
@@ -129,43 +151,51 @@ number (Number): (("-"? (([0-9]+ "." [0-9]+) / ("." [0-9]+) / "0x" [0-9a-fA-F]+
-- Variables can be nameless (i.e. just %) and can only contain identifier chars.
-- This ensures you don't get weird parsings of `%x+%y` or `%'s thing`.
-variable (Var): "%" {%ident_char*}
+variable (Var): "%" {ident_char*}
inline_list (List):
!('[..]')
- "[" %ws*
- (inline_list_item (%ws* ',' %ws* inline_list_item)* (%ws* ',')?)? %ws*
- ("]" / (","? (
- (!! eol -> "Line ended before finding a closing ]-bracket" !!)
- /(!! [^%nl]+ -> "Unexpected code while parsing List" !!)
- )))
+ "[" ws*
+ (inline_list_item (ws* ',' ws* inline_list_item)* (ws* ',')?)? ws*
+ ("]" / (","? (missing_bracket_error / unexpected_code)))
indented_list (List):
"[..]" eol nl_indent
- list_line (nl_nodent list_line)* (nl_nodent comment)*
- (","? (!! [^%nl]+ -> "Unexpected code while parsing List" !!))?
+ list_line (nl_nodent list_line)*
+ (%nl (ws* %nl)* nodent (comment / eol / unexpected_code))*
+ (","? unexpected_code)?
list_line:
- (inline_list_item %ws* "," %ws*)+ eol
- / (inline_list_item %ws* "," %ws*)* (action / expression) eol
+ (inline_list_item ws* "," ws*)+ eol
+ / (inline_list_item ws* "," ws*)* (action / expression) eol
inline_list_item: inline_action / inline_expression
inline_dict (Dict):
!('{..}')
- "{" %ws*
- (inline_dict_entry (%ws* ',' %ws* inline_dict_entry)*)? %ws*
- ("}" / (","? (
- (!! eol -> "Line ended before finding a closing }-brace" !!)
- / (!! [^%nl]* -> "Unexpected code while parsing Dictionary" !!)
- )))
+ "{" ws*
+ (inline_dict_entry (ws* ',' ws* inline_dict_entry)*)? ws*
+ ("}" / (","? (missing_brace_error / unexpected_code)))
indented_dict (Dict):
"{..}" eol nl_indent
- dict_line (nl_nodent dict_line)* (nl_nodent comment)*
- (","? (!! [^%nl]+ -> "Unexpected code while parsing Dictionary" !!))?
+ dict_line (nl_nodent dict_line)*
+ (%nl (ws* %nl)* nodent (comment / eol / unexpected_code))*
+ (","? unexpected_code)?
dict_line:
- (inline_dict_entry %ws* "," %ws*)+ eol
- / (inline_dict_entry %ws* "," %ws*)* dict_entry eol
+ (inline_dict_entry ws* "," ws*)+ eol
+ / (inline_dict_entry ws* "," ws*)* dict_entry eol
dict_entry(DictEntry):
- dict_key (%ws* ":" %ws* (action / expression))?
+ dict_key (ws* ":" ws* (action / expression))?
inline_dict_entry(DictEntry):
- dict_key (%ws* ":" %ws* (inline_action / inline_expression)?)?
+ dict_key (ws* ":" ws* (inline_action / inline_expression)?)?
dict_key:
text_word / inline_expression
+
+operator_char: ['`~!@$^&*+=|<>?/-]
+ident_char: [a-zA-Z0-9_] / %utf8_char
+ws: [ %tab]
+
+escaped_char:
+ ("\"->'') (
+ (([xX]->'') ((({[0-9a-fA-F]^2} %number_16) -> tonumber) -> tochar))
+ / ((([0-9] [0-9]^-2) -> tonumber) -> tochar)
+ / ("a"->ascii_7) / ("b"->ascii_8) / ("t"->ascii_9) / ("n"->ascii_10)
+ / ("v"->ascii_11) / ("f"->ascii_12) / ("r"->ascii_13)
+ )
diff --git a/nomsu.4.peg b/nomsu.4.peg
index eb0c878..8d8296e 100644
--- a/nomsu.4.peg
+++ b/nomsu.4.peg
@@ -11,14 +11,14 @@ shebang: "#!" (!"nomsu" [^%nl])* "nomsu" ws+ "-V" ws* {:version: [0-9.]+ :} [^%n
file_chunks (FileChunks):
{:curr_indent: ' '* :}
shebang? comment? blank_lines?
- (top_block (section_division nl_nodent top_block)*)
+ (top_block (nl_nodent section_division top_block)*)
blank_lines?
ws* unexpected_chunk?
{:curr_indent: %nil :}
top_block (Block):
{:curr_indent: ' '* :}
- comment? blank_lines? statement (nl_nodent statement?)*
+ comment? blank_lines? statement (nl_nodent statement)*
{:curr_indent: %nil :}
empty_block (Block):
@@ -71,7 +71,7 @@ inline_block:
raw_inline_block (Block):
(!"::") ":" ws* ((inline_statement (ws* ";" ws* inline_statement)*) / !(eol nl_indent))
indented_block (Block):
- ":" eol nl_indent statement (nl_nodent statement?)*
+ ":" eol nl_indent statement (nl_nodent statement)*
(%nl (ws* %nl)* nodent (comment / eol / unexpected_code))*
{:curr_indent: %nil :}
@@ -149,19 +149,16 @@ indented_text (Text):
cool_quote:
'"' !(%nl+ !(=curr_indent))
cool_indented_text (Text):
- ({|
- '"'
- _inline_text*
- (('\' %nl+ {:curr_indent: indent :} '..')
- / disallowed_interpolation? {%nl+} {:curr_indent: indent :})
- (indented_cool_plain_text / text_interpolation / {~ %nl+ (=curr_indent -> "") ~})*
- ('"' eol / missing_quote_err)
- |} -> unpack)
+ '"'
+ _inline_text*
+ (('\' %nl+ {:curr_indent: indent :} '..')
+ / disallowed_interpolation? {%nl+} {:curr_indent: indent :})
+ (indented_cool_plain_text / text_interpolation / {~ %nl+ (=curr_indent -> "") ~})*
+ ('"' eol / missing_quote_err)
indented_cool_plain_text (Text):
{~ ((("\" blank_lines =curr_indent "..") -> "") / (!text_interpolation ((!("\n") escaped_char) / ('\\' -> '\') / '\')) / (cool_quote / [^%nl"\])+)+
(%nl+ (=curr_indent -> ""))* ~}
-
-- Tracking text-lines-within-indented-text as separate objects allows for better debugging line info
indented_plain_text (Text):
{~ (("\\" -> "\") / (("\" blank_lines =curr_indent "..") -> "") / (!text_interpolation "\") / [^%nl\]+)+
@@ -182,7 +179,7 @@ inline_list (List):
("]" / (","? (missing_bracket_error / unexpected_code)))
indented_list (List):
"[..]" eol nl_indent
- list_line (nl_nodent list_line?)*
+ list_line (nl_nodent list_line)*
(%nl (ws* %nl)* nodent (comment / eol / unexpected_code))*
(","? unexpected_code)?
list_line:
@@ -197,7 +194,7 @@ inline_dict (Dict):
("}" / (","? (missing_brace_error / unexpected_code)))
indented_dict (Dict):
"{..}" eol nl_indent
- dict_line (nl_nodent dict_line?)*
+ dict_line (nl_nodent dict_line)*
(%nl (ws* %nl)* nodent (comment / eol / unexpected_code))*
(","? unexpected_code)?
dict_line:
diff --git a/nomsu_compiler.lua b/nomsu_compiler.lua
index 510de16..5578e0e 100644
--- a/nomsu_compiler.lua
+++ b/nomsu_compiler.lua
@@ -62,12 +62,45 @@ table.copy = function(t)
return _tbl_0
end)(), getmetatable(t))
end
+local make_tree
+make_tree = function(tree, userdata)
+ local cls = AST[tree.type]
+ tree.source = Source(userdata.filename, tree.start, tree.stop)
+ tree.start, tree.stop = nil, nil
+ tree.type = nil
+ do
+ local _accum_0 = { }
+ local _len_0 = 1
+ for _index_0 = 1, #tree do
+ local t = tree[_index_0]
+ if AST.is_syntax_tree(t, "Comment") then
+ _accum_0[_len_0] = t
+ _len_0 = _len_0 + 1
+ end
+ end
+ tree.comments = _accum_0
+ end
+ if #tree.comments == 0 then
+ tree.comments = nil
+ end
+ for i = #tree, 1, -1 do
+ if AST.is_syntax_tree(tree[i], "Comment") then
+ table.remove(tree, i)
+ end
+ end
+ tree = setmetatable(tree, cls)
+ cls.source_code_for_tree[tree] = userdata.source
+ if tree.__init then
+ tree:__init()
+ end
+ return tree
+end
local Parsers = { }
local max_parser_version = 0
for version = 1, 999 do
local _continue_0 = false
repeat
- if not (version == 4) then
+ if not (version == 4 or version == 3) then
_continue_0 = true
break
end
@@ -84,40 +117,8 @@ for version = 1, 999 do
break
end
max_parser_version = version
- local make_tree
- make_tree = function(tree, userdata)
- local cls = AST[tree.type]
- tree.source = Source(userdata.filename, tree.start, tree.stop)
- tree.start, tree.stop = nil, nil
- tree.type = nil
- do
- local _accum_0 = { }
- local _len_0 = 1
- for _index_0 = 1, #tree do
- local t = tree[_index_0]
- if AST.is_syntax_tree(t, "Comment") then
- _accum_0[_len_0] = t
- _len_0 = _len_0 + 1
- end
- end
- tree.comments = _accum_0
- end
- if #tree.comments == 0 then
- tree.comments = nil
- end
- for i = #tree, 1, -1 do
- if AST.is_syntax_tree(tree[i], "Comment") then
- table.remove(tree, i)
- end
- end
- tree = setmetatable(tree, cls)
- cls.source_code_for_tree[tree] = userdata.source
- if tree.__init then
- tree:__init()
- end
- return tree
- end
- Parsers[version] = make_parser(peg_file:read("*a"), make_tree)
+ local peg_contents = peg_file:read("*a")
+ Parsers[version] = make_parser(peg_contents, make_tree)
peg_file:close()
_continue_0 = true
until true
diff --git a/nomsu_compiler.moon b/nomsu_compiler.moon
index 4300327..606bf45 100644
--- a/nomsu_compiler.moon
+++ b/nomsu_compiler.moon
@@ -38,10 +38,25 @@ table.copy = (t)-> setmetatable({k,v for k,v in pairs(t)}, getmetatable(t))
-- consider non-linear codegen, rather than doing thunks for things like comprehensions
-- Re-implement nomsu-to-lua comment translation?
+make_tree = (tree, userdata)->
+ cls = AST[tree.type]
+ tree.source = Source(userdata.filename, tree.start, tree.stop)
+ tree.start, tree.stop = nil, nil
+ tree.type = nil
+ tree.comments = [t for t in *tree when AST.is_syntax_tree(t, "Comment")]
+ if #tree.comments == 0 then tree.comments = nil
+ for i=#tree,1,-1
+ if AST.is_syntax_tree(tree[i], "Comment")
+ table.remove(tree, i)
+ tree = setmetatable(tree, cls)
+ cls.source_code_for_tree[tree] = userdata.source
+ if tree.__init then tree\__init!
+ return tree
+
Parsers = {}
max_parser_version = 0
for version=1,999
- continue unless version == 4 -- TODO: remove
+ continue unless version == 4 or version == 3 -- TODO: remove
peg_file = io.open("nomsu.#{version}.peg")
if not peg_file and package.nomsupath
for path in package.nomsupath\gmatch("[^;]+")
@@ -49,21 +64,8 @@ for version=1,999
break if peg_file
break unless peg_file
max_parser_version = version
- make_tree = (tree, userdata)->
- cls = AST[tree.type]
- tree.source = Source(userdata.filename, tree.start, tree.stop)
- tree.start, tree.stop = nil, nil
- tree.type = nil
- tree.comments = [t for t in *tree when AST.is_syntax_tree(t, "Comment")]
- if #tree.comments == 0 then tree.comments = nil
- for i=#tree,1,-1
- if AST.is_syntax_tree(tree[i], "Comment")
- table.remove(tree, i)
- tree = setmetatable(tree, cls)
- cls.source_code_for_tree[tree] = userdata.source
- if tree.__init then tree\__init!
- return tree
- Parsers[version] = make_parser(peg_file\read("*a"), make_tree)
+ peg_contents = peg_file\read("*a")
+ Parsers[version] = make_parser(peg_contents, make_tree)
peg_file\close!
MAX_LINE = 80 -- For beautification purposes, try not to make lines much longer than this value
diff --git a/parser.lua b/parser.lua
index 8a94314..5eed3be 100644
--- a/parser.lua
+++ b/parser.lua
@@ -113,126 +113,9 @@ setmetatable(NOMSU_DEFS, {
end
})
local Parser = {
- version = 3,
+ version = 4,
patterns = { }
}
-do
- local peg_tidier = re.compile([[ file <- %nl* {~ (def/comment) (%nl+ (def/comment))* %nl* ~}
- def <- anon_def / captured_def
- anon_def <- ({ident} (" "*) ":"
- {~ ((%nl " "+ def_line?)+) / def_line ~}) -> "%1 <- %2"
- captured_def <- ({ident} (" "*) "(" {ident} ")" (" "*) ":"
- {~ ((%nl " "+ def_line?)+) / def_line ~}) -> "%1 <- (({} {| %3 |} {} %%userdata) -> %2)"
- def_line <- (err / [^%nl])+
- err <- ("(!!" { (!("!!)") .)* } "!!)") -> "(({} (%1) %%userdata) => error)"
- ident <- [a-zA-Z_][a-zA-Z0-9_]*
- comment <- "--" [^%nl]*
- ]])
- for version = 1, Parser.version do
- local peg_file = io.open("nomsu." .. tostring(version) .. ".peg")
- if not peg_file and package.nomsupath then
- for path in package.nomsupath:gmatch("[^;]+") do
- peg_file = io.open(path .. "/nomsu." .. tostring(version) .. ".peg")
- if peg_file then
- break
- end
- end
- end
- assert(peg_file, "could not find nomsu .peg file")
- local nomsu_peg = peg_tidier:match(peg_file:read('*a'))
- peg_file:close()
- Parser.patterns[version] = re.compile(nomsu_peg, NOMSU_DEFS)
- end
-end
-local _anon_chunk = 0
-Parser.parse = function(nomsu_code, source, version)
- if source == nil then
- source = nil
- end
- if version == nil then
- version = nil
- end
- source = source or nomsu_code.source
- nomsu_code = tostring(nomsu_code)
- if not (source) then
- source = Source("anonymous chunk #" .. tostring(_anon_chunk), 1, #nomsu_code)
- _anon_chunk = _anon_chunk + 1
- end
- version = version or nomsu_code:match("^#![^\n]*nomsu[ ]+-V[ ]*([0-9.]+)")
- local syntax_version = version and tonumber(version:match("^[0-9]+")) or Parser.version
- local userdata = {
- errors = { },
- source = source,
- comments = { }
- }
- local tree = Parser.patterns[syntax_version]:match(nomsu_code, nil, userdata)
- if not tree or type(tree) == 'number' then
- error("In file " .. tostring(colored.blue(tostring(source or "<unknown>"))) .. " failed to parse:\n" .. tostring(colored.onyellow(colored.black(nomsu_code))))
- end
- if next(userdata.errors) then
- local keys
- do
- local _accum_0 = { }
- local _len_0 = 1
- for k, v in pairs(userdata.errors) do
- _accum_0[_len_0] = k
- _len_0 = _len_0 + 1
- end
- keys = _accum_0
- end
- table.sort(keys)
- local errors
- do
- local _accum_0 = { }
- local _len_0 = 1
- for _index_0 = 1, #keys do
- local k = keys[_index_0]
- _accum_0[_len_0] = userdata.errors[k]
- _len_0 = _len_0 + 1
- end
- errors = _accum_0
- end
- error("Errors occurred while parsing (v" .. tostring(syntax_version) .. "):\n\n" .. table.concat(errors, "\n\n"), 0)
- end
- local comments
- do
- local _accum_0 = { }
- local _len_0 = 1
- for p, c in pairs(userdata.comments) do
- _accum_0[_len_0] = {
- comment = c,
- pos = p
- }
- _len_0 = _len_0 + 1
- end
- comments = _accum_0
- end
- table.sort(comments, function(a, b)
- return a.pos > b.pos
- end)
- local comment_i = 1
- local walk_tree
- walk_tree = function(t)
- local comment_buff = { }
- while comments[#comments] and comments[#comments].pos <= t.source.start do
- table.insert(comment_buff, table.remove(comments))
- end
- for _index_0 = 1, #t do
- local x = t[_index_0]
- if AST.is_syntax_tree(x) then
- walk_tree(x)
- end
- end
- while comments[#comments] and comments[#comments].pos <= t.source.stop do
- table.insert(comment_buff, table.remove(comments))
- end
- if #comment_buff > 0 then
- t.comments = comment_buff
- end
- end
- walk_tree(tree)
- return tree
-end
Parser.is_operator = function(s)
return not not (NOMSU_DEFS.operator_char ^ 1 * -1):match(s)
end
diff --git a/parser.moon b/parser.moon
index f2e5b17..2adfe1b 100644
--- a/parser.moon
+++ b/parser.moon
@@ -74,73 +74,7 @@ setmetatable(NOMSU_DEFS, {__index:(key)=>
return make_node
})
-Parser = {version:3, patterns:{}}
-do
- -- 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 " "+ def_line?)+) / def_line ~}) -> "%1 <- %2"
- captured_def <- ({ident} (" "*) "(" {ident} ")" (" "*) ":"
- {~ ((%nl " "+ def_line?)+) / def_line ~}) -> "%1 <- (({} {| %3 |} {} %%userdata) -> %2)"
- def_line <- (err / [^%nl])+
- err <- ("(!!" { (!("!!)") .)* } "!!)") -> "(({} (%1) %%userdata) => error)"
- ident <- [a-zA-Z_][a-zA-Z0-9_]*
- comment <- "--" [^%nl]*
- ]]
- for version=1,Parser.version
- peg_file = io.open("nomsu.#{version}.peg")
- if not peg_file and package.nomsupath
- for path in package.nomsupath\gmatch("[^;]+")
- peg_file = io.open(path.."/nomsu.#{version}.peg")
- break if peg_file
- assert(peg_file, "could not find nomsu .peg file")
- nomsu_peg = peg_tidier\match(peg_file\read('*a'))
- peg_file\close!
- Parser.patterns[version] = re.compile(nomsu_peg, NOMSU_DEFS)
-
-_anon_chunk = 0
-Parser.parse = (nomsu_code, source=nil, version=nil)->
- source or= nomsu_code.source
- nomsu_code = tostring(nomsu_code)
- unless source
- source = Source("anonymous chunk ##{_anon_chunk}", 1, #nomsu_code)
- _anon_chunk += 1
- version or= nomsu_code\match("^#![^\n]*nomsu[ ]+-V[ ]*([0-9.]+)")
- syntax_version = version and tonumber(version\match("^[0-9]+")) or Parser.version
- userdata = {
- errors: {}, :source, comments: {}
- }
- tree = Parser.patterns[syntax_version]\match(nomsu_code, nil, userdata)
- if not tree or type(tree) == 'number'
- error "In file #{colored.blue tostring(source or "<unknown>")} failed to parse:\n#{colored.onyellow colored.black nomsu_code}"
-
- if next(userdata.errors)
- keys = [k for k,v in pairs(userdata.errors)]
- table.sort(keys)
- errors = [userdata.errors[k] for k in *keys]
- error("Errors occurred while parsing (v#{syntax_version}):\n\n"..table.concat(errors, "\n\n"), 0)
-
- comments = [{comment:c, pos:p} for p,c in pairs(userdata.comments)]
- -- Sort in descending order so we can pop the first comments off the end one at a time
- table.sort comments, (a,b)-> a.pos > b.pos
- comment_i = 1
- walk_tree = (t)->
- export comment_i
- comment_buff = {}
- while comments[#comments] and comments[#comments].pos <= t.source.start
- table.insert(comment_buff, table.remove(comments))
- for x in *t
- if AST.is_syntax_tree x
- walk_tree x
- while comments[#comments] and comments[#comments].pos <= t.source.stop
- table.insert(comment_buff, table.remove(comments))
- t.comments = comment_buff if #comment_buff > 0
- walk_tree tree
-
- return tree
+Parser = {version:4, patterns:{}}
Parser.is_operator = (s)->
return not not (NOMSU_DEFS.operator_char^1 * -1)\match(s)
diff --git a/pretty_errors.lua b/pretty_errors.lua
index 7402703..ae6b48f 100644
--- a/pretty_errors.lua
+++ b/pretty_errors.lua
@@ -42,6 +42,7 @@ format_error = function(err)
err_msg = err_msg .. "\n\027[2m" .. tostring(fmt_str:format(err_linenum)) .. tostring(err_line) .. "\027[0m"
end
local _, err_linenum_end, err_linepos_end = string2.line_at(err.source, err.stop)
+ err_linenum_end = err_linenum_end or err_linenum
if err_linenum_end == err_linenum then
err_msg = err_msg .. "\n" .. tostring(pointer)
else
diff --git a/pretty_errors.moon b/pretty_errors.moon
index 3b583b7..b0d81f9 100644
--- a/pretty_errors.moon
+++ b/pretty_errors.moon
@@ -34,6 +34,7 @@ format_error = (err)->
err_line = "\027[0m#{before}\027[41;30m#{during}#{nl_indicator}\027[0m#{after}"
err_msg ..= "\n\027[2m#{fmt_str\format(err_linenum)}#{err_line}\027[0m"
_, err_linenum_end, err_linepos_end = string2.line_at(err.source, err.stop)
+ err_linenum_end or= err_linenum
if err_linenum_end == err_linenum
err_msg ..= "\n#{pointer}"
else