-- Nomsu version 2
file (File):
    %nl*
    {:curr_indent: ' '* :}
    (chunk (nl_nodent chunk_delimeter nl_nodent chunk)*)?
    %nl*
    (!! .+ -> "Parse error" !!)?

nodent: =curr_indent !(" ")
indent: =curr_indent "    "
blank_lines: %nl (%ws* %nl)*
eol: (!. / &%nl)

comment (Comment):
    !inline_comment
    "#" {~ [^%nl]* (blank_lines (indent -> '') [^%nl]*)* ~}
inline_comment (Comment):
    "#(" {~ (inline_comment / [^%nl])* ~} ")#"

nl_nodent: blank_lines nodent
nl_indent: blank_lines {:curr_indent: indent :}

chunk: block / ((comment nl_nodent)* (action / expression)? (nl_nodent comment)*)
chunk_delimeter: ("~")^+3

inline_block (Block):
    inline_statement (%ws* ";" %ws* inline_statement)+ (%ws* inline_comment)*
block (Block):
    block_line (nl_nodent block_line)+ (nl_nodent comment)*
block_line:
    statement %ws* (!! [^%nl]+ -> "Unexpected character while parsing block line" !!)?

statement: (comment nl_nodent)* (action / expression) %ws* (!! [^%nl]+ -> "Unexpected character while parsing line" !!)?
inline_statement: (inline_comment %ws*)* (inline_action / inline_expression)

noindex_inline_expression:
    number / variable / inline_text / inline_list / inline_dict / inline_nomsu
    / ( "("
            %ws* (inline_block / inline_action / inline_expression) %ws*
            (%ws* ',' %ws* (inline_block / inline_action / inline_expression) %ws*)*
        (")"
            / (!! %ws* eol -> 'Line ended without finding a closing )-parenthesis' !!)
            / (!! [^%nl]+ -> 'Unexpected character while parsing subexpression' !!)
        )
      )
inline_expression: index_chain / noindex_inline_expression 
indented_expression:
    indented_text / indented_nomsu / indented_list / indented_dict / ({|
        ("(..)" / ":")? nl_indent (comment nl_nodent)*
            (block / action / expression)
            (!! [^%nl]+ -> "Unexpected character while parsing indented expression" !!)?
    |} -> unpack)
expression:
    inline_expression
    / (":" %ws*
        (!! eol -> "Missing expression after the ':'" !!)?
        (inline_block / inline_action / inline_expression) %ws* eol)
    / indented_expression

inline_nomsu (EscapedNomsu): "\" inline_expression
indented_nomsu (EscapedNomsu):
    "\" (
        noindex_inline_expression
        / (":" %ws*
            (!! eol -> "Missing expression after the '\:'" !!)?
            (inline_block / inline_action / inline_expression) %ws* eol)
        / indented_expression)

index_chain (IndexChain):
    noindex_inline_expression ("." (text_word / noindex_inline_expression))+

-- Actions need either at least 1 word, or at least 2 tokens
inline_action (Action):
    !chunk_delimeter
    (inline_comment %ws*)* 
    (   (inline_expression ((%ws* inline_comment)* %ws* (inline_expression / word))+)
      / (word              ((%ws* inline_comment)* %ws* (inline_expression / word))*))
    ((%ws* inline_comment)* %ws* ":" %ws* (inline_block / inline_action / inline_expression
        / (!! '' -> "Missing expression after the ':'" !!)))?
action (Action):
    !chunk_delimeter
    (inline_comment %ws*)* 
    (  (expression (((nl_nodent comment)* nl_nodent "..")? %ws* (inline_comment %ws*)* (expression / word))+)
     / (word       (((nl_nodent comment)* nl_nodent "..")? %ws* (inline_comment %ws*)* (expression / word))*))

word: !number { %operator_char+ / %ident_char+ }

text_word (Text): word

inline_text (Text):
    !('".."' %ws* eol)
    '"'
        ({~ (('\"' -> '"') / ('\\' -> '\') / %escaped_char / [^%nl\"])+ ~}
        / inline_text_interpolation)*
    ('"'
     / (!! eol -> 'Line ended before finding a closing double quotation mark' !!)
     / (!! [^%nl]+ -> 'Unexpected character while parsing Text' !!))
inline_text_interpolation:
    "\" (
        variable / inline_list / inline_dict / inline_text
        / ("("
            %ws* (inline_block / inline_action / inline_expression) %ws*
            (%ws* ',' %ws* (inline_block / inline_action / inline_expression) %ws*)*
        (")"
         / (!! %ws* eol -> 'Line ended without finding a closing )-parenthesis' !!)
         / (!! [^%nl]+ -> 'Unexpected character while parsing Text interpolation' !!)))
    )

indented_text (Text):
    '".."' %ws* %nl {:curr_indent: indent :}
        (indented_plain_text / text_interpolation / {~ blank_lines (=curr_indent -> "") ~})*
    (!! [^%nl]+ -> "Unexpected character while parsing Text" !!)?
indented_plain_text (Text):
    {~ (("\\" -> "\") / (("\" (blank_lines =curr_indent comment)* blank_lines =curr_indent "..") -> "") / (!text_interpolation "\") / [^%nl\]+)+
        (blank_lines (=curr_indent -> ""))* ~}
text_interpolation:
    inline_text_interpolation / ("\" indented_expression blank_lines =curr_indent "..")

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): "%" {(%ident_char+ ((!"'" %operator_char+) / %ident_char+)*)?}

inline_list (List):
    !('[..]')
    "[" %ws*
        (inline_list_item (%ws* ',' %ws* inline_list_item)* (%ws* ',')?)? %ws*
    ("]" / (","? (
        (!! %ws* eol -> "Line ended before finding a closing ]-bracket" !!)
       /(!! [^%nl]+ -> "Unexpected character while parsing List" !!)?
    )))
indented_list (List):
    "[..]" nl_indent (comment nl_nodent)*
        list_line (nl_nodent list_line)*
    (","? (!! [^%nl]+ -> "Unexpected character while parsing List" !!))?
list_line:
      (inline_list_item %ws* "," %ws*)+ %ws* eol
    / (inline_list_item %ws* "," %ws*)* (action / expression)
inline_list_item: inline_block / inline_action / inline_expression

inline_dict (Dict):
    !('{..}')
    "{" %ws*
        (inline_dict_entry (%ws* ',' %ws* inline_dict_entry)*)? %ws*
    ("}" / (","? (
        (!! %ws* eol -> "Line ended before finding a closing }-brace" !!)
      / (!! [^%nl]* -> "Unexpected character while parsing Dictionary" !!)
    )))
indented_dict (Dict):
    "{..}" nl_indent (comment nl_nodent)*
        dict_line ((nl_nodent comment)* nl_nodent dict_line)* (nl_nodent comment)*
    (","? (!! [^%nl]+ -> "Unexpected character while parsing Dictionary" !!))?
dict_line:
      (inline_dict_entry %ws* "," %ws*)+ %ws* eol
    / (inline_dict_entry %ws* "," %ws*)* dict_entry
dict_entry(DictEntry):
    dict_key (%ws* ":" %ws* (action / expression))?
inline_dict_entry(DictEntry):
    dict_key (%ws* ":" %ws* (inline_block / inline_action / inline_expression)?)?
dict_key:
    text_word / inline_expression