rus3 0.1.2 → 0.2.0
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/CHANGELOG.md +9 -1
- data/Gemfile.lock +1 -1
- data/README.md +14 -6
- data/exe/rus3 +26 -2
- data/lib/rus3.rb +3 -0
- data/lib/rus3/ast.rb +70 -0
- data/lib/rus3/ast/branch_node.rb +412 -0
- data/lib/rus3/ast/error.rb +8 -0
- data/lib/rus3/ast/leaf_node.rb +55 -0
- data/lib/rus3/error.rb +15 -1
- data/lib/rus3/evaluator.rb +38 -54
- data/lib/rus3/evaluator/environment.rb +25 -0
- data/lib/rus3/evaluator/scheme_evaluator.rb +79 -0
- data/lib/rus3/evaluator/translator.rb +337 -0
- data/lib/rus3/{parser/lexer.rb → lexer.rb} +22 -52
- data/lib/rus3/parser.rb +39 -23
- data/lib/rus3/parser/scheme_parser.rb +595 -306
- data/lib/rus3/procedure/char.rb +21 -17
- data/lib/rus3/procedure/control.rb +28 -24
- data/lib/rus3/procedure/list.rb +210 -207
- data/lib/rus3/procedure/predicate.rb +267 -264
- data/lib/rus3/procedure/utils.rb +20 -16
- data/lib/rus3/procedure/vector.rb +68 -65
- data/lib/rus3/procedure/write.rb +107 -103
- data/lib/rus3/repl.rb +57 -47
- data/lib/rus3/token.rb +35 -0
- data/lib/rus3/version.rb +2 -2
- metadata +11 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8b1f3c9f79ba7f452ff3a2f6d7ec904ac3a1e0ffd836bafd4b4892a8cb0b12ac
|
4
|
+
data.tar.gz: 8c65e739832e954d9ca16fac40e437ca73bb3cddf48c35fbd3eb2f86658d8fd6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9b87669992f65b1279ceb003d2767d7ae6173374c6d810c646ee2914643050514c483aadb81cebafbd505fbbea41b89e297e6026f20749e571e84b423bc3cc8c
|
7
|
+
data.tar.gz: fec0ac13faa9880b10f6245d660b3e95430bfcd6cf48a65787634a55fe32c32e4e5f2eeb8f9321467c6a8dede5c03d34d7ab23ef0a0045de698e8bdf821c5534
|
data/CHANGELOG.md
CHANGED
@@ -5,7 +5,15 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/)
|
|
5
5
|
and this project adheres to [Semantic Versioning](https://semver.org/).
|
6
6
|
|
7
7
|
## [Unreleased]
|
8
|
-
- (nothing to record)
|
8
|
+
- (nothing to record here)
|
9
|
+
|
10
|
+
## [0.2.0] - 2021-05-03
|
11
|
+
### Added
|
12
|
+
- Re-write the parser and evaluator mechanism.
|
13
|
+
- Add tests for SchemeParser and Translator.
|
14
|
+
- Add a mechanism to replace comparison operator characters in
|
15
|
+
identifiers.
|
16
|
+
- e.g. `char<?` -> `char_lt?`
|
9
17
|
|
10
18
|
## [0.1.2] - 2021-04-23
|
11
19
|
### Added
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -17,12 +17,7 @@ You can start the Rus3 REPL with the command, `rus3`.
|
|
17
17
|
|
18
18
|
``` scheme
|
19
19
|
> rus3
|
20
|
-
A simple REPL
|
21
|
-
- Rus3 version: 0.1.0
|
22
|
-
- REPL version: 0.1.0
|
23
|
-
- Parser version 0.1.0 ((scheme-parser-version . 0.1.0) (scheme-lexer-version . 0.1.0))
|
24
|
-
- Evaluator version: 0.1.0
|
25
|
-
- using built-in PRINTER
|
20
|
+
A simple REPL to run Rus3:
|
26
21
|
Rus3(scheme)>
|
27
22
|
```
|
28
23
|
|
@@ -32,6 +27,19 @@ In the REPL, you can enter Scheme expressions. The REPL reads your
|
|
32
27
|
Scheme expressions, translates it to Ruby expressions, and
|
33
28
|
evaluated them. Then, the REPL prints the result after `==> `.
|
34
29
|
|
30
|
+
If you want to run verbosely, use "-d" (or "--debug") option, then it
|
31
|
+
will become very verbose:
|
32
|
+
|
33
|
+
``` scheme
|
34
|
+
A simple REPL to run Rus3:
|
35
|
+
(rus3 :version 0.2.0 :release 2021-05-02
|
36
|
+
(repl :version 0.2.0
|
37
|
+
(parser-module :version 0.2.0 ((scheme-parser :version 0.2.0) (scheme-lexer :version 0.2.0)))
|
38
|
+
(evaluator-module version: 0.2.0 ((scheme-evaluator :version 0.2.0) (scheme-ruby-translator :version 0.1.0)))
|
39
|
+
(:using :built-in :printer)))
|
40
|
+
Rus3(scheme)>
|
41
|
+
```
|
42
|
+
|
35
43
|
### Literal of Scheme values
|
36
44
|
|
37
45
|
Boolean (`#f` and `#t`), an empty list (`()`), a string, and numbers
|
data/exe/rus3
CHANGED
@@ -2,17 +2,41 @@
|
|
2
2
|
|
3
3
|
require "rus3"
|
4
4
|
|
5
|
+
def usage
|
6
|
+
puts <<HELP
|
7
|
+
usage:
|
8
|
+
rus3 [option]
|
9
|
+
option:
|
10
|
+
-e, --evaluator NAME : specify evaluator
|
11
|
+
-d, --debug : specify to run verbose mode
|
12
|
+
-v, --version : print version
|
13
|
+
-h, --help : show this message
|
14
|
+
|
15
|
+
Following names are available as evaluator name:
|
16
|
+
scheme (use by default), passthrough
|
17
|
+
HELP
|
18
|
+
end
|
19
|
+
|
5
20
|
opts = {}
|
6
21
|
|
7
22
|
while ARGV.size > 0
|
8
23
|
arg = ARGV.shift
|
9
24
|
case arg
|
25
|
+
when "-p", "--parser"
|
26
|
+
parser_name = ARGV.shift
|
27
|
+
opts[:parser] = parser_name
|
28
|
+
when "-e", "--evaluator"
|
29
|
+
evaluator_name = ARGV.shift
|
30
|
+
opts[:evaluator] = evaluator_name
|
10
31
|
when "-d", "--debug"
|
11
|
-
opts[:
|
32
|
+
opts[:verbose] = true
|
12
33
|
when "-v", "--version"
|
13
34
|
puts "rus3 version #{Rus3::VERSION} (#{Rus3::RELEASE})"
|
14
35
|
exit 0
|
36
|
+
when "-h", "--help"
|
37
|
+
usage
|
38
|
+
exit 0
|
15
39
|
end
|
16
40
|
end
|
17
41
|
|
18
|
-
Rus3::Repl.start(
|
42
|
+
Rus3::Repl.start(**opts)
|
data/lib/rus3.rb
CHANGED
@@ -49,6 +49,9 @@ module Rus3
|
|
49
49
|
require_relative "rus3/procedure/control"
|
50
50
|
require_relative "rus3/procedure/write"
|
51
51
|
|
52
|
+
require_relative "rus3/ast"
|
53
|
+
require_relative "rus3/token"
|
54
|
+
require_relative "rus3/lexer"
|
52
55
|
require_relative "rus3/parser"
|
53
56
|
require_relative "rus3/evaluator"
|
54
57
|
require_relative "rus3/printer"
|
data/lib/rus3/ast.rb
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Rus3
|
4
|
+
|
5
|
+
module AST
|
6
|
+
|
7
|
+
require_relative "ast/error"
|
8
|
+
|
9
|
+
module Utils
|
10
|
+
class << self
|
11
|
+
def camel_case(snake_case)
|
12
|
+
snake_case.to_s.split("_").map(&:capitalize).join("")
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class Node
|
18
|
+
attr_reader :literal
|
19
|
+
|
20
|
+
def initialize(literal = nil)
|
21
|
+
@literal = literal
|
22
|
+
end
|
23
|
+
|
24
|
+
def leaf?; false; end
|
25
|
+
def branch?; false; end
|
26
|
+
def illegal?; false; end
|
27
|
+
|
28
|
+
def type; nil; end
|
29
|
+
|
30
|
+
def to_s
|
31
|
+
@literal
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
class IllegalNode < Node
|
36
|
+
def initialize(ast_type, literal)
|
37
|
+
super(literal)
|
38
|
+
@given_type = ast_type
|
39
|
+
end
|
40
|
+
|
41
|
+
def illegal?
|
42
|
+
true
|
43
|
+
end
|
44
|
+
|
45
|
+
def type
|
46
|
+
@given_type
|
47
|
+
end
|
48
|
+
|
49
|
+
def to_s
|
50
|
+
"type: #{@given_type}, literal: #{@literal}"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
require_relative "ast/leaf_node"
|
55
|
+
require_relative "ast/branch_node"
|
56
|
+
|
57
|
+
class << self
|
58
|
+
def instantiate(ast_type, literal = nil)
|
59
|
+
klass_name = Utils.camel_case(ast_type) + "Node"
|
60
|
+
klass = AST.const_get(klass_name)
|
61
|
+
if klass.nil? or klass == IllegalNode
|
62
|
+
IllegalNode.new(ast_type, literal)
|
63
|
+
else
|
64
|
+
klass.new(literal)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,412 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Rus3
|
4
|
+
module AST
|
5
|
+
|
6
|
+
class BranchNode < Node
|
7
|
+
include Enumerable
|
8
|
+
|
9
|
+
def initialize(size = nil)
|
10
|
+
super(nil)
|
11
|
+
@nodes = size.nil? ? [] : Array.new(size)
|
12
|
+
end
|
13
|
+
|
14
|
+
def branch?
|
15
|
+
true
|
16
|
+
end
|
17
|
+
|
18
|
+
def <<(node)
|
19
|
+
@nodes << node
|
20
|
+
end
|
21
|
+
|
22
|
+
def [](index)
|
23
|
+
raise OutOfRangeError, index if index >= @nodes.size
|
24
|
+
@nodes[index]
|
25
|
+
end
|
26
|
+
|
27
|
+
def each(&block)
|
28
|
+
if block.nil?
|
29
|
+
@nodes.each
|
30
|
+
else
|
31
|
+
@nodes.each(&block)
|
32
|
+
self
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def to_s
|
37
|
+
@nodes.map(&:to_s).join(" ")
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
class ProgramNode < BranchNode
|
43
|
+
def initialize(_ = nil)
|
44
|
+
super(nil)
|
45
|
+
end
|
46
|
+
|
47
|
+
def type
|
48
|
+
:program
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
class VectorNode < BranchNode
|
53
|
+
def initialize(_ = nil)
|
54
|
+
super(nil)
|
55
|
+
end
|
56
|
+
|
57
|
+
def type
|
58
|
+
:vector
|
59
|
+
end
|
60
|
+
|
61
|
+
def to_s
|
62
|
+
"#(" + super + ")"
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
class ListNode < BranchNode
|
67
|
+
def initialize(first_literal = nil, initial_size = nil)
|
68
|
+
super(initial_size)
|
69
|
+
@nodes[0] = IdentifierNode.new(first_literal) if first_literal
|
70
|
+
end
|
71
|
+
|
72
|
+
def type
|
73
|
+
:list
|
74
|
+
end
|
75
|
+
|
76
|
+
def car
|
77
|
+
@nodes[0]
|
78
|
+
end
|
79
|
+
|
80
|
+
def cdr
|
81
|
+
@nodes[1..-1]
|
82
|
+
end
|
83
|
+
|
84
|
+
def to_s
|
85
|
+
"(" + super + ")"
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
class QuotationNode < ListNode
|
90
|
+
def initialize(_ = nil)
|
91
|
+
super("quote")
|
92
|
+
end
|
93
|
+
|
94
|
+
def type
|
95
|
+
:quotation
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
class ProcedureCallNode < ListNode
|
100
|
+
def initialize(_ = nil)
|
101
|
+
# @nodes = [<operator>, <operand>*]
|
102
|
+
super(nil, 1)
|
103
|
+
end
|
104
|
+
|
105
|
+
def type
|
106
|
+
:procedure_call
|
107
|
+
end
|
108
|
+
|
109
|
+
def operator
|
110
|
+
@nodes[0]
|
111
|
+
end
|
112
|
+
|
113
|
+
def operator=(node)
|
114
|
+
@nodes[0] = node
|
115
|
+
end
|
116
|
+
|
117
|
+
def operands
|
118
|
+
@nodes[1..-1]
|
119
|
+
end
|
120
|
+
|
121
|
+
def add_operand(node)
|
122
|
+
@nodes << node
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
class LambdaExpressionNode < ListNode
|
127
|
+
def initialize(_ = nil)
|
128
|
+
# @nodes = [<lambda>, <formals>, <body> ...]
|
129
|
+
super("lambda", 2)
|
130
|
+
end
|
131
|
+
|
132
|
+
def type
|
133
|
+
:lambda_expression
|
134
|
+
end
|
135
|
+
|
136
|
+
def formals
|
137
|
+
@nodes[1]
|
138
|
+
end
|
139
|
+
|
140
|
+
def formals=(list_node)
|
141
|
+
@nodes[1] = list_node
|
142
|
+
end
|
143
|
+
|
144
|
+
def body
|
145
|
+
@nodes[2..-1]
|
146
|
+
end
|
147
|
+
|
148
|
+
def body=(nodes)
|
149
|
+
nodes.each_with_index { |node, i|
|
150
|
+
@nodes[i + 2] = node
|
151
|
+
}
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
class ConditionalNode < ListNode
|
156
|
+
def initialize(_ = nil)
|
157
|
+
# @nodes = [<if>, <test>, <consequent>] or
|
158
|
+
# [<if>, <test>, <consequent>, <alternate>]
|
159
|
+
super("if", 3)
|
160
|
+
end
|
161
|
+
|
162
|
+
def type
|
163
|
+
:conditional
|
164
|
+
end
|
165
|
+
|
166
|
+
def test
|
167
|
+
@nodes[1]
|
168
|
+
end
|
169
|
+
|
170
|
+
def consequent
|
171
|
+
@nodes[2]
|
172
|
+
end
|
173
|
+
|
174
|
+
def alternate
|
175
|
+
if @nodes.size > 3
|
176
|
+
@nodes[3]
|
177
|
+
else
|
178
|
+
nil
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
def test=(node)
|
183
|
+
@nodes[1] = node
|
184
|
+
end
|
185
|
+
|
186
|
+
def consequent=(node)
|
187
|
+
@nodes[2] = node
|
188
|
+
end
|
189
|
+
|
190
|
+
def alternate=(node)
|
191
|
+
@nodes[3] = node
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
class AssignmentNode < ListNode
|
196
|
+
def initialize(_ = nil)
|
197
|
+
super("set!", 3)
|
198
|
+
end
|
199
|
+
|
200
|
+
def type
|
201
|
+
:assignment
|
202
|
+
end
|
203
|
+
|
204
|
+
def identifier
|
205
|
+
@nodes[1]
|
206
|
+
end
|
207
|
+
|
208
|
+
def identifier=(node)
|
209
|
+
@nodes[1] = node
|
210
|
+
end
|
211
|
+
|
212
|
+
def expression
|
213
|
+
@nodes[2]
|
214
|
+
end
|
215
|
+
|
216
|
+
def expression=(node)
|
217
|
+
@nodes[2] = node
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
class IdentifierDefinitionNode < ListNode
|
222
|
+
def initialize(_ = nil)
|
223
|
+
super("define", 3)
|
224
|
+
end
|
225
|
+
|
226
|
+
def type
|
227
|
+
:identifier_definition
|
228
|
+
end
|
229
|
+
|
230
|
+
def identifier
|
231
|
+
@nodes[1]
|
232
|
+
end
|
233
|
+
|
234
|
+
def identifier=(node)
|
235
|
+
@nodes[1] = node
|
236
|
+
end
|
237
|
+
|
238
|
+
def expression
|
239
|
+
@nodes[2]
|
240
|
+
end
|
241
|
+
|
242
|
+
def expression=(node)
|
243
|
+
@nodes[2] = node
|
244
|
+
end
|
245
|
+
|
246
|
+
def def_formals
|
247
|
+
if lambda?
|
248
|
+
expression.formals
|
249
|
+
else
|
250
|
+
nil
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
def body
|
255
|
+
if lambda?
|
256
|
+
expression.body
|
257
|
+
else
|
258
|
+
nil
|
259
|
+
end
|
260
|
+
end
|
261
|
+
|
262
|
+
private
|
263
|
+
|
264
|
+
def lambda?
|
265
|
+
expression.type == :lambda_expression
|
266
|
+
end
|
267
|
+
|
268
|
+
end
|
269
|
+
|
270
|
+
class SyntaxDefinitionNode < ListNode
|
271
|
+
def type
|
272
|
+
:syntax_definition
|
273
|
+
end
|
274
|
+
|
275
|
+
end
|
276
|
+
|
277
|
+
class ValuesDefinitionNode < ListNode
|
278
|
+
def type
|
279
|
+
:values_definition
|
280
|
+
end
|
281
|
+
|
282
|
+
end
|
283
|
+
|
284
|
+
class RecordTypeDefinitionNode < ListNode
|
285
|
+
def type
|
286
|
+
:record_type_definition
|
287
|
+
end
|
288
|
+
|
289
|
+
end
|
290
|
+
|
291
|
+
class MacroBlockNode < ListNode
|
292
|
+
def initialize(literal)
|
293
|
+
super(literal)
|
294
|
+
end
|
295
|
+
|
296
|
+
def type
|
297
|
+
:macro_block
|
298
|
+
end
|
299
|
+
|
300
|
+
end
|
301
|
+
|
302
|
+
class CondNode < ListNode
|
303
|
+
def initialize(_ = nil)
|
304
|
+
super("cond")
|
305
|
+
end
|
306
|
+
|
307
|
+
def type
|
308
|
+
:cond
|
309
|
+
end
|
310
|
+
|
311
|
+
def cond_clauses
|
312
|
+
@nodes[1..-1]
|
313
|
+
end
|
314
|
+
|
315
|
+
def add_clause(node)
|
316
|
+
@nodes << node
|
317
|
+
end
|
318
|
+
end
|
319
|
+
|
320
|
+
class CondClauseNode < ListNode
|
321
|
+
def initialize(_ = nil)
|
322
|
+
super(nil, 1)
|
323
|
+
end
|
324
|
+
|
325
|
+
def type
|
326
|
+
:cond_clause
|
327
|
+
end
|
328
|
+
|
329
|
+
def test
|
330
|
+
@nodes[0]
|
331
|
+
end
|
332
|
+
|
333
|
+
def test=(node)
|
334
|
+
@nodes[0] = node
|
335
|
+
end
|
336
|
+
|
337
|
+
def sequence
|
338
|
+
@nodes[1..-1]
|
339
|
+
end
|
340
|
+
|
341
|
+
def add_expression(node)
|
342
|
+
@nodes << node
|
343
|
+
end
|
344
|
+
end
|
345
|
+
|
346
|
+
class LetNode < ListNode
|
347
|
+
def initialize(_ = nil)
|
348
|
+
super("let", 2)
|
349
|
+
end
|
350
|
+
|
351
|
+
def type
|
352
|
+
:let
|
353
|
+
end
|
354
|
+
|
355
|
+
def bind_specs
|
356
|
+
@nodes[1]
|
357
|
+
end
|
358
|
+
|
359
|
+
def bind_specs=(node)
|
360
|
+
@nodes[1] = node
|
361
|
+
end
|
362
|
+
|
363
|
+
def body
|
364
|
+
@nodes[2..-1]
|
365
|
+
end
|
366
|
+
|
367
|
+
def body=(nodes)
|
368
|
+
nodes.each_with_index { |node, i|
|
369
|
+
@nodes[i + 2] = node
|
370
|
+
}
|
371
|
+
end
|
372
|
+
end
|
373
|
+
|
374
|
+
class BindSpecNode < ListNode
|
375
|
+
def initialize(_ = nil)
|
376
|
+
super(nil, 2)
|
377
|
+
end
|
378
|
+
|
379
|
+
def type
|
380
|
+
:bind_spec
|
381
|
+
end
|
382
|
+
|
383
|
+
def identifier
|
384
|
+
@nodes[1]
|
385
|
+
end
|
386
|
+
|
387
|
+
def identifier=(node)
|
388
|
+
@nodes[1] = node
|
389
|
+
end
|
390
|
+
|
391
|
+
def expression
|
392
|
+
@nodes[2]
|
393
|
+
end
|
394
|
+
|
395
|
+
def expression=(node)
|
396
|
+
@nodes[2] = node
|
397
|
+
end
|
398
|
+
end
|
399
|
+
|
400
|
+
class AndNode < ListNode
|
401
|
+
def initialize(_ = nil)
|
402
|
+
super("and")
|
403
|
+
end
|
404
|
+
|
405
|
+
def type
|
406
|
+
:and
|
407
|
+
end
|
408
|
+
|
409
|
+
end
|
410
|
+
|
411
|
+
end
|
412
|
+
end
|