loxxy 0.1.16 → 0.1.17
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -0
- data/lib/loxxy/back_end/engine.rb +4 -4
- data/lib/loxxy/back_end/lox_class.rb +9 -2
- data/lib/loxxy/back_end/lox_function.rb +6 -0
- data/lib/loxxy/back_end/lox_instance.rb +0 -4
- data/lib/loxxy/back_end/resolver.rb +8 -2
- data/lib/loxxy/version.rb +1 -1
- data/spec/interpreter_spec.rb +25 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2c7d720e2638407882bfd3f34384748a872086e1b1f7a3849f0e029e8672fc1c
|
4
|
+
data.tar.gz: c3aa7ebe4a625ef1b0a257cc750430b9a0aa404bb39dab900b409b2987e09dea
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1eb8bb6575dd39834c55ce3ad359fbdb9a2129f91d25bc39ea093c5a4ca2aa38300ab28e673b39991678c304aea64ffda473707f9d317980b976c8f98fc3a55f
|
7
|
+
data.tar.gz: d3dd5baae665ab27a60a13b7392e9d57ef32ff72a37892d8f08e314888a1bfcc3db9ceeb071a28c00dda44f4bce7afed6aadf6c33c411a93d561a30fef833edd
|
data/CHANGELOG.md
CHANGED
@@ -74,7 +74,9 @@ module Loxxy
|
|
74
74
|
meths = aClassStmt.body.map do |func_node|
|
75
75
|
func_node.is_method = true
|
76
76
|
func_node.accept(aVisitor)
|
77
|
-
stack.pop
|
77
|
+
mth = stack.pop
|
78
|
+
mth.is_initializer = true if mth.name == 'init'
|
79
|
+
mth
|
78
80
|
end
|
79
81
|
|
80
82
|
klass = LoxClass.new(aClassStmt.name, meths, self)
|
@@ -234,15 +236,13 @@ module Loxxy
|
|
234
236
|
case callee
|
235
237
|
when NativeFunction
|
236
238
|
stack.push callee.call # Pass arguments
|
237
|
-
when LoxFunction
|
239
|
+
when LoxFunction, LoxClass
|
238
240
|
arg_count = aCallExpr.arguments.size
|
239
241
|
if arg_count != callee.arity
|
240
242
|
msg = "Expected #{callee.arity} arguments but got #{arg_count}."
|
241
243
|
raise Loxxy::RuntimeError, msg
|
242
244
|
end
|
243
245
|
callee.call(self, aVisitor)
|
244
|
-
when LoxClass
|
245
|
-
callee.call(self, aVisitor)
|
246
246
|
else
|
247
247
|
raise Loxxy::RuntimeError, 'Can only call functions and classes.'
|
248
248
|
end
|
@@ -30,11 +30,18 @@ module Loxxy
|
|
30
30
|
end
|
31
31
|
|
32
32
|
def arity
|
33
|
-
|
33
|
+
initializer = find_method('init')
|
34
|
+
initializer ? initializer.arity : 0
|
34
35
|
end
|
35
36
|
|
36
|
-
def call(engine,
|
37
|
+
def call(engine, visitor)
|
37
38
|
instance = LoxInstance.new(self, engine)
|
39
|
+
initializer = find_method('init')
|
40
|
+
if initializer
|
41
|
+
constructor = initializer.bind(instance)
|
42
|
+
constructor.call(engine, visitor)
|
43
|
+
end
|
44
|
+
|
38
45
|
engine.stack.push(instance)
|
39
46
|
end
|
40
47
|
|
@@ -15,6 +15,7 @@ module Loxxy
|
|
15
15
|
attr_reader :body
|
16
16
|
attr_reader :stack
|
17
17
|
attr_reader :closure
|
18
|
+
attr_accessor :is_initializer
|
18
19
|
|
19
20
|
# Create a function with given name
|
20
21
|
# @param aName [String] The name of the function
|
@@ -24,6 +25,7 @@ module Loxxy
|
|
24
25
|
@body = aBody.kind_of?(Ast::LoxNoopExpr) ? aBody : aBody.subnodes[0]
|
25
26
|
@stack = anEngine.stack
|
26
27
|
@closure = anEngine.symbol_table.current_env
|
28
|
+
@is_initializer = false
|
27
29
|
anEngine.symbol_table.current_env.embedding = true
|
28
30
|
end
|
29
31
|
|
@@ -48,6 +50,10 @@ module Loxxy
|
|
48
50
|
(body.nil? || body.kind_of?(Ast::LoxNoopExpr)) ? Datatype::Nil.instance : body.accept(aVisitor)
|
49
51
|
throw(:return)
|
50
52
|
end
|
53
|
+
if is_initializer
|
54
|
+
enclosing_env = engine.symbol_table.current_env.enclosing
|
55
|
+
engine.stack.push(enclosing_env.defns['this'].value)
|
56
|
+
end
|
51
57
|
|
52
58
|
engine.symbol_table.leave_environment
|
53
59
|
end
|
@@ -47,10 +47,6 @@ module Loxxy
|
|
47
47
|
# Set the value of property with given name
|
48
48
|
# aName [String] name of object property
|
49
49
|
def set(aName, aValue)
|
50
|
-
unless fields.include? aName
|
51
|
-
raise StandardError, "Undefined property '#{aName}'."
|
52
|
-
end
|
53
|
-
|
54
50
|
fields[aName] = aValue
|
55
51
|
end
|
56
52
|
end # class
|
@@ -70,7 +70,8 @@ module Loxxy
|
|
70
70
|
begin_scope
|
71
71
|
define('this')
|
72
72
|
aClassStmt.body.each do |fun_stmt|
|
73
|
-
|
73
|
+
mth_type = fun_stmt.name == 'init' ? :initializer : :method
|
74
|
+
resolve_function(fun_stmt, mth_type, aVisitor)
|
74
75
|
end
|
75
76
|
end_scope
|
76
77
|
@current_class = previous_class
|
@@ -92,7 +93,7 @@ module Loxxy
|
|
92
93
|
anIfStmt.else_stmt&.accept(aVisitor)
|
93
94
|
end
|
94
95
|
|
95
|
-
def before_return_stmt(
|
96
|
+
def before_return_stmt(returnStmt)
|
96
97
|
if scopes.size < 2
|
97
98
|
msg = "Error at 'return': Can't return from top-level code."
|
98
99
|
raise StandardError, msg
|
@@ -102,6 +103,11 @@ module Loxxy
|
|
102
103
|
msg = "Error at 'return': Can't return from outside a function."
|
103
104
|
raise StandardError, msg
|
104
105
|
end
|
106
|
+
|
107
|
+
if current_function == :initializer
|
108
|
+
msg = "Error at 'return': Can't return a value from an initializer."
|
109
|
+
raise StandardError, msg unless returnStmt.subnodes[0].kind_of?(Datatype::Nil)
|
110
|
+
end
|
105
111
|
end
|
106
112
|
|
107
113
|
def after_while_stmt(aWhileStmt, aVisitor)
|
data/lib/loxxy/version.rb
CHANGED
data/spec/interpreter_spec.rb
CHANGED
@@ -543,7 +543,7 @@ LOX_END
|
|
543
543
|
closure;
|
544
544
|
LOX_END
|
545
545
|
# Expected result: Backend::LoxFunction('closure')
|
546
|
-
# Expected function's closure (
|
546
|
+
# Expected function's closure (environment layout):
|
547
547
|
# Environment('global')
|
548
548
|
# defns
|
549
549
|
# +- ['clock'] => BackEnd::Engine::NativeFunction
|
@@ -567,6 +567,30 @@ LOX_END
|
|
567
567
|
expect(global_env.defns['clock'].value).to be_kind_of(BackEnd::Engine::NativeFunction)
|
568
568
|
expect(global_env.defns['Foo'].value).to be_kind_of(BackEnd::LoxClass)
|
569
569
|
end
|
570
|
+
|
571
|
+
it 'should support custom initializer' do
|
572
|
+
lox_snippet = <<-LOX_END
|
573
|
+
// From section 3.9.5
|
574
|
+
class Breakfast {
|
575
|
+
init(meat, bread) {
|
576
|
+
this.meat = meat;
|
577
|
+
this.bread = bread;
|
578
|
+
}
|
579
|
+
|
580
|
+
serve(who) {
|
581
|
+
print "Enjoy your " + this.meat + " and " +
|
582
|
+
this.bread + ", " + who + ".";
|
583
|
+
}
|
584
|
+
}
|
585
|
+
|
586
|
+
var baconAndToast = Breakfast("bacon", "toast");
|
587
|
+
baconAndToast.serve("Dear Reader");
|
588
|
+
// Output: "Enjoy your bacon and toast, Dear Reader."
|
589
|
+
LOX_END
|
590
|
+
expect { subject.evaluate(lox_snippet) }.not_to raise_error
|
591
|
+
predicted = 'Enjoy your bacon and toast, Dear Reader.'
|
592
|
+
expect(sample_cfg[:ostream].string).to eq(predicted)
|
593
|
+
end
|
570
594
|
end # context
|
571
595
|
end # describe
|
572
596
|
# rubocop: enable Metrics/BlockLength
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: loxxy
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.17
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dimitri Geshef
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-04-
|
11
|
+
date: 2021-04-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rley
|