loxxy 0.1.15 → 0.2.02
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/.rubocop.yml +47 -11
- data/CHANGELOG.md +66 -0
- data/README.md +177 -90
- data/bin/loxxy +54 -6
- data/lib/loxxy.rb +1 -0
- data/lib/loxxy/ast/all_lox_nodes.rb +1 -0
- data/lib/loxxy/ast/ast_builder.rb +20 -1
- data/lib/loxxy/ast/ast_visitor.rb +7 -0
- data/lib/loxxy/ast/lox_class_stmt.rb +5 -1
- data/lib/loxxy/ast/lox_super_expr.rb +35 -0
- data/lib/loxxy/back_end/engine.rb +41 -13
- data/lib/loxxy/back_end/lox_class.rb +22 -4
- data/lib/loxxy/back_end/lox_function.rb +6 -0
- data/lib/loxxy/back_end/lox_instance.rb +0 -4
- data/lib/loxxy/back_end/resolver.rb +38 -2
- data/lib/loxxy/back_end/symbol_table.rb +1 -18
- data/lib/loxxy/cli_parser.rb +68 -0
- data/lib/loxxy/error.rb +3 -0
- data/lib/loxxy/front_end/grammar.rb +2 -2
- data/lib/loxxy/front_end/scanner.rb +32 -7
- data/lib/loxxy/interpreter.rb +12 -1
- data/lib/loxxy/version.rb +1 -1
- data/loxxy.gemspec +6 -2
- data/spec/back_end/engine_spec.rb +0 -8
- data/spec/front_end/scanner_spec.rb +34 -0
- data/spec/interpreter_spec.rb +94 -0
- metadata +9 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: afc822710c5023cdffd8eeb9e9316736f2b2d9ddb2d05e4c4e835dee9b9b4d8b
|
4
|
+
data.tar.gz: 5debd7264833555cc34c64586de96d4e811eef4ebebe25f6c42a0832dee8e433
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d988772978387faa28692101e6b2dab580a93b6f5738ad9094faf22d8aed78aca68123982ff0a25d9b9029d4d27ef4f82788009b10942a14ce5dd9bd9f1e37a7
|
7
|
+
data.tar.gz: 711b3188b0dd14a9821eee5227ee0d574c60144b7be88a3f722d10b4506556fa864685659c7493acfd6d63c2cf82f8c0c6c36cc0431a57a2d476efe3b4bf7efd
|
data/.rubocop.yml
CHANGED
@@ -3,6 +3,9 @@ AllCops:
|
|
3
3
|
- 'exp/**/*'
|
4
4
|
- 'demo/**/*'
|
5
5
|
|
6
|
+
Gemspec/DateAssignment:
|
7
|
+
Enabled: true
|
8
|
+
|
6
9
|
Layout/ArgumentAlignment:
|
7
10
|
Enabled: false
|
8
11
|
|
@@ -34,7 +37,7 @@ Layout/EndOfLine:
|
|
34
37
|
|
35
38
|
Layout/FirstArgumentIndentation:
|
36
39
|
Enabled: false
|
37
|
-
|
40
|
+
|
38
41
|
Layout/HashAlignment:
|
39
42
|
Enabled: false
|
40
43
|
|
@@ -56,7 +59,7 @@ Layout/MultilineMethodCallBraceLayout:
|
|
56
59
|
|
57
60
|
Layout/SpaceAroundOperators:
|
58
61
|
Enabled: true
|
59
|
-
|
62
|
+
|
60
63
|
Layout/SpaceBeforeBrackets:
|
61
64
|
Enabled: true
|
62
65
|
|
@@ -74,10 +77,13 @@ Layout/TrailingEmptyLines:
|
|
74
77
|
|
75
78
|
Layout/TrailingWhitespace:
|
76
79
|
Enabled: true
|
77
|
-
|
80
|
+
|
78
81
|
Lint/AmbiguousAssignment:
|
79
82
|
Enabled: true
|
80
83
|
|
84
|
+
Lint/DeprecatedConstants:
|
85
|
+
Enabled: true
|
86
|
+
|
81
87
|
Lint/DuplicateBranch:
|
82
88
|
Enabled: true
|
83
89
|
|
@@ -90,24 +96,42 @@ Lint/EmptyBlock:
|
|
90
96
|
Lint/EmptyClass:
|
91
97
|
Enabled: false
|
92
98
|
|
99
|
+
Lint/LambdaWithoutLiteralBlock:
|
100
|
+
Enabled: true
|
101
|
+
|
93
102
|
Lint/Loop:
|
94
103
|
Enabled: true
|
95
104
|
|
96
105
|
Lint/NoReturnInBeginEndBlocks:
|
97
106
|
Enabled: true
|
98
107
|
|
108
|
+
Lint/NumberedParameterAssignment:
|
109
|
+
Enabled: true
|
110
|
+
|
111
|
+
Lint/OrAssignmentToConstant:
|
112
|
+
Enabled: true
|
113
|
+
|
99
114
|
Lint/RaiseException:
|
100
115
|
Enabled: true
|
101
116
|
|
117
|
+
Lint/RedundantDirGlobSort:
|
118
|
+
Enabled: true
|
119
|
+
|
102
120
|
Lint/RescueException:
|
103
121
|
Enabled: true
|
104
122
|
|
105
123
|
Lint/StructNewOverride:
|
106
124
|
Enabled: true
|
107
125
|
|
126
|
+
Lint/SymbolConversion:
|
127
|
+
Enabled: true
|
128
|
+
|
108
129
|
Lint/ToEnumArguments:
|
109
130
|
Enabled: true
|
110
131
|
|
132
|
+
Lint/TripleQuotes:
|
133
|
+
Enabled: true
|
134
|
+
|
111
135
|
Lint/UnexpectedBlockArity:
|
112
136
|
Enabled: true
|
113
137
|
|
@@ -170,7 +194,7 @@ Naming/BlockParameterName:
|
|
170
194
|
|
171
195
|
Naming/MethodParameterName:
|
172
196
|
Enabled: false
|
173
|
-
|
197
|
+
|
174
198
|
Naming/MethodName:
|
175
199
|
Enabled: false
|
176
200
|
|
@@ -200,7 +224,7 @@ Style/ClassCheck:
|
|
200
224
|
|
201
225
|
Style/ClassVars:
|
202
226
|
Enabled: false
|
203
|
-
|
227
|
+
|
204
228
|
Style/CollectionCompact:
|
205
229
|
Enabled: true
|
206
230
|
|
@@ -221,7 +245,7 @@ Style/DefWithParentheses:
|
|
221
245
|
|
222
246
|
Style/Documentation:
|
223
247
|
Enabled: false
|
224
|
-
|
248
|
+
|
225
249
|
Style/DocumentDynamicEvalDefinition:
|
226
250
|
Enabled: true
|
227
251
|
|
@@ -236,7 +260,7 @@ Style/GuardClause:
|
|
236
260
|
|
237
261
|
Style/HashEachMethods:
|
238
262
|
Enabled: true
|
239
|
-
|
263
|
+
|
240
264
|
Style/HashExcept:
|
241
265
|
Enabled: true
|
242
266
|
|
@@ -254,13 +278,13 @@ Style/InverseMethods:
|
|
254
278
|
|
255
279
|
Style/MissingRespondToMissing:
|
256
280
|
Enabled: false
|
257
|
-
|
281
|
+
|
258
282
|
Style/NegatedIfElseCondition:
|
259
283
|
Enabled: true
|
260
284
|
|
261
285
|
Style/Next:
|
262
286
|
Enabled: false
|
263
|
-
|
287
|
+
|
264
288
|
Style/NilLambda:
|
265
289
|
Enabled: true
|
266
290
|
|
@@ -269,7 +293,7 @@ Style/NumericLiterals:
|
|
269
293
|
|
270
294
|
Style/RaiseArgs:
|
271
295
|
Enabled: true
|
272
|
-
|
296
|
+
|
273
297
|
Style/RedundantArgument:
|
274
298
|
Enabled: true
|
275
299
|
|
@@ -290,7 +314,7 @@ Style/StderrPuts:
|
|
290
314
|
|
291
315
|
Style/StringLiterals:
|
292
316
|
Enabled: true
|
293
|
-
|
317
|
+
|
294
318
|
Style/SwapValues:
|
295
319
|
Enabled: true
|
296
320
|
|
@@ -352,6 +376,9 @@ Style/BisectedAttrAccessor:
|
|
352
376
|
Style/CaseLikeIf:
|
353
377
|
Enabled: true
|
354
378
|
|
379
|
+
Style/EndlessMethod:
|
380
|
+
Enabled: true
|
381
|
+
|
355
382
|
Style/ExplicitBlockArgument:
|
356
383
|
Enabled: true
|
357
384
|
|
@@ -361,9 +388,15 @@ Style/GlobalStdStream:
|
|
361
388
|
Style/HashAsLastArrayItem:
|
362
389
|
Enabled: true
|
363
390
|
|
391
|
+
Style/HashConversion:
|
392
|
+
Enabled: true
|
393
|
+
|
364
394
|
Style/HashLikeCase:
|
365
395
|
Enabled: true
|
366
396
|
|
397
|
+
Style/IfWithBooleanLiteralBranches:
|
398
|
+
Enabled: true
|
399
|
+
|
367
400
|
Style/OptionalBooleanParameter:
|
368
401
|
Enabled: true
|
369
402
|
|
@@ -388,5 +421,8 @@ Style/SingleArgumentDig:
|
|
388
421
|
Style/SlicingWithRange:
|
389
422
|
Enabled: true
|
390
423
|
|
424
|
+
Style/StringChars:
|
425
|
+
Enabled: true
|
426
|
+
|
391
427
|
Style/StringConcatenation:
|
392
428
|
Enabled: true
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,69 @@
|
|
1
|
+
## [0.2.02] - 2021-04-21
|
2
|
+
- Improvements in the scanner class (escape sequence for quotes and newlines), error messages closer to jlox.
|
3
|
+
|
4
|
+
### Changed
|
5
|
+
- File `loxxy` executable doesn't show a stack trace for scanner errors
|
6
|
+
- Class `ScannerError` is now a subclass of `Loxxy::Error`
|
7
|
+
- Class `Scanner` now returns a specific error message for unterminated strings
|
8
|
+
- Class `Scanner` error messages are closer to the ones from jlox
|
9
|
+
- Class `Scanner` supports now escape sequences \" for double quotes, \n for newlines
|
10
|
+
- File `README.md` Reshuffled some text
|
11
|
+
|
12
|
+
## [0.2.01] - 2021-04-18
|
13
|
+
- Minor improvements in CLI, starting re-documenting `README.md`.
|
14
|
+
|
15
|
+
### New
|
16
|
+
- Class `Loxxy::CLIParser` parser for the command-line options
|
17
|
+
|
18
|
+
### Changed
|
19
|
+
- File `loxxy` executable now uses commad-line parsing
|
20
|
+
- File `.rubocop.yml` updated with new cops
|
21
|
+
- File `README.md` Added examples for command-line interface
|
22
|
+
- File `loxxy.gemspec` expanded description of gem
|
23
|
+
|
24
|
+
## [0.2.00] - 2021-04-17
|
25
|
+
- `Loxxy` implements the complete `Lox` language including its object-oriented features.
|
26
|
+
|
27
|
+
### New
|
28
|
+
- Class `Ast::LoxSuperExpr` an AST node that represents the occurrence of `super` in source code.
|
29
|
+
- Method `Ast::ASTBuilder#reduce_class_subclassing` action launched by the parser when detecting inheritance
|
30
|
+
- Method `Ast::ASTBuilder#reduce_super_expr` action launched by the parser when detecting the super keyword
|
31
|
+
- Method `Ast::Visitor#visit_super_expr` visit of an `Ast::LoxSuperExpr` node
|
32
|
+
- Method `BackEnd::Engine#after_super_stmt` does the lookup of an inherited method.
|
33
|
+
- Method `BackEnd::Resolver#after_super_stmt` checks for correct context for super occurrence
|
34
|
+
|
35
|
+
|
36
|
+
### Changed
|
37
|
+
- Method `Ast::ASTBuilder#reduce_class_decl` expanded in order to support superclass
|
38
|
+
- Class `Ast::LoxClassStmt` added `superclass` attribute, expanded constructor signature.
|
39
|
+
- Method `BackEnd::Engine#after_class_stmt` adds an environment for super variable.
|
40
|
+
- Class `BackEnd::LoxClass` added `superclass` attribute, expanded constructor signature.
|
41
|
+
- Method `BackEnd::LoxClass#find_method` now does the lookup in superclass(es)
|
42
|
+
- Method `BackEnd::Resolver#after_class_stmt` super variable resolution
|
43
|
+
- File `grammar.rb` changed rules to cope with superclass name and super keyword
|
44
|
+
- File `README.md` updated to reflect current implementation level
|
45
|
+
|
46
|
+
## [0.1.17] - 2021-04-11
|
47
|
+
- `Loxxy` now support custom initializer.
|
48
|
+
|
49
|
+
### Changed
|
50
|
+
- Method `BackEnd::Class#call` updated for custom initializer.
|
51
|
+
- Class `BackEnd::LoxFunction` added an attribute `is_initializer`
|
52
|
+
- Class `BackEnd::Resolver#before_return_stmt` added a check that return in initializer may not return a value
|
53
|
+
|
54
|
+
### Fixed
|
55
|
+
- Method `BackEnd::Engine#after_call_expr` now does arity checking also for initalizer.
|
56
|
+
- Method `BackEnd::LoxInstance#set` removed the check of field existence that prevented the creation of ... fields
|
57
|
+
|
58
|
+
## [0.1.16] - 2021-04-10
|
59
|
+
- Fixed an issue in name lookup. All the `this` test suite is passing.
|
60
|
+
|
61
|
+
### Changed
|
62
|
+
- Method `BackEnd::Engine#after_var_stmt` now it creates the variable and pouts it in the symbol table
|
63
|
+
|
64
|
+
### Removed
|
65
|
+
- Method `BackEnd::Engine#before_var_stmt` it generated bug when assigning a value to a var, when that var name occurred elsewhere
|
66
|
+
|
1
67
|
## [0.1.15] - 2021-04-08
|
2
68
|
- Fixed the `dangling else`by tweaking the grammar rules
|
3
69
|
|
data/README.md
CHANGED
@@ -1,59 +1,202 @@
|
|
1
1
|
# loxxy
|
2
2
|
[](https://badge.fury.io/rb/loxxy)
|
3
|
+
[](https://ci.appveyor.com/project/famished-tiger/loxxy)
|
3
4
|
[](https://github.com/famished-tiger/loxxy/blob/main/LICENSE.txt)
|
4
5
|
|
5
|
-
|
6
|
+
## What is loxxy?
|
6
7
|
A Ruby implementation of the [Lox programming language](https://craftinginterpreters.com/the-lox-language.html ),
|
7
|
-
a simple language defined in Bob Nystrom's online book [Crafting Interpreters](https://craftinginterpreters.com/ ).
|
8
|
+
a simple language defined in Bob Nystrom's excellent online book [Crafting Interpreters](https://craftinginterpreters.com/ ).
|
8
9
|
|
9
|
-
|
10
|
-
-
|
11
|
-
|
12
|
-
-
|
13
|
-
|
10
|
+
Although __Lox__ is fairly simple, it is far from being a toy language:
|
11
|
+
- Dynamically typed,
|
12
|
+
- Provides data types such as booleans, number, strings,
|
13
|
+
- Supports arithmetic operations (+, -, *, / ) and comparison ( >, >= , <, <=)
|
14
|
+
- Implements equality operators (==, !=) and the logical connectors `and` and `or`.
|
15
|
+
- Control flow statements `if`, `for` and `while`
|
16
|
+
- Functions and closures
|
17
|
+
- Object-orientation (classes, methods, inheritance).
|
18
|
+
|
19
|
+
### Loxxy gem features
|
20
|
+
- Complete tree-walking interpreter including lexer, parser and resolver
|
21
|
+
- 100% pure Ruby with clean design (not a port from some other language)
|
22
|
+
- Minimal runtime dependency (Rley gem). Won't drag a bunch of gems...
|
23
|
+
- Ruby API for integrating a Lox interpreter with your code.
|
24
|
+
- A command-line interpreter `loxxy`
|
25
|
+
- Open for your language extensions
|
26
|
+
|
27
|
+
## How to start in 1, 2, 3...?
|
28
|
+
... in less than 3 minutes...
|
29
|
+
|
30
|
+
### 1. Installing
|
31
|
+
Install __Loxxy__ as a gem:
|
32
|
+
|
33
|
+
|
34
|
+
$ gem install loxxy
|
35
|
+
|
36
|
+
### 2. Your first `Lox` program
|
37
|
+
Create a text file and enter the following lines:
|
38
|
+
```javascript
|
39
|
+
// Your firs Lox program
|
40
|
+
print "Hello, world.";
|
41
|
+
```
|
42
|
+
|
43
|
+
### 3. Running your program...
|
44
|
+
Assuming that you named the file `hello.lox`, launch the `Loxxy` interpreter in same directory:
|
45
|
+
|
46
|
+
$ loxxy hello.lox
|
47
|
+
|
48
|
+
Lo and behold! The output device displays the famous greeting:
|
49
|
+
|
50
|
+
Hello, world.
|
51
|
+
|
52
|
+
|
53
|
+
Congrats! You ran your first `Lox` program thanks __Loxxy__ gem.
|
54
|
+
For a less superficial encounter with the language jump to the next section.
|
55
|
+
|
56
|
+
## So you want something beefier?...
|
57
|
+
Let's admit it, the hello world example was unimpressive.
|
58
|
+
To a get a taste of `Lox` object-oriented capabilities, let's try another `Hello world` variant:
|
59
|
+
|
60
|
+
```javascript
|
61
|
+
// Object-oriented hello world
|
62
|
+
class Greeter {
|
63
|
+
// in Lox, initializers/constructors are named `init`
|
64
|
+
init(who) {
|
65
|
+
this.interjection = "Hello";
|
66
|
+
this.subject = who;
|
67
|
+
}
|
68
|
+
|
69
|
+
greeting() {
|
70
|
+
this.interjection + ", " + this.subject + ".";
|
71
|
+
}
|
72
|
+
}
|
73
|
+
|
74
|
+
var greeter = Greeter("world"); // an instance is created here...
|
75
|
+
print greeter.greeting();
|
76
|
+
```
|
77
|
+
|
78
|
+
Running this version will result in the same famous greeting.
|
79
|
+
|
80
|
+
Our next assignment: compute the first 20 elements of the Fibbonacci sequence.
|
81
|
+
Here's an answer using the `while` loop construct:
|
82
|
+
|
83
|
+
```javascript
|
84
|
+
// Compute the first 20 elements from the Fibbonacci sequence
|
85
|
+
|
86
|
+
var a = 0; // Use the var keyword to declare a new variable
|
87
|
+
var b = 1;
|
88
|
+
var count = 20;
|
89
|
+
|
90
|
+
while (count > 0) {
|
91
|
+
print a;
|
92
|
+
print " ";
|
93
|
+
var tmp = a;
|
94
|
+
a = b;
|
95
|
+
b = tmp + b;
|
96
|
+
count = count - 1;
|
97
|
+
}
|
98
|
+
```
|
99
|
+
|
100
|
+
Assuming, that this source code was put in a file named `fibbonacci.lox`, then
|
101
|
+
the command line
|
102
|
+
|
103
|
+
$ loxxy fibbonacci.lox
|
104
|
+
|
105
|
+
Results in:
|
14
106
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
107
|
+
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181
|
108
|
+
|
109
|
+
Fans of `for` loops will be pleased to find their favorite looping construct.
|
110
|
+
Here again, the Fibbonacci sequence refactored with a `for` loop:
|
19
111
|
|
112
|
+
```javascript
|
113
|
+
// Fibbonacci sequence - version 2
|
114
|
+
var a = 0;
|
115
|
+
var b = 1;
|
116
|
+
var count = 20;
|
117
|
+
|
118
|
+
for (var i = 0; i < count; i = i + 1) {
|
119
|
+
print a;
|
120
|
+
print " ";
|
121
|
+
var tmp = a;
|
122
|
+
a = b;
|
123
|
+
b = tmp + b;
|
124
|
+
}
|
125
|
+
```
|
126
|
+
Lets's call this file `fibbonacci_v2.lox` and execute it thanks `loxxy` CLI:
|
127
|
+
|
128
|
+
$ loxxy fibbonacci_v2.lox
|
129
|
+
|
130
|
+
We see again the same sequence:
|
131
|
+
|
132
|
+
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181
|
133
|
+
|
134
|
+
To complete our quick tour of `Lox` language, let's calculate the sequence with a recursive function:
|
135
|
+
|
136
|
+
```javascript
|
137
|
+
// Fibbonacci sequence - version 3
|
138
|
+
var count = 20;
|
139
|
+
|
140
|
+
// Let's define a recursive function
|
141
|
+
fun fib(n) {
|
142
|
+
if (n < 2) return n;
|
143
|
+
return fib(n - 1) + fib(n - 2);
|
144
|
+
}
|
145
|
+
|
146
|
+
// For demo purposes, let's assign the function to a variable
|
147
|
+
var fib_fun = fib;
|
148
|
+
|
149
|
+
for (var i = 0; i < count; i = i + 1) {
|
150
|
+
print fib_fun(i);
|
151
|
+
print " ";
|
152
|
+
}
|
153
|
+
```
|
154
|
+
|
155
|
+
This completes our quick tour of `Lox`, to learn more about the language,
|
156
|
+
check the online book [Crafting Interpreters](https://craftinginterpreters.com/ )
|
20
157
|
|
21
158
|
## What's the fuss about Lox?
|
22
159
|
... Nothing...
|
23
|
-
Bob Nystrom designed a language __simple__ enough so that he could present
|
160
|
+
Bob Nystrom designed a language __simple__ enough so that he could present
|
24
161
|
two implementations (an interpreter, then a compiler) in one single book.
|
25
162
|
|
26
|
-
|
27
|
-
-
|
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).
|
163
|
+
In other words, __Lox__ contains interesting features found in most general-purpose
|
164
|
+
languages. In addition to that, there are [numerous implementations](https://github.com/munificent/craftinginterpreters/wiki/Lox-implementations) in different languages
|
34
165
|
|
35
|
-
|
36
|
-
languages.
|
166
|
+
Lox interpreters, like `Loxxy` give the unique opportunity for the curious to learn the internals of reasonably-sized language.
|
37
167
|
|
38
168
|
### What's missing in Lox?
|
39
|
-
|
40
|
-
|
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)
|
169
|
+
While `Lox` blends interesting features from the two mainstream paradigms (OO and functional),
|
170
|
+
it doesn't pretend to be used in real-life projects.
|
45
171
|
|
46
|
-
|
172
|
+
In fact, the language was designed to be simple to implement at the expense of missing advanced features.
|
173
|
+
Here are features I'll like to put on my wish list:
|
174
|
+
- Collection classes (e.g. Arrays, Maps (Hash))
|
175
|
+
- Modules
|
176
|
+
- Standard library
|
177
|
+
- Concurrency / parallelism constructs
|
47
178
|
|
48
|
-
|
49
|
-
|
179
|
+
That `Lox` cannot be compared to a full-featured language, is both a drawback and and an opportunity.
|
180
|
+
Indeed, an open-source language that misses some features is an invitation for the curious to tinker and experiment with extensions.
|
181
|
+
There are already a number of programming languages derived from `Lox`...
|
50
182
|
|
51
|
-
|
52
|
-
language, that might be even funnier...
|
183
|
+
## Why `Loxxy`? What's in it for me?...
|
53
184
|
|
54
|
-
|
185
|
+
### Purpose of this project:
|
186
|
+
- To deliver an open source example of a programming language fully implemented in Ruby
|
187
|
+
(from the scanner and parser to an interpreter).
|
188
|
+
- The implementation should be mature enough to run [LoxLox](https://github.com/benhoyt/loxlox),
|
189
|
+
a Lox interpreter written in Lox.
|
190
|
+
|
191
|
+
### Roadmap
|
192
|
+
- Extend the test suite
|
193
|
+
- Improve the error handling
|
194
|
+
- Improve the documentation
|
195
|
+
- Ability run the LoxLox interpreter
|
55
196
|
|
56
197
|
## Hello world example
|
198
|
+
The next examples show how to use the interpreter directly from Ruby code.
|
199
|
+
|
57
200
|
```ruby
|
58
201
|
require 'loxxy'
|
59
202
|
|
@@ -108,48 +251,10 @@ lox_input = <<-LOX_END
|
|
108
251
|
print "Hello, world!";
|
109
252
|
LOX_END
|
110
253
|
|
111
|
-
# Show that the raw parser accepts the above program
|
112
|
-
base_parser = Loxxy::FrontEnd::RawParser.new
|
113
254
|
|
114
|
-
# Now parse the input into a concrete parse tree...
|
115
|
-
ptree = base_parser.parse(lox_input)
|
116
|
-
|
117
|
-
# Display the parse tree thanks to Rley formatters...
|
118
|
-
visitor = Rley::ParseTreeVisitor.new(ptree)
|
119
|
-
tree_formatter = Rley::Formatter::Asciitree.new($stdout)
|
120
|
-
tree_formatter.render(visitor)
|
121
|
-
```
|
122
|
-
|
123
|
-
This is the output produced by the above example:
|
124
|
-
```
|
125
|
-
program
|
126
|
-
+-- declaration_plus
|
127
|
-
| +-- declaration
|
128
|
-
| +-- statement
|
129
|
-
| +-- printStmt
|
130
|
-
| +-- PRINT: 'print'
|
131
|
-
| +-- expression
|
132
|
-
| | +-- assignment
|
133
|
-
| | +-- logic_or
|
134
|
-
| | +-- logic_and
|
135
|
-
| | +-- equality
|
136
|
-
| | +-- comparison
|
137
|
-
| | +-- term
|
138
|
-
| | +-- factor
|
139
|
-
| | +-- unary
|
140
|
-
| | +-- call
|
141
|
-
| | +-- primary
|
142
|
-
| | +-- STRING: '"Hello, world!"'
|
143
|
-
| +-- SEMICOLON: ';'
|
144
|
-
+-- EOF: ''
|
145
|
-
```
|
146
255
|
|
147
256
|
## Suppported Lox language features
|
148
|
-
On one hand, the parser covers the complete Lox grammar and should therefore, in principle,
|
149
|
-
parse any valid Lox program.
|
150
257
|
|
151
|
-
On the other hand, the interpreter is under development and currently it can evaluate only a subset of __Lox__.
|
152
|
-
But the situation is changing almost daily, stay tuned...
|
153
258
|
|
154
259
|
Here are the language features currently supported by the interpreter:
|
155
260
|
|
@@ -377,25 +482,7 @@ fun add4(n) // `add4` will be the name of the function
|
|
377
482
|
print add4(6); // output: 10
|
378
483
|
```
|
379
484
|
|
380
|
-
## Installation
|
381
|
-
|
382
|
-
Add this line to your application's Gemfile:
|
383
|
-
|
384
|
-
```ruby
|
385
|
-
gem 'loxxy'
|
386
|
-
```
|
387
|
-
|
388
|
-
And then execute:
|
389
|
-
|
390
|
-
$ bundle install
|
391
|
-
|
392
|
-
Or install it yourself as:
|
393
|
-
|
394
|
-
$ gem install loxxy
|
395
|
-
|
396
|
-
## Usage
|
397
485
|
|
398
|
-
TODO: Write usage instructions here
|
399
486
|
|
400
487
|
## Other Lox implementations in Ruby
|
401
488
|
|