mix-language 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,238 @@
1
+ # encoding: UTF-8
2
+ #
3
+ # Copyright © 2011 Jesse Sielaff
4
+ #
5
+
6
+ class MixCompiler
7
+ options no_result_var
8
+
9
+ prechigh
10
+ right '!'
11
+ right '-·' '-1'
12
+ left '*' '/' '%'
13
+ left '+' '-'
14
+ left '<<' '>>'
15
+ left '<' '<=' '>' '>='
16
+ nonassoc '==' '!='
17
+ left '&&'
18
+ left '||'
19
+ right '?' ':'
20
+ right '=' '&&=' '||=' '·='
21
+ nonassoc IF UNLESS WHILE UNTIL
22
+ preclow
23
+
24
+ rule
25
+ statements
26
+ : statement
27
+ | statements statement { append_statement(val[0], val[1]) }
28
+
29
+ statement
30
+ : indented_statement { newline node(:statement, val[0], nil) }
31
+ | inline_statements opt_semicolon newline { newline val[0] }
32
+
33
+ opt_semicolon
34
+ : # nothing
35
+ | ';'
36
+
37
+ newline
38
+ : NEWLINE { @location = val[0][1] }
39
+
40
+ indented_statement
41
+ : mixin_statement
42
+ | control_statement
43
+ | function_statement
44
+
45
+ mixin_statement
46
+ : MIXIN ':' newline INDENT mixin_body OUTDENT { node :mixin, val[0][0], val[4] }
47
+
48
+ mixin_body
49
+ : statements { [val[0], []] }
50
+ | definitions { [newline(node(:null)), val[0]] }
51
+ | statements definitions { [val[0], val[1]] }
52
+
53
+ definitions
54
+ : definition { [val[0]] }
55
+ | definitions definition { val[0] << val[1] }
56
+
57
+ definition
58
+ : IDENTIFIER function_block { node :set, node(:access_hash, node(:self), val[0][0]), val[1] }
59
+ | IDENTIFIER inline_function newline { node :newline, @location, node(:set, node(:access_hash, node(:self), val[0][0]), val[1]) }
60
+
61
+ function_block
62
+ : parameter_list indent_block { node :function, pop_variables, val[1] }
63
+
64
+ parameter_list
65
+ : '#' { push_variables; nil }
66
+ | '|' { push_variables } parameters '|' { nil }
67
+
68
+ parameters
69
+ : IDENTIFIER { parameter val[0][0]; nil }
70
+ | parameters ',' IDENTIFIER { parameter val[2][0]; nil }
71
+
72
+ indent_block
73
+ : newline INDENT statements OUTDENT { val[2] }
74
+
75
+ control_statement
76
+ : IF exp indent_block else_statement { node :if, val[1], val[2], val[3] }
77
+ | UNLESS exp indent_block opt_else { node :if, val[1], val[3], val[2] }
78
+ | WHILE exp indent_block { node :while, val[1], val[2] }
79
+ | UNTIL exp indent_block { node :while, node(:not, val[1]), val[2] }
80
+ | SWITCH exp newline INDENT cases opt_else OUTDENT { node :switch, val[1], val[4], val[5] }
81
+
82
+ else_statement
83
+ : opt_else
84
+ | ELSIF exp indent_block else_statement { node :if, val[1], val[2], val[3] }
85
+
86
+ opt_else
87
+ : { node :null }
88
+ | ELSE indent_block { val[1] }
89
+
90
+ cases
91
+ : case { [val[0]] }
92
+ | cases case { val[0] << val[1] }
93
+
94
+ case
95
+ : CASE exp indent_block { [node(:newline, @location, val[1]), val[2]] }
96
+ | CASE exp ':' inline_statements newline { [node(:newline, @location, val[1]), val[3]] }
97
+
98
+ inline_statements
99
+ : inline_statement { node :statement, val[0], nil }
100
+ | inline_statements ';' inline_statement { append_statement(val[0], node(:statement, val[2], nil)) }
101
+
102
+ inline_statement
103
+ : postfix_statement
104
+ | mix_statement
105
+ | keyword_statement
106
+ | exp
107
+
108
+ postfix_statement
109
+ : inline_statement IF exp { node :if, val[2], val[0], node(:null) }
110
+ | inline_statement UNLESS exp { node :if, val[2], node(:null), val[0] }
111
+ | inline_statement WHILE exp { node :while, val[2], val[0] }
112
+ | inline_statement UNTIL exp { node :while, node(:not, val[2]), val[0] }
113
+
114
+ mix_statement
115
+ : '+' MIXIN object { node :mix, val[2], val[1][0] }
116
+ | '+' MIXIN { node :mix, node(:self), val[1][0] }
117
+
118
+ keyword_statement
119
+ : BREAK exp { node :break, val[1] }
120
+ | BREAK { node :break, node(:null) }
121
+ | RETURN exp { node :return, val[1] }
122
+ | RETURN { node :return, node(:null) }
123
+
124
+ function_statement
125
+ : function_block
126
+ | dot_access function_block { node :call, val[0], [val[1]] }
127
+ | dot_access '(' arguments ')' function_block { node :call, val[0], val[2] << val[4] }
128
+ | functional_object '(' arguments ')' function_block { node :call, val[0], val[2] << val[4] }
129
+ | lhs '=' function_statement { node :set, val[0], val[2] }
130
+
131
+ dot_access
132
+ : object '.' IDENTIFIER { node :access_hash, val[0], val[2][0] }
133
+ | '.' IDENTIFIER { node :access_hash, node(:self), val[1][0] }
134
+
135
+ arguments
136
+ : exp { [val[0]] }
137
+ | arguments ',' exp { val[0] << val[2] }
138
+ | { [] }
139
+
140
+ lhs
141
+ : object '·[' exp ']' { node :access_brackets, val[0], val[2] }
142
+ | object '·#' IDENTIFIER { node :access_hash, val[0], val[2][0] }
143
+ | object '·:' IDENTIFIER { node :access_colon, val[0], val[2][0] }
144
+ | '#' IDENTIFIER { node :access_hash, node(:self), val[1][0] }
145
+ | ':' IDENTIFIER { node :access_colon, node(:self), val[1][0] }
146
+ | IDENTIFIER { variable val[0][0] }
147
+
148
+ exp
149
+ : lhs '=' exp { node :set, val[0], val[2] }
150
+ | lhs '&&=' exp { node :set, val[0], node(:and, val[0], val[2]) }
151
+ | lhs '||=' exp { node :set, val[0], node(:or, val[0], val[2]) }
152
+ | lhs '·=' exp { node :set, val[0], node(:op, val[1][0], val[0], val[2]) }
153
+ | '!' exp { node :not, val[1] }
154
+ | '-·' exp { node :op, "-", node(:number, "0"), val[1] }
155
+ | exp '*' exp { node :op, val[1][0], val[0], val[2] }
156
+ | exp '/' exp { node :op, val[1][0], val[0], val[2] }
157
+ | exp '%' exp { node :op, val[1][0], val[0], val[2] }
158
+ | exp '+' exp { node :op, val[1][0], val[0], val[2] }
159
+ | exp '-' exp { node :op, val[1][0], val[0], val[2] }
160
+ | exp '<<' exp { node :op, val[1][0], val[0], val[2] }
161
+ | exp '>>' exp { node :op, val[1][0], val[0], val[2] }
162
+ | exp '<' exp { node :op, val[1][0], val[0], val[2] }
163
+ | exp '<=' exp { node :op, val[1][0], val[0], val[2] }
164
+ | exp '>' exp { node :op, val[1][0], val[0], val[2] }
165
+ | exp '>=' exp { node :op, val[1][0], val[0], val[2] }
166
+ | exp '==' exp { node :op, val[1][0], val[0], val[2] }
167
+ | exp '!=' exp { node :op, val[1][0], val[0], val[2] }
168
+ | exp '&&' exp { node :and, val[0], val[2] }
169
+ | exp '||' exp { node :or, val[0], val[2] }
170
+ | exp '?' exp ':' exp { node :if, val[0], val[2], val[4] }
171
+ | object
172
+
173
+ object
174
+ : literal
175
+ | functional_object
176
+ | dot_access { node :call, val[0], [] }
177
+
178
+ literal
179
+ : literal_number
180
+ | literal_string
181
+ | literal_constant
182
+ | literal_array
183
+ | literal_object
184
+
185
+ literal_number
186
+ : NUMBER { node :number, val[0][0] }
187
+ | '-1' NUMBER { node :number, -val[1][0] }
188
+
189
+ literal_string
190
+ : '\'' STRING '\'' { node :string, val[1][0] }
191
+
192
+ literal_constant
193
+ : APP { node :app }
194
+ | FALSE { node :false }
195
+ | NULL { node :null }
196
+ | SELF { node :self }
197
+ | TRUE { node :true }
198
+
199
+ literal_array
200
+ : '[' arguments opt_comma ']' { node :array, val[1] }
201
+
202
+ opt_comma
203
+ : # nothing
204
+ | ','
205
+
206
+ literal_object
207
+ : '{' fields opt_comma '}' { node :object, val[1], [] }
208
+ | MIXIN { node :object, [], [val[0][0]] }
209
+ | MIXIN literal_object { val[1][:values][1] << val[0][0]; val[1] }
210
+
211
+ fields
212
+ : KEY exp { [[val[0][0], val[1]]]}
213
+ | fields ',' KEY exp { val[0] << [val[2][0], val[3]] }
214
+ | { [] }
215
+
216
+ functional_object
217
+ : lhs
218
+ | parenthetical
219
+ | inline_function
220
+ | call
221
+
222
+ parenthetical
223
+ : '(' inline_statements ')' { val[1] }
224
+
225
+ inline_function
226
+ : parameter_list curly_brace_block { node :function, pop_variables, val[1] }
227
+
228
+ curly_brace_block
229
+ : '{' inline_statements '}' { val[1] }
230
+ | '{' '}' { node :null }
231
+
232
+ call
233
+ : functional_object '(' arguments ')' inline_function { node :call, val[0], val[2] << val[4] }
234
+ | functional_object '(' arguments ')' { node :call, val[0], val[2] }
235
+ | dot_access '(' arguments ')' inline_function { node :call, val[0], val[2] << val[4] }
236
+ | dot_access '(' arguments ')' { node :call, val[0], val[2] }
237
+ | dot_access inline_function { node :call, val[0], [val[1]] }
238
+ end