rus3 0.2.0 → 0.2.1
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 +8 -0
- data/Gemfile.lock +6 -1
- data/lib/rus3.rb +5 -4
- data/lib/rus3/evaluator/environment.rb +2 -0
- data/lib/rus3/evaluator/scheme_evaluator.rb +7 -12
- data/lib/rus3/evaluator/translator.rb +89 -46
- data/lib/rus3/printer.rb +41 -5
- data/lib/rus3/procedure/arithmetic.rb +45 -0
- data/lib/rus3/procedure/comparison.rb +45 -0
- data/lib/rus3/repl.rb +26 -31
- data/lib/rus3/version.rb +2 -2
- data/rus3.gemspec +4 -7
- metadata +35 -13
- data/lib/rus3/ast.rb +0 -70
- data/lib/rus3/ast/branch_node.rb +0 -412
- data/lib/rus3/ast/error.rb +0 -8
- data/lib/rus3/ast/leaf_node.rb +0 -55
- data/lib/rus3/lexer.rb +0 -104
- data/lib/rus3/parser.rb +0 -87
- data/lib/rus3/parser/scheme_parser.rb +0 -657
- data/lib/rus3/token.rb +0 -35
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5309fbc8e935c7fea460f7084c02e36d082c17ec4f61f6343e5c340aacfa8eec
|
4
|
+
data.tar.gz: 30ad12bdae593004cf1d23e7f82676ae5b5b4f7e7c92d51857de1bc916d61452
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fe695566d2706dc9121278a76589085b46de790c0b8b6bfae7f9befaabb53239ffe52f4aa77e8311eb5648388d35f51130c4056020b80cb1cc8a2318908192c2
|
7
|
+
data.tar.gz: e70a4aef0e3d336f9fde29aa4a6030c75d4c53bd04f2c0b901f2506aa629d3ea10eff29f6674574ad4bb7b587a9ce723965aab51a18b206b402dd2b36056e1ff
|
data/CHANGELOG.md
CHANGED
@@ -7,6 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/).
|
|
7
7
|
## [Unreleased]
|
8
8
|
- (nothing to record here)
|
9
9
|
|
10
|
+
## [0.2.1] - 20201-05-20
|
11
|
+
### Changed
|
12
|
+
- Use Rbscmlex instead of built-in lexer. (#6)
|
13
|
+
- Use Rubasteme instead of built-in AST and parser. (#6)
|
14
|
+
|
15
|
+
### Fixed
|
16
|
+
- Fix #5: too old `required_ruby_version`.
|
17
|
+
|
10
18
|
## [0.2.0] - 2021-05-03
|
11
19
|
### Added
|
12
20
|
- Re-write the parser and evaluator mechanism.
|
data/Gemfile.lock
CHANGED
@@ -1,13 +1,18 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
rus3 (0.2.
|
4
|
+
rus3 (0.2.1)
|
5
|
+
rbscmlex (>= 0.1.3)
|
6
|
+
rubasteme (>= 0.1.3)
|
5
7
|
|
6
8
|
GEM
|
7
9
|
remote: https://rubygems.org/
|
8
10
|
specs:
|
9
11
|
minitest (5.14.4)
|
10
12
|
rake (13.0.3)
|
13
|
+
rbscmlex (0.1.3)
|
14
|
+
rubasteme (0.1.3)
|
15
|
+
rbscmlex (>= 0.1.3)
|
11
16
|
|
12
17
|
PLATFORMS
|
13
18
|
x86_64-darwin-20
|
data/lib/rus3.rb
CHANGED
@@ -1,5 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "rbscmlex"
|
4
|
+
require "rubasteme"
|
5
|
+
|
3
6
|
module Rus3
|
4
7
|
|
5
8
|
# An empty list is a special object in Scheme language. The role
|
@@ -43,16 +46,14 @@ module Rus3
|
|
43
46
|
|
44
47
|
require_relative "rus3/procedure/utils"
|
45
48
|
require_relative "rus3/procedure/predicate"
|
49
|
+
require_relative "rus3/procedure/arithmetic"
|
50
|
+
require_relative "rus3/procedure/comparison"
|
46
51
|
require_relative "rus3/procedure/char"
|
47
52
|
require_relative "rus3/procedure/list"
|
48
53
|
require_relative "rus3/procedure/vector"
|
49
54
|
require_relative "rus3/procedure/control"
|
50
55
|
require_relative "rus3/procedure/write"
|
51
56
|
|
52
|
-
require_relative "rus3/ast"
|
53
|
-
require_relative "rus3/token"
|
54
|
-
require_relative "rus3/lexer"
|
55
|
-
require_relative "rus3/parser"
|
56
57
|
require_relative "rus3/evaluator"
|
57
58
|
require_relative "rus3/printer"
|
58
59
|
require_relative "rus3/repl"
|
@@ -19,10 +19,9 @@ module Rus3
|
|
19
19
|
super
|
20
20
|
|
21
21
|
@env = Environment.new
|
22
|
-
define_procs_for_infix_ops
|
23
|
-
|
24
22
|
@translator = Translator.new
|
25
|
-
@translator.add_procedure_map(
|
23
|
+
@translator.add_procedure_map(ARITHMETIC_OPS_MAP)
|
24
|
+
@translator.add_procedure_map(COMPARISON_OPS_MAP)
|
26
25
|
end
|
27
26
|
|
28
27
|
def verbose=(verbose)
|
@@ -48,17 +47,20 @@ module Rus3
|
|
48
47
|
@env.binding
|
49
48
|
end
|
50
49
|
|
51
|
-
|
50
|
+
ARITHMETIC_OPS_MAP = {
|
52
51
|
"+" => "add",
|
53
52
|
"-" => "subtract",
|
54
53
|
"*" => "mul",
|
55
54
|
"/" => "div",
|
56
55
|
"%" => "mod",
|
56
|
+
}
|
57
|
+
|
58
|
+
COMPARISON_OPS_MAP = {
|
57
59
|
"<" => "lt?",
|
58
60
|
"<=" => "le?",
|
59
61
|
">" => "gt?",
|
60
62
|
">=" => "ge?",
|
61
|
-
"
|
63
|
+
"=" => "same_value?",
|
62
64
|
}
|
63
65
|
|
64
66
|
private
|
@@ -67,13 +69,6 @@ module Rus3
|
|
67
69
|
ast.map{|node| @translator.translate(node)}.join("\n")
|
68
70
|
end
|
69
71
|
|
70
|
-
def define_procs_for_infix_ops
|
71
|
-
r = @env.binding.receiver
|
72
|
-
INFIX_OPS_MAP.each { |op, proc_name|
|
73
|
-
r.instance_eval("def #{proc_name}(op1, op2); op1 #{op} op2; end")
|
74
|
-
}
|
75
|
-
end
|
76
|
-
|
77
72
|
end
|
78
73
|
end
|
79
74
|
end
|
@@ -36,7 +36,8 @@ module Rus3
|
|
36
36
|
pp ast_node
|
37
37
|
end
|
38
38
|
|
39
|
-
|
39
|
+
type = ast_node.type.to_s.delete_prefix("ast_")
|
40
|
+
method_name = "translate_#{type}".intern
|
40
41
|
begin
|
41
42
|
m = method(method_name)
|
42
43
|
rescue
|
@@ -49,6 +50,10 @@ module Rus3
|
|
49
50
|
|
50
51
|
private
|
51
52
|
|
53
|
+
def translate_empty_list(_)
|
54
|
+
EmptyList::EMPTY_LIST.to_s
|
55
|
+
end
|
56
|
+
|
52
57
|
def translate_boolean(ast_node)
|
53
58
|
case ast_node.literal[0..1]
|
54
59
|
when "#f"
|
@@ -56,7 +61,7 @@ module Rus3
|
|
56
61
|
when "#t"
|
57
62
|
"true"
|
58
63
|
else
|
59
|
-
raise SchemeSyntaxError.new([:
|
64
|
+
raise SchemeSyntaxError.new([:ast_boolean, ast_node.to_s])
|
60
65
|
end
|
61
66
|
end
|
62
67
|
|
@@ -96,13 +101,6 @@ module Rus3
|
|
96
101
|
"#{converter}(\"#{ast_node.literal}\")"
|
97
102
|
end
|
98
103
|
|
99
|
-
def translate_peculiar_identifier(ast_node)
|
100
|
-
op_literal = ast_node.literal == "=" ? "==" : ast_node.literal
|
101
|
-
sym = @procedure_map[op_literal]
|
102
|
-
raise Rus3::UnknownOperatorError, op_literal if sym.nil?
|
103
|
-
sym.to_s
|
104
|
-
end
|
105
|
-
|
106
104
|
def translate_list(ast_node)
|
107
105
|
elements = ast_node.map{|e| translate(e)}.join(", ")
|
108
106
|
"[#{elements}]"
|
@@ -113,10 +111,33 @@ module Rus3
|
|
113
111
|
"vector(#{obj_src})"
|
114
112
|
end
|
115
113
|
|
114
|
+
def translate_quotation(ast_node)
|
115
|
+
propagate_quotation(ast_node[0])
|
116
|
+
end
|
117
|
+
|
118
|
+
def propagate_quotation(ast_node)
|
119
|
+
case ast_node.type
|
120
|
+
when :ast_list, :ast_procedure_call, :ast_lambda_expression, :ast_conditional, :ast_assignment
|
121
|
+
elements = ast_node.map{|child| propagate_quotation(child)}
|
122
|
+
"[" + elements.join(", ") + "]"
|
123
|
+
when :ast_vector
|
124
|
+
elements = ast_node.map{|child| propagate_quotation(child)}
|
125
|
+
"vector(" + elements.join(", ") + ")"
|
126
|
+
when :ast_boolean, :ast_character, :ast_string
|
127
|
+
translate(ast_node)
|
128
|
+
when :ast_number
|
129
|
+
translate_number(ast_node)
|
130
|
+
when :ast_identifier
|
131
|
+
":#{ast_node.to_s}"
|
132
|
+
else
|
133
|
+
raise SchemeSyntaxError.new([ast_node.type, ast_node.to_s])
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
116
137
|
def translate_procedure_call(ast_node)
|
117
138
|
operands = ast_node.operands.map{|e| translate(e)}.join(", ")
|
118
139
|
operator = translate(ast_node.operator)
|
119
|
-
if ast_node.operator.type == :
|
140
|
+
if ast_node.operator.type == :ast_lambda_expression
|
120
141
|
"#{operator}.call(#{operands})"
|
121
142
|
else
|
122
143
|
"#{operator}(#{operands})"
|
@@ -155,32 +176,9 @@ module Rus3
|
|
155
176
|
"#{identifier} = #{expression}"
|
156
177
|
end
|
157
178
|
|
158
|
-
def translate_quotation(ast_node)
|
159
|
-
propagate_quotation(ast_node[1])
|
160
|
-
end
|
161
|
-
|
162
|
-
def propagate_quotation(ast_node)
|
163
|
-
case ast_node.type
|
164
|
-
when :list, :procedure_call, :lambda_expression, :conditional, :assignment
|
165
|
-
elements = ast_node.map{|child| propagate_quotation(child)}
|
166
|
-
"[" + elements.join(", ") + "]"
|
167
|
-
when :vector
|
168
|
-
elements = ast_node.map{|child| propagate_quotation(child)}
|
169
|
-
"vector(" + elements.join(", ") + ")"
|
170
|
-
when :boolean, :character, :string
|
171
|
-
translate(ast_node)
|
172
|
-
when :number
|
173
|
-
ast_node.to_s
|
174
|
-
when :identifier, :peculiar_identifier
|
175
|
-
":#{ast_node.to_s}"
|
176
|
-
else
|
177
|
-
raise SchemeSyntaxError.new([ast_node.type, ast_node.to_s])
|
178
|
-
end
|
179
|
-
end
|
180
|
-
|
181
179
|
def translate_identifier_definition(ast_node)
|
182
180
|
name = translate_identifier(ast_node.identifier)
|
183
|
-
if ast_node.expression.type == :
|
181
|
+
if ast_node.expression.type == :ast_lambda_expression
|
184
182
|
def_formals = translate_formals(ast_node.expression)
|
185
183
|
body = translate_body(ast_node.expression)
|
186
184
|
"def #{name}(#{def_formals}); #{body}; end"
|
@@ -229,11 +227,31 @@ module Rus3
|
|
229
227
|
"#{test_src}; #{exps_src}"
|
230
228
|
end
|
231
229
|
|
230
|
+
def translate_case(ast_node)
|
231
|
+
"not implemented yet"
|
232
|
+
end
|
233
|
+
|
234
|
+
def translate_and(ast_node)
|
235
|
+
"not implemented yet"
|
236
|
+
end
|
237
|
+
|
238
|
+
def translate_or(ast_node)
|
239
|
+
"not implemented yet"
|
240
|
+
end
|
241
|
+
|
242
|
+
def translate_when(ast_node)
|
243
|
+
"not implemented yet"
|
244
|
+
end
|
245
|
+
|
246
|
+
def translate_unless(ast_node)
|
247
|
+
"not implemented yet"
|
248
|
+
end
|
249
|
+
|
232
250
|
def translate_let(ast_node)
|
233
251
|
formals = []
|
234
252
|
args = []
|
235
253
|
|
236
|
-
ast_node.
|
254
|
+
ast_node.bindings.each { |spec|
|
237
255
|
formals << translate_identifier(spec.identifier)
|
238
256
|
args << translate(spec.expression)
|
239
257
|
}
|
@@ -243,6 +261,26 @@ module Rus3
|
|
243
261
|
"lambda{|#{formals.join(', ')}| #{body}}.call(#{args.join(', ')})"
|
244
262
|
end
|
245
263
|
|
264
|
+
def translate_let_star(ast_node)
|
265
|
+
"not implemented yet"
|
266
|
+
end
|
267
|
+
|
268
|
+
def translate_letrec(ast_node)
|
269
|
+
"not implemented yet"
|
270
|
+
end
|
271
|
+
|
272
|
+
def translate_letrec_star(ast_node)
|
273
|
+
"not implemented yet"
|
274
|
+
end
|
275
|
+
|
276
|
+
def translate_begin(ast_node)
|
277
|
+
"not implemented yet"
|
278
|
+
end
|
279
|
+
|
280
|
+
def translate_do(ast_node)
|
281
|
+
"not implemented yet"
|
282
|
+
end
|
283
|
+
|
246
284
|
RB_KEYWORDS_MAP = {
|
247
285
|
"BEGIN" => nil,
|
248
286
|
"END" => nil,
|
@@ -295,7 +333,7 @@ module Rus3
|
|
295
333
|
">=" => "ge",
|
296
334
|
}
|
297
335
|
|
298
|
-
EXTENDED_REGEXP = Regexp.new("[
|
336
|
+
EXTENDED_REGEXP = Regexp.new("[!\\$%&\\*\\+\\-\\./:<=>\\?@\\^_~]")
|
299
337
|
|
300
338
|
EXTENDED_CHARS_MAP = {
|
301
339
|
"!" => "!", # no conversion
|
@@ -319,16 +357,21 @@ module Rus3
|
|
319
357
|
}
|
320
358
|
|
321
359
|
def replace_extended_char(literal)
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
360
|
+
case literal
|
361
|
+
when /\A[+\-*\/%=]\Z/, /\A[<>]=?\Z/
|
362
|
+
md = Regexp.last_match
|
363
|
+
@procedure_map[md.to_s]
|
364
|
+
else
|
365
|
+
result = literal
|
366
|
+
COMPARISON_OPS_MAP.each { |op, word|
|
367
|
+
comparison_regexp = Regexp.new("#{op}\\?\\Z")
|
368
|
+
if comparison_regexp === literal
|
369
|
+
result = literal.sub(comparison_regexp, "_#{word}?")
|
370
|
+
end
|
371
|
+
}
|
372
|
+
|
373
|
+
result.gsub(EXTENDED_REGEXP, EXTENDED_CHARS_MAP)
|
374
|
+
end
|
332
375
|
end
|
333
376
|
|
334
377
|
# :startdoc:
|
data/lib/rus3/printer.rb
CHANGED
@@ -4,23 +4,59 @@ module Rus3
|
|
4
4
|
module Printer
|
5
5
|
|
6
6
|
# Indicates the version of the printer module.
|
7
|
-
VERSION = "0.1
|
7
|
+
VERSION = "0.2.1"
|
8
8
|
|
9
9
|
class Printer
|
10
|
-
include Rus3::Procedure::Write
|
11
|
-
|
12
10
|
attr_accessor :verbose
|
13
11
|
|
14
12
|
def initialize
|
15
13
|
@verbose = false
|
16
14
|
end
|
17
15
|
|
16
|
+
def self.version
|
17
|
+
""
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
class RubyPrinter < Printer
|
22
|
+
def print(obj)
|
23
|
+
prefix = "==> "
|
24
|
+
prefix += "[#{obj.class}]: " if @verbose
|
25
|
+
Kernel.print prefix
|
26
|
+
pp obj
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.version
|
30
|
+
"ruby-object-printer :version #{VERSION}"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
class SchemePrinter < Printer
|
35
|
+
include Rus3::Procedure::Write
|
36
|
+
|
18
37
|
def print(obj)
|
19
38
|
display(obj)
|
20
39
|
end
|
21
40
|
|
22
|
-
def version
|
23
|
-
"
|
41
|
+
def self.version
|
42
|
+
"scheme-printer :version #{VERSION}"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
class ChainPrinter < Printer
|
47
|
+
CHAIN = [RubyPrinter.new, SchemePrinter.new]
|
48
|
+
|
49
|
+
def self.version
|
50
|
+
chain_printers = CHAIN.map{|e| e.class}
|
51
|
+
"chain-printer :version #{VERSION} :chain (#{chain_printers})"
|
52
|
+
end
|
53
|
+
|
54
|
+
def verbose=(flag)
|
55
|
+
CHAIN.each{|printer| printer.verbose = flag}
|
56
|
+
end
|
57
|
+
|
58
|
+
def print(obj)
|
59
|
+
CHAIN.each{|printer| printer.print(obj)}
|
24
60
|
end
|
25
61
|
end
|
26
62
|
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Rus3
|
4
|
+
module Procedure
|
5
|
+
|
6
|
+
# This module holds arithmetic operation procedures of Scheme.
|
7
|
+
|
8
|
+
module Arithmetic
|
9
|
+
|
10
|
+
def add(*args)
|
11
|
+
a_calc(:+, *args)
|
12
|
+
end
|
13
|
+
|
14
|
+
def subtract(*args)
|
15
|
+
a_calc(:-, *args)
|
16
|
+
end
|
17
|
+
|
18
|
+
def mul(*args)
|
19
|
+
a_calc(:*, *args)
|
20
|
+
end
|
21
|
+
|
22
|
+
def div(*args)
|
23
|
+
a_calc(:/, *args)
|
24
|
+
end
|
25
|
+
|
26
|
+
def mod(*args)
|
27
|
+
a_calc(:%, *args)
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def a_calc(op, *args)
|
33
|
+
case args.size
|
34
|
+
when 0
|
35
|
+
0
|
36
|
+
when 1
|
37
|
+
args[0]
|
38
|
+
else
|
39
|
+
a_calc(op, args[0].send(op, args[1]), *args[2..-1])
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|