mix-language 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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