loxxy 0.0.12 → 0.0.17

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: 7274fd2d139354b984962f9317cae890344e528540f2f157772e7395cdfd7d33
4
- data.tar.gz: c1b38a4dfcb441c00604926cbaf397ab555624270ca647448d9cc4d4f463f500
3
+ metadata.gz: 6eed6a7de54b89c276b0f098cd7d824f26c0ce9ba957d4fb9e3a4d12e6dfbc4f
4
+ data.tar.gz: ba7c00f11c5b69322aec0d447c2fef9cf6d6d74b2ea7bb16096581508a786427
5
5
  SHA512:
6
- metadata.gz: 27d5de6532213d1a995f86da84ccbd41a11b5f85c305e57a62f64637ad17852e622685e4261b1c62deb31c924bb8f8c29c4edd97e9776fabf7e0d06e5c302534
7
- data.tar.gz: dab4a9e391c120c159a63e316f90065faf1415b54c9aa4c6f349f6be8e95de1289a2478f395e6b9e19b2e6f09482ae4db49a70e0d5d857eb5475cecad0590c69
6
+ metadata.gz: 1b2c3826f085ce3f723cdbc70c3bdc3563817270985a321db05f97ca1ff81971bf872db49631d3fa20580932f7a0e2910bf3c6c84daf7873cdcd1f04c3392a99
7
+ data.tar.gz: 4e3d075facaf9c370d78f3f3ac89b7226e375eb32064535e3401c5ef52b8ca43c9d4c6cfb8f027b4037c7baa7c5945b0fd0dbe1e8b1e580fc732c4a38f7c57c6
@@ -250,7 +250,7 @@ Style/IfUnlessModifier:
250
250
  Enabled: false
251
251
 
252
252
  Style/InverseMethods:
253
- Enabled: true
253
+ Enabled: false
254
254
 
255
255
  Style/MissingRespondToMissing:
256
256
  Enabled: false
@@ -1,3 +1,79 @@
1
+ ## [0.0.17] - 2021-01-12
2
+ - The interpreter can evaluate all arithmetic and comparison operations.
3
+ - It implements `==`, `!=` and the unary operations `!`, `-`
4
+
5
+ ## Added
6
+ - Class `AST::LoxUnaryExpr`
7
+ - Method `AST::ASTBuilder#reduce_unary_expr` to support the evaluation of `!` and ``-@`
8
+ - Method `Ast::ASTVisitor#visit_unnary_expr` for visiting unary expressions
9
+ - Method `Backend::Engine#after_unary_expr` evaluating an unary expression
10
+ - In class `Datatype::BuiltinDatatype` the methods `falsey?`, `truthy?`, `!`, `!=`
11
+ - In class `Datatype::Number`the methods `<`, `<=`, ´>´, `>=` and `-@`
12
+
13
+ ## Changed
14
+ - File `README.md` updated.
15
+
16
+ ## [0.0.16] - 2021-01-11
17
+ - The interpreter can evaluate product and division of two numbers.
18
+ - It also implements equality `==` and inequality `!=` operators
19
+
20
+ ## Added
21
+ - Method `Datatype::False#==` for equality testing
22
+ - Method `Datatype::False#!=` for inequality testing
23
+ - Method `Datatype::LXString#==` for equality testing
24
+ - Method `Datatype::LXString#!=` for inequality testing
25
+ - Method `Datatype::Nil#==` for equality testing
26
+ - Method `Datatype::Nil#!=` for inequality testing
27
+ - Method `Datatype::Number#==` for equality testing
28
+ - Method `Datatype::Number#!=` for inequality testing
29
+ - Method `Datatype::Number#*` for multiply operator
30
+ - Method `Datatype::Number#/` for divide operator
31
+ - Method `Datatype::True#==` for equality testing
32
+ - Method `Datatype::True#!=` for inequality testing
33
+
34
+ ## Changed
35
+ - Method `BackEnd::Engine#after_binary_expr` to allow `*`, `/`, `==`, `!=` operators
36
+ - File `README.md` updated for the newly implemented operators
37
+
38
+ ## [0.0.15] - 2021-01-11
39
+ - The interpreter can evaluate substraction between two numbers.
40
+
41
+ ## Added
42
+ - Method `Datatype::Number#-` implmenting the subtraction operation
43
+
44
+ ## Changed
45
+ - File `README.md` minor editorial changes.
46
+ - File `lx_string_spec.rb` Added test for string concatentation
47
+ - File `number_spec.rb` Added tests for addition and subtraction operations
48
+ - File `interpreter_spec.rb` Added tests for subtraction operation
49
+
50
+ ## [0.0.14] - 2021-01-10
51
+ - The interpreter can evaluate addition of numbers and string concatenation
52
+
53
+ ## Added
54
+ - Method `Ast::ASTVisitor#visit_binary_expr` for visiting binary expressions
55
+ - Method `Ast::LoxBinaryExpr#accept` for visitor pattern
56
+ - Method `BackEnd::Engine#after_binary_expr` to trigger execution of binary operator
57
+ - `Boolean` class hierarchy: added methos `true?` and `false?` to ease spec test writing
58
+ - Method `Datatype::LXString#+` implementation of the string concatenation
59
+ - Method `Datatype::Number#+` implementation of the addition of numbers
60
+
61
+ ## Changed
62
+ - File `interpreter_spec.rb` Added tests for addition operation and string concatenation
63
+
64
+
65
+ ## [0.0.13] - 2021-01-10
66
+ - The interpreter can evaluate directly simple literals.
67
+
68
+ ## Changed
69
+ - Class `AST::ASTBuilder` added `reduce_exprStmt` to support the evaluation of literals.
70
+ - File `README.md` added one more example.
71
+ - File `parser_spec.rb` Updated the tests to reflect the change in the AST.
72
+ - File `interpreter_spec.rb` Added a test for literal expression.
73
+
74
+ ## Fixed
75
+ - File `loxxy.rb`: shorthand method `lox_true` referenced the ... false object (oops).
76
+
1
77
  ## [0.0.12] - 2021-01-09
2
78
  - Initial interpreter capable of evaluating a tiny subset of Lox language.
3
79
 
data/README.md CHANGED
@@ -2,21 +2,56 @@
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 project is still in inception and the interpreter is being implemented...
17
- Currently it can execute a very limited subset of __Lox__ language.
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.
18
47
 
19
- The __loxxy__ gem also a parser class `RawPaser` that can, in principle, any valid Lox input.
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)
20
55
 
21
56
  ## Hello world example
22
57
  ```ruby
@@ -28,7 +63,22 @@ lox_program = <<LOX_END
28
63
  LOX_END
29
64
 
30
65
  lox = Loxxy::Interpreter.new
31
- lox.evaluate(lox_program) # => Hello, world!
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
32
82
  ```
33
83
 
34
84
  ## Example using RawParser class
@@ -81,11 +131,81 @@ program
81
131
  Although the interpreter should parse almost any valid Lox program,
82
132
  it currently can evaluate a tiny set of AST node (AST = Abstract Syntax Tree).
83
133
 
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.
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
88
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`, `print`, `true`
158
+
159
+ ### Operators and Special Chars
160
+ #### Operators
161
+ The __loxxy__ interpreter supports all the __Lox__ unary and binary operators:
162
+ - Arithmetic operators: `+`, `-`, `*`, `/`
163
+ - Comparison operators: `>`, `>=`, `<`, `<=`
164
+ - Equality operators: `==`, `!=`
165
+ - Unary negate (change sign): `-`
166
+ - Unary not: `!`
167
+
168
+ #### Delimiters
169
+ The parser knows all the __Lox__ grouping delimiters:
170
+ (`, ), `{`, `}`
171
+
172
+ These aren't yet implemented in the interpreter.
173
+
174
+ The other characters that have a special meaning in __Lox__ are:
175
+ - `,` Used in parameter list
176
+ - `.` For the dot notation (i.e. calling a method)
177
+ - `;` The semicolon is used to terminates expressions
178
+ - `=` Assignment
179
+
180
+ The parser recognizes them all but the interpreter accepts the semicolons only.
181
+
182
+ ### Datatypes
183
+
184
+ loxxy supports all the standard __Lox__ datatypes:
185
+ - `Boolean`: Can be `true` or `false`
186
+ - `Number`: Can be an integer or a floating-point numbers. For example: `123, 12.34, -45.67`
187
+ - `String`: Sequence of characters surrounded by `"`. For example: `"Hello!"`
188
+ - `Nil`: Used to define a null value, denoted by the `nil` keyword
189
+
190
+ ## Statements
191
+ ### Implemented expressions
192
+ Loxxy implements expressions:
193
+ - Plain literals only; or,
194
+ - (In)equality testing between two values; or,
195
+ - Basic arithmetic operations (`+`, `-`, `*`, `/`, `unary -`); or,
196
+ - Comparison between two numbers; or,
197
+ - Concatenation of two strings,
198
+ - Negation `!`
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 string concatenation
207
+ print "Hello" + ", " + "world!";
208
+ ```
89
209
 
90
210
  ## Installation
91
211
 
@@ -108,7 +228,6 @@ Or install it yourself as:
108
228
  TODO: Write usage instructions here
109
229
 
110
230
  ## Other Lox implementations in Ruby
111
- An impressive list of Lox implementations can be found [here](https://github.com/munificent/craftinginterpreters/wiki/Lox-implementations)
112
231
 
113
232
  For Ruby, there is the [lox](https://github.com/rdodson41/ruby-lox) gem.
114
233
  There are other Ruby-based projects as well:
@@ -7,13 +7,13 @@ require_relative 'loxxy/front_end/raw_parser'
7
7
  # Namespace for all classes and constants of __loxxy__ gem.
8
8
  module Loxxy
9
9
  class Error < StandardError; end
10
-
10
+
11
11
  # Shorthand method. Returns the sole object that represents
12
12
  # a Lox false literal.
13
13
  # @return [Loxxy::Datatype::False]
14
14
  def self.lox_false
15
15
  Datatype::False.instance
16
- end
16
+ end
17
17
 
18
18
  # Shorthand method. Returns the sole object that represents
19
19
  # a Lox nil literal.
@@ -21,11 +21,11 @@ module Loxxy
21
21
  def self.lox_nil
22
22
  Datatype::Nil.instance
23
23
  end
24
-
24
+
25
25
  # Shorthand method. Returns the sole object that represents
26
26
  # a Lox true literal.
27
27
  # @return [Loxxy::Datatype::True]
28
28
  def self.lox_true
29
- Datatype::False.instance
30
- end
29
+ Datatype::True.instance
30
+ end
31
31
  end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'lox_print_stmt'
4
3
  require_relative 'lox_literal_expr'
5
4
  require_relative 'lox_noop_expr'
5
+ require_relative 'lox_binary_expr'
6
+ require_relative 'lox_unary_expr'
7
+ require_relative 'lox_print_stmt'
@@ -15,7 +15,6 @@ module Loxxy
15
15
  # @return [Hash{String => String}]
16
16
  Name2special = {
17
17
  'AND' => 'and',
18
- 'BANG' => '!',
19
18
  'BANG_EQUAL' => '!=',
20
19
  'COMMA' => ',',
21
20
  'DOT' => '.',
@@ -36,6 +35,11 @@ module Loxxy
36
35
  'SLASH' => '/',
37
36
  'STAR' => '*'
38
37
  }.freeze
38
+
39
+ Name2unary = {
40
+ 'BANG' => '!',
41
+ 'MINUS' => '-@'
42
+ }.freeze
39
43
  end # defined
40
44
 
41
45
  attr_reader :strict
@@ -124,13 +128,18 @@ module Loxxy
124
128
  #####################################
125
129
 
126
130
  # rule('program' => 'EOF').as 'null_program'
127
- def reduce_null_program(_production, range, _tokens, _theChildren)
131
+ def reduce_null_program(_production, _range, _tokens, _theChildren)
128
132
  Ast::LoxNoopExpr.new(tokens[0].position)
129
133
  end
130
134
 
131
135
  # rule('program' => 'declaration_plus EOF').as ''
132
136
  def reduce_lox_program(_production, range, tokens, theChildren)
133
- return_first_child(range, tokens, theChildren)
137
+ return_first_child(range, tokens, theChildren) # Discard the semicolon
138
+ end
139
+
140
+ # rule('exprStmt' => 'expression SEMICOLON')
141
+ def reduce_exprStmt(_production, range, tokens, theChildren)
142
+ return_first_child(range, tokens, theChildren) # Discard the semicolon
134
143
  end
135
144
 
136
145
  # rule('printStmt' => 'PRINT expression SEMICOLON')
@@ -226,6 +235,13 @@ module Loxxy
226
235
  reduce_binary_plus_end(production, range, tokens, theChildren)
227
236
  end
228
237
 
238
+ # rule('unary' => 'unaryOp unary')
239
+ def reduce_unary_expr(_production, _range, tokens, theChildren)
240
+ operator = Name2unary[theChildren[0].symbol.name].to_sym
241
+ operand = theChildren[1]
242
+ LoxUnaryExpr.new(tokens[0].position, operator, operand)
243
+ end
244
+
229
245
  # rule('primary' => 'FALSE' | TRUE').as 'literal_expr'
230
246
  def reduce_literal_expr(_production, _range, _tokens, theChildren)
231
247
  first_child = theChildren.first
@@ -51,7 +51,7 @@ module Loxxy
51
51
  broadcast(:after_ptree, aParseTree)
52
52
  end
53
53
 
54
- # Visit event. The visitor is about to visit a print statement expression.
54
+ # Visit event. The visitor is about to visit a print statement.
55
55
  # @param aPrintStmt [AST::LOXPrintStmt] the print statement node to visit
56
56
  def visit_print_stmt(aPrintStmt)
57
57
  broadcast(:before_print_stmt, aPrintStmt)
@@ -59,6 +59,22 @@ module Loxxy
59
59
  broadcast(:after_print_stmt, aPrintStmt)
60
60
  end
61
61
 
62
+ # Visit event. The visitor is about to visit a binary expression.
63
+ # @param aBinaryExpr [AST::LOXBinaryExpr] the binary expression node to visit
64
+ def visit_binary_expr(aBinaryExpr)
65
+ broadcast(:before_binary_expr, aBinaryExpr)
66
+ traverse_subnodes(aBinaryExpr)
67
+ broadcast(:after_binary_expr, aBinaryExpr)
68
+ end
69
+
70
+ # Visit event. The visitor is about to visit an unary expression.
71
+ # @param anUnaryExpr [AST::anUnaryExpr] unary expression node to visit
72
+ def visit_unary_expr(anUnaryExpr)
73
+ broadcast(:before_unary_expr, anUnaryExpr)
74
+ traverse_subnodes(anUnaryExpr)
75
+ broadcast(:after_unary_expr, anUnaryExpr)
76
+ end
77
+
62
78
  # Visit event. The visitor is visiting the
63
79
  # given terminal node containing a datatype object.
64
80
  # @param aLiteralExpr [AST::LoxLiteralExpr] the leaf node to visit.
@@ -5,7 +5,7 @@ require_relative 'lox_compound_expr'
5
5
  module Loxxy
6
6
  module Ast
7
7
  class LoxBinaryExpr < LoxCompoundExpr
8
- # @return [Symbol]
8
+ # @return [Symbol] message name to be sent to receiver
9
9
  attr_reader :operator
10
10
 
11
11
  # @param aPosition [Rley::Lexical::Position] Position of the entry in the input stream.
@@ -16,6 +16,12 @@ module Loxxy
16
16
  @operator = anOperator
17
17
  end
18
18
 
19
+ # Part of the 'visitee' role in Visitor design pattern.
20
+ # @param visitor [Ast::ASTVisitor] the visitor
21
+ def accept(visitor)
22
+ visitor.visit_binary_expr(self)
23
+ end
24
+
19
25
  alias operands subnodes
20
26
  end # class
21
27
  end # module
@@ -11,7 +11,6 @@ module Loxxy
11
11
  super(aPosition, [anExpression])
12
12
  end
13
13
 
14
- # Abstract method.
15
14
  # Part of the 'visitee' role in Visitor design pattern.
16
15
  # @param visitor [Ast::ASTVisitor] the visitor
17
16
  def accept(visitor)
@@ -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 LoxUnaryExpr < LoxCompoundExpr
8
+ # @return [Symbol] message name to be sent to receiver
9
+ attr_reader :operator
10
+
11
+ # @param aPosition [Rley::Lexical::Position] Position of the entry in the input stream.
12
+ # @param operand [Loxxy::Ast::LoxNode]
13
+ def initialize(aPosition, anOperator, operand)
14
+ super(aPosition, [operand])
15
+ @operator = anOperator
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_unary_expr(self)
22
+ end
23
+
24
+ alias operands subnodes
25
+ end # class
26
+ end # module
27
+ end # module