delorean_lang 0.1.6 → 0.1.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +13 -5
- data/lib/delorean/base.rb +38 -11
- data/lib/delorean/engine.rb +17 -13
- data/lib/delorean/nodes.rb +11 -7
- data/lib/delorean/version.rb +1 -1
- data/spec/eval_spec.rb +15 -12
- data/spec/parse_spec.rb +11 -0
- metadata +9 -8
checksums.yaml
CHANGED
@@ -1,7 +1,15 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
NjRmOWNjNTZjNTM5MWE0ZmE3OTM4MGE3MTY1MjRjZDgzNDdjZWRlMQ==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
ZDlhMDJkNjhmODM4Yjg0OTAxYWZhMDk1MDE2M2M2NGU4ZTQ4Yzc2ZA==
|
5
7
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
YmQ4NjNlMDgyMDBkMTczNzc5NGU5YjE1NmJlMDAzODhkMWJmMTkwNzIzZDc4
|
10
|
+
ZDQzZTVmMmQ4MTlmYzllOTc3ZDdhZGJiNjk5NDA3MmUwNTY4OGFkNmRjODYw
|
11
|
+
YjM2ZWEyMTliMjY4OWUxOTg5NGUzODVkMzQxODVhMmFlYTJjYTY=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
NzE3NWI2ZGE2OTVjMDQ2NDg4YTAwN2ZmNjRkOWE4YTRmZjI3NDY1ZGI5N2Vk
|
14
|
+
ODU2MmZjMzM0YzYyNDgwYzlmODlmZDc1YjFhYjQyMWI5N2JjOTZlOTgxMDBi
|
15
|
+
ZTQwNzEyY2M4ZjA2ZmEzMDAwZTQ0M2M4MGQzNjM3ODQ2MTk4ODk=
|
data/lib/delorean/base.rb
CHANGED
@@ -18,6 +18,17 @@ module Delorean
|
|
18
18
|
sort: [Array],
|
19
19
|
split: [String, String],
|
20
20
|
uniq: [Array],
|
21
|
+
sum: [Array],
|
22
|
+
zip: [Array, [Array, Array, Array]],
|
23
|
+
index: [Array, [Integer, Numeric, String, Array, Fixnum]],
|
24
|
+
product: [Array, Array],
|
25
|
+
first: [Enumerable, [nil, Fixnum]],
|
26
|
+
|
27
|
+
keys: [Hash],
|
28
|
+
values: [Hash],
|
29
|
+
upcase: [String],
|
30
|
+
downcase: [String],
|
31
|
+
match: [String, [String], [nil, Fixnum]],
|
21
32
|
|
22
33
|
hour: [[Date, Time, ActiveSupport::TimeWithZone]],
|
23
34
|
min: [[Date, Time, ActiveSupport::TimeWithZone, Array]],
|
@@ -28,6 +39,24 @@ module Delorean
|
|
28
39
|
day: [[Date, Time, ActiveSupport::TimeWithZone]],
|
29
40
|
year: [[Date, Time, ActiveSupport::TimeWithZone]],
|
30
41
|
|
42
|
+
next_month: [[Date, Time, ActiveSupport::TimeWithZone],
|
43
|
+
[nil, Fixnum],
|
44
|
+
],
|
45
|
+
prev_month: [[Date, Time, ActiveSupport::TimeWithZone],
|
46
|
+
[nil, Fixnum],
|
47
|
+
],
|
48
|
+
|
49
|
+
beginning_of_month: [[Date, Time, ActiveSupport::TimeWithZone]],
|
50
|
+
|
51
|
+
end_of_month: [[Date, Time, ActiveSupport::TimeWithZone]],
|
52
|
+
|
53
|
+
next_day: [[Date, Time, ActiveSupport::TimeWithZone],
|
54
|
+
[nil, Fixnum],
|
55
|
+
],
|
56
|
+
prev_day: [[Date, Time, ActiveSupport::TimeWithZone],
|
57
|
+
[nil, Fixnum],
|
58
|
+
],
|
59
|
+
|
31
60
|
to_i: [[Numeric, String]],
|
32
61
|
to_f: [[Numeric, String]],
|
33
62
|
to_d: [[Numeric, String]],
|
@@ -37,12 +66,7 @@ module Delorean
|
|
37
66
|
}
|
38
67
|
|
39
68
|
module BaseModule
|
40
|
-
class NodeCall
|
41
|
-
attr_reader :engine, :node, :params
|
42
|
-
def initialize(engine, node, params)
|
43
|
-
@engine, @node, @params = engine, node, params
|
44
|
-
end
|
45
|
-
|
69
|
+
class NodeCall < Struct.new(:_e, :engine, :node, :params)
|
46
70
|
def evaluate(attr)
|
47
71
|
engine.evaluate(node, attr, params)
|
48
72
|
end
|
@@ -57,7 +81,6 @@ module Delorean
|
|
57
81
|
end
|
58
82
|
|
59
83
|
class BaseClass
|
60
|
-
|
61
84
|
def self._get_attr(obj, attr, _e)
|
62
85
|
return nil if obj.nil?
|
63
86
|
|
@@ -114,10 +137,14 @@ module Delorean
|
|
114
137
|
raise str
|
115
138
|
end
|
116
139
|
|
117
|
-
def self._node_call(node,
|
140
|
+
def self._node_call(node, _e, params)
|
118
141
|
context = _e[:_engine]
|
119
|
-
|
120
|
-
|
142
|
+
|
143
|
+
engine = node.is_a?(Class) &&
|
144
|
+
context.module_name != node.module_name ?
|
145
|
+
context.get_import_engine(node.module_name) : context
|
146
|
+
|
147
|
+
NodeCall.new(_e, engine, node || self, params)
|
121
148
|
end
|
122
149
|
|
123
150
|
######################################################################
|
@@ -150,7 +177,7 @@ module Delorean
|
|
150
177
|
break
|
151
178
|
end
|
152
179
|
}
|
153
|
-
raise "bad arg #{i}
|
180
|
+
raise "bad arg #{i}, method #{method}: #{ai}/#{ai.class} #{s}" if !ok
|
154
181
|
}
|
155
182
|
|
156
183
|
obj.send(msg, *args)
|
data/lib/delorean/engine.rb
CHANGED
@@ -5,11 +5,12 @@ require 'pp'
|
|
5
5
|
|
6
6
|
module Delorean
|
7
7
|
class Engine
|
8
|
-
attr_reader :last_node, :module_name, :
|
8
|
+
attr_reader :last_node, :module_name, :version,
|
9
|
+
:line_no, :comp_set, :pm, :m, :imports
|
9
10
|
|
10
|
-
def initialize(module_name)
|
11
|
+
def initialize(module_name, version=nil)
|
11
12
|
# name of current module
|
12
|
-
@module_name = module_name
|
13
|
+
@module_name, @version = module_name, version
|
13
14
|
reset
|
14
15
|
end
|
15
16
|
|
@@ -142,13 +143,14 @@ module Delorean
|
|
142
143
|
@node_attrs[@last_node].member? name
|
143
144
|
|
144
145
|
@node_attrs[@last_node] << name
|
145
|
-
|
146
|
+
|
146
147
|
checks = spec.map { |a|
|
147
|
-
n = a.index('.') ? a :
|
148
|
+
n = a.index('.') ? a : "#{@last_node}.#{a}"
|
148
149
|
"_x.member?('#{n}') ? raise('#{n}') : #{a}#{POST}(_x + ['#{n}'])"
|
149
150
|
}.join(';')
|
150
151
|
|
151
|
-
code =
|
152
|
+
code =
|
153
|
+
"class #{@last_node}; def self.#{name}#{POST}(_x); #{checks}; end; end"
|
152
154
|
|
153
155
|
# pp code
|
154
156
|
|
@@ -213,8 +215,12 @@ module Delorean
|
|
213
215
|
def generate(t, sset=nil)
|
214
216
|
t.check(self, sset)
|
215
217
|
|
216
|
-
|
217
|
-
|
218
|
+
begin
|
219
|
+
# generate ruby code
|
220
|
+
gen = t.rewrite(self)
|
221
|
+
rescue RuntimeError => exc
|
222
|
+
err(ParseError, "codegen error: " + exc.message)
|
223
|
+
end
|
218
224
|
|
219
225
|
# puts gen
|
220
226
|
|
@@ -251,7 +257,7 @@ module Delorean
|
|
251
257
|
# Inside a multiline and next line doesn't look like a
|
252
258
|
# continuation => syntax error.
|
253
259
|
err(ParseError, "syntax error") unless line =~ /^\s+/
|
254
|
-
|
260
|
+
|
255
261
|
multi_line += line
|
256
262
|
t = parser.parse(multi_line)
|
257
263
|
|
@@ -362,16 +368,14 @@ module Delorean
|
|
362
368
|
}
|
363
369
|
end
|
364
370
|
|
365
|
-
|
366
|
-
# be confused with other parse_* calls which occur at parse time.
|
367
|
-
def parse_runtime_exception(exc)
|
371
|
+
def self.grok_runtime_exception(exc)
|
368
372
|
# parse out the delorean-related backtrace records
|
369
373
|
bt = exc.backtrace.map{ |x|
|
370
374
|
x.match(/^#{MOD}(.+?):(\d+)(|:in `(.+)')$/);
|
371
375
|
$1 && [$1, $2.to_i, $4.sub(/#{POST}$/, '')]
|
372
376
|
}.reject(&:!)
|
373
377
|
|
374
|
-
|
378
|
+
{"error" => exc.message, "backtrace" => bt}
|
375
379
|
end
|
376
380
|
|
377
381
|
######################################################################
|
data/lib/delorean/nodes.rb
CHANGED
@@ -68,15 +68,20 @@ eos
|
|
68
68
|
context.parse_define_node(n.text_value, nil)
|
69
69
|
end
|
70
70
|
|
71
|
-
def
|
71
|
+
def def_class(context, base_name)
|
72
72
|
# Nodes are simply translated to classes. Define our own
|
73
73
|
# self.name() since it's extremely slow in MRI 2.0.
|
74
|
-
"class #{n.text_value} <
|
74
|
+
"class #{n.text_value} < #{base_name}; " +
|
75
|
+
"def self.module_name; '#{context.module_name}'; end;" +
|
75
76
|
"def self.name; '#{n.text_value}'; end; end"
|
76
77
|
end
|
78
|
+
|
79
|
+
def rewrite(context)
|
80
|
+
def_class(context, "BaseClass")
|
81
|
+
end
|
77
82
|
end
|
78
83
|
|
79
|
-
class SubNode <
|
84
|
+
class SubNode < BaseNode
|
80
85
|
def check(context, *)
|
81
86
|
mname = mod.m.text_value if defined?(mod.m)
|
82
87
|
context.parse_define_node(n.text_value, p.text_value, mname)
|
@@ -87,8 +92,7 @@ eos
|
|
87
92
|
sname = context.super_name(p.text_value, mname)
|
88
93
|
|
89
94
|
# A sub-node (derived node) is just a subclass.
|
90
|
-
|
91
|
-
"def self.name; '#{n.text_value}'; end; end"
|
95
|
+
def_class(context, sname)
|
92
96
|
end
|
93
97
|
end
|
94
98
|
|
@@ -302,9 +306,9 @@ eos
|
|
302
306
|
raise "No positional arguments to node call" unless
|
303
307
|
args.empty?
|
304
308
|
|
305
|
-
kw_str =
|
309
|
+
kw_str = kw.map {|k, v| "'#{k}' => #{v}"}.join(',')
|
306
310
|
|
307
|
-
"_node_call(#{node_name},
|
311
|
+
"_node_call(#{node_name}, _e, {#{kw_str}})"
|
308
312
|
end
|
309
313
|
end
|
310
314
|
|
data/lib/delorean/version.rb
CHANGED
data/spec/eval_spec.rb
CHANGED
@@ -23,7 +23,7 @@ describe "Delorean" do
|
|
23
23
|
" b = -(a + 1)",
|
24
24
|
" c = -a + 1",
|
25
25
|
)
|
26
|
-
|
26
|
+
|
27
27
|
engine.evaluate_attrs("A", ["a"]).should == [123]
|
28
28
|
|
29
29
|
r = engine.evaluate_attrs("A", ["x", "b"])
|
@@ -143,28 +143,31 @@ describe "Delorean" do
|
|
143
143
|
" a = 1/0",
|
144
144
|
" b = 10 * a",
|
145
145
|
)
|
146
|
-
|
146
|
+
|
147
147
|
begin
|
148
148
|
engine.evaluate("A", "b")
|
149
149
|
rescue => exc
|
150
|
-
res =
|
150
|
+
res = Delorean::Engine.grok_runtime_exception(exc)
|
151
151
|
end
|
152
152
|
|
153
|
-
res.should ==
|
153
|
+
res.should == {
|
154
|
+
"error" => "divided by 0",
|
155
|
+
"backtrace" => [["XXX", 2, "/"], ["XXX", 2, "a"], ["XXX", 3, "b"]],
|
156
|
+
}
|
154
157
|
end
|
155
158
|
|
156
159
|
it "should handle runtime errors 2" do
|
157
160
|
engine.parse defn("A:",
|
158
161
|
" b = Dummy.call_me_maybe('a', 'b')",
|
159
162
|
)
|
160
|
-
|
163
|
+
|
161
164
|
begin
|
162
165
|
engine.evaluate("A", "b")
|
163
166
|
rescue => exc
|
164
|
-
res =
|
167
|
+
res = Delorean::Engine.grok_runtime_exception(exc)
|
165
168
|
end
|
166
169
|
|
167
|
-
res[
|
170
|
+
res["backtrace"].should == [["XXX", 2, "b"]]
|
168
171
|
end
|
169
172
|
|
170
173
|
it "should handle operator precedence properly" do
|
@@ -190,7 +193,7 @@ describe "Delorean" do
|
|
190
193
|
|
191
194
|
engine.parse text
|
192
195
|
r = engine.evaluate("A", "e", {"d" => -100})
|
193
|
-
r.should == "
|
196
|
+
r.should == "gungamstyle"
|
194
197
|
|
195
198
|
r = engine.evaluate("A", "e")
|
196
199
|
r.should == "korea"
|
@@ -206,7 +209,7 @@ describe "Delorean" do
|
|
206
209
|
"C:",
|
207
210
|
" c = A.c + B.c",
|
208
211
|
)
|
209
|
-
|
212
|
+
|
210
213
|
r = engine.evaluate("B", "c")
|
211
214
|
r.should == 123*123
|
212
215
|
r = engine.evaluate("C", "c", {"c" => 5})
|
@@ -369,13 +372,13 @@ eoc
|
|
369
372
|
|
370
373
|
r = engine.evaluate("B", "b", {"a" => 10})
|
371
374
|
r.should == 10*3
|
372
|
-
|
375
|
+
|
373
376
|
lambda {
|
374
377
|
r = engine.evaluate("B", "b")
|
375
378
|
}.should raise_error(Delorean::UndefinedParamError)
|
376
379
|
|
377
380
|
end
|
378
|
-
|
381
|
+
|
379
382
|
sample_script = <<eof
|
380
383
|
A:
|
381
384
|
a = 2
|
@@ -618,7 +621,7 @@ eof
|
|
618
621
|
" n =?",
|
619
622
|
" fact = if n <= 1 then 1 else n * A(n: n-1).fact",
|
620
623
|
)
|
621
|
-
|
624
|
+
|
622
625
|
engine.evaluate("A", "fact", "n" => 10).should == 3628800
|
623
626
|
end
|
624
627
|
|
data/spec/parse_spec.rb
CHANGED
@@ -648,6 +648,17 @@ describe "Delorean" do
|
|
648
648
|
)
|
649
649
|
end
|
650
650
|
|
651
|
+
it "should not allow positional args to node calls" do
|
652
|
+
begin
|
653
|
+
engine.parse defn("A:",
|
654
|
+
" d = A(1, 2, 3)",
|
655
|
+
)
|
656
|
+
raise "fail"
|
657
|
+
rescue Delorean::ParseError => exc
|
658
|
+
exc.line.should == 2
|
659
|
+
end
|
660
|
+
end
|
661
|
+
|
651
662
|
it "should parse instance calls" do
|
652
663
|
engine.parse defn("A:",
|
653
664
|
" a = [1,2,[4]].flatten(1)",
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: delorean_lang
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Arman Bostani
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2014-01-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: treetop
|
@@ -42,28 +42,28 @@ dependencies:
|
|
42
42
|
name: rspec
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- - '>='
|
45
|
+
- - ! '>='
|
46
46
|
- !ruby/object:Gem::Version
|
47
47
|
version: '0'
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- - '>='
|
52
|
+
- - ! '>='
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '0'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: sqlite3
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
|
-
- - '>='
|
59
|
+
- - ! '>='
|
60
60
|
- !ruby/object:Gem::Version
|
61
61
|
version: '0'
|
62
62
|
type: :development
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
|
-
- - '>='
|
66
|
+
- - ! '>='
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '0'
|
69
69
|
description: A "compiler" for the Delorean programming language
|
@@ -105,12 +105,12 @@ require_paths:
|
|
105
105
|
- lib
|
106
106
|
required_ruby_version: !ruby/object:Gem::Requirement
|
107
107
|
requirements:
|
108
|
-
- - '>='
|
108
|
+
- - ! '>='
|
109
109
|
- !ruby/object:Gem::Version
|
110
110
|
version: '0'
|
111
111
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
112
112
|
requirements:
|
113
|
-
- - '>='
|
113
|
+
- - ! '>='
|
114
114
|
- !ruby/object:Gem::Version
|
115
115
|
version: '0'
|
116
116
|
requirements: []
|
@@ -125,3 +125,4 @@ test_files:
|
|
125
125
|
- spec/func_spec.rb
|
126
126
|
- spec/parse_spec.rb
|
127
127
|
- spec/spec_helper.rb
|
128
|
+
has_rdoc:
|