loxxy 0.0.11 → 0.0.12
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 +13 -0
- data/README.md +28 -50
- data/lib/loxxy.rb +23 -2
- data/lib/loxxy/ast/all_lox_nodes.rb +5 -0
- data/lib/loxxy/ast/ast_builder.rb +48 -27
- data/lib/loxxy/ast/ast_visitor.rb +36 -56
- data/lib/loxxy/ast/lox_compound_expr.rb +1 -1
- data/lib/loxxy/ast/lox_node.rb +5 -0
- data/lib/loxxy/ast/lox_noop_expr.rb +16 -0
- data/lib/loxxy/ast/lox_print_stmt.rb +22 -0
- data/lib/loxxy/back_end/engine.rb +48 -0
- data/lib/loxxy/datatype/builtin_datatype.rb +6 -0
- data/lib/loxxy/datatype/lx_string.rb +6 -0
- data/lib/loxxy/datatype/nil.rb +6 -0
- data/lib/loxxy/front_end/grammar.rb +3 -3
- data/lib/loxxy/interpreter.rb +38 -0
- data/lib/loxxy/version.rb +1 -1
- data/spec/back_end/engine_spec.rb +43 -0
- data/spec/datatype/boolean_spec.rb +31 -0
- data/spec/datatype/lx_string_spec.rb +4 -0
- data/spec/datatype/nil_spec.rb +26 -0
- data/spec/datatype/number_spec.rb +31 -0
- data/spec/front_end/parser_spec.rb +24 -34
- data/spec/interpreter_spec.rb +37 -0
- metadata +17 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7274fd2d139354b984962f9317cae890344e528540f2f157772e7395cdfd7d33
|
4
|
+
data.tar.gz: c1b38a4dfcb441c00604926cbaf397ab555624270ca647448d9cc4d4f463f500
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 27d5de6532213d1a995f86da84ccbd41a11b5f85c305e57a62f64637ad17852e622685e4261b1c62deb31c924bb8f8c29c4edd97e9776fabf7e0d06e5c302534
|
7
|
+
data.tar.gz: dab4a9e391c120c159a63e316f90065faf1415b54c9aa4c6f349f6be8e95de1289a2478f395e6b9e19b2e6f09482ae4db49a70e0d5d857eb5475cecad0590c69
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,16 @@
|
|
1
|
+
## [0.0.12] - 2021-01-09
|
2
|
+
- Initial interpreter capable of evaluating a tiny subset of Lox language.
|
3
|
+
|
4
|
+
## Added
|
5
|
+
- Class `AST::LoxNoopExpr`
|
6
|
+
- Class `AST::LoxPrintStmt`
|
7
|
+
- Class `BackEnd::Engine` implementation of the print statement logic
|
8
|
+
- Class `Interpreter`
|
9
|
+
|
10
|
+
## Changed
|
11
|
+
- Class `Ast::ASTVisitor` Added visit method
|
12
|
+
- File `README.md` added Hello world example.
|
13
|
+
|
1
14
|
## [0.0.11] - 2021-01-08
|
2
15
|
- AST node generation for logical expression (and, or).
|
3
16
|
|
data/README.md
CHANGED
@@ -13,58 +13,26 @@ a simple language used in Bob Nystrom's online book [Crafting Interpreters](http
|
|
13
13
|
a Lox interpreter written in Lox.
|
14
14
|
|
15
15
|
## Current status
|
16
|
-
The
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
### TODO
|
35
|
-
AST Node generation
|
36
|
-
Goal: parser should generate AST for any input Lox program
|
37
|
-
- [X] Equality operator
|
38
|
-
- [X] Logical operator (and, or)
|
39
|
-
- [] Unary expressions (negate, not)
|
40
|
-
- [] Grouping expressions
|
41
|
-
- [] Print statement
|
42
|
-
- [] Simple assignment expressions
|
43
|
-
- [] Variable declaration
|
44
|
-
- [] Dot notation
|
45
|
-
- [] Block statement
|
46
|
-
- [] If statement
|
47
|
-
- [] For statement
|
48
|
-
- [] While statement
|
49
|
-
- [] Function declaration
|
50
|
-
- [] Call expression
|
51
|
-
- [] Return statement
|
52
|
-
- [] Class declaration
|
53
|
-
- [] AST generation covers complete grammar
|
54
|
-
|
55
|
-
Tree-walking:
|
56
|
-
- [] Tree visitor recognizes all AST node types
|
57
|
-
|
58
|
-
Interpreter:
|
59
|
-
- Keywords: symbol table, scope, activation record, class & object model, Lox test suite
|
60
|
-
- [] Milestone: Interpreter handles expressions but function calls
|
61
|
-
- [] Milestone: Interpreter handles `for`, `if`, `print`, `while` and block statements
|
62
|
-
- [] Milestone: Interpreter handles variable declarations (global, block)
|
63
|
-
- [] Milestone: Interpreter handles function declarations and calls
|
64
|
-
- [] Milestone: Interpreter supports class and object definition
|
65
|
-
- [] Milestone: Lox interpreter complete
|
16
|
+
The project is still in inception and the interpreter is being implemented...
|
17
|
+
Currently it can execute a very limited subset of __Lox__ language.
|
18
|
+
|
19
|
+
The __loxxy__ gem also a parser class `RawPaser` that can, in principle, any valid Lox input.
|
20
|
+
|
21
|
+
## Hello world example
|
22
|
+
```ruby
|
23
|
+
require 'loxxy'
|
24
|
+
|
25
|
+
lox_program = <<LOX_END
|
26
|
+
// Your first Lox program!
|
27
|
+
print "Hello, world!";
|
28
|
+
LOX_END
|
29
|
+
|
30
|
+
lox = Loxxy::Interpreter.new
|
31
|
+
lox.evaluate(lox_program) # => Hello, world!
|
32
|
+
```
|
66
33
|
|
67
34
|
## Example using RawParser class
|
35
|
+
|
68
36
|
```ruby
|
69
37
|
require 'loxxy'
|
70
38
|
|
@@ -109,6 +77,16 @@ program
|
|
109
77
|
+-- EOF: ''
|
110
78
|
```
|
111
79
|
|
80
|
+
## Suppported Lox language features
|
81
|
+
Although the interpreter should parse almost any valid Lox program,
|
82
|
+
it currently can evaluate a tiny set of AST node (AST = Abstract Syntax Tree).
|
83
|
+
|
84
|
+
Here are the language features supported by the interpreter:
|
85
|
+
- Line comments,
|
86
|
+
- All the Lox literals (booleans, numbers, strings and nil),
|
87
|
+
- `print` statement.
|
88
|
+
|
89
|
+
|
112
90
|
## Installation
|
113
91
|
|
114
92
|
Add this line to your application's Gemfile:
|
data/lib/loxxy.rb
CHANGED
@@ -1,10 +1,31 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require_relative 'loxxy/version'
|
4
|
+
require_relative 'loxxy/interpreter'
|
4
5
|
require_relative 'loxxy/front_end/raw_parser'
|
5
|
-
require_relative 'loxxy/front_end/parser'
|
6
6
|
|
7
|
+
# Namespace for all classes and constants of __loxxy__ gem.
|
7
8
|
module Loxxy
|
8
9
|
class Error < StandardError; end
|
9
|
-
|
10
|
+
|
11
|
+
# Shorthand method. Returns the sole object that represents
|
12
|
+
# a Lox false literal.
|
13
|
+
# @return [Loxxy::Datatype::False]
|
14
|
+
def self.lox_false
|
15
|
+
Datatype::False.instance
|
16
|
+
end
|
17
|
+
|
18
|
+
# Shorthand method. Returns the sole object that represents
|
19
|
+
# a Lox nil literal.
|
20
|
+
# @return [Loxxy::Datatype::Nil]
|
21
|
+
def self.lox_nil
|
22
|
+
Datatype::Nil.instance
|
23
|
+
end
|
24
|
+
|
25
|
+
# Shorthand method. Returns the sole object that represents
|
26
|
+
# a Lox true literal.
|
27
|
+
# @return [Loxxy::Datatype::True]
|
28
|
+
def self.lox_true
|
29
|
+
Datatype::False.instance
|
30
|
+
end
|
10
31
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require_relative '../datatype/all_datatypes'
|
4
|
-
require_relative '
|
4
|
+
require_relative 'all_lox_nodes'
|
5
5
|
require_relative 'lox_binary_expr'
|
6
6
|
|
7
7
|
module Loxxy
|
@@ -10,31 +10,33 @@ module Loxxy
|
|
10
10
|
# (Abstract Syntax Tree) from a sequence of input tokens and
|
11
11
|
# visit events produced by walking over a GFGParsing object.
|
12
12
|
class ASTBuilder < Rley::ParseRep::ASTBaseBuilder
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
13
|
+
unless defined?(Name2special)
|
14
|
+
# Mapping Token name => operator | separator | delimiter characters
|
15
|
+
# @return [Hash{String => String}]
|
16
|
+
Name2special = {
|
17
|
+
'AND' => 'and',
|
18
|
+
'BANG' => '!',
|
19
|
+
'BANG_EQUAL' => '!=',
|
20
|
+
'COMMA' => ',',
|
21
|
+
'DOT' => '.',
|
22
|
+
'EQUAL' => '=',
|
23
|
+
'EQUAL_EQUAL' => '==',
|
24
|
+
'GREATER' => '>',
|
25
|
+
'GREATER_EQUAL' => '>=',
|
26
|
+
'LEFT_BRACE' => '{',
|
27
|
+
'LEFT_PAREN' => '(',
|
28
|
+
'LESS' => '<',
|
29
|
+
'LESS_EQUAL' => '<=',
|
30
|
+
'MINUS' => '-',
|
31
|
+
'OR' => 'or',
|
32
|
+
'PLUS' => '+',
|
33
|
+
'RIGHT_BRACE' => '}',
|
34
|
+
'RIGHT_PAREN' => ')',
|
35
|
+
'SEMICOLON' => ';',
|
36
|
+
'SLASH' => '/',
|
37
|
+
'STAR' => '*'
|
38
|
+
}.freeze
|
39
|
+
end # defined
|
38
40
|
|
39
41
|
attr_reader :strict
|
40
42
|
|
@@ -117,6 +119,25 @@ module Loxxy
|
|
117
119
|
[[operator, operand2]]
|
118
120
|
end
|
119
121
|
|
122
|
+
#####################################
|
123
|
+
# SEMANTIC ACTIONS
|
124
|
+
#####################################
|
125
|
+
|
126
|
+
# rule('program' => 'EOF').as 'null_program'
|
127
|
+
def reduce_null_program(_production, range, _tokens, _theChildren)
|
128
|
+
Ast::LoxNoopExpr.new(tokens[0].position)
|
129
|
+
end
|
130
|
+
|
131
|
+
# rule('program' => 'declaration_plus EOF').as ''
|
132
|
+
def reduce_lox_program(_production, range, tokens, theChildren)
|
133
|
+
return_first_child(range, tokens, theChildren)
|
134
|
+
end
|
135
|
+
|
136
|
+
# rule('printStmt' => 'PRINT expression SEMICOLON')
|
137
|
+
def reduce_print_stmt(_production, _range, tokens, theChildren)
|
138
|
+
Ast::LoxPrintStmt.new(tokens[1].position, theChildren[1])
|
139
|
+
end
|
140
|
+
|
120
141
|
# rule('logic_or' => 'logic_and disjunct_plus')
|
121
142
|
def reduce_logic_or_plus(production, range, tokens, theChildren)
|
122
143
|
reduce_binary_operator(production, range, tokens, theChildren)
|
@@ -141,7 +162,7 @@ module Loxxy
|
|
141
162
|
def reduce_logic_and_plus_more(production, range, tokens, theChildren)
|
142
163
|
reduce_binary_plus_more(production, range, tokens, theChildren)
|
143
164
|
end
|
144
|
-
|
165
|
+
|
145
166
|
# rule('conjunct_plus' => 'AND equality')
|
146
167
|
def reduce_logic_and_plus_end(production, range, tokens, theChildren)
|
147
168
|
reduce_binary_plus_end(production, range, tokens, theChildren)
|
@@ -39,75 +39,55 @@ module Loxxy
|
|
39
39
|
top.accept(self)
|
40
40
|
end
|
41
41
|
|
42
|
-
# Visit event. The visitor is
|
43
|
-
#
|
44
|
-
|
45
|
-
|
46
|
-
broadcast(:before_literal_expr, aLiteralExpr)
|
47
|
-
broadcast(:after_literal_expr, aLiteralExpr)
|
42
|
+
# Visit event. The visitor is about to visit the ptree.
|
43
|
+
# @param aParseTree [Rley::PTre::ParseTree] the ptree to visit.
|
44
|
+
def start_visit_ptree(aParseTree)
|
45
|
+
broadcast(:before_ptree, aParseTree)
|
48
46
|
end
|
49
47
|
|
50
|
-
|
51
|
-
|
48
|
+
# Visit event. The visitor has completed the visit of the ptree.
|
49
|
+
# @param aParseTree [Rley::PTre::ParseTree] the visited ptree.
|
50
|
+
def end_visit_ptree(aParseTree)
|
51
|
+
broadcast(:after_ptree, aParseTree)
|
52
|
+
end
|
52
53
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
broadcast(:
|
54
|
+
# Visit event. The visitor is about to visit a print statement expression.
|
55
|
+
# @param aPrintStmt [AST::LOXPrintStmt] the print statement node to visit
|
56
|
+
def visit_print_stmt(aPrintStmt)
|
57
|
+
broadcast(:before_print_stmt, aPrintStmt)
|
58
|
+
traverse_subnodes(aPrintStmt)
|
59
|
+
broadcast(:after_print_stmt, aPrintStmt)
|
57
60
|
end
|
58
61
|
|
59
62
|
# Visit event. The visitor is visiting the
|
60
|
-
# given
|
61
|
-
# @param
|
62
|
-
def
|
63
|
-
broadcast(:
|
64
|
-
broadcast(:
|
63
|
+
# given terminal node containing a datatype object.
|
64
|
+
# @param aLiteralExpr [AST::LoxLiteralExpr] the leaf node to visit.
|
65
|
+
def visit_literal_expr(aLiteralExpr)
|
66
|
+
broadcast(:before_literal_expr, aLiteralExpr)
|
67
|
+
broadcast(:after_literal_expr, aLiteralExpr)
|
65
68
|
end
|
66
69
|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
=begin
|
74
|
-
# Visit event. The visitor is about to visit the given non terminal node.
|
75
|
-
# @param aNonTerminalNode [NonTerminalNode] the node to visit.
|
76
|
-
def visit_nonterminal(aNonTerminalNode)
|
77
|
-
if @traversal == :post_order
|
78
|
-
broadcast(:before_non_terminal, aNonTerminalNode)
|
79
|
-
traverse_subnodes(aNonTerminalNode)
|
80
|
-
else
|
81
|
-
traverse_subnodes(aNonTerminalNode)
|
82
|
-
broadcast(:before_non_terminal, aNonTerminalNode)
|
70
|
+
# Visit event. The visitor is about to visit the given non terminal node.
|
71
|
+
# @param aNonTerminalNode [Rley::PTre::NonTerminalNode] the node to visit.
|
72
|
+
def visit_nonterminal(_non_terminal_node)
|
73
|
+
# Loxxy interpreter encountered a CST node (Concrete Syntax Tree)
|
74
|
+
# that it cannot handle.
|
75
|
+
raise NotImplementedError, 'Loxxy cannot execute this code yet.'
|
83
76
|
end
|
84
|
-
broadcast(:after_non_terminal, aNonTerminalNode)
|
85
|
-
end
|
86
|
-
=end
|
87
77
|
|
88
78
|
private
|
89
79
|
|
90
|
-
|
91
|
-
|
92
|
-
|
80
|
+
# Visit event. The visitor is about to visit the subnodes of a non
|
81
|
+
# terminal node.
|
82
|
+
# @param aParentNode [Ast::LocCompoundExpr] the parent node.
|
83
|
+
def traverse_subnodes(aParentNode)
|
84
|
+
subnodes = aParentNode.subnodes
|
85
|
+
broadcast(:before_subnodes, aParentNode, subnodes)
|
93
86
|
|
94
|
-
# Let's proceed with the visit of
|
95
|
-
|
87
|
+
# Let's proceed with the visit of subnodes
|
88
|
+
subnodes.each { |a_node| a_node.accept(self) }
|
96
89
|
|
97
|
-
broadcast(:
|
98
|
-
end
|
99
|
-
|
100
|
-
def traverse_car_cdr(aPair)
|
101
|
-
if aPair.car
|
102
|
-
broadcast(:before_car, aPair, aPair.car)
|
103
|
-
aPair.car.accept(self)
|
104
|
-
broadcast(:after_car, aPair, aPair.car)
|
105
|
-
end
|
106
|
-
if aPair.cdr
|
107
|
-
broadcast(:before_cdr, aPair, aPair.cdr)
|
108
|
-
aPair.cdr.accept(self)
|
109
|
-
broadcast(:after_cdr, aPair, aPair.cdr)
|
110
|
-
end
|
90
|
+
broadcast(:after_subnodes, aParentNode, subnodes)
|
111
91
|
end
|
112
92
|
|
113
93
|
# Send a notification to all subscribers.
|
@@ -117,7 +97,7 @@ module Loxxy
|
|
117
97
|
subscribers.each do |subscr|
|
118
98
|
next unless subscr.respond_to?(msg) || subscr.respond_to?(:accept_all)
|
119
99
|
|
120
|
-
subscr.send(msg,
|
100
|
+
subscr.send(msg, *args)
|
121
101
|
end
|
122
102
|
end
|
123
103
|
end # class
|
@@ -5,7 +5,7 @@ require_relative 'lox_node'
|
|
5
5
|
module Loxxy
|
6
6
|
module Ast
|
7
7
|
class LoxCompoundExpr < LoxNode
|
8
|
-
# @return [Array<Ast::LoxNode>]
|
8
|
+
# @return [Array<Ast::LoxNode>] the children nodes (sub-expressions)
|
9
9
|
attr_reader :subnodes
|
10
10
|
|
11
11
|
# @param aPosition [Rley::Lexical::Position] Position of the entry in the input stream.
|
data/lib/loxxy/ast/lox_node.rb
CHANGED
@@ -11,6 +11,11 @@ module Loxxy
|
|
11
11
|
@position = aPosition
|
12
12
|
end
|
13
13
|
|
14
|
+
# Notification that the parsing was successfully completed
|
15
|
+
def done!
|
16
|
+
# Default: do nothing ...
|
17
|
+
end
|
18
|
+
|
14
19
|
# Abstract method.
|
15
20
|
# Part of the 'visitee' role in Visitor design pattern.
|
16
21
|
# @param _visitor [LoxxyTreeVisitor] the visitor
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'lox_node'
|
4
|
+
|
5
|
+
module Loxxy
|
6
|
+
module Ast
|
7
|
+
class LoxNoopExpr < LoxNode
|
8
|
+
# Abstract method.
|
9
|
+
# Part of the 'visitee' role in Visitor design pattern.
|
10
|
+
# @param _visitor [LoxxyTreeVisitor] the visitor
|
11
|
+
def accept(_visitor)
|
12
|
+
# Do nothing...
|
13
|
+
end
|
14
|
+
end # class
|
15
|
+
end # module
|
16
|
+
end # module
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'lox_compound_expr'
|
4
|
+
|
5
|
+
module Loxxy
|
6
|
+
module Ast
|
7
|
+
class LoxPrintStmt < LoxCompoundExpr
|
8
|
+
# @param aPosition [Rley::Lexical::Position] Position of the entry in the input stream.
|
9
|
+
# @param anExpression [Ast::LoxNode] expression to output
|
10
|
+
def initialize(aPosition, anExpression)
|
11
|
+
super(aPosition, [anExpression])
|
12
|
+
end
|
13
|
+
|
14
|
+
# Abstract method.
|
15
|
+
# Part of the 'visitee' role in Visitor design pattern.
|
16
|
+
# @param visitor [Ast::ASTVisitor] the visitor
|
17
|
+
def accept(visitor)
|
18
|
+
visitor.visit_print_stmt(self)
|
19
|
+
end
|
20
|
+
end # class
|
21
|
+
end # module
|
22
|
+
end # module
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Load all the classes implementing AST nodes
|
4
|
+
require_relative '../ast/all_lox_nodes'
|
5
|
+
|
6
|
+
module Loxxy
|
7
|
+
module BackEnd
|
8
|
+
# An instance of this class executes the statements as when they
|
9
|
+
# occur during the abstract syntax tree walking.
|
10
|
+
# @note WIP: very crude implementation.
|
11
|
+
class Engine
|
12
|
+
# @return [Hash] A set of configuration options
|
13
|
+
attr_reader :config
|
14
|
+
|
15
|
+
# @return [Array] Data stack used for passing data between statements
|
16
|
+
attr_reader :stack
|
17
|
+
|
18
|
+
# @param theOptions [Hash]
|
19
|
+
def initialize(theOptions)
|
20
|
+
@config = theOptions
|
21
|
+
@ostream = config.include?(:ostream) ? config[:ostream] : $stdout
|
22
|
+
@stack = []
|
23
|
+
end
|
24
|
+
|
25
|
+
# Given an abstract syntax parse tree visitor, luanch the visit
|
26
|
+
# and execute the visit events in the output stream.
|
27
|
+
# @param aVisitor [AST::ASTVisitor]
|
28
|
+
def execute(aVisitor)
|
29
|
+
aVisitor.subscribe(self)
|
30
|
+
aVisitor.start
|
31
|
+
aVisitor.unsubscribe(self)
|
32
|
+
stack.empty? ? Datatype::Nil.instance : stack.pop
|
33
|
+
end
|
34
|
+
|
35
|
+
# Visit event handling
|
36
|
+
|
37
|
+
def after_print_stmt(_printStmt)
|
38
|
+
tos = stack.pop
|
39
|
+
@ostream.print tos.to_str
|
40
|
+
end
|
41
|
+
|
42
|
+
# @param literalExpr [Ast::LoxLiteralExpr]
|
43
|
+
def before_literal_expr(literalExpr)
|
44
|
+
stack.push(literalExpr.literal)
|
45
|
+
end
|
46
|
+
end # class
|
47
|
+
end # module
|
48
|
+
end # module
|
@@ -14,6 +14,12 @@ module Loxxy
|
|
14
14
|
@value = validated_value(aValue)
|
15
15
|
end
|
16
16
|
|
17
|
+
# Method called from Lox to obtain the text representation of the boolean.
|
18
|
+
# @return [String]
|
19
|
+
def to_str
|
20
|
+
value.to_s # Default implementation...
|
21
|
+
end
|
22
|
+
|
17
23
|
protected
|
18
24
|
|
19
25
|
def validated_value(aValue)
|
data/lib/loxxy/datatype/nil.rb
CHANGED
@@ -13,6 +13,12 @@ module Loxxy
|
|
13
13
|
def initialize
|
14
14
|
super(nil)
|
15
15
|
end
|
16
|
+
|
17
|
+
# Method called from Lox to obtain the text representation of nil.
|
18
|
+
# @return [String]
|
19
|
+
def to_str
|
20
|
+
'nil'
|
21
|
+
end
|
16
22
|
end # class
|
17
23
|
|
18
24
|
Nil.instance.freeze # Make the sole instance immutable
|
@@ -26,8 +26,8 @@ module Loxxy
|
|
26
26
|
add_terminals('EOF')
|
27
27
|
|
28
28
|
# Top-level rule that matches an entire Lox program
|
29
|
-
rule('program' => 'EOF')
|
30
|
-
rule('program' => 'declaration_plus EOF')
|
29
|
+
rule('program' => 'EOF').as 'null_program'
|
30
|
+
rule('program' => 'declaration_plus EOF').as 'lox_program'
|
31
31
|
|
32
32
|
# Declarations: bind an identifier to something
|
33
33
|
rule('declaration_plus' => 'declaration_plus declaration')
|
@@ -73,7 +73,7 @@ module Loxxy
|
|
73
73
|
rule('elsePart_opt' => 'ELSE statement')
|
74
74
|
rule('elsePart_opt' => [])
|
75
75
|
|
76
|
-
rule('printStmt' => 'PRINT expression SEMICOLON')
|
76
|
+
rule('printStmt' => 'PRINT expression SEMICOLON').as 'print_stmt'
|
77
77
|
rule('returnStmt' => 'RETURN expression_opt SEMICOLON')
|
78
78
|
rule('whileStmt' => 'WHILE LEFT_PAREN expression RIGHT_PAREN statement')
|
79
79
|
rule('block' => 'LEFT_BRACE declaration_plus RIGHT_BRACE')
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative './front_end/parser'
|
4
|
+
require_relative './ast/ast_visitor'
|
5
|
+
require_relative './back_end/engine'
|
6
|
+
|
7
|
+
module Loxxy
|
8
|
+
# A Lox tree-walking interpreter.
|
9
|
+
# It acts as a facade object that:
|
10
|
+
# - hides the internal plumbings of the front-end and back-end parts.
|
11
|
+
# - delegates all the core work to its subordinate objects.
|
12
|
+
# @note WIP: very crude implementation.
|
13
|
+
class Interpreter
|
14
|
+
# return [Hash]
|
15
|
+
attr_reader :config
|
16
|
+
|
17
|
+
# @param theOptions [Hash]
|
18
|
+
def initialize(theOptions = {})
|
19
|
+
@config = theOptions
|
20
|
+
end
|
21
|
+
|
22
|
+
# Evaluate the given Lox program
|
23
|
+
# @param lox_input [String] Lox program to evaluate
|
24
|
+
def evaluate(lox_input)
|
25
|
+
# Front-end scans, parses the input and blurps an AST...
|
26
|
+
parser = FrontEnd::Parser.new
|
27
|
+
|
28
|
+
# The AST is the data object passed to the back-end
|
29
|
+
ast_tree = parser.parse(lox_input)
|
30
|
+
visitor = Ast::ASTVisitor.new(ast_tree)
|
31
|
+
|
32
|
+
# Back-end launches the tree walking & reponds to visit events
|
33
|
+
# by executing the code determined by the visited AST node.
|
34
|
+
engine = BackEnd::Engine.new(config)
|
35
|
+
engine.execute(visitor)
|
36
|
+
end
|
37
|
+
end # class
|
38
|
+
end # module
|
data/lib/loxxy/version.rb
CHANGED
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../spec_helper' # Use the RSpec framework
|
4
|
+
require 'stringio'
|
5
|
+
|
6
|
+
# Load the class under test
|
7
|
+
require_relative '../../lib/loxxy/back_end/engine'
|
8
|
+
|
9
|
+
module Loxxy
|
10
|
+
module BackEnd
|
11
|
+
describe Engine do
|
12
|
+
let(:sample_options) do
|
13
|
+
{ ostream: StringIO.new }
|
14
|
+
end
|
15
|
+
subject { Engine.new(sample_options) }
|
16
|
+
|
17
|
+
context 'Initialization:' do
|
18
|
+
it 'should accept a option Hash at initialization' do
|
19
|
+
expect { Engine.new(sample_options) }.not_to raise_error
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'should know its config options' do
|
23
|
+
expect(subject.config).to eq(sample_options)
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'should have an empty stack' do
|
27
|
+
expect(subject.stack).to be_empty
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
context 'Listening to visitor events:' do
|
32
|
+
let(:greeting) { Datatype::LXString.new('Hello, world') }
|
33
|
+
let(:sample_pos) { double('fake-position') }
|
34
|
+
let(:lit_expr) { Ast::LoxLiteralExpr.new(sample_pos, greeting) }
|
35
|
+
|
36
|
+
it "should react to 'before_literal_expr' event" do
|
37
|
+
expect { subject.before_literal_expr(lit_expr) }.not_to raise_error
|
38
|
+
expect(subject.stack.pop).to eq(greeting)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end # describe
|
42
|
+
end # module
|
43
|
+
end # module
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../spec_helper' # Use the RSpec framework
|
4
|
+
|
5
|
+
# Load the class under test
|
6
|
+
require_relative '../../lib/loxxy/datatype/boolean'
|
7
|
+
|
8
|
+
module Loxxy
|
9
|
+
module Datatype
|
10
|
+
describe Boolean do
|
11
|
+
let(:thruth_value) { false }
|
12
|
+
subject { Boolean.new(thruth_value) }
|
13
|
+
|
14
|
+
context 'Initialization:' do
|
15
|
+
it 'should accept a boolean value at initialization' do
|
16
|
+
expect { Boolean.new(thruth_value) }.not_to raise_error
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'should know its value' do
|
20
|
+
expect(subject.value).to eq(thruth_value)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
context 'Provided services:' do
|
25
|
+
it 'should give its display representation' do
|
26
|
+
expect(subject.to_str).to eq('false')
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end # describe
|
30
|
+
end # module
|
31
|
+
end # module
|
@@ -22,6 +22,10 @@ module Loxxy
|
|
22
22
|
end
|
23
23
|
|
24
24
|
context 'Provided services:' do
|
25
|
+
it 'should give its display representation' do
|
26
|
+
expect(subject.to_str).to eq(sample_text)
|
27
|
+
end
|
28
|
+
|
25
29
|
it 'compares with another string' do
|
26
30
|
expect(subject).to eq(sample_text)
|
27
31
|
expect(subject).to eq(LXString.new(sample_text.dup))
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../spec_helper' # Use the RSpec framework
|
4
|
+
|
5
|
+
# Load the class under test
|
6
|
+
require_relative '../../lib/loxxy/datatype/boolean'
|
7
|
+
|
8
|
+
module Loxxy
|
9
|
+
module Datatype
|
10
|
+
describe Nil do
|
11
|
+
subject { Nil.instance }
|
12
|
+
|
13
|
+
context 'Initialization:' do
|
14
|
+
it 'should know its value' do
|
15
|
+
expect(subject.value).to be_nil
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
context 'Provided services:' do
|
20
|
+
it 'should give its display representation' do
|
21
|
+
expect(subject.to_str).to eq('nil')
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end # describe
|
25
|
+
end # module
|
26
|
+
end # module
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../spec_helper' # Use the RSpec framework
|
4
|
+
|
5
|
+
# Load the class under test
|
6
|
+
require_relative '../../lib/loxxy/datatype/number'
|
7
|
+
|
8
|
+
module Loxxy
|
9
|
+
module Datatype
|
10
|
+
describe Number do
|
11
|
+
let(:sample_value) { -12.34 }
|
12
|
+
subject { Number.new(sample_value) }
|
13
|
+
|
14
|
+
context 'Initialization:' do
|
15
|
+
it 'should accept a Numeric value at initialization' do
|
16
|
+
expect { Number.new(sample_value) }.not_to raise_error
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'should know its value' do
|
20
|
+
expect(subject.value).to eq(sample_value)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
context 'Provided services:' do
|
25
|
+
it 'should give its display representation' do
|
26
|
+
expect(subject.to_str).to eq(sample_value.to_s)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end # describe
|
30
|
+
end # module
|
31
|
+
end # module
|
@@ -37,7 +37,7 @@ module Loxxy
|
|
37
37
|
# Parse results MUST to comply to grammar rule:
|
38
38
|
# program => declaration_star EOF
|
39
39
|
# where the declaration_star MUST be empty
|
40
|
-
expect(aParseTree.root
|
40
|
+
expect(aParseTree.root).to be_kind_of(Ast::LoxNoopExpr)
|
41
41
|
end
|
42
42
|
|
43
43
|
it 'should cope with an empty input' do
|
@@ -64,7 +64,7 @@ module Loxxy
|
|
64
64
|
it 'should parse a false literal' do
|
65
65
|
input = 'false;'
|
66
66
|
ptree = subject.parse(input)
|
67
|
-
leaf =
|
67
|
+
leaf = ptree.root.subnodes[0]
|
68
68
|
expect(leaf).to be_kind_of(Ast::LoxLiteralExpr)
|
69
69
|
expect(leaf.literal).to be_equal(Datatype::False.instance)
|
70
70
|
end
|
@@ -72,7 +72,7 @@ module Loxxy
|
|
72
72
|
it 'should parse a true literal' do
|
73
73
|
input = 'true;'
|
74
74
|
ptree = subject.parse(input)
|
75
|
-
leaf =
|
75
|
+
leaf = ptree.root.subnodes[0]
|
76
76
|
expect(leaf).to be_kind_of(Ast::LoxLiteralExpr)
|
77
77
|
expect(leaf.literal).to be_equal(Datatype::True.instance)
|
78
78
|
end
|
@@ -81,7 +81,7 @@ module Loxxy
|
|
81
81
|
inputs = %w[1234; 12.34;]
|
82
82
|
inputs.each do |source|
|
83
83
|
ptree = subject.parse(source)
|
84
|
-
leaf =
|
84
|
+
leaf = ptree.root.subnodes[0]
|
85
85
|
expect(leaf).to be_kind_of(Ast::LoxLiteralExpr)
|
86
86
|
expect(leaf.literal).to be_kind_of(Datatype::Number)
|
87
87
|
expect(leaf.literal.value).to eq(source.to_f)
|
@@ -96,7 +96,7 @@ module Loxxy
|
|
96
96
|
]
|
97
97
|
inputs.each do |source|
|
98
98
|
ptree = subject.parse(source)
|
99
|
-
leaf =
|
99
|
+
leaf = ptree.root.subnodes[0]
|
100
100
|
expect(leaf).to be_kind_of(Ast::LoxLiteralExpr)
|
101
101
|
expect(leaf.literal).to be_kind_of(Datatype::LXString)
|
102
102
|
expect(leaf.literal.value).to eq(source.gsub(/(^")|(";$)/, ''))
|
@@ -106,7 +106,7 @@ module Loxxy
|
|
106
106
|
it 'should parse a nil literal' do
|
107
107
|
input = 'nil;'
|
108
108
|
ptree = subject.parse(input)
|
109
|
-
leaf =
|
109
|
+
leaf = ptree.root.subnodes[0]
|
110
110
|
expect(leaf).to be_kind_of(Ast::LoxLiteralExpr)
|
111
111
|
expect(leaf.literal).to be_equal(Datatype::Nil.instance)
|
112
112
|
end
|
@@ -119,21 +119,11 @@ module Loxxy
|
|
119
119
|
print "Hello, world!";
|
120
120
|
LOX_END
|
121
121
|
ptree = subject.parse(program)
|
122
|
-
|
123
|
-
expect(
|
124
|
-
(prnt_stmt
|
125
|
-
expect(prnt_stmt).to be_kind_of(
|
126
|
-
expect(prnt_stmt.
|
127
|
-
expect(prnt_stmt.subnodes.size).to eq(3)
|
128
|
-
expect(prnt_stmt.subnodes[0]).to be_kind_of(Rley::PTree::TerminalNode)
|
129
|
-
expect(prnt_stmt.subnodes[0].symbol.name).to eq('PRINT')
|
130
|
-
expect(prnt_stmt.subnodes[1]).to be_kind_of(Loxxy::Ast::LoxLiteralExpr)
|
131
|
-
expect(prnt_stmt.subnodes[1].literal).to be_kind_of(Loxxy::Datatype::LXString)
|
132
|
-
expect(prnt_stmt.subnodes[1].literal.value).to eq('Hello, world!')
|
133
|
-
expect(prnt_stmt.subnodes[2]).to be_kind_of(Rley::PTree::TerminalNode)
|
134
|
-
expect(prnt_stmt.subnodes[2].symbol.name).to eq('SEMICOLON')
|
135
|
-
expect(eof).to be_kind_of(Rley::PTree::TerminalNode)
|
136
|
-
expect(eof.symbol.name).to eq('EOF')
|
122
|
+
prnt_stmt = ptree.root
|
123
|
+
expect(prnt_stmt).to be_kind_of(Ast::LoxPrintStmt)
|
124
|
+
expect(prnt_stmt.subnodes[0]).to be_kind_of(Ast::LoxLiteralExpr)
|
125
|
+
expect(prnt_stmt.subnodes[0].literal).to be_kind_of(Loxxy::Datatype::LXString)
|
126
|
+
expect(prnt_stmt.subnodes[0].literal.value).to eq('Hello, world!')
|
137
127
|
end
|
138
128
|
end # context
|
139
129
|
|
@@ -141,7 +131,7 @@ LOX_END
|
|
141
131
|
it 'should parse the addition of two number literals' do
|
142
132
|
input = '123 + 456;'
|
143
133
|
ptree = subject.parse(input)
|
144
|
-
parent = ptree.root
|
134
|
+
parent = ptree.root
|
145
135
|
expect(parent).to be_kind_of(Rley::PTree::NonTerminalNode)
|
146
136
|
expect(parent.symbol.name).to eq('exprStmt')
|
147
137
|
expr = parent.subnodes[0]
|
@@ -154,7 +144,7 @@ LOX_END
|
|
154
144
|
it 'should parse the subtraction of two number literals' do
|
155
145
|
input = '4 - 3;'
|
156
146
|
ptree = subject.parse(input)
|
157
|
-
parent = ptree.root
|
147
|
+
parent = ptree.root
|
158
148
|
expect(parent).to be_kind_of(Rley::PTree::NonTerminalNode)
|
159
149
|
expect(parent.symbol.name).to eq('exprStmt')
|
160
150
|
expr = parent.subnodes[0]
|
@@ -167,7 +157,7 @@ LOX_END
|
|
167
157
|
it 'should parse multiple additive operations' do
|
168
158
|
input = '5 + 2 - 3;'
|
169
159
|
ptree = subject.parse(input)
|
170
|
-
parent = ptree.root
|
160
|
+
parent = ptree.root
|
171
161
|
expect(parent).to be_kind_of(Rley::PTree::NonTerminalNode)
|
172
162
|
expect(parent.symbol.name).to eq('exprStmt')
|
173
163
|
expr = parent.subnodes[0]
|
@@ -183,7 +173,7 @@ LOX_END
|
|
183
173
|
it 'should parse the division of two number literals' do
|
184
174
|
input = '8 / 2;'
|
185
175
|
ptree = subject.parse(input)
|
186
|
-
parent = ptree.root
|
176
|
+
parent = ptree.root
|
187
177
|
expect(parent).to be_kind_of(Rley::PTree::NonTerminalNode)
|
188
178
|
expect(parent.symbol.name).to eq('exprStmt')
|
189
179
|
expr = parent.subnodes[0]
|
@@ -196,7 +186,7 @@ LOX_END
|
|
196
186
|
it 'should parse the product of two number literals' do
|
197
187
|
input = '12.34 * 0.3;'
|
198
188
|
ptree = subject.parse(input)
|
199
|
-
parent = ptree.root
|
189
|
+
parent = ptree.root
|
200
190
|
expect(parent).to be_kind_of(Rley::PTree::NonTerminalNode)
|
201
191
|
expect(parent.symbol.name).to eq('exprStmt')
|
202
192
|
expr = parent.subnodes[0]
|
@@ -209,7 +199,7 @@ LOX_END
|
|
209
199
|
it 'should parse multiple multiplicative operations' do
|
210
200
|
input = '5 * 2 / 3;'
|
211
201
|
ptree = subject.parse(input)
|
212
|
-
parent = ptree.root
|
202
|
+
parent = ptree.root
|
213
203
|
expect(parent).to be_kind_of(Rley::PTree::NonTerminalNode)
|
214
204
|
expect(parent.symbol.name).to eq('exprStmt')
|
215
205
|
expr = parent.subnodes[0]
|
@@ -225,7 +215,7 @@ LOX_END
|
|
225
215
|
it 'should parse combination of terms and factors' do
|
226
216
|
input = '5 + 2 / 3;'
|
227
217
|
ptree = subject.parse(input)
|
228
|
-
parent = ptree.root
|
218
|
+
parent = ptree.root
|
229
219
|
expect(parent).to be_kind_of(Rley::PTree::NonTerminalNode)
|
230
220
|
expect(parent.symbol.name).to eq('exprStmt')
|
231
221
|
expr = parent.subnodes[0]
|
@@ -243,7 +233,7 @@ LOX_END
|
|
243
233
|
it 'should parse the concatenation of two string literals' do
|
244
234
|
input = '"Lo" + "ve";'
|
245
235
|
ptree = subject.parse(input)
|
246
|
-
parent = ptree.root
|
236
|
+
parent = ptree.root
|
247
237
|
expect(parent).to be_kind_of(Rley::PTree::NonTerminalNode)
|
248
238
|
expect(parent.symbol.name).to eq('exprStmt')
|
249
239
|
expr = parent.subnodes[0]
|
@@ -259,7 +249,7 @@ LOX_END
|
|
259
249
|
%w[> >= < <=].each do |predicate|
|
260
250
|
input = "3 #{predicate} 2;"
|
261
251
|
ptree = subject.parse(input)
|
262
|
-
parent = ptree.root
|
252
|
+
parent = ptree.root
|
263
253
|
expect(parent).to be_kind_of(Rley::PTree::NonTerminalNode)
|
264
254
|
expect(parent.symbol.name).to eq('exprStmt')
|
265
255
|
expr = parent.subnodes[0]
|
@@ -276,7 +266,7 @@ LOX_END
|
|
276
266
|
%w[!= ==].each do |predicate|
|
277
267
|
input = "3 #{predicate} 2;"
|
278
268
|
ptree = subject.parse(input)
|
279
|
-
parent = ptree.root
|
269
|
+
parent = ptree.root
|
280
270
|
expect(parent).to be_kind_of(Rley::PTree::NonTerminalNode)
|
281
271
|
expect(parent.symbol.name).to eq('exprStmt')
|
282
272
|
expr = parent.subnodes[0]
|
@@ -290,7 +280,7 @@ LOX_END
|
|
290
280
|
it 'should parse combination of equality expressions' do
|
291
281
|
input = '5 != 2 == false; // A bit contrived example'
|
292
282
|
ptree = subject.parse(input)
|
293
|
-
parent = ptree.root
|
283
|
+
parent = ptree.root
|
294
284
|
expect(parent).to be_kind_of(Rley::PTree::NonTerminalNode)
|
295
285
|
expect(parent.symbol.name).to eq('exprStmt')
|
296
286
|
expr = parent.subnodes[0]
|
@@ -309,7 +299,7 @@ LOX_END
|
|
309
299
|
%w[or and].each do |connector|
|
310
300
|
input = "5 > 2 #{connector} 3 <= 4;"
|
311
301
|
ptree = subject.parse(input)
|
312
|
-
parent = ptree.root
|
302
|
+
parent = ptree.root
|
313
303
|
expect(parent).to be_kind_of(Rley::PTree::NonTerminalNode)
|
314
304
|
expect(parent.symbol.name).to eq('exprStmt')
|
315
305
|
expr = parent.subnodes[0]
|
@@ -329,7 +319,7 @@ LOX_END
|
|
329
319
|
it 'should parse a combinations of logical expressions' do
|
330
320
|
input = '4 > 3 and 1 < 2 or 4 >= 5;'
|
331
321
|
ptree = subject.parse(input)
|
332
|
-
parent = ptree.root
|
322
|
+
parent = ptree.root
|
333
323
|
expect(parent).to be_kind_of(Rley::PTree::NonTerminalNode)
|
334
324
|
expect(parent.symbol.name).to eq('exprStmt')
|
335
325
|
expr = parent.subnodes[0]
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'spec_helper' # Use the RSpec framework
|
4
|
+
require 'stringio'
|
5
|
+
|
6
|
+
# Load the class under test
|
7
|
+
require_relative '../lib/loxxy/interpreter'
|
8
|
+
|
9
|
+
module Loxxy
|
10
|
+
# This spec contains the bare bones test for the Interpreter class.
|
11
|
+
# The execution of Lox code is tested elsewhere.
|
12
|
+
describe Interpreter do
|
13
|
+
let(:sample_cfg) do
|
14
|
+
{ ostream: StringIO.new }
|
15
|
+
end
|
16
|
+
subject { Interpreter.new(sample_cfg) }
|
17
|
+
|
18
|
+
context 'Initialization:' do
|
19
|
+
it 'should accept a option Hash at initialization' do
|
20
|
+
expect { Interpreter.new(sample_cfg) }.not_to raise_error
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'should know its config options' do
|
24
|
+
expect(subject.config).to eq(sample_cfg)
|
25
|
+
end
|
26
|
+
end # context
|
27
|
+
|
28
|
+
context 'Evaluating Lox code:' do
|
29
|
+
let(:hello_world) { 'print "Hello, world!";' }
|
30
|
+
|
31
|
+
it 'should print the hello world message' do
|
32
|
+
expect { subject.evaluate(hello_world) }.not_to raise_error
|
33
|
+
expect(sample_cfg[:ostream].string).to eq('Hello, world!')
|
34
|
+
end
|
35
|
+
end # context
|
36
|
+
end # describe
|
37
|
+
end # module
|
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.0.
|
4
|
+
version: 0.0.12
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dimitri Geshef
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-01-
|
11
|
+
date: 2021-01-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rley
|
@@ -84,12 +84,16 @@ files:
|
|
84
84
|
- README.md
|
85
85
|
- Rakefile
|
86
86
|
- lib/loxxy.rb
|
87
|
+
- lib/loxxy/ast/all_lox_nodes.rb
|
87
88
|
- lib/loxxy/ast/ast_builder.rb
|
88
89
|
- lib/loxxy/ast/ast_visitor.rb
|
89
90
|
- lib/loxxy/ast/lox_binary_expr.rb
|
90
91
|
- lib/loxxy/ast/lox_compound_expr.rb
|
91
92
|
- lib/loxxy/ast/lox_literal_expr.rb
|
92
93
|
- lib/loxxy/ast/lox_node.rb
|
94
|
+
- lib/loxxy/ast/lox_noop_expr.rb
|
95
|
+
- lib/loxxy/ast/lox_print_stmt.rb
|
96
|
+
- lib/loxxy/back_end/engine.rb
|
93
97
|
- lib/loxxy/datatype/all_datatypes.rb
|
94
98
|
- lib/loxxy/datatype/boolean.rb
|
95
99
|
- lib/loxxy/datatype/builtin_datatype.rb
|
@@ -103,12 +107,18 @@ files:
|
|
103
107
|
- lib/loxxy/front_end/parser.rb
|
104
108
|
- lib/loxxy/front_end/raw_parser.rb
|
105
109
|
- lib/loxxy/front_end/scanner.rb
|
110
|
+
- lib/loxxy/interpreter.rb
|
106
111
|
- lib/loxxy/version.rb
|
107
112
|
- loxxy.gemspec
|
113
|
+
- spec/back_end/engine_spec.rb
|
114
|
+
- spec/datatype/boolean_spec.rb
|
108
115
|
- spec/datatype/lx_string_spec.rb
|
116
|
+
- spec/datatype/nil_spec.rb
|
117
|
+
- spec/datatype/number_spec.rb
|
109
118
|
- spec/front_end/parser_spec.rb
|
110
119
|
- spec/front_end/raw_parser_spec.rb
|
111
120
|
- spec/front_end/scanner_spec.rb
|
121
|
+
- spec/interpreter_spec.rb
|
112
122
|
- spec/loxxy_spec.rb
|
113
123
|
- spec/spec_helper.rb
|
114
124
|
homepage: https://github.com/famished-tiger/loxxy
|
@@ -136,8 +146,13 @@ signing_key:
|
|
136
146
|
specification_version: 4
|
137
147
|
summary: An implementation of the Lox programming language. WIP
|
138
148
|
test_files:
|
149
|
+
- spec/back_end/engine_spec.rb
|
150
|
+
- spec/datatype/boolean_spec.rb
|
139
151
|
- spec/datatype/lx_string_spec.rb
|
152
|
+
- spec/datatype/nil_spec.rb
|
153
|
+
- spec/datatype/number_spec.rb
|
140
154
|
- spec/front_end/parser_spec.rb
|
141
155
|
- spec/front_end/raw_parser_spec.rb
|
142
156
|
- spec/front_end/scanner_spec.rb
|
157
|
+
- spec/interpreter_spec.rb
|
143
158
|
- spec/loxxy_spec.rb
|