nomsu/nomsu.peg
Bruce Hill f97ab858ed Modernized the codebase a bit to include "immediately:" for immediately
running code before further parsing takes place. That means that in the
default case, whole files can be run at once, which makes all but the
weirdest edge cases make a lot more sense and operate smoothly.
2018-01-08 18:53:57 -08:00

104 lines
4.1 KiB
Plaintext

file (File):
{| shebang?
(ignored_line %nl)*
statement (nodent statement)*
(%nl ignored_line)*
(!. / (("" -> "Parse error") => error)?) |}
shebang: "#!" [^%nl]* %nl
statement: functioncall / expression
noeol_statement: noeol_functioncall / noeol_expression
inline_statement: inline_functioncall / inline_expression
inline_block (Block): {| ":" %ws* inline_statement |}
eol_block (Block): {| ":" %ws* noeol_statement eol |}
indented_block (Block):
{| ":" indent
statement (nodent statement)*
(dedent / (("" -> "Error while parsing block") => error))
|}
inline_nomsu (Nomsu): "\" inline_expression
eol_nomsu (Nomsu): "\" noeol_expression
indented_nomsu (Nomsu): "\" expression
inline_expression:
number / variable / inline_string / inline_list / inline_dict / inline_nomsu
/ ("(" %ws* (inline_block / inline_statement) %ws* ")")
noeol_expression:
indented_string / indented_nomsu / indented_list / indented_dict / indented_block
/ ("(..)" indent
statement
(dedent / (("" -> "Error while parsing indented expression") => error))
) / inline_expression
expression: eol_block / eol_nomsu / noeol_expression
-- Function calls need at least one word in them
inline_functioncall (FunctionCall):
{| (inline_expression %ws*)* word (%ws* (inline_expression / word))* (%ws* inline_block)?|}
noeol_functioncall (FunctionCall):
{| (noeol_expression %ws*)* word (%ws* (noeol_expression / word))* |}
functioncall (FunctionCall):
{| (expression (dotdot / %ws*))* word ((dotdot / %ws*) (expression / word))* |}
word (Word): { %operator / (!number plain_word) }
inline_string (String):
'"' {|
({~ (('\"' -> '"') / ('\\' -> '\') / ('\..' -> '..') / %escape_char / [^%nl\"])+ ~}
/ string_interpolation)*
|} '"'
indented_string (String):
'".."' %ws* line_comment? %nl %gt_nodented? {|
({~
(("\\" -> "\") / (("\" eol %nl %gt_nodented "..") -> "")
/ (%nl+ {~ %gt_nodented -> "" ~}) / [^%nl\])+
~} / string_interpolation)*
|} ((!.) / (&(%nl+ !%gt_nodented)) / (("" -> "Error while parsing String") => error))
string_interpolation:
"\" (variable / inline_list / inline_dict / inline_string / ("(" %ws* (inline_block / inline_statement) %ws* ")"))
number (Number): (("-"? (([0-9]+ "." [0-9]+) / ("." [0-9]+) / ([0-9]+)))-> tonumber)
-- Variables can be nameless (i.e. just %) and can't contain operators like apostrophe
-- which is a hack to allow %'s to parse as "%" and "' s" separately
variable (Var): "%" { plain_word? }
inline_list (List):
"[" %ws* {| (inline_list_item (comma inline_list_item)* comma?)? |} %ws* "]"
indented_list (List):
"[..]" indent {|
list_line (nodent list_line)*
|}
(dedent / (("" -> "Error while parsing list") => error))
list_line:
(inline_list_item (comma inline_list_item)* (comma (functioncall / expression)?)?)
/ (functioncall / expression)
inline_list_item: inline_functioncall / inline_expression
inline_dict (Dict):
"{" %ws* {| (inline_dict_item (comma inline_dict_item)* comma?)? |} %ws* "}"
indented_dict (Dict):
"{..}" indent {|
dict_line (nodent dict_line)*
|}
(dedent / (("" -> "Error while parsing dict") => error))
dict_line:
(inline_dict_item (comma inline_dict_item)* (comma (functioncall / expression)?)?)
/ {| {:dict_key: inline_expression / word :} %ws* "=" %ws* {:dict_value: functioncall / expression :} |}
inline_dict_item:
{| {:dict_key: inline_expression / word :} %ws* "=" %ws* {:dict_value: inline_functioncall / inline_expression :} |}
block_comment: "#.." [^%nl]* (%nl (%ws* &%nl))* %nl %indented [^%nl]+ (%nl ((%ws* ((!.) / &%nl)) / (!%dedented [^%nl]+)))*
line_comment: "#" [^%nl]*
eol: %ws* line_comment? (!. / &%nl)
ignored_line: (%nodented (block_comment / line_comment)) / (%ws* (!. / &%nl))
indent: eol (%nl ignored_line)* %nl %indented ((block_comment/line_comment) (%nl ignored_line)* nodent)?
nodent: eol (%nl ignored_line)* %nl %nodented
dedent: eol (%nl ignored_line)* (((!.) &%dedented) / (&(%nl %dedented)))
comma: %ws* "," %ws*
dotdot: nodent ".." %ws*
plain_word: ([a-zA-Z0-9_] / %utf8_char)+