aboutsummaryrefslogtreecommitdiff
path: root/nomsu.peg
blob: bf2c6397d2bd2862ab07ff7c828fcce04f11bf05 (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
file (File):
    {| shebang?
        (ignored_line %nl)*
        statement (nodent statement)*
        (%nl ignored_line)*
    (!. / (("" -> "Parse error") => error)?) |} -> Tuple

shebang: "#!" [^%nl]* %nl

statement: action / expression

indented_block (Block):
    {| (":" / "(..)")? indent
            statement (nodent statement)*
        (dedent / (("" -> "Error while parsing block") => error))
    |} -> Tuple

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

index_chain (IndexChain):
    {| noindex_inline_expression ("." ((({} ({|{%operator / (!number plain_word)}|} -> Tuple) {}) -> Text) / noindex_inline_expression))+ |} -> Tuple

noindex_inline_expression:
    number / variable / inline_text / inline_list / inline_dict / inline_nomsu
    / ("(" %ws* (inline_action / inline_expression) %ws* ")")

inline_expression:
    index_chain / noindex_inline_expression 
indented_expression:
    indented_text / indented_nomsu / indented_list / indented_dict / indented_block
expression:
    inline_expression / (":" %ws* (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_action / inline_expression))?|} -> Tuple
action (Action):
    {| (expression (dotdot / %ws*))* word ((dotdot / %ws*) (expression / word))* |} -> Tuple

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

inline_text (Text):
    !('".."' eol)
    '"' ({|
        ({~ (('\"' -> '"') / ('\\' -> '\') / %escaped_char / [^%nl\"])+ ~}
        / inline_text_interpolation)*
    |} -> Tuple) '"'
-- Have to use "%indent" instead of "indent" etc. to avoid messing up text lines that start with "#"
indented_text (Text):
    '".."' eol %nl ({|
        {~ (%nl*) (%indent -> "") ~}
        ({~
            (("\\" -> "\") / (("\" eol %nl+ %nodent "..") -> "")
            / (%nl+ {~ %nodent -> "" ~}) / [^%nl\])+
        ~} / text_interpolation)*
    |} -> Tuple) (((!.) &%dedent) / (&(%nl %dedent)) / (("" -> "Error while parsing Text") => error))
inline_text_interpolation:
    "\" (
        variable / inline_list / inline_dict / inline_text
        / ("(" %ws* (inline_action / inline_expression) %ws* ")")
    )
text_interpolation:
    inline_text_interpolation /
    ("\" (
        variable / inline_list / inline_dict / inline_text
        / ("(" %ws* (inline_action / inline_expression) %ws* ")")
        / (%ws* (block_comment / line_comment)? nodent "..")
        / (indented_text %nl+ %nodent "..")
        / ((indented_list / indented_block) 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* "]"
indented_list (List):
    "[..]" indent ({|
        list_line (nodent list_line)*
    |} -> Tuple)
    (dedent / (("" -> "Error while parsing list") => error))
list_line:
     ((action / expression) !comma)
     / (inline_list_item (comma list_line?)?)
inline_list_item: inline_action / inline_expression

inline_dict (Dict):
    !('{..}')
    "{" %ws* ({| (inline_dict_item (comma inline_dict_item)* comma?)? |} -> Tuple) %ws* "}"
indented_dict (Dict):
    "{..}" indent ({|
        dict_line (nodent dict_line)*
    |} -> Tuple)
    (dedent / (("" -> "Error while parsing dict") => error))
dict_line:
    ((dict_key %ws* ":" %ws* (action / expression)) -> DictEntry !comma)
    / (inline_dict_item (comma dict_line?)?)
inline_dict_item:
    (dict_key %ws* ":" %ws* (inline_action / inline_expression)) -> DictEntry
dict_key:
    (({} ({|{%operator / (!number plain_word)}|} -> Tuple) {}) -> Text) / inline_expression

block_comment: "#.." [^%nl]* (%nl+ %indent [^%nl]* (%nl+ %nodent [^%nl]*)* %dedent)?
line_comment: "#" [^%nl]*

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