loxxy 0.2.00 → 0.2.01
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 +34 -0
- data/README.md +173 -89
- data/bin/loxxy +50 -6
- data/lib/loxxy.rb +1 -0
- data/lib/loxxy/cli_parser.rb +68 -0
- data/lib/loxxy/version.rb +1 -1
- data/loxxy.gemspec +5 -1
- metadata +7 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3137f0d16bb2c3dbbc4e2036abbf45888ba06b863fef69a8682898ffdb2a146b
|
|
4
|
+
data.tar.gz: 344ff5f99e7d64dd45074aaacde5622ecb676d8d3112773555b0fbcffbd5aa89
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f3cd447081d53619afeb040d9eade7fab0c0d5db79b8407fba412df727fb72849e5671679d7fd13fded703b9009399febfac6506ef91ac0bdd3220ef26472408
|
|
7
|
+
data.tar.gz: 4a83b84a9853787369d51f48d7c2eacfe8a7e58b4ab8cb5d5322b02e0a5de68c4481effa61587db70f066902d21c7b2a310509de74d13f2cf1476a490e2728a7
|
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,37 @@
|
|
|
1
|
+
## [0.2.01] - 2021-04-18
|
|
2
|
+
- Minor improvements in CLI, starting re-documenting `README.md`.
|
|
3
|
+
|
|
4
|
+
### New
|
|
5
|
+
- Class `Loxxy::CLIParser` parser for the command-line options
|
|
6
|
+
|
|
7
|
+
### Changed
|
|
8
|
+
- File `loxxy` executable now uses commad-line parsing
|
|
9
|
+
- File `.rubocop.yml` updated with new cops
|
|
10
|
+
- File `README.md` Added examples for command-line interface
|
|
11
|
+
- File `loxxy.gemspec` expanded description of gem
|
|
12
|
+
|
|
13
|
+
## [0.2.00] - 2021-04-17
|
|
14
|
+
- `Loxxy` implements the complete `Lox` language including its object-oriented features.
|
|
15
|
+
|
|
16
|
+
### New
|
|
17
|
+
- Class `Ast::LoxSuperExpr` an AST node that represents the occurrence of `super` in source code.
|
|
18
|
+
- Method `Ast::ASTBuilder#reduce_class_subclassing` action launched by the parser when detecting inheritance
|
|
19
|
+
- Method `Ast::ASTBuilder#reduce_super_expr` action launched by the parser when detecting the super keyword
|
|
20
|
+
- Method `Ast::Visitor#visit_super_expr` visit of an `Ast::LoxSuperExpr` node
|
|
21
|
+
- Method `BackEnd::Engine#after_super_stmt` does the lookup of an inherited method.
|
|
22
|
+
- Method `BackEnd::Resolver#after_super_stmt` checks for correct context for super occurrence
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
### Changed
|
|
26
|
+
- Method `Ast::ASTBuilder#reduce_class_decl` expanded in order to support superclass
|
|
27
|
+
- Class `Ast::LoxClassStmt` added `superclass` attribute, expanded constructor signature.
|
|
28
|
+
- Method `BackEnd::Engine#after_class_stmt` adds an environment for super variable.
|
|
29
|
+
- Class `BackEnd::LoxClass` added `superclass` attribute, expanded constructor signature.
|
|
30
|
+
- Method `BackEnd::LoxClass#find_method` now does the lookup in superclass(es)
|
|
31
|
+
- Method `BackEnd::Resolver#after_class_stmt` super variable resolution
|
|
32
|
+
- File `grammar.rb` changed rules to cope with superclass name and super keyword
|
|
33
|
+
- File `README.md` updated to reflect current implementation level
|
|
34
|
+
|
|
1
35
|
## [0.1.17] - 2021-04-11
|
|
2
36
|
- `Loxxy` now support custom initializer.
|
|
3
37
|
|
data/README.md
CHANGED
|
@@ -1,59 +1,199 @@
|
|
|
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
|
+
## How to start in 1, 2, 3...?
|
|
20
|
+
... in less than 3 minutes...
|
|
21
|
+
|
|
22
|
+
### 1. Installing
|
|
23
|
+
Install __Loxxy__ as a gem:
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
$ gem install loxxy
|
|
27
|
+
|
|
28
|
+
### 2. Your first `Lox` program
|
|
29
|
+
Create a text file and enter the following lines:
|
|
30
|
+
```javascript
|
|
31
|
+
// Your firs Lox program
|
|
32
|
+
print "Hello, world.";
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### 3. Running your program...
|
|
36
|
+
Assuming that you named the file `hello.lox`, launch the `Loxxy` interpreter in same directory:
|
|
37
|
+
|
|
38
|
+
$ loxxy hello.lox
|
|
39
|
+
|
|
40
|
+
Lo and behold! The output device displays the famous greeting:
|
|
41
|
+
|
|
42
|
+
Hello, world.
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
Congrats! You ran your first `Lox` program with __Loxxy__.
|
|
46
|
+
|
|
47
|
+
### Something beefier?...
|
|
48
|
+
Let's admit it, the hello world example was unimpressive.
|
|
49
|
+
To a get a taste of `Lox` object-oriented capabilities, let's try another `Hello world` variant:
|
|
50
|
+
|
|
51
|
+
```javascript
|
|
52
|
+
// Object-oriented hello world
|
|
53
|
+
class Greeter {
|
|
54
|
+
// in Lox, initializers/constructors are named `init`
|
|
55
|
+
init(who) {
|
|
56
|
+
this.interjection = "Hello";
|
|
57
|
+
this.subject = who;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
greeting() {
|
|
61
|
+
this.interjection + ", " + this.subject + ".";
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
var greeter = Greeter("world"); // an instance is created here...
|
|
66
|
+
print greeter.greeting();
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Running this version will result in the same famous greeting.
|
|
70
|
+
|
|
71
|
+
Our next assignment: compute the first 20 elements of the Fibbonacci sequence.
|
|
72
|
+
Here's an answer using the `while` loop construct:
|
|
73
|
+
|
|
74
|
+
```javascript
|
|
75
|
+
// Compute the first 20 elements from the Fibbonacci sequence
|
|
76
|
+
|
|
77
|
+
var a = 0; // Use the var keyword to declare a new variable
|
|
78
|
+
var b = 1;
|
|
79
|
+
var count = 20;
|
|
80
|
+
|
|
81
|
+
while (count > 0) {
|
|
82
|
+
print a;
|
|
83
|
+
print " ";
|
|
84
|
+
var tmp = a;
|
|
85
|
+
a = b;
|
|
86
|
+
b = tmp + b;
|
|
87
|
+
count = count - 1;
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Assuming, that this source code was put in a file named `fibbonacci.lox`, then
|
|
92
|
+
the command line
|
|
93
|
+
|
|
94
|
+
$ loxxy fibbonacci.lox
|
|
95
|
+
|
|
96
|
+
Results in:
|
|
97
|
+
|
|
98
|
+
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181
|
|
99
|
+
|
|
100
|
+
Fans of `for` loops will be pleased to find their favorite looping construct.
|
|
101
|
+
Here again, the Fibbonacci sequence refactored with a `for` loop:
|
|
14
102
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
103
|
+
```javascript
|
|
104
|
+
// Fibbonacci sequence - version 2
|
|
105
|
+
var a = 0;
|
|
106
|
+
var b = 1;
|
|
107
|
+
var count = 20;
|
|
108
|
+
|
|
109
|
+
for (var i = 0; i < count; i = i + 1) {
|
|
110
|
+
print a;
|
|
111
|
+
print " ";
|
|
112
|
+
var tmp = a;
|
|
113
|
+
a = b;
|
|
114
|
+
b = tmp + b;
|
|
115
|
+
}
|
|
116
|
+
```
|
|
117
|
+
Lets's call this file `fibbonacci_v2.lox` and execute it thanks `loxxy` CLI:
|
|
118
|
+
|
|
119
|
+
$ loxxy fibbonacci_v2.lox
|
|
120
|
+
|
|
121
|
+
We see again the same sequence:
|
|
122
|
+
|
|
123
|
+
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181
|
|
124
|
+
|
|
125
|
+
To complete our quick tour of `Lox` language, let's calculate the sequence with a recursive function:
|
|
126
|
+
|
|
127
|
+
```javascript
|
|
128
|
+
// Fibbonacci sequence - version 3
|
|
129
|
+
var count = 20;
|
|
130
|
+
|
|
131
|
+
// Let's define a recursive function
|
|
132
|
+
fun fib(n) {
|
|
133
|
+
if (n < 2) return n;
|
|
134
|
+
return fib(n - 1) + fib(n - 2);
|
|
135
|
+
}
|
|
19
136
|
|
|
137
|
+
// For demo purposes, let's assign the function to a variable
|
|
138
|
+
var fib_fun = fib;
|
|
139
|
+
|
|
140
|
+
for (var i = 0; i < count; i = i + 1) {
|
|
141
|
+
print fib_fun(i);
|
|
142
|
+
print " ";
|
|
143
|
+
}
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
This completes our quick tour of `Lox`, to learn more about the language,
|
|
147
|
+
check the online book [Crafting Interpreters](https://craftinginterpreters.com/ )
|
|
20
148
|
|
|
21
149
|
## What's the fuss about Lox?
|
|
22
150
|
... Nothing...
|
|
23
|
-
Bob Nystrom designed a language __simple__ enough so that he could present
|
|
151
|
+
Bob Nystrom designed a language __simple__ enough so that he could present
|
|
24
152
|
two implementations (an interpreter, then a compiler) in one single book.
|
|
25
153
|
|
|
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).
|
|
154
|
+
In other words, __Lox__ contains interesting features found in most general-purpose
|
|
155
|
+
languages. In addition to that, there are [numerous implementations](https://github.com/munificent/craftinginterpreters/wiki/Lox-implementations) in different languages
|
|
34
156
|
|
|
35
|
-
|
|
36
|
-
languages.
|
|
157
|
+
Lox interpreters, like `Loxxy` give the unique opportunity for the curious to learn the internals of reasonably-sized language.
|
|
37
158
|
|
|
38
159
|
### 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)
|
|
160
|
+
While `Lox` blends interesting features from the two mainstream paradigms (OO and functional),
|
|
161
|
+
it doesn't pretend to be used in real-life projects.
|
|
45
162
|
|
|
46
|
-
|
|
163
|
+
In fact, the language was designed to be simple to implement at the expense of missing advanced features.
|
|
164
|
+
Here are features I'll like to put on my wish list:
|
|
165
|
+
- Collection classes (e.g. Arrays, Maps (Hash))
|
|
166
|
+
- Modules
|
|
167
|
+
- Standard library
|
|
168
|
+
- Concurrency / parallelism constructs
|
|
47
169
|
|
|
48
|
-
|
|
49
|
-
|
|
170
|
+
That `Lox` cannot be compared to a full-featured language, is both a drawback and and an opportunity.
|
|
171
|
+
Indeed, an open-source language that misses some features is an invitation for the curious to tinker and experiment with extensions.
|
|
172
|
+
There are already a number of programming languages derived from `Lox`...
|
|
50
173
|
|
|
51
|
-
|
|
52
|
-
|
|
174
|
+
## Why `Loxxy`? What's in it for me?...
|
|
175
|
+
Features:
|
|
176
|
+
- Complete tree-walking interpreter including lexer, parser and resolver
|
|
177
|
+
- 100% pure Ruby with clean design (not a port from some other language)
|
|
178
|
+
- Ruby API for integrating a Lox interpreter with your code.
|
|
179
|
+
- Minimal runtime dependency (Rley gem). Won't drag a bunch of gems...
|
|
53
180
|
|
|
54
|
-
|
|
181
|
+
|
|
182
|
+
### Purpose of this project:
|
|
183
|
+
- To deliver an open source example of a programming language fully implemented in Ruby
|
|
184
|
+
(from the scanner and parser to an interpreter).
|
|
185
|
+
- The implementation should be mature enough to run [LoxLox](https://github.com/benhoyt/loxlox),
|
|
186
|
+
a Lox interpreter written in Lox.
|
|
187
|
+
|
|
188
|
+
### Roadmap
|
|
189
|
+
- Extend the test suite
|
|
190
|
+
- Improve the error handling
|
|
191
|
+
- Improve the documentation
|
|
192
|
+
- Ability run the LoxLox interpreter
|
|
55
193
|
|
|
56
194
|
## Hello world example
|
|
195
|
+
The next examples show how to use the interpreter directly from Ruby code.
|
|
196
|
+
|
|
57
197
|
```ruby
|
|
58
198
|
require 'loxxy'
|
|
59
199
|
|
|
@@ -108,48 +248,10 @@ lox_input = <<-LOX_END
|
|
|
108
248
|
print "Hello, world!";
|
|
109
249
|
LOX_END
|
|
110
250
|
|
|
111
|
-
# Show that the raw parser accepts the above program
|
|
112
|
-
base_parser = Loxxy::FrontEnd::RawParser.new
|
|
113
251
|
|
|
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
252
|
|
|
147
253
|
## 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
254
|
|
|
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
255
|
|
|
154
256
|
Here are the language features currently supported by the interpreter:
|
|
155
257
|
|
|
@@ -377,25 +479,7 @@ fun add4(n) // `add4` will be the name of the function
|
|
|
377
479
|
print add4(6); // output: 10
|
|
378
480
|
```
|
|
379
481
|
|
|
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
482
|
|
|
398
|
-
TODO: Write usage instructions here
|
|
399
483
|
|
|
400
484
|
## Other Lox implementations in Ruby
|
|
401
485
|
|
data/bin/loxxy
CHANGED
|
@@ -3,9 +3,53 @@
|
|
|
3
3
|
|
|
4
4
|
require 'loxxy'
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
6
|
+
class LoxxyRunner
|
|
7
|
+
DefaultLoxExtension = 'lox'
|
|
8
|
+
attr_reader(:cli_options)
|
|
9
|
+
|
|
10
|
+
def initialize(prog_name, args)
|
|
11
|
+
my_version = Loxxy::VERSION
|
|
12
|
+
cli = Loxxy::CLIParser.new(prog_name, my_version)
|
|
13
|
+
@cli_options = cli.parse!(args)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def run!(file_names)
|
|
17
|
+
return if file_names.nil? || file_names.empty?
|
|
18
|
+
|
|
19
|
+
lox = Loxxy::Interpreter.new
|
|
20
|
+
file_names.each do |lox_file|
|
|
21
|
+
fname = validate_filename(lox_file)
|
|
22
|
+
next unless file_exist?(fname)
|
|
23
|
+
|
|
24
|
+
File.open(fname, 'r') { |f| lox.evaluate(f.read) }
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
private
|
|
29
|
+
|
|
30
|
+
def validate_filename(raw_fname)
|
|
31
|
+
# When necessary add extension to file name
|
|
32
|
+
fname = raw_fname.dup
|
|
33
|
+
basename = File.basename(fname)
|
|
34
|
+
has_extension = basename =~ /(?<=[^.])\.[^.]+$/
|
|
35
|
+
fname << '.' << DefaultLoxExtension unless has_extension
|
|
36
|
+
|
|
37
|
+
fname
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def file_exist?(fname)
|
|
41
|
+
exists = File.exist?(fname)
|
|
42
|
+
$stderr.puts "No such file '#{fname}'" unless exists
|
|
43
|
+
|
|
44
|
+
exists
|
|
45
|
+
end
|
|
46
|
+
end # class
|
|
47
|
+
|
|
48
|
+
########################################
|
|
49
|
+
# ENTRY POINT
|
|
50
|
+
########################################
|
|
51
|
+
program = LoxxyRunner.new(File.basename(__FILE__), ARGV)
|
|
52
|
+
|
|
53
|
+
# All options from CLI gobbled from ARGV, remains only file name
|
|
54
|
+
program.run!(ARGV)
|
|
55
|
+
# End of file
|
data/lib/loxxy.rb
CHANGED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'optparse' # Use standard OptionParser class for command-line parsing
|
|
4
|
+
|
|
5
|
+
module Loxxy
|
|
6
|
+
# A command-line option parser for the Loxxy interpreter.
|
|
7
|
+
# It is a specialisation of the OptionParser class.
|
|
8
|
+
class CLIParser < OptionParser
|
|
9
|
+
# @return [Hash{Symbol=>String, Array}]
|
|
10
|
+
attr_reader(:parsed_options)
|
|
11
|
+
|
|
12
|
+
# Constructor.
|
|
13
|
+
def initialize(prog_name, ver)
|
|
14
|
+
super()
|
|
15
|
+
reset(prog_name, ver)
|
|
16
|
+
|
|
17
|
+
heading
|
|
18
|
+
separator 'Options:'
|
|
19
|
+
separator ''
|
|
20
|
+
add_tail_options
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def parse!(args)
|
|
24
|
+
super
|
|
25
|
+
parsed_options
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
private
|
|
29
|
+
|
|
30
|
+
def reset(prog_name, ver)
|
|
31
|
+
@program_name = prog_name
|
|
32
|
+
@version = ver
|
|
33
|
+
@banner = "Usage: #{prog_name} LOX_FILE [options]"
|
|
34
|
+
@parsed_options = {}
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def description
|
|
38
|
+
<<-DESCR
|
|
39
|
+
Description:
|
|
40
|
+
loxxy is a Lox interpreter, it executes the Lox file(s) given in command-line.
|
|
41
|
+
More on Lox Language: https://craftinginterpreters.com/the-lox-language.html
|
|
42
|
+
|
|
43
|
+
Example:
|
|
44
|
+
#{program_name} hello.lox
|
|
45
|
+
DESCR
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def heading
|
|
49
|
+
banner
|
|
50
|
+
separator ''
|
|
51
|
+
separator description
|
|
52
|
+
separator ''
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def add_tail_options
|
|
56
|
+
on_tail('--version', 'Display the program version then quit.') do
|
|
57
|
+
puts version
|
|
58
|
+
exit(0)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
on_tail('-?', '-h', '--help', 'Display this help then quit.') do
|
|
62
|
+
puts help
|
|
63
|
+
exit(0)
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end # class
|
|
67
|
+
end # module
|
|
68
|
+
# End of file
|
data/lib/loxxy/version.rb
CHANGED
data/loxxy.gemspec
CHANGED
|
@@ -41,7 +41,11 @@ Gem::Specification.new do |spec|
|
|
|
41
41
|
spec.authors = ['Dimitri Geshef']
|
|
42
42
|
spec.email = ['famished.tiger@yahoo.com']
|
|
43
43
|
spec.summary = 'An implementation of the Lox programming language.'
|
|
44
|
-
spec.description =
|
|
44
|
+
spec.description = <<-DESCR_END
|
|
45
|
+
A Ruby implementation of the Lox programming language. Lox is a dynamically typed,
|
|
46
|
+
object-oriented programming language that features first-class functions, closures,
|
|
47
|
+
classes, and inheritance.
|
|
48
|
+
DESCR_END
|
|
45
49
|
spec.homepage = 'https://github.com/famished-tiger/loxxy'
|
|
46
50
|
spec.license = 'MIT'
|
|
47
51
|
spec.required_ruby_version = '~> 2.4'
|
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.2.
|
|
4
|
+
version: 0.2.01
|
|
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-04-
|
|
11
|
+
date: 2021-04-18 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rley
|
|
@@ -66,7 +66,10 @@ dependencies:
|
|
|
66
66
|
- - "~>"
|
|
67
67
|
- !ruby/object:Gem::Version
|
|
68
68
|
version: '3.0'
|
|
69
|
-
description:
|
|
69
|
+
description: |2
|
|
70
|
+
A Ruby implementation of the Lox programming language. Lox is a dynamically typed,
|
|
71
|
+
object-oriented programming language that features first-class functions, closures,
|
|
72
|
+
classes, and inheritance.
|
|
70
73
|
email:
|
|
71
74
|
- famished.tiger@yahoo.com
|
|
72
75
|
executables:
|
|
@@ -125,6 +128,7 @@ files:
|
|
|
125
128
|
- lib/loxxy/back_end/symbol_table.rb
|
|
126
129
|
- lib/loxxy/back_end/unary_operator.rb
|
|
127
130
|
- lib/loxxy/back_end/variable.rb
|
|
131
|
+
- lib/loxxy/cli_parser.rb
|
|
128
132
|
- lib/loxxy/datatype/all_datatypes.rb
|
|
129
133
|
- lib/loxxy/datatype/boolean.rb
|
|
130
134
|
- lib/loxxy/datatype/builtin_datatype.rb
|