loxxy 0.1.10 → 0.1.11

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1fc5399ac3346487808eeb40403b3324cca384e3c6820d965b75f2e320759d2c
4
- data.tar.gz: f9b6497d87036f6c88ed09a72113a1ea004df9db8fd9bb945672c370993f7fde
3
+ metadata.gz: aee9fb6c5101bc39682ab401ffc0434aea9e6c4115f74a4f641d0df2d68a03ad
4
+ data.tar.gz: ccc11c428ef206db9129fabbb97526df3477e03c5dce0b1b5a2f758425c8f9cb
5
5
  SHA512:
6
- metadata.gz: 0b0fa0313a0b37882d0398238a65f10b6ea8ab4325447e1f4690ea7100bdb85dead8cb15d8e1e56b422741697d636c7e2c114cf17ad43781dc23462ab51c93af
7
- data.tar.gz: b93b3d01a0e80def496ecfeb955e64000cc88149229ceb97e2743ccda863ec23677958aad9423dd0ca433d72451e120be6fa40247db7cbc49710ac8c17ea8987
6
+ metadata.gz: dbb1a28eb85868636b304aa3ec3c2fb71f3f37f5c573740bd7d577ed4e88374ce1fea5446e39429168228e68bedbddfccd554bc6c88ec7996621956e11a42a3c
7
+ data.tar.gz: 3b4c1d6b0996a351cfd7dae5d8f80683fcbdd1eeecc17c3a7932b0675285700dfecdabecc31f505243ffaf2f1bbc1bd8babb604c154f53dad0019c4ad96b007a
data/CHANGELOG.md CHANGED
@@ -1,3 +1,23 @@
1
+ ## [0.1.11] - 2021-04-03
2
+ - Intermediate version: `Loxxy` does class declarations
3
+
4
+ ### New
5
+ - Class `Ast::LoxClassStmt` a syntax node that represents a class declaration
6
+ - Method `Ast::ASTBuilder#reduce_class_decl` creates a `LoxClassStmt` instance
7
+ - Method `Ast::ASTBuilder#reduce_class_name`
8
+ - Method `Ast::ASTBuilder#reduce_reduce_class_body` collect the methods of the class
9
+ - Method `Ast::ASTBuilder#reduce_method_plus_more` for dealing with methods
10
+ - Method `Ast::ASTBuilder#reduce_method_plus_end`
11
+ - Method `Ast::ASTVisitor#visit_class_stmt` for visiting an `Ast::LoxClassStmt` node
12
+ - Method `Ast::LoxBlockStmt#empty?` returns true if the code block is empty
13
+ - Method `BackEnd::Engine#after_class_stmt`
14
+ - Method `BackEnd::Resolver#after_class_stmt`
15
+ - Method `BackEnd::Resolver#before_class_stmt`
16
+ - Class `BackEnd::LoxClass` implementation of a Lox class.
17
+
18
+ ### CHANGED
19
+ - File `grammar.rb` refactoring of class declaration syntax rules
20
+
1
21
  ## [0.1.10] - 2021-03-31
2
22
  - Flag return statements occurring outside functions as an error
3
23
 
@@ -110,9 +130,9 @@
110
130
  - Method `Ast::ASTVisitor#visit_fun_stmt` for visiting an `Ast::LoxFunStmt` node
111
131
  - Method `Ast::LoxBlockStmt#empty?` returns true if the code block is empty
112
132
  - Method `BackEnd::Engine#after_fun_stmt`
113
- - Method `Backend::NativeFunction#call`
114
- - Method `Backend::NativeFunction#to_str`
115
- - Method `Backend::Function` implementation of a function object.
133
+ - Method `BackEnd::NativeFunction#call`
134
+ - Method `BackEnd::NativeFunction#to_str`
135
+ - Method `BackEnd::LoxFunction` implementation of a function object.
116
136
 
117
137
  ### Changed
118
138
  - Method `BackEnd::Engine#after_call_expr`
@@ -17,4 +17,5 @@ require_relative 'lox_print_stmt'
17
17
  require_relative 'lox_if_stmt'
18
18
  require_relative 'lox_for_stmt'
19
19
  require_relative 'lox_var_stmt'
20
+ require_relative 'lox_class_stmt'
20
21
  require_relative 'lox_seq_decl'
@@ -163,6 +163,31 @@ module Loxxy
163
163
  [theChildren[0]]
164
164
  end
165
165
 
166
+ # rule('classDecl' => 'CLASS classNaming class_body')
167
+ def reduce_class_decl(_production, _range, _tokens, theChildren)
168
+ Ast::LoxClassStmt.new(tokens[1].position, theChildren[1], theChildren[2])
169
+ end
170
+
171
+ # rule('classNaming' => 'IDENTIFIER')
172
+ def reduce_class_name(_production, _range, _tokens, theChildren)
173
+ theChildren[0].token.lexeme
174
+ end
175
+
176
+ # rule('class_body' => 'LEFT_BRACE methods_opt RIGHT_BRACE')
177
+ def reduce_class_body(_production, _range, _tokens, theChildren)
178
+ theChildren[1]
179
+ end
180
+
181
+ # rule('method_plus' => 'method_plus function')
182
+ def reduce_method_plus_more(_production, _range, _tokens, theChildren)
183
+ theChildren[0] << theChildren[1]
184
+ end
185
+
186
+ # rule('method_plus' => 'function')
187
+ def reduce_method_plus_end(_production, _range, _tokens, theChildren)
188
+ theChildren
189
+ end
190
+
166
191
  # rule('funDecl' => 'FUN function')
167
192
  def reduce_fun_decl(_production, _range, _tokens, theChildren)
168
193
  theChildren[1]
@@ -67,6 +67,14 @@ module Loxxy
67
67
  broadcast(:after_var_stmt, aVarStmt)
68
68
  end
69
69
 
70
+ # Visit event. The visitor is about to visit a class declaration.
71
+ # @param aXlassStmt [AST::LOXClassStmt] the for statement node to visit
72
+ def visit_class_stmt(aClassStmt)
73
+ broadcast(:before_class_stmt, aClassStmt)
74
+ traverse_subnodes(aClassStmt) # The methods are visited here...
75
+ broadcast(:after_class_stmt, aClassStmt, self)
76
+ end
77
+
70
78
  # Visit event. The visitor is about to visit a for statement.
71
79
  # @param aForStmt [AST::LOXForStmt] the for statement node to visit
72
80
  def visit_for_stmt(aForStmt)
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'lox_compound_expr'
4
+
5
+ module Loxxy
6
+ module Ast
7
+ class LoxClassStmt < LoxCompoundExpr
8
+ attr_reader :name
9
+
10
+ # @param aPosition [Rley::Lexical::Position] Position of the entry in the input stream.
11
+ # @param condExpr [Loxxy::Ast::LoxNode] iteration condition
12
+ # @param theBody [Loxxy::Ast::LoxNode]
13
+ def initialize(aPosition, aName, theMethods)
14
+ super(aPosition, theMethods)
15
+ @name = aName.dup
16
+ end
17
+
18
+ # Part of the 'visitee' role in Visitor design pattern.
19
+ # @param visitor [Ast::ASTVisitor] the visitor
20
+ def accept(visitor)
21
+ visitor.visit_class_stmt(self)
22
+ end
23
+
24
+ alias body subnodes
25
+ end # class
26
+ end # module
27
+ end # module
@@ -16,7 +16,7 @@ module Loxxy
16
16
  # @param body [Ast::LoxBlockStmt]
17
17
  def initialize(aPosition, aName, paramList, aBody)
18
18
  super(aPosition, [])
19
- @name = aName
19
+ @name = aName.dup
20
20
  @params = paramList
21
21
  @body = aBody
22
22
  end
@@ -3,6 +3,7 @@
3
3
  # Load all the classes implementing AST nodes
4
4
  require_relative '../ast/all_lox_nodes'
5
5
  require_relative 'binary_operator'
6
+ require_relative 'lox_class'
6
7
  require_relative 'lox_function'
7
8
  require_relative 'resolver'
8
9
  require_relative 'symbol_table'
@@ -68,6 +69,12 @@ module Loxxy
68
69
  # Do nothing, subnodes were already evaluated
69
70
  end
70
71
 
72
+ def after_class_stmt(aClassStmt, _visitor)
73
+ klass = LoxClass.new(aClassStmt.name, aClassStmt.methods, self)
74
+ new_var = Variable.new(aClassStmt.name, klass)
75
+ symbol_table.insert(new_var)
76
+ end
77
+
71
78
  def before_var_stmt(aVarStmt)
72
79
  new_var = Variable.new(aVarStmt.name, Datatype::Nil.instance)
73
80
  symbol_table.insert(new_var)
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../datatype/all_datatypes'
4
+
5
+ module Loxxy
6
+ module BackEnd
7
+ # Representation of a Lox class.
8
+ class LoxClass
9
+ # @return [String] The name of the class
10
+ attr_reader :name
11
+
12
+ # @return [Array<>] the list of methods
13
+ attr_reader :methods
14
+ attr_reader :stack
15
+
16
+ # Create a class with given name
17
+ # @param aName [String] The name of the class
18
+ def initialize(aName, theMethods, anEngine)
19
+ @name = aName.dup
20
+ @methods = theMethods
21
+ @stack = anEngine.stack
22
+ end
23
+
24
+ def accept(_visitor)
25
+ stack.push self
26
+ end
27
+
28
+ # Logical negation.
29
+ # As a function is a truthy thing, its negation is thus false.
30
+ # @return [Datatype::False]
31
+ def !
32
+ Datatype::False.instance
33
+ end
34
+
35
+ # Text representation of a Lox function
36
+ def to_str
37
+ name
38
+ end
39
+ end # class
40
+ end # module
41
+ end # module
@@ -6,7 +6,6 @@ module Loxxy
6
6
  module BackEnd
7
7
  # rubocop: disable Style/AccessorGrouping
8
8
  # Representation of a Lox function.
9
- # It is a named slot that can be associated with a value at the time.
10
9
  class LoxFunction
11
10
  # @return [String] The name of the function (if any)
12
11
  attr_reader :name
@@ -18,7 +17,7 @@ module Loxxy
18
17
  attr_reader :closure
19
18
 
20
19
  # Create a function with given name
21
- # @param aName [String] The name of the variable
20
+ # @param aName [String] The name of the function
22
21
  def initialize(aName, parameterList, aBody, anEngine)
23
22
  @name = aName.dup
24
23
  @parameters = parameterList
@@ -53,6 +53,15 @@ module Loxxy
53
53
  end_scope
54
54
  end
55
55
 
56
+ # A class declaration adds a new variable to current scope
57
+ def before_class_stmt(aClassStmt)
58
+ declare(aClassStmt.name)
59
+ end
60
+
61
+ def after_class_stmt(aClassStmt, _visitor)
62
+ define(aClassStmt.name)
63
+ end
64
+
56
65
  def before_for_stmt(aForStmt)
57
66
  before_block_stmt(aForStmt)
58
67
  end
@@ -122,7 +131,7 @@ module Loxxy
122
131
  def before_fun_stmt(aFunStmt, aVisitor)
123
132
  declare(aFunStmt.name)
124
133
  define(aFunStmt.name)
125
- resolve_function(aFunStmt, :function ,aVisitor)
134
+ resolve_function(aFunStmt, :function, aVisitor)
126
135
  end
127
136
 
128
137
  private
@@ -37,12 +37,14 @@ module Loxxy
37
37
  rule('declaration' => 'varDecl')
38
38
  rule('declaration' => 'statement')
39
39
 
40
- rule('classDecl' => 'CLASS classNaming class_body')
40
+ rule('classDecl' => 'CLASS classNaming class_body').as 'class_decl'
41
41
  rule('classNaming' => 'IDENTIFIER LESS IDENTIFIER')
42
- rule('classNaming' => 'IDENTIFIER')
43
- rule('class_body' => 'LEFT_BRACE function_star RIGHT_BRACE')
44
- rule('function_star' => 'function_star function')
45
- rule('function_star' => [])
42
+ rule('classNaming' => 'IDENTIFIER').as 'class_name'
43
+ rule('class_body' => 'LEFT_BRACE methods_opt RIGHT_BRACE').as 'class_body'
44
+ rule('methods_opt' => 'method_plus')
45
+ rule('methods_opt' => [])
46
+ rule('method_plus' => 'method_plus function').as 'method_plus_more'
47
+ rule('method_plus' => 'function').as 'method_plus_end'
46
48
 
47
49
  rule('funDecl' => 'FUN function').as 'fun_decl'
48
50
 
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.10'
4
+ VERSION = '0.1.11'
5
5
  end
@@ -451,6 +451,23 @@ LOX_END
451
451
  end
452
452
  # rubocop: enable Style/StringConcatenation
453
453
 
454
+ it 'should support class declaration' do
455
+ program = <<-LOX_END
456
+ class Duck {
457
+ noise() {
458
+ quack();
459
+ }
460
+
461
+ quack() {
462
+ print "quack";
463
+ }
464
+ }
465
+ print Duck;
466
+ LOX_END
467
+ expect { subject.evaluate(program) }.not_to raise_error
468
+ expect(sample_cfg[:ostream].string).to eq('Duck')
469
+ end
470
+
454
471
  it 'should print the hello world message' do
455
472
  program = <<-LOX_END
456
473
  var greeting = "Hello"; // Declaring a variable
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.10
4
+ version: 0.1.11
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-03-31 00:00:00.000000000 Z
11
+ date: 2021-04-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rley
@@ -93,6 +93,7 @@ files:
93
93
  - lib/loxxy/ast/lox_binary_expr.rb
94
94
  - lib/loxxy/ast/lox_block_stmt.rb
95
95
  - lib/loxxy/ast/lox_call_expr.rb
96
+ - lib/loxxy/ast/lox_class_stmt.rb
96
97
  - lib/loxxy/ast/lox_compound_expr.rb
97
98
  - lib/loxxy/ast/lox_for_stmt.rb
98
99
  - lib/loxxy/ast/lox_fun_stmt.rb
@@ -113,6 +114,7 @@ files:
113
114
  - lib/loxxy/back_end/engine.rb
114
115
  - lib/loxxy/back_end/entry.rb
115
116
  - lib/loxxy/back_end/environment.rb
117
+ - lib/loxxy/back_end/lox_class.rb
116
118
  - lib/loxxy/back_end/lox_function.rb
117
119
  - lib/loxxy/back_end/resolver.rb
118
120
  - lib/loxxy/back_end/symbol_table.rb