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 +4 -4
- data/CHANGELOG.md +23 -3
- data/lib/loxxy/ast/all_lox_nodes.rb +1 -0
- data/lib/loxxy/ast/ast_builder.rb +25 -0
- data/lib/loxxy/ast/ast_visitor.rb +8 -0
- data/lib/loxxy/ast/lox_class_stmt.rb +27 -0
- data/lib/loxxy/ast/lox_fun_stmt.rb +1 -1
- data/lib/loxxy/back_end/engine.rb +7 -0
- data/lib/loxxy/back_end/lox_class.rb +41 -0
- data/lib/loxxy/back_end/lox_function.rb +1 -2
- data/lib/loxxy/back_end/resolver.rb +10 -1
- data/lib/loxxy/front_end/grammar.rb +7 -5
- data/lib/loxxy/version.rb +1 -1
- data/spec/interpreter_spec.rb +17 -0
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: aee9fb6c5101bc39682ab401ffc0434aea9e6c4115f74a4f641d0df2d68a03ad
|
4
|
+
data.tar.gz: ccc11c428ef206db9129fabbb97526df3477e03c5dce0b1b5a2f758425c8f9cb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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 `
|
114
|
-
- Method `
|
115
|
-
- Method `
|
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`
|
@@ -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
|
@@ -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
|
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
|
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
|
44
|
-
rule('
|
45
|
-
rule('
|
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
data/spec/interpreter_spec.rb
CHANGED
@@ -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.
|
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
|
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
|