aboutsummaryrefslogtreecommitdiff
path: root/nomsu.peg
blob: e7c8a7f7fc9defa424e0d42b97a19185469fc46e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
file:
    shebang?
    (ignored_line %nl)*
    (block / action / expression)?
    (%nl ignored_line)*
    (!. / (({} (.* -> "Parse error")) => error))

shebang: "#!" [^%nl]* (!. / %nl)

statement: (action / expression) (eol / (({} ([^%nl]* -> "Error while parsing line")) => error))
inline_statement: inline_action / inline_expression

inline_block (Block):
    {| inline_statement (%ws* ";" %ws*  inline_statement)+ |} -> Tuple
block (Block):
    {| statement (nodent (statement / (({} ([^%nl]* -> "Error while parsing block line")) => error)))+ |} -> Tuple

inline_nomsu (Nomsu): "\" noindex_inline_expression
indented_nomsu (Nomsu):
    "\" (noindex_inline_expression / (":" %ws* (inline_block / inline_action / inline_expression) eol) / indented_expression)

index_chain (IndexChain):
    {|
        noindex_inline_expression ("." (text_word / noindex_inline_expression))+
    |} -> Tuple

noindex_inline_expression:
    number / variable / inline_text / inline_list / inline_dict / inline_nomsu
    / ( "("
            %ws* (inline_block / inline_action / inline_expression) %ws*
        (")"
            / (({} ((!. / &%nl) -> 'Expected to find a ) before the end of the line')) => error)
            / (({} ([^%nl]* -> 'Error while parsing subexpression')) => error)
        )
      )

inline_expression:
    index_chain / noindex_inline_expression 
indented_expression:
    indented_text / indented_nomsu / indented_list / indented_dict
    / ("(..)"? indent
        (block / action / expression)
        (dedent / (({} (non_dedent_error -> "Error while parsing indented expression")) => error))
      )
expression:
    inline_expression / (":" %ws* (inline_block / inline_action / inline_expression) eol) / indented_expression

-- Function calls need at least one word in them
inline_action (Action):
    {| (inline_expression %ws*)* word (%ws* (inline_expression / word))*
        (%ws* ":" %ws* (inline_block / inline_action / inline_expression))?|} -> Tuple
action (Action):
    {| (expression (dotdot? %ws*))* word ((dotdot? %ws*) (expression / word))* |} -> Tuple

word (Word): { %operator / (!number plain_word) }

text_word (Text): {| {%operator / (!number plain_word)} |} -> Tuple

inline_text (Text):
    !('".."' eol)
    '"' ({|
        ({~ (('\"' -> '"') / ('\\' -> '\') / %escaped_char / [^%nl\"])+ ~}
        / inline_text_interpolation)*
    |} -> Tuple) ('"' / (({} ([^%nl]*->'Failed to find a closing " mark on the same line')) => error))

-- Have to use "%indent" instead of "indent" etc. to avoid messing up text lines that start with "#"
indented_text (Text):
    '".."' eol %nl ({|
        {~ (%nl*) (%indent -> "") ~}
        ({~
            (("\\" -> "\") / (("\" nodent "..") -> "")/ (%nl+ {~ %nodent -> "" ~}) / [^%nl\] / (!text_interpolation "\"))+
        ~} / text_interpolation)*
    |} -> Tuple) (((!.) &%dedent) / (&(%nl %dedent)) / (({} (non_dedent_error -> "Error while parsing Text")) => error))
inline_text_interpolation:
    "\" (
        variable / inline_list / inline_dict / inline_text
        / ("("
            %ws* (inline_block / inline_action / inline_expression) %ws*
        (")"
            / (({} (&%nl -> 'Expected to find a ")" before the end of the line')) => error)
            / (({} ([^%nl]* -> 'Error while parsing text interpolation')) => error))
        )
    )
text_interpolation:
    inline_text_interpolation /
    ("\" indented_expression nodent "..")

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?)? |} -> Tuple) %ws*
    ("]" / (({} ([^%nl]*->"Failed to find a closing ] on the same line")) => error))
indented_list (List):
    "[..]" indent ({|
        list_line (nodent list_line)*
    |} -> Tuple)
    (dedent / (({} (non_dedent_error -> "Error while parsing list")) => error))
list_line:
     ((action / expression) !comma)
     / (inline_list_item (comma list_line?)?)
inline_list_item: inline_block / inline_action / inline_expression

inline_dict (Dict):
    !('{..}')
    "{" %ws* ({| (inline_dict_entry (comma inline_dict_entry)*)? |} -> Tuple) %ws*
    ("}"
      / (({} (%ws* comma? (!. / &%nl)->"Failed to find a closing } on the same line")) => error)
      / (({} ([^%nl]*->"Error while parsing dictionary")) => error))
indented_dict (Dict):
    "{..}" indent ({|
        dict_line (nodent dict_line)*
    |} -> Tuple)
    (dedent / (({} (non_dedent_error -> "Error while parsing dict")) => error))
dict_line:
    (dict_entry !comma) / (inline_dict_entry (comma dict_line?)?)
dict_entry(DictEntry):
    {| dict_key %ws* ":" %ws* (action / expression) |} -> Tuple
inline_dict_entry(DictEntry):
    {| dict_key %ws* (":" %ws* (inline_block / inline_action / inline_expression)?) |} -> Tuple
dict_key:
    text_word / inline_expression

comment: "#" [^%nl]* (%nl+ %indent [^%nl]* (%nl+ %nodent [^%nl]*)* %dedent)?
eol_comment: "#" [^%nl]*

eol: %ws* eol_comment? (!. / &%nl)
ignored_line: (%nodent comment) / (%ws* (!. / &%nl))
indent: eol (%nl ignored_line)* %nl %indent (comment (%nl ignored_line)* nodent)?
nodent: eol (%nl ignored_line)* %nl %nodent
dedent: eol (%nl ignored_line)* (((!.) &%dedent) / (&(%nl %dedent)))
non_dedent_error: (!dedent .)* eol (%nl ignored_line)* (!. / &%nl)
comma: %ws* "," %ws*
dotdot: nodent ".."
plain_word: ([a-zA-Z0-9_] / %utf8_char)+