rus3 0.1.2 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|