loxxy 0.2.00 → 0.2.01
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
[![Gem Version](https://badge.fury.io/rb/loxxy.svg)](https://badge.fury.io/rb/loxxy)
|
3
|
+
[![Build status](https://ci.appveyor.com/api/projects/status/8e5p7dgjanm0qjkp?svg=true)](https://ci.appveyor.com/project/famished-tiger/loxxy)
|
3
4
|
[![License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat)](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
|