loxxy 0.3.03 → 0.4.00

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: 734fc040d2487c17abd8d89d4f3422e4d55db226ef79b354e52402fc24cd61fc
4
- data.tar.gz: e799c5d1044159e9bfdc1b337c370e95878c85752dcaaf60578e71c4763a7da1
3
+ metadata.gz: 47c5d65fa1f3c2d0025013577f46edf741572df743d8986e238f49a08ea32702
4
+ data.tar.gz: 72a3beb6828362e6dc7c73072555ed6f87ed5bf57b4052ac55e06503b9582e29
5
5
  SHA512:
6
- metadata.gz: d6d393729d977e6493979f4e89c664a1bba685b08c67a5e9e9b0d12354ac552deadae4e15a213560b752bdb9b44c7a05a5652fc8b4ed6500409fa04fe3cf29c1
7
- data.tar.gz: f3b121e4a5ca07b4297aca8c43a3325b00dd30fb131f412a17a5e82d7887e8fc8749a2e1a422c75fe0c1045652970a121a78883b06c6bbc6baa6d896b0fea03f
6
+ metadata.gz: e83ee511c1ead4592153bb1e8ed8167439894bfefa2bb54060100eb9d221d77c453b4bad3d3e4a36209f3761812a5b9b0aa98b02a53556314c022d1f0b605bca
7
+ data.tar.gz: 8d939d7ff60687dd64c4dc6e4beccffa512e3483f5b38042a83fffbc0a5cc83d218999f855b8765a47e24b8c0df7808ecd649e70cec11832a0591b5c141a659c
data/CHANGELOG.md CHANGED
@@ -1,12 +1,21 @@
1
- ## [0.3.03] - 2021-05-23
2
- - Fixes in the location of an undefined variable. Rewrite of the scanning of lox string.
1
+ ## [0.4.00] - 2021-05-24
2
+ - Version bump. `Loxxy` is capable to run the LoxLox interpreter, an interpreter written in `Lox`.
3
+
4
+ ### New
5
+ - Method `BackEnd::LoxInstance#falsey?` added
6
+ - Method `BackEnd::LoxInstance#truthy?` added
3
7
 
4
8
  ### Changed
5
9
  - Method `BackEnd::Engine#after_variable_expr` the error message `Undefined variable` nows gives the location of the offending variable.
6
- - Class `FrontEnd#Scanner` complete refactoring of String recognition.
10
+ - Class `Ast::LoxClassStmt`is now a subclass of `LoxNode`
11
+
12
+ - File `README.md` added an explanation on how to run `LoxLox`interpreter.
7
13
 
8
14
  ### Fixed
9
- - Method `Ast::AstBuilder#reduce_variable_expr` now associates the correct location of the variable.
15
+ - Method `Ast::LoxClassStmt#initialize` fixed inconsistencies in its Yard/RDoc documentation.
16
+ - Method `Ast::LoxFunStmt#initialize` fixed inconsistencies in its Yard/RDoc documentation.
17
+ - Method `BackEnd::Engine#native_getc` now returns -1 when its reaches EOF.
18
+ - Method `BackEnd::Resolver#after_logical_expr` was missing and this caused the lack of resultation in the second operand.
10
19
 
11
20
  ## [0.3.02] - 2021-05-22
12
21
  - New built-in expressions `getc`, `chr`, `exit` and `print_eeror` , fixes with deeply nested returns, set expressions
data/README.md CHANGED
@@ -19,7 +19,8 @@ Although __Lox__ is fairly simple, it is far from being a toy language:
19
19
  ### Loxxy gem features
20
20
  - Complete tree-walking interpreter including lexer, parser and resolver
21
21
  - 100% pure Ruby with clean design (not a port from some other language)
22
- - Passes the `jox` (THE reference `Lox` implementation) test suite
22
+ - Passes the `jox` (THE reference `Lox` implementation) test suite
23
+ - Can run a Lox imterpreter implemented in ... `Lox` [LoxLox](https://github.com/benhoyt/loxlox),
23
24
  - Minimal runtime dependency (Rley gem). Won't drag a bunch of gems...
24
25
  - Ruby API for integrating a Lox interpreter with your code.
25
26
  - A command-line interpreter `loxxy`
@@ -53,6 +54,7 @@ And then execute:
53
54
  ### 2. Your first `Lox` program
54
55
  Create a text file and enter the following lines:
55
56
  ```javascript
57
+ // hello.lox
56
58
  // Your firs Lox program
57
59
  print "Hello, world.";
58
60
  ```
@@ -75,6 +77,7 @@ Let's admit it, the hello world example was unimpressive.
75
77
  To a get a taste of `Lox` object-oriented capabilities, let's try another `Hello world` variant:
76
78
 
77
79
  ```javascript
80
+ // oo_hello.lox
78
81
  // Object-oriented hello world
79
82
  class Greeter {
80
83
  // in Lox, initializers/constructors are named `init`
@@ -98,6 +101,7 @@ Our next assignment: compute the first 20 elements of the Fibbonacci sequence.
98
101
  Here's an answer using the `while` loop construct:
99
102
 
100
103
  ```javascript
104
+ // fibbonacci.lox
101
105
  // Compute the first 20 elements from the Fibbonacci sequence
102
106
 
103
107
  var a = 0; // Use the var keyword to declare a new variable
@@ -127,6 +131,7 @@ Fans of `for` loops will be pleased to find their favorite looping construct.
127
131
  Here again, the Fibbonacci sequence refactored with a `for` loop:
128
132
 
129
133
  ```javascript
134
+ // fibbonacci_v2.lox
130
135
  // Fibbonacci sequence - version 2
131
136
  var a = 0;
132
137
  var b = 1;
@@ -169,13 +174,69 @@ for (var i = 0; i < count; i = i + 1) {
169
174
  }
170
175
  ```
171
176
 
177
+ ### Loxxy goes meta...
178
+ The `Loxxy` is able to run the `LoxLox` interpreter.
179
+ [LoxLox](https://github.com/benhoyt/loxlox) is a Lox interpreter written in Lox by Ben Hoyt.
180
+ This interpreter with over 1900 lines long is (one of) the longest Lox pragram.
181
+ As such, it is a good testbed for any Lox interpreter.
182
+
183
+ Executing a lox program with the LoxLox interpreter that is itself running on top of Loxxy.
184
+ #### Step 1 Download `lox.lox´ file
185
+ Download the [LoxLox](https://github.com/benhoyt/loxlox) source file in Github.
186
+
187
+ #### Step 2 (alternative a): running from the command line
188
+
189
+ ```
190
+ $ loxxy lox.lox
191
+ ```
192
+
193
+ Once loxxy CLI starts its interpreter that, in turn, executes the LoxLox interpreter.
194
+ This may take a couple of seconds.
195
+ Don't be surprised, if the program seems unresponsive: it is waiting for you input.
196
+ Enter a line like this:
197
+ ```
198
+ print "Hello, world!";
199
+ ```
200
+ Then terminate with an end of file (crtl-D on Linuxes, crtl-z on Windows) followed by an enter key.
201
+ You should see the famous greeting.
202
+
203
+ #### Step 2 (alternative b): launching the interpreter from Ruby snippet
204
+ The following snippet executes the LoxLox interpreter and feeds to it the
205
+ input text. That input text is made available through a StringIO that replaces
206
+ the `$stdio` device.
207
+
208
+ ```ruby
209
+ require 'stringio'
210
+ require 'loxxy'
211
+
212
+ # Place your Lox pragram within the heredoc
213
+ program = <<-LOX_END
214
+ print "Hello, world!";
215
+ LOX_END
216
+
217
+ lox_filename = 'lox.lox'
218
+ File.open(lox_filename, 'r') do |f|
219
+ source = f.read
220
+ cfg = { istream: StringIO.new(program, 'r')}
221
+ lox = Loxxy::Interpreter.new(cfg)
222
+ lox.evaluate(source)
223
+ end
224
+ ```
225
+
226
+ Save this snippet as a Ruby file, launch Ruby with this file in command line.
227
+ After a couple of seconds, you'll see the Ruby interpreter that executes the
228
+ Loxxy interpreter that itself executes the LoxLox interpreter written in Lox.
229
+ That last interpreter is the one that run the hello world line.
230
+
231
+ That's definitively meta...
232
+
172
233
  This completes our quick tour of `Lox`, to learn more about the language,
173
234
  check the online book [Crafting Interpreters](https://craftinginterpreters.com/ )
174
235
 
175
236
  ## What's the fuss about Lox?
176
237
  ... Nothing...
177
238
  Bob Nystrom designed a language __simple__ enough so that he could present
178
- two implementations (an interpreter, then a compiler) in one single book.
239
+ two interpreter implementations (a tree-walking one, then a bytecode one) in one single book.
179
240
 
180
241
  In other words, __Lox__ contains interesting features found in most general-purpose
181
242
  languages. In addition to that, there are [numerous implementations](https://github.com/munificent/craftinginterpreters/wiki/Lox-implementations) in different languages
@@ -202,14 +263,11 @@ There are already a number of programming languages derived from `Lox`...
202
263
  ### Purpose of this project:
203
264
  - To deliver an open source example of a programming language fully implemented in Ruby
204
265
  (from the scanner and parser to an interpreter).
205
- - The implementation should be mature enough to run [LoxLox](https://github.com/benhoyt/loxlox),
206
- a Lox interpreter written in Lox.
207
266
 
208
267
  ### Roadmap
209
268
  - Extend the test suite
210
269
  - Improve the error handling
211
270
  - Improve the documentation
212
- - Ability run the LoxLox interpreter
213
271
 
214
272
  ## Hello world example
215
273
  The next examples show how to use the interpreter directly from Ruby code.
@@ -71,7 +71,6 @@ module Loxxy
71
71
  # @param aClassStmt [AST::LOXClassStmt] the for statement node to visit
72
72
  def visit_class_stmt(aClassStmt)
73
73
  broadcast(:before_class_stmt, aClassStmt)
74
- traverse_subnodes(aClassStmt) # The methods are visited here...
75
74
  broadcast(:after_class_stmt, aClassStmt, self)
76
75
  end
77
76
 
@@ -1,10 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'lox_compound_expr'
3
+ require_relative 'lox_node'
4
4
 
5
5
  module Loxxy
6
6
  module Ast
7
- class LoxClassStmt < LoxCompoundExpr
7
+ # A parse tree node that represents a Lox class declaration.
8
+ class LoxClassStmt < LoxNode
8
9
  # @return [String] the class name
9
10
  attr_reader :name
10
11
 
@@ -14,11 +15,13 @@ module Loxxy
14
15
  # @return [Array<Ast::LoxFunStmt>] the methods
15
16
  attr_reader :body
16
17
 
18
+ # Constructor for a parse node that represents a Lox function declaration
17
19
  # @param aPosition [Rley::Lexical::Position] Position of the entry in the input stream.
18
- # @param condExpr [Loxxy::Ast::LoxNode] iteration condition
19
- # @param theBody [Array<Loxxy::Ast::LoxNode>]
20
+ # @param aName [String] the class name
21
+ # @param aSuperclassName [String] the super class name
22
+ # @param theMethods [Array<Loxxy::Ast::LoxFunStmt>] the methods
20
23
  def initialize(aPosition, aName, aSuperclassName, theMethods)
21
- super(aPosition, [])
24
+ super(aPosition)
22
25
  @name = aName.dup
23
26
  @superclass = aSuperclassName
24
27
  @body = theMethods
@@ -4,17 +4,25 @@ require_relative 'lox_node'
4
4
 
5
5
  module Loxxy
6
6
  module Ast
7
- # rubocop: disable Style/AccessorGrouping
7
+ # A parse tree node that represents a Lox function declaration.
8
8
  class LoxFunStmt < LoxNode
9
+ # @return [String] the function name
9
10
  attr_reader :name
11
+
12
+ # @return [Array<String>] the parameter names
10
13
  attr_reader :params
14
+
15
+ # @return [Ast::LoxBlockStmt] the parse tree representing the function's body
11
16
  attr_reader :body
17
+
18
+ # @return [Boolean] true if the function is a method
12
19
  attr_accessor :is_method
13
20
 
21
+ # Constructor for a parse node that represents a Lox function declaration
14
22
  # @param aPosition [Rley::Lexical::Position] Position of the entry in the input stream.
15
- # @param aName [String]
16
- # @param arguments [Array<String>]
17
- # @param body [Ast::LoxBlockStmt]
23
+ # @param aName [String] the function name
24
+ # @param paramList [Array<String>] the parameter names
25
+ # @param aBody [Ast::LoxBlockStmt] the parse tree representing the function's body
18
26
  def initialize(aPosition, aName, paramList, aBody)
19
27
  super(aPosition)
20
28
  @name = aName.dup
@@ -25,6 +33,5 @@ module Loxxy
25
33
 
26
34
  define_accept # Add `accept` method as found in Visitor design pattern
27
35
  end # class
28
- # rubocop: enable Style/AccessorGrouping
29
36
  end # module
30
37
  end # module
@@ -475,10 +475,12 @@ module Loxxy
475
475
  end
476
476
 
477
477
  # Read a single character and return the character code as an integer.
478
+ # LoxLox requires the end of input to be a negative number
478
479
  def native_getc
479
480
  proc do
480
481
  ch = @istream.getc
481
- Datatype::Number.new(ch.codepoints[0])
482
+ val = ch ? ch.codepoints[0] : -1
483
+ Datatype::Number.new(val)
482
484
  end
483
485
  end
484
486
 
@@ -22,8 +22,16 @@ module Loxxy
22
22
  @fields = {}
23
23
  end
24
24
 
25
- def accept(_visitor)
26
- engine.expr_stack.push self
25
+ # In Lox, only false and Nil have false value...
26
+ # @return [FalseClass]
27
+ def falsey?
28
+ false # Default implementation
29
+ end
30
+
31
+ # Any instance is truthy
32
+ # @return [TrueClass]
33
+ def truthy?
34
+ true # Default implementation
27
35
  end
28
36
 
29
37
  # Text representation of a Lox instance
@@ -31,6 +39,10 @@ module Loxxy
31
39
  "#{klass.to_str} instance"
32
40
  end
33
41
 
42
+ def accept(_visitor)
43
+ engine.expr_stack.push self
44
+ end
45
+
34
46
  # Look up the value of property with given name
35
47
  # aName [String] name of object property
36
48
  def get(aName)
@@ -138,6 +138,11 @@ module Loxxy
138
138
  aSetExpr.object.accept(aVisitor)
139
139
  end
140
140
 
141
+ def after_logical_expr(aLogicalExpr, aVisitor)
142
+ # Force the visit of second operand (resolver should ignore shortcuts)
143
+ aLogicalExpr.operands.last.accept(aVisitor)
144
+ end
145
+
141
146
  # Variable expressions require their variables resolved
142
147
  def before_variable_expr(aVarExpr)
143
148
  var_name = aVarExpr.name
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.3.03'
4
+ VERSION = '0.4.00'
5
5
  end
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.3.03
4
+ version: 0.4.00
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-05-23 00:00:00.000000000 Z
11
+ date: 2021-05-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rley