delorean_lang 0.1.6 → 0.1.7
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.
- 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:
|