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
data/lib/rus3/repl.rb
CHANGED
@@ -21,13 +21,13 @@ module Rus3
|
|
21
21
|
class Repl
|
22
22
|
|
23
23
|
# Indicates the version of the Repl class.
|
24
|
-
|
24
|
+
REPL_VERSION = "0.2.0"
|
25
25
|
|
26
26
|
class << self
|
27
27
|
|
28
28
|
# Starts REPL.
|
29
|
-
def start(verbose: false)
|
30
|
-
repl = Repl.new(verbose: verbose)
|
29
|
+
def start(parser: nil, evaluator: nil, verbose: false)
|
30
|
+
repl = Repl.new(parser: parser, evaluator: evaluator, verbose: verbose)
|
31
31
|
repl.loop
|
32
32
|
end
|
33
33
|
|
@@ -35,9 +35,9 @@ module Rus3
|
|
35
35
|
|
36
36
|
# Hods major component names of the REPL.
|
37
37
|
COMPONENTS = {
|
38
|
-
:parser
|
39
|
-
:evaluator => Evaluator,
|
40
|
-
:printer
|
38
|
+
:parser => Parser::DEFAULT_PARSER,
|
39
|
+
:evaluator => Evaluator::DEFAULT_EVALUATOR,
|
40
|
+
:printer => nil,
|
41
41
|
}
|
42
42
|
|
43
43
|
# Prompt for input.
|
@@ -49,14 +49,20 @@ module Rus3
|
|
49
49
|
@@value_history = [] # :nodoc:
|
50
50
|
|
51
51
|
attr_accessor :verbose # :nodoc:
|
52
|
+
attr_accessor :prompt # :nodoc:
|
52
53
|
|
53
|
-
def initialize(verbose: false)
|
54
|
-
COMPONENTS.
|
54
|
+
def initialize(parser: nil, evaluator: nil, verbose: false)
|
55
|
+
comps = COMPONENTS.dup
|
56
|
+
|
57
|
+
comps[:parser] = Parser.const_get("#{parser.capitalize}Parser") if parser
|
58
|
+
comps[:evaluator] = Evaluator.const_get("#{evaluator.capitalize}Evaluator") if evaluator
|
59
|
+
|
60
|
+
comps.each { |name, klass|
|
55
61
|
instance_variable_set("@#{name}", klass.nil? ? self : klass.new)
|
56
62
|
}
|
57
63
|
|
58
64
|
@prompt = PROMPT
|
59
|
-
@parser.prompt = PROMPT
|
65
|
+
@parser.prompt = PROMPT
|
60
66
|
|
61
67
|
@verbose = verbose
|
62
68
|
@evaluator.verbose = verbose
|
@@ -73,15 +79,15 @@ module Rus3
|
|
73
79
|
def loop
|
74
80
|
msg = Kernel.loop { # LOOP
|
75
81
|
begin
|
76
|
-
|
82
|
+
ast = @parser.read(STDIN) # READ
|
77
83
|
rescue SchemeSyntaxError => e
|
78
84
|
puts "ERROR" + (@verbose ? "(READ)" : "") + ": %s" % e
|
79
85
|
next
|
80
86
|
end
|
81
|
-
break FAREWELL_MESSAGE if
|
87
|
+
break FAREWELL_MESSAGE if ast.nil?
|
82
88
|
|
83
89
|
begin
|
84
|
-
value = @evaluator.eval(
|
90
|
+
value = @evaluator.eval(ast) # EVAL
|
85
91
|
rescue SyntaxError, StandardError => e
|
86
92
|
puts "ERROR" + (@verbose ? "(EVAL)" : "") + ": %s" % e
|
87
93
|
next
|
@@ -96,15 +102,20 @@ module Rus3
|
|
96
102
|
|
97
103
|
# Shows the greeting message.
|
98
104
|
def greeting
|
99
|
-
puts "A simple REPL
|
100
|
-
puts "- Rus3 version: #{Rus3::VERSION} (#{Rus3::RELEASE})"
|
105
|
+
puts "A simple REPL to run Rus3:"
|
101
106
|
return unless @verbose
|
102
107
|
|
103
|
-
|
108
|
+
vmsg = "(rus3 :version #{Rus3::VERSION} :release #{Rus3::RELEASE}\n"
|
109
|
+
vmsg += " (repl :version #{REPL_VERSION}\n"
|
110
|
+
|
111
|
+
comp_vmsgs = []
|
104
112
|
COMPONENTS.keys.each { |comp_name|
|
105
|
-
|
106
|
-
print_version(comp_name)
|
113
|
+
comp_vmsgs << " (#{version_message(comp_name)})"
|
107
114
|
}
|
115
|
+
vmsg += comp_vmsgs.join("\n")
|
116
|
+
vmsg += "))"
|
117
|
+
|
118
|
+
puts vmsg
|
108
119
|
end
|
109
120
|
|
110
121
|
# :stopdoc:
|
@@ -117,8 +128,8 @@ module Rus3
|
|
117
128
|
Readline::readline(@prompt, true)
|
118
129
|
end
|
119
130
|
|
120
|
-
def eval(
|
121
|
-
|
131
|
+
def eval(ast)
|
132
|
+
ast
|
122
133
|
end
|
123
134
|
|
124
135
|
def print(obj)
|
@@ -130,12 +141,21 @@ module Rus3
|
|
130
141
|
|
131
142
|
private
|
132
143
|
|
144
|
+
def version_message(comp_name)
|
145
|
+
vmsg = nil
|
146
|
+
component = instance_variable_get("@#{comp_name}")
|
147
|
+
if component.nil? or component == self
|
148
|
+
vmsg = ":using :built-in :#{comp_name}"
|
149
|
+
else
|
150
|
+
vmsg = "#{component.version}"
|
151
|
+
end
|
152
|
+
vmsg
|
153
|
+
end
|
154
|
+
|
133
155
|
def define_constants # :nodoc:
|
134
156
|
return if @evaluator.nil?
|
135
157
|
|
136
|
-
|
137
|
-
|
138
|
-
r.instance_eval {
|
158
|
+
@evaluator.instance_eval {
|
139
159
|
self.class.const_set(:RUS3_VERSION, "#{VERSION}")
|
140
160
|
}
|
141
161
|
end
|
@@ -143,9 +163,7 @@ module Rus3
|
|
143
163
|
def define_help_feature # :nodoc:
|
144
164
|
return if @evaluator.nil?
|
145
165
|
|
146
|
-
|
147
|
-
|
148
|
-
r.instance_eval {
|
166
|
+
@evaluator.instance_eval {
|
149
167
|
def _help
|
150
168
|
puts <<HELP
|
151
169
|
A simple REPL for Rus3.
|
@@ -167,10 +185,8 @@ HELP
|
|
167
185
|
def define_history_feature # :nodoc:
|
168
186
|
return if @evaluator.nil?
|
169
187
|
|
170
|
-
|
171
|
-
|
172
|
-
r.instance_variable_set(:@value_history, @@value_history)
|
173
|
-
r.instance_eval {
|
188
|
+
@evaluator.instance_variable_set(:@value_history, @@value_history)
|
189
|
+
@evaluator.instance_eval {
|
174
190
|
|
175
191
|
def _last_value
|
176
192
|
@value_history[-1]
|
@@ -201,30 +217,24 @@ HELP
|
|
201
217
|
def define_load_feature
|
202
218
|
return if @evaluator.nil?
|
203
219
|
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
r.instance_eval {
|
220
|
+
@evaluator.instance_variable_set(:@scm_parser, @parser)
|
221
|
+
@evaluator.instance_variable_set(:@scm_evaluator, @evaluator)
|
222
|
+
@evaluator.instance_eval {
|
208
223
|
def load_scm(path)
|
209
224
|
raise Rus3::CannotFindFileError, path unless FileTest.exist?(path)
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
225
|
+
scheme_source = File.readlines(path, chomp: true).join(" ")
|
226
|
+
result = ast = nil
|
227
|
+
if @scm_parser.respond_to?(:parse)
|
228
|
+
ast = @scm_parser.parse(scheme_source)
|
229
|
+
end
|
230
|
+
if @scm_evaluator.respond_to?(:eval)
|
231
|
+
result = @scm_evaluator.eval(ast)
|
232
|
+
end
|
233
|
+
pp result
|
215
234
|
end
|
216
235
|
}
|
217
236
|
end
|
218
237
|
|
219
|
-
def print_version(comp_name)
|
220
|
-
component = instance_variable_get("@#{comp_name}")
|
221
|
-
if component.nil? or component == self
|
222
|
-
puts "using built-in #{comp_name.upcase}"
|
223
|
-
else
|
224
|
-
puts "#{component.version}"
|
225
|
-
end
|
226
|
-
end
|
227
|
-
|
228
238
|
def history_push(value)
|
229
239
|
prev_value = @@value_history[-1]
|
230
240
|
if prev_value != value and UNDEF != value
|
data/lib/rus3/token.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Rus3
|
4
|
+
|
5
|
+
TOKEN_TYPES = [ # :nodoc:
|
6
|
+
# delimiters
|
7
|
+
:lparen, # `(`
|
8
|
+
:rparen, # `)`
|
9
|
+
:vec_lparen, # `#(`
|
10
|
+
:bytevec_lparen, # `#u8(`
|
11
|
+
:quotation, # `'`
|
12
|
+
:backquote, # "`" (aka quasiquote)
|
13
|
+
:comma, # `,`
|
14
|
+
:comma_at, # `,@`
|
15
|
+
:dot, # `.`
|
16
|
+
:semicolon, # `;`
|
17
|
+
:comment_lparen, # `#|`
|
18
|
+
:comment_rparen, # `|#`
|
19
|
+
# value types
|
20
|
+
:identifier, # `foo`
|
21
|
+
:boolean, # `#f` or `#t` (`#false` or `#true`)
|
22
|
+
:number, # `123`, `456.789`, `1/2`, `3+4i`
|
23
|
+
:character, # `#\a`
|
24
|
+
:string, # `"hoge"`
|
25
|
+
# operators
|
26
|
+
:op_proc, # `+`, `-`, ...
|
27
|
+
# control
|
28
|
+
:illegal,
|
29
|
+
]
|
30
|
+
|
31
|
+
Token = Struct.new(:type, :literal) {
|
32
|
+
alias :to_s :literal
|
33
|
+
}
|
34
|
+
|
35
|
+
end
|
data/lib/rus3/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rus3
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- mnbi
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-05-03 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: Ruby with Syntax Sugar of Scheme
|
14
14
|
email:
|
@@ -33,12 +33,19 @@ files:
|
|
33
33
|
- examples/iota.scm
|
34
34
|
- exe/rus3
|
35
35
|
- lib/rus3.rb
|
36
|
+
- lib/rus3/ast.rb
|
37
|
+
- lib/rus3/ast/branch_node.rb
|
38
|
+
- lib/rus3/ast/error.rb
|
39
|
+
- lib/rus3/ast/leaf_node.rb
|
36
40
|
- lib/rus3/char.rb
|
37
41
|
- lib/rus3/error.rb
|
38
42
|
- lib/rus3/evaluator.rb
|
43
|
+
- lib/rus3/evaluator/environment.rb
|
44
|
+
- lib/rus3/evaluator/scheme_evaluator.rb
|
45
|
+
- lib/rus3/evaluator/translator.rb
|
46
|
+
- lib/rus3/lexer.rb
|
39
47
|
- lib/rus3/pair.rb
|
40
48
|
- lib/rus3/parser.rb
|
41
|
-
- lib/rus3/parser/lexer.rb
|
42
49
|
- lib/rus3/parser/scheme_parser.rb
|
43
50
|
- lib/rus3/port.rb
|
44
51
|
- lib/rus3/printer.rb
|
@@ -50,6 +57,7 @@ files:
|
|
50
57
|
- lib/rus3/procedure/vector.rb
|
51
58
|
- lib/rus3/procedure/write.rb
|
52
59
|
- lib/rus3/repl.rb
|
60
|
+
- lib/rus3/token.rb
|
53
61
|
- lib/rus3/vector.rb
|
54
62
|
- lib/rus3/version.rb
|
55
63
|
- rus3.gemspec
|