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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 60e57ef9264b4239571378ddcbefe044ff63192534ce94fc99b9a3b1c1813f02
4
- data.tar.gz: 94c26f57455d0e267354f68655e86288dd00f5c322df3e4d1b6f5478cad0eb17
3
+ metadata.gz: 2c7d720e2638407882bfd3f34384748a872086e1b1f7a3849f0e029e8672fc1c
4
+ data.tar.gz: c3aa7ebe4a625ef1b0a257cc750430b9a0aa404bb39dab900b409b2987e09dea
5
5
  SHA512:
6
- metadata.gz: 8e5d6f864c1a340aecc7a362d8f2c311dc553869fc72b40d287736df2b62715eb208b2b299f1106dba5645dc4bb859f1d96fbfa79441c83c0e5faa223dd6642d
7
- data.tar.gz: 452f9815e8812d9313c228697410a4c7433ec12c58269da305999f1de2822c89ad0b9a0f4e72865c333ddbee725b0ff102b4bc14ab4c51dcf7dba2784a08074a
6
+ metadata.gz: 1eb8bb6575dd39834c55ce3ad359fbdb9a2129f91d25bc39ea093c5a4ca2aa38300ab28e673b39991678c304aea64ffda473707f9d317980b976c8f98fc3a55f
7
+ data.tar.gz: d3dd5baae665ab27a60a13b7392e9d57ef32ff72a37892d8f08e314888a1bfcc3db9ceeb071a28c00dda44f4bce7afed6aadf6c33c411a93d561a30fef833edd
data/CHANGELOG.md CHANGED
@@ -1,3 +1,9 @@
1
+ ## [0.1.17] - 2021-04-11
2
+ - TODO
3
+
4
+ ### Fixed
5
+ - TODO
6
+
1
7
  ## [0.1.16] - 2021-04-10
2
8
  - Fixed an issue in name lookup. All the `this` test suite is passing.
3
9
 
@@ -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
- 0
33
+ initializer = find_method('init')
34
+ initializer ? initializer.arity : 0
34
35
  end
35
36
 
36
- def call(engine, _visitor)
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
- resolve_function(fun_stmt, :method, aVisitor)
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(_returnStmt)
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Loxxy
4
- VERSION = '0.1.16'
4
+ VERSION = '0.1.17'
5
5
  end
@@ -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 ()environment layout):
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.16
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-10 00:00:00.000000000 Z
11
+ date: 2021-04-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rley