loxxy 0.0.10 → 0.0.15

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: e4f33203580d2b83ee7139e449787b439c0fb56c5a8c3dcc8035d114ffd957d3
4
- data.tar.gz: 46c9fb2f55849c6aa9b9e4d58588746ddb3ac3353f7ed09922d9394a9fc512c6
3
+ metadata.gz: 7624afc97e5e8d3cee171dc9fbbe7a45c45698595109a5281d9f58fcaebd73ec
4
+ data.tar.gz: 67ec959b7758245f414314ea9c8b0a2bbf40a5e01133f17325fa40ab720858f0
5
5
  SHA512:
6
- metadata.gz: 30f554af6338b50297ce6befaa62c86c8406df681e25098cc95dc28da64bb6feabbb9e085846eb8032f51d8d3655332105eb1d7165903bbd0d6be24cb13c4d0b
7
- data.tar.gz: d9d9a69a010d16807f6c4bf24b15e8135367bb62b6d2e052943e0d6030751f282c777f652dd3fced08093aee8abae228e63d365cae156fa6e87ac7f52fc7e2e6
6
+ metadata.gz: adcb9cf6b353b09cf623df330fbdff35255571f8781dfd0b46ea6ab32c02cf55bd0130f94414cd91aa8cb798b1ea7cd4aef4844acc556147b5e4b387d099b8c0
7
+ data.tar.gz: 47230281481b965fe1dddd74f763568a0ca125454800984c41fb29629d26c37ae8f7fa0320a38ca784abe605dfb5dc14f4a9c26b0d269240ea07c5e2feb6241b
@@ -1,3 +1,67 @@
1
+ ## [0.0.15] - 2021-01-11
2
+ - The interpreter can evaluate substraction between two numbers.
3
+
4
+ ## Added
5
+ - Method `Datatype::Number#-` implmenting the subtraction operation
6
+
7
+ ## Changed
8
+ - File `README.md` minor editorial changes.
9
+ - File `lx_string_spec.rb` Added test for string concatentation
10
+ - File `number_spec.rb` Added tests for addition and subtraction operations
11
+ - File `interpreter_spec.rb` Added tests for subtraction operation
12
+
13
+ ## [0.0.14] - 2021-01-10
14
+ - The interpreter can evaluate addition of numbers and string concatenation
15
+
16
+ ## Added
17
+ - Method `Ast::ASTVisitor::visit_binary_expr` for visiting binary expressions
18
+ - Method `Ast::LoxBinaryExpr#accept` for visitor pattern
19
+ - Method `BackEnd::Engine#after_binary_expr` to trigger execution of binary operator
20
+ - `Boolean` class hierarchy: added methos `true?` and `false?` to ease spec test writing
21
+ - Method `Datatype::LXString#+` implementation of the string concatenation
22
+ - Method `Datatype::Number#+` implementation of the addition of numbers
23
+
24
+ ## Changed
25
+ - File `interpreter_spec.rb` Added tests for addition operation and string concatenation
26
+
27
+
28
+ ## [0.0.13] - 2021-01-10
29
+ - The interpreter can evaluate directly simple literals.
30
+
31
+ ## Changed
32
+ - Class `AST::ASTBuilder` added `reduce_exprStmt` to support the evaluation of literals.
33
+ - File `README.md` added one more example.
34
+ - File `parser_spec.rb` Updated the tests to reflect the change in the AST.
35
+ - File `interpreter_spec.rb` Added a test for literal expression.
36
+
37
+ ## Fixed
38
+ - File `loxxy.rb`: shorthand method `lox_true` referenced the ... false object (oops).
39
+
40
+ ## [0.0.12] - 2021-01-09
41
+ - Initial interpreter capable of evaluating a tiny subset of Lox language.
42
+
43
+ ## Added
44
+ - Class `AST::LoxNoopExpr`
45
+ - Class `AST::LoxPrintStmt`
46
+ - Class `BackEnd::Engine` implementation of the print statement logic
47
+ - Class `Interpreter`
48
+
49
+ ## Changed
50
+ - Class `Ast::ASTVisitor` Added visit method
51
+ - File `README.md` added Hello world example.
52
+
53
+ ## [0.0.11] - 2021-01-08
54
+ - AST node generation for logical expression (and, or).
55
+
56
+ ## Changed
57
+ - Class `AST::ASTBuilder` added `reduce_` methods for logical operations.
58
+ - File `grammar.rb`added name to logical expression rules
59
+ - File `README.md` added gem version and license badges, expanded roadmap section.
60
+
61
+ ## Fixed
62
+ - File `grammar.rb`: a rule had incomplete non-terminal name `conjunct_` in its lhs.
63
+
64
+
1
65
  ## [0.0.10] - 2021-01-08
2
66
  - AST node generation for equality expression.
3
67
 
data/README.md CHANGED
@@ -2,69 +2,87 @@
2
2
  [![Gem Version](https://badge.fury.io/rb/loxxy.svg)](https://badge.fury.io/rb/loxxy)
3
3
  [![License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat)](https://github.com/famished-tiger/loxxy/blob/main/LICENSE.txt)
4
4
 
5
-
5
+ ### What is loxxy?
6
6
  A Ruby implementation of the [Lox programming language](https://craftinginterpreters.com/the-lox-language.html ),
7
7
  a simple language used in Bob Nystrom's online book [Crafting Interpreters](https://craftinginterpreters.com/ ).
8
8
 
9
- ## Purpose of this project:
9
+ ### Purpose of this project:
10
10
  - To deliver an open source example of a programming language fully implemented in Ruby
11
- (from the scanner, parser, code generation).
11
+ (from the scanner, parser, an interpreter).
12
12
  - The implementation should be mature enough to run [LoxLox](https://github.com/benhoyt/loxlox),
13
13
  a Lox interpreter written in Lox.
14
14
 
15
- ## Current status
16
- The __loxxy__ gem hosts two distinct parsers classes (`RawParser` and `Parser`).
17
- - A `RawParser` instance is able to recognize valid Lox input and to generate
18
- a concrete parse tree from it.
19
- - A `Parser` instance can also parse Lox source code but will generate an AST
20
- (Abstract Syntax Tree) that will be used by the future tree-walking interpreter.
21
- Currently it generates AST for arithmetic expressions with literal numbers only.
22
-
23
- ## Roadmap
24
- ### Done
25
- - Scanner (tokenizer)
26
- - Lox grammar (in format required by Rley gem)
27
- - Raw parser. It parses Lox programs and generates a raw parse tree.
28
- - Tailored parser for generating AST (Abstract Syntax Tree)
29
-
30
- ### Started
31
- - Custom AST builder class
32
- - Classes for representing Lox expressions in AST
33
-
34
- ### TODO
35
- AST Node generation
36
- Goal: parser should generate AST for any input Lox program
37
- - [X] Equality operator
38
- - [] 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
15
+ ### Current status
16
+ The project is still in inception and the interpreter is being implemented...
17
+ Currently it can execute a tiny subset of __Lox__ language.
18
+
19
+ But the __loxxy__ gem hosts also a parser class `RawPaser` that can parse, in principle, any valid Lox input.
20
+
21
+ ## What's the fuss about Lox?
22
+ ... Nothing...
23
+ Bob Nystrom designed a language __simple__ enough so that he could present
24
+ two implementations (an interpreter, then a compiler) in one single book.
25
+
26
+ Although __Lox__ is fairly simple, it is far from a toy language:
27
+ - Dynamically typed,
28
+ - Provides datatypes such as booleans, number, strings,
29
+ - Supports arithmetic operations (+, -, *, / ) and comparison ( >, >= , <, <=)
30
+ - Implements equality operators (==, !=) and the logical connectors `and` and `or`.
31
+ - Control flow statements `if`, `for` and `while`
32
+ - Functions and closures
33
+ - Object-orientation (classes, methods, inheritance).
34
+
35
+ In other words, __Lox__ contains interesting features expected from most general-purpose
36
+ languages.
37
+
38
+ ### What's missing in Lox?
39
+ __Lox__ was constrained by design and therefore was not aimed to be a language used in real-world applications.
40
+ Here are some missing parts to make it a _practical_ language:
41
+ - Collections (arrays, maps, ...)
42
+ - Modules (importing stuff from other packages/files)
43
+ - Error handling (e.g. exceptions)
44
+ - Support for concurrency (e.g. threads, coroutines)
45
+
46
+ Also a decent standard library for IO, networking,... is lacking.
47
+
48
+ For sure, the language has shortcomings but on the other hand, it exhibits the essential features
49
+ to cover in an introduction to language implementation.
50
+
51
+ That's already fun... and if all this gives you the inspiration for creating your own
52
+ language, that might be even funnier...
53
+
54
+ Last point: what's makes __Lox__ interesting is the fact that there are implementations in many [languages](https://github.com/munificent/craftinginterpreters/wiki/Lox-implementations)
55
+
56
+ ## Hello world example
57
+ ```ruby
58
+ require 'loxxy'
59
+
60
+ lox_program = <<LOX_END
61
+ // Your first Lox program!
62
+ print "Hello, world!";
63
+ LOX_END
64
+
65
+ lox = Loxxy::Interpreter.new
66
+ lox.evaluate(lox_program) # Output: Hello, world!
67
+ ```
68
+
69
+ ## Retrieving the result from a Lox program
70
+ The __Loxxy__ interpreter returns the value of the last evaluated expression.
71
+
72
+ ```ruby
73
+ require 'loxxy'
74
+
75
+ lox = Loxxy::Interpreter.new
76
+
77
+ lox_program = '47 - 5; // THE answer'
78
+ result = lox.evaluate(lox_program) # => Loxxy::Datatype::Number
79
+
80
+ # `result` is a Ruby object, so let's use it...
81
+ puts result.value # Output: 42
82
+ ```
66
83
 
67
84
  ## Example using RawParser class
85
+
68
86
  ```ruby
69
87
  require 'loxxy'
70
88
 
@@ -109,6 +127,86 @@ program
109
127
  +-- EOF: ''
110
128
  ```
111
129
 
130
+ ## Suppported Lox language features
131
+ Although the interpreter should parse almost any valid Lox program,
132
+ it currently can evaluate a tiny set of AST node (AST = Abstract Syntax Tree).
133
+
134
+ Here are the language features currently supported by the interpreter:
135
+
136
+ - [Comments](#comments)
137
+ - [Keywords](#keywords)
138
+ - [Operators and Special Chars](#operators-and-special-chars)
139
+ - [Datatypes](#datatypes)
140
+ - [Statements](#statements)
141
+
142
+ ### Comments
143
+
144
+ Loxxy supports single line C-style comments.
145
+
146
+ ```javascript
147
+ // single line comment
148
+ ```
149
+
150
+ ### Keywords
151
+
152
+ The parser knows all the __Lox__ reserved keywords:
153
+ ```lang-none
154
+ and, class, else, false, fun, for, if, nil, or,
155
+ print, return, super, this, true, var, while
156
+ ```
157
+ Of these, the interpreter implements: `false`, `nil`, `true`
158
+
159
+ ### Operators and Special Chars
160
+ #### Operators
161
+ The parser recognizes all the __Lox__ operators, delimiters and separators:
162
+ - Arithmetic operators: `+`, `-`, `*`, `/`
163
+ - Comparison operators: `>`, `>=`, `<`, `<=`
164
+ - Equality operators: `==`, `!=`
165
+
166
+ Of these, the interpreter implements:
167
+ `+` (addition of two numbers or string concatenation)
168
+ `-` (difference between two numbers)
169
+
170
+ #### Delimiters
171
+ The parser knows all the __Lox__ grouping delimiters:
172
+ (`, ), `{`, `}`
173
+
174
+ These aren't yet implemented in the interpreter.
175
+
176
+ The other characters that have a special meaning in __Lox__ are:
177
+ - `,` Used in parameter list
178
+ - `.` For the dot notation (i.e. calling a method)
179
+ - `;` The semicolon is used to terminates expressions
180
+ - `=` Assignment
181
+
182
+ The parser recognizes them all but the interpreter accepts the semicolons only.
183
+
184
+ ### Datatypes
185
+
186
+ loxxy supports all the standard __Lox__ datatypes:
187
+ - `Boolean`: Can be `true` or `false`
188
+ - `Number`: Can be an integer or a floating-point numbers. For example: `123, 12.34, -45.67`
189
+ - `String`: Sequence of characters surrounded by `"`. For example: `"Hello!"`
190
+ - `Nil`: Used to define a null value, denoted by the `nil` keyword
191
+
192
+ ## Statements
193
+ ### Implemented expressions
194
+ Loxxy implements expressions:
195
+ - Plain literals only; or,
196
+ - Addition of two numbers; or,
197
+ - Subtraction of two numbers; or,
198
+ - Concatenation of two strings
199
+
200
+ ### Implemented statements
201
+ Loxxy implements the following statements:
202
+ - Expressions (see above sub-section)
203
+ - Print statement
204
+
205
+ ```javascript
206
+ // Print statement with nested concatenation
207
+ print "Hello" + ", " + "world!";
208
+ ```
209
+
112
210
  ## Installation
113
211
 
114
212
  Add this line to your application's Gemfile:
@@ -130,7 +228,6 @@ Or install it yourself as:
130
228
  TODO: Write usage instructions here
131
229
 
132
230
  ## Other Lox implementations in Ruby
133
- An impressive list of Lox implementations can be found [here](https://github.com/munificent/craftinginterpreters/wiki/Lox-implementations)
134
231
 
135
232
  For Ruby, there is the [lox](https://github.com/rdodson41/ruby-lox) gem.
136
233
  There are other Ruby-based projects as well:
@@ -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
- # Your code goes here...
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::True.instance
30
+ end
10
31
  end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'lox_print_stmt'
4
+ require_relative 'lox_literal_expr'
5
+ require_relative 'lox_noop_expr'
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative '../datatype/all_datatypes'
4
- require_relative 'lox_literal_expr'
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
- # Mapping Token name => operator | separator | delimiter characters
14
- # @return [Hash{String => String}]
15
- Name2special = {
16
- 'AND' => 'and',
17
- 'BANG' => '!',
18
- 'BANG_EQUAL' => '!=',
19
- 'COMMA' => ',',
20
- 'DOT' => '.',
21
- 'EQUAL' => '=',
22
- 'EQUAL_EQUAL' => '==',
23
- 'GREATER' => '>',
24
- 'GREATER_EQUAL' => '>=',
25
- 'LEFT_BRACE' => '{',
26
- 'LEFT_PAREN' => '(',
27
- 'LESS' => '<',
28
- 'LESS_EQUAL' => '<=',
29
- 'MINUS' => '-',
30
- 'OR' => 'or',
31
- 'PLUS' => '+',
32
- 'RIGHT_BRACE' => '}',
33
- 'RIGHT_PAREN' => ')',
34
- 'SEMICOLON' => ';',
35
- 'SLASH' => '/',
36
- 'STAR' => '*'
37
- }.freeze
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,60 @@ 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) # Discard the semicolon
134
+ end
135
+
136
+ # rule('exprStmt' => 'expression SEMICOLON')
137
+ def reduce_exprStmt(_production, range, tokens, theChildren)
138
+ return_first_child(range, tokens, theChildren) # Discard the semicolon
139
+ end
140
+
141
+ # rule('printStmt' => 'PRINT expression SEMICOLON')
142
+ def reduce_print_stmt(_production, _range, tokens, theChildren)
143
+ Ast::LoxPrintStmt.new(tokens[1].position, theChildren[1])
144
+ end
145
+
146
+ # rule('logic_or' => 'logic_and disjunct_plus')
147
+ def reduce_logic_or_plus(production, range, tokens, theChildren)
148
+ reduce_binary_operator(production, range, tokens, theChildren)
149
+ end
150
+
151
+ # rule('disjunct_plus' => 'disjunct_plus OR logic_and')
152
+ def reduce_logic_or_plus_more(production, range, tokens, theChildren)
153
+ reduce_binary_plus_more(production, range, tokens, theChildren)
154
+ end
155
+
156
+ # rule('disjunct_plus' => 'OR logic_and')
157
+ def reduce_logic_or_plus_end(production, range, tokens, theChildren)
158
+ reduce_binary_plus_end(production, range, tokens, theChildren)
159
+ end
160
+
161
+ # rule('logic_and' => 'equality conjunct_plus')
162
+ def reduce_logic_and_plus(production, range, tokens, theChildren)
163
+ reduce_binary_operator(production, range, tokens, theChildren)
164
+ end
165
+
166
+ # rule('conjunct_plus' => 'conjunct_plus AND equality')
167
+ def reduce_logic_and_plus_more(production, range, tokens, theChildren)
168
+ reduce_binary_plus_more(production, range, tokens, theChildren)
169
+ end
170
+
171
+ # rule('conjunct_plus' => 'AND equality')
172
+ def reduce_logic_and_plus_end(production, range, tokens, theChildren)
173
+ reduce_binary_plus_end(production, range, tokens, theChildren)
174
+ end
175
+
120
176
  # rule('equality' => 'comparison equalityTest_plus')
121
177
  def reduce_equality_plus(production, range, tokens, theChildren)
122
178
  reduce_binary_operator(production, range, tokens, theChildren)