delorean_lang 0.0.33

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,45 @@
1
+ module Delorean
2
+ ######################################################################
3
+ # Parse Errors
4
+
5
+ class ParseError < StandardError
6
+ attr_reader :line, :module_name
7
+
8
+ def initialize(message, module_name, line)
9
+ super(message)
10
+ @line = line
11
+ @module_name = module_name
12
+ end
13
+ end
14
+
15
+ class UndefinedError < ParseError
16
+ end
17
+
18
+ class RedefinedError < ParseError
19
+ end
20
+
21
+ class UndefinedFunctionError < ParseError
22
+ end
23
+
24
+ class UndefinedNodeError < ParseError
25
+ end
26
+
27
+ class RecursionError < ParseError
28
+ end
29
+
30
+ class BadCallError < ParseError
31
+ end
32
+
33
+ class ImportError < ParseError
34
+ end
35
+
36
+ ######################################################################
37
+ # Runtime Errors
38
+
39
+ class InvalidGetAttribute < StandardError
40
+ end
41
+
42
+ class UndefinedParamError < StandardError
43
+ end
44
+
45
+ end
@@ -0,0 +1,134 @@
1
+ module Delorean
2
+ module Functions
3
+ ######################################################################
4
+
5
+ def MAX(*args)
6
+ args.max
7
+ end
8
+
9
+ MAX_SIG = [ 2, Float::INFINITY ]
10
+
11
+ ######################################################################
12
+
13
+ def MIN(*args)
14
+ args.min
15
+ end
16
+
17
+ MIN_SIG = MAX_SIG
18
+
19
+ ######################################################################
20
+
21
+ def MAXLIST(arg)
22
+ raise "argument must be list" unless arg.is_a? Array
23
+ arg.max
24
+ end
25
+
26
+ MAXLIST_SIG = [ 1, 1 ]
27
+
28
+ def MINLIST(arg)
29
+ raise "argument must be list" unless arg.is_a? Array
30
+ arg.min
31
+ end
32
+
33
+ MINLIST_SIG = [ 1, 1 ]
34
+
35
+ ######################################################################
36
+
37
+ def ROUND(number, *args)
38
+ number.round(*args)
39
+ end
40
+
41
+ ROUND_SIG = [ 1, 2 ]
42
+
43
+ ######################################################################
44
+
45
+ def TIMEPART(time, part)
46
+ if time == Float::INFINITY
47
+ return time if part == "d"
48
+ raise "Can only access date part of Infinity"
49
+ end
50
+
51
+ raise "non-time arg to TIMEPART" unless time.is_a?(Time)
52
+
53
+ return time.hour if part == "h"
54
+ return time.min if part == "m"
55
+ return time.sec if part == "s"
56
+ return time.to_date if part == "d"
57
+
58
+ raise "unknown part arg to TIMEPART"
59
+ end
60
+
61
+ TIMEPART_SIG = [ 2, 2 ]
62
+
63
+ ######################################################################
64
+
65
+ def DATEPART(date, part)
66
+ raise "non-date arg to DATEPART" unless date.is_a?(Date)
67
+
68
+ return date.month if part == "m"
69
+ return date.day if part == "d"
70
+ return date.year if part == "y"
71
+
72
+ raise "unknown part arg to DATEPART"
73
+ end
74
+
75
+ DATEPART_SIG = [ 2, 2 ]
76
+
77
+ ######################################################################
78
+
79
+ def DATEADD(date, interval, part)
80
+ raise "non-date arg to DATEADD" unless date.is_a?(Date)
81
+ raise "non-integer interval arg to DATEADD" unless interval.is_a?(Fixnum)
82
+
83
+ return date >> interval if part == "m"
84
+ return date + interval if part == "d"
85
+ return date >> (interval * 12) if part == "y"
86
+
87
+ raise "unknown part arg to DATEADD"
88
+ end
89
+
90
+ DATEADD_SIG = [ 3, 3 ]
91
+
92
+ ######################################################################
93
+
94
+ def INDEX(array, i)
95
+ raise "non-array arg to INDEX" unless array.is_a?(Array)
96
+ raise "non-integer index on call to INDEX" unless i.is_a?(Fixnum)
97
+ array.at(i)
98
+ end
99
+
100
+ INDEX_SIG = [ 2, 2 ]
101
+
102
+ ######################################################################
103
+
104
+ def FLATTEN(array, *args)
105
+ raise "non-array arg to FLATTEN" unless array.is_a?(Array)
106
+ raise "non-integer flatten on call to FLATTEN" unless
107
+ (args.empty? || args[0].is_a?(Fixnum))
108
+ array.flatten(*args)
109
+ end
110
+
111
+ FLATTEN_SIG = [ 1, 2 ]
112
+
113
+ ######################################################################
114
+
115
+ def ERR(*args)
116
+ str = args.map(&:to_s).join(", ")
117
+ raise str
118
+ end
119
+
120
+ ERR_SIG = [ 1, Float::INFINITY ]
121
+
122
+ ######################################################################
123
+
124
+ def TOSYM(s)
125
+ # raise "non-String arg to SYM" unless s.is_a?(String)
126
+ s.to_sym
127
+ end
128
+
129
+ TOSYM_SIG = [ 1, 1 ]
130
+
131
+ ######################################################################
132
+
133
+ end
134
+ end
@@ -0,0 +1,25 @@
1
+ module Delorean
2
+ module Model
3
+ def self.included(base)
4
+ base.send :extend, ClassMethods
5
+ end
6
+
7
+ module ClassMethods
8
+ def delorean_fn(name, options = {}, &block)
9
+ define_singleton_method(name) do |*args|
10
+ block.call(*args)
11
+ end
12
+
13
+ sig = options[:sig]
14
+
15
+ raise "no signature" unless sig
16
+
17
+ if sig
18
+ sig = [sig, sig] if sig.is_a? Fixnum
19
+ raise "Bad signature" unless (sig.is_a? Array and sig.length==2)
20
+ self.const_set(name.to_s.upcase+SIG, sig)
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,401 @@
1
+ module Delorean
2
+ class SNode < Treetop::Runtime::SyntaxNode
3
+ end
4
+
5
+ class Line < SNode
6
+ def check(context, *a)
7
+ f.check(context, *a)
8
+ end
9
+ def rewrite(context)
10
+ f.rewrite(context)
11
+ end
12
+ end
13
+
14
+ class Parameter < SNode
15
+ def check(context, *)
16
+ context.parse_define_param(i.text_value, [])
17
+ end
18
+
19
+ def rewrite(context)
20
+ # Adds a parameter to the current node. Parameters are
21
+ # implemented as functions (just like attrs). The environment
22
+ # arg (_e) is a Hash. To find a param (aname) in node (cname),
23
+ # we first check to see if cname.aname has already been computed
24
+ # in _e. If not, to compute it we check for the value in _e
25
+ # (i.e. check for aname). Otherwise, we use the default value
26
+ # if any.
27
+ aname, cname = i.text_value, context.last_node
28
+ exc = "raise UndefinedParamError, 'undefined parameter #{aname}'"
29
+ <<eos
30
+ class #{cname}
31
+ def self.#{aname}#{POST}(_e)
32
+ _e['#{cname}.#{aname}'] ||=
33
+ begin
34
+ _e.fetch('#{aname}')
35
+ rescue KeyError
36
+ #{defined?(e) ? e.rewrite(context) : exc}
37
+ end
38
+ end
39
+ end
40
+ eos
41
+ end
42
+ end
43
+
44
+ class ParameterDefault < Parameter
45
+ def check(context, *)
46
+ # The check function returns the list of attrs used in the
47
+ # default expression. This is then used to make check if the
48
+ # attrs are available in the param's context. NOTE: in a
49
+ # previous implementation, spec used to include attr type
50
+ # information so that we could perform static type checking.
51
+ # This mechanism has been removed.
52
+ spec = e.check(context)
53
+ context.parse_define_param(i.text_value, spec)
54
+ end
55
+ end
56
+
57
+ class Import < SNode
58
+ def check(context, sset)
59
+ context.parse_import(sset, n.text_value, v.text_value)
60
+ end
61
+
62
+ def rewrite(context)
63
+ context.gen_import(n.text_value, v.text_value)
64
+ ""
65
+ end
66
+ end
67
+
68
+ class BaseNode < SNode
69
+ # defines a base node
70
+ def check(context, *)
71
+ context.parse_define_node(n.text_value, nil)
72
+ end
73
+
74
+ def rewrite(context)
75
+ # Nodes are simply translated to classes.
76
+ "class #{n.text_value} < BaseClass; end"
77
+ end
78
+ end
79
+
80
+ class SubNode < SNode
81
+ def check(context, *)
82
+ mname = mod.m.text_value if defined?(mod.m)
83
+
84
+ context.parse_define_node(n.text_value, p.text_value, mname)
85
+ end
86
+
87
+ def rewrite(context)
88
+ mname = mod.m.text_value if defined?(mod.m)
89
+ sname = context.super_name(p.text_value, mname)
90
+
91
+ # A sub-node (derived node) is just a subclass.
92
+ "class #{n.text_value} < #{sname}; end"
93
+ end
94
+ end
95
+
96
+ class Formula < SNode
97
+ def check(context, *)
98
+ context.parse_define_attr(i.text_value, e.check(context))
99
+ end
100
+
101
+ def rewrite(context)
102
+ # an attr is defined as a class function on the node class.
103
+ "class #{context.last_node}; " +
104
+ "def self.#{i.text_value}#{POST}(_e); " +
105
+ "_e['#{context.last_node}.#{i.text_value}'] ||= " +
106
+ e.rewrite(context) + "; end; end;"
107
+ end
108
+ end
109
+
110
+ class Expr < SNode
111
+ def check(context, *)
112
+ e.check(context)
113
+ end
114
+
115
+ def rewrite(context)
116
+ "(" + e.rewrite(context) + ")"
117
+ end
118
+ end
119
+
120
+ # unary operator
121
+ class UnOp < SNode
122
+ def check(context, *)
123
+ e.check(context)
124
+ end
125
+
126
+ def rewrite(context)
127
+ op.text_value + e.rewrite(context)
128
+ end
129
+ end
130
+
131
+ class BinOp < SNode
132
+ def check(context, *)
133
+ vc, ec = v.check(context), e.check(context)
134
+ # returns list of attrs used in RHS and LHS
135
+ ec + vc
136
+ end
137
+
138
+ def rewrite(context)
139
+ v.rewrite(context) + " " + op.text_value + " " + e.rewrite(context)
140
+ end
141
+ end
142
+
143
+ class Literal < SNode
144
+ def check(context, *)
145
+ []
146
+ end
147
+
148
+ # Delorean literals have same syntax as Ruby
149
+ def rewrite(context)
150
+ text_value
151
+ end
152
+ end
153
+
154
+ class String < Literal
155
+ def rewrite(context)
156
+ # remove the quotes and requote. We don't want the likes of #{}
157
+ # evals to just pass through.
158
+ text_value[1..-2].inspect
159
+ end
160
+ end
161
+
162
+ class Identifier < SNode
163
+ def check(context, *)
164
+ context.parse_call_last_node_attr(text_value)
165
+ [text_value]
166
+ end
167
+
168
+ def rewrite(context)
169
+ # Identifiers are just attr accesses. These are translated to
170
+ # class method calls. POST is used in mangling the attr names.
171
+ # _e is the environment. Comprehension vars (in comp_set) are
172
+ # not passed the env arg.
173
+ arg = context.comp_set.member?(text_value) ? "" : '(_e)'
174
+ text_value + POST + arg
175
+ end
176
+ end
177
+
178
+ class NodeGetAttr < SNode
179
+ def check(context, *)
180
+ context.parse_call_attr(n.text_value, i.text_value)
181
+ [text_value]
182
+ end
183
+
184
+ def rewrite(context)
185
+ text_value + POST + '(_e)'
186
+ end
187
+ end
188
+
189
+ class GetAttr < SNode
190
+ def check(context, *)
191
+ i.check(context)
192
+ end
193
+
194
+ def rewrite(context)
195
+ attr_list = ga.text_value.split('.')
196
+ attr_list.inject(i.rewrite(context)) {|x, y| "_get_attr(#{x}, '#{y}')"}
197
+ end
198
+ end
199
+
200
+ class ModelFnGetAttr < SNode
201
+ def check(context, *)
202
+ mfn.check(context)
203
+ end
204
+
205
+ def rewrite(context)
206
+ x = mfn.rewrite(context)
207
+ "_get_attr(#{x}, '#{i.text_value}')"
208
+ end
209
+ end
210
+
211
+ class Fn < SNode
212
+ def check(context, *)
213
+ acount, res =
214
+ defined?(args) ? [args.arg_count, args.check(context)] : [0, []]
215
+
216
+ context.parse_check_call_fn(fn.text_value, acount)
217
+ res
218
+ end
219
+
220
+ def rewrite(context)
221
+ fn.text_value + "(" + (defined?(args) ? args.rewrite(context) : "") + ")"
222
+ end
223
+ end
224
+
225
+ class FnArgs < SNode
226
+ def check(context, *)
227
+ arg0.check(context) +
228
+ (defined?(args_rest.args) && !args_rest.args.text_value.empty? ?
229
+ args_rest.args.check(context) : [])
230
+ end
231
+
232
+ def rewrite(context)
233
+ arg0.rewrite(context) +
234
+ (defined?(args_rest.args) && !args_rest.args.text_value.empty? ?
235
+ ", " + args_rest.args.rewrite(context) : "")
236
+ end
237
+
238
+ def arg_count
239
+ defined?(args_rest.args) ? 1 + args_rest.args.arg_count : 1
240
+ end
241
+ end
242
+
243
+ class ModelFn < SNode
244
+ def check(context, *)
245
+ acount, res =
246
+ defined?(args) ? [args.arg_count, args.check(context)] : [0, []]
247
+
248
+ context.parse_check_call_fn(fn.text_value, acount, m.text_value)
249
+ res
250
+ end
251
+
252
+ def rewrite(context)
253
+ m.text_value + "." + fn.text_value +
254
+ "(" + (defined?(args) ? args.rewrite(context) : "") + ")"
255
+ end
256
+ end
257
+
258
+ class IfElse < SNode
259
+ def check(context, *)
260
+ vc, e1c, e2c =
261
+ v.check(context), e1.check(context), e2.check(context)
262
+ vc + e1c + e2c
263
+ end
264
+
265
+ def rewrite(context)
266
+ "(" + v.rewrite(context) + ") ? (" +
267
+ e1.rewrite(context) + ") : (" + e2.rewrite(context) + ")"
268
+ end
269
+ end
270
+
271
+ class ListExpr < SNode
272
+ def check(context, *)
273
+ defined?(args) ? args.check(context) : []
274
+ end
275
+
276
+ def rewrite(context)
277
+ "[" + (defined?(args) ? args.rewrite(context) : "") + "]"
278
+ end
279
+ end
280
+
281
+ class ListComprehension < SNode
282
+ def check(context, *)
283
+ vname = i.text_value
284
+
285
+ e1c = e1.check(context)
286
+ context.parse_define_var(vname)
287
+ # need to check e2/e3 in a context where the comprehension var
288
+ # is defined.
289
+ e2c = e2.check(context)
290
+ e3c = defined?(ifexp.e3) ? ifexp.e3.check(context) : []
291
+
292
+ context.parse_undef_var(vname)
293
+ e2c.delete(vname)
294
+ e3c.delete(vname)
295
+
296
+ e1c + e2c + e3c
297
+ end
298
+
299
+ def rewrite(context)
300
+ res = "(#{e1.rewrite(context)}).map{"
301
+ context.parse_define_var(i.text_value)
302
+ res += "|#{i.rewrite(context)}| (#{e2.rewrite(context)}) }"
303
+
304
+ res += ".select{|#{i.rewrite(context)}| (#{ifexp.e3.rewrite(context)}) }" if
305
+ defined?(ifexp.e3)
306
+
307
+ context.parse_undef_var(i.text_value)
308
+ res
309
+ end
310
+ end
311
+
312
+ class HashExpr < SNode
313
+ def check(context, *)
314
+ defined?(args) ? args.check(context) : {}
315
+ end
316
+
317
+ def rewrite(context)
318
+ "{" + (defined?(args) ? args.rewrite(context) : "") + "}"
319
+ end
320
+ end
321
+
322
+ class KwArgs < SNode
323
+ def check(context, *)
324
+ arg0.check(context) + (defined?(args_rest.args) ?
325
+ args_rest.args.check(context) : [])
326
+ end
327
+
328
+ def rewrite(context)
329
+ arg0_rw = arg0.rewrite(context)
330
+
331
+ if defined?(args_rest.al)
332
+ args, kw = args_rest.al.rewrite(context)
333
+ else
334
+ args, kw = [], {}
335
+ end
336
+
337
+ if defined?(k.i)
338
+ kw[k.i.text_value] = arg0_rw
339
+ else
340
+ args << arg0_rw
341
+ end
342
+
343
+ [args, kw]
344
+ end
345
+ end
346
+
347
+ class HashArgs < SNode
348
+ def check(context, *)
349
+ e0.check(context) + e1.check(context) +
350
+ (defined?(args_rest.args) ? args_rest.args.check(context) : [])
351
+ end
352
+
353
+ def rewrite(context)
354
+ e0.rewrite(context) + " => " + e1.rewrite(context) +
355
+ (defined?(args_rest.al) && !args_rest.al.text_value.empty? ?
356
+ ", " + args_rest.al.rewrite(context) : "")
357
+ end
358
+ end
359
+
360
+ class ScriptCall < SNode
361
+ def check(context, *)
362
+ i.check(context) unless i.text_value.empty?
363
+ al.check(context) if defined?(al)
364
+ []
365
+ end
366
+
367
+ def rewrite(context)
368
+ node_name = i.text_value.empty? ? "nil" : i.rewrite(context)
369
+ do_rewrite(context, node_name)
370
+ end
371
+
372
+ def do_rewrite(context, node_name, mname="nil")
373
+ args, kw = al.rewrite(context)
374
+
375
+ args_str = '[' + args.reverse.join(',') + ']'
376
+ kw_str = '{' + kw.map {|k, v| "'#{k}' => #{v}" }.join(',') + '}'
377
+
378
+ "_script_call(#{node_name}, #{mname}, _e, #{args_str}, #{kw_str})"
379
+ end
380
+ end
381
+
382
+ class ScriptCallNode < ScriptCall
383
+ def check(context, *)
384
+ # FIXME: for both this and when node_name is nil, should check
385
+ # to see if attributes exist on the node before allowing the
386
+ # call. Also, can check parameters.
387
+
388
+ mname = mod.m.text_value if defined?(mod.m)
389
+ context.parse_check_defined_mod_node(c.text_value, mname)
390
+
391
+ al.check(context) if defined?(al)
392
+ []
393
+ end
394
+
395
+ def rewrite(context)
396
+ node_name = c.text_value.inspect
397
+ mname = defined?(mod.m) ? mod.m.text_value.inspect : "nil"
398
+ do_rewrite(context, node_name, mname)
399
+ end
400
+ end
401
+ end