loxxy 0.1.16 → 0.1.17
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 +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
|