rus3 0.2.0 → 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
data/lib/rus3/ast/error.rb
DELETED
data/lib/rus3/ast/leaf_node.rb
DELETED
@@ -1,55 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Rus3
|
4
|
-
module AST
|
5
|
-
|
6
|
-
class LeafNode < Node
|
7
|
-
def leaf?
|
8
|
-
true
|
9
|
-
end
|
10
|
-
end
|
11
|
-
|
12
|
-
class BooleanNode < LeafNode
|
13
|
-
def type
|
14
|
-
:boolean
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
class IdentifierNode < LeafNode
|
19
|
-
def type
|
20
|
-
:identifier
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
class PeculiarIdentifierNode < IdentifierNode
|
25
|
-
def type
|
26
|
-
:peculiar_identifier
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
class CharacterNode < LeafNode
|
31
|
-
def type
|
32
|
-
:character
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
class StringNode < LeafNode
|
37
|
-
def type
|
38
|
-
:string
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
class NumberNode < LeafNode
|
43
|
-
def type
|
44
|
-
:number
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
class DotNode < LeafNode
|
49
|
-
def type
|
50
|
-
:dot
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
end
|
55
|
-
end
|
data/lib/rus3/lexer.rb
DELETED
@@ -1,104 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Rus3
|
4
|
-
|
5
|
-
class Lexer < Enumerator
|
6
|
-
|
7
|
-
# Indicates the version of the lexer class
|
8
|
-
LEXER_VERSION = "0.2.0"
|
9
|
-
|
10
|
-
class << self
|
11
|
-
|
12
|
-
def version # :nodoc:
|
13
|
-
"(scheme-lexer :version #{LEXER_VERSION})"
|
14
|
-
end
|
15
|
-
|
16
|
-
end
|
17
|
-
|
18
|
-
# :stopdoc:
|
19
|
-
|
20
|
-
BOOLEAN = /\A#(f(alse)?|t(rue)?)\Z/
|
21
|
-
STRING = /\A\"[^\"]*\"\Z/
|
22
|
-
|
23
|
-
# idents
|
24
|
-
EXTENDED_CHARS = "!\\$%&\\*\\+\\-\\./:<=>\\?@\\^_~"
|
25
|
-
IDENT_PAT = "[a-zA-Z_][a-zA-Z0-9#{EXTENDED_CHARS}]*"
|
26
|
-
IDENTIFIER = Regexp.new("\\A#{IDENT_PAT}\\Z")
|
27
|
-
|
28
|
-
# operators
|
29
|
-
ARITHMETIC_OPS = /\A[+\-*\/%]\Z/
|
30
|
-
COMPARISON_OPS = /\A([<>]=?|=)\Z/
|
31
|
-
|
32
|
-
# numbers
|
33
|
-
REAL_PAT = "(([1-9][0-9]*)|0)(\.[0-9]+)?"
|
34
|
-
RAT_PAT = "#{REAL_PAT}\\/#{REAL_PAT}"
|
35
|
-
C_REAL_PAT = "(#{REAL_PAT}|#{RAT_PAT})"
|
36
|
-
C_IMAG_PAT = "#{C_REAL_PAT}"
|
37
|
-
COMP_PAT = "#{C_REAL_PAT}(\\+|\\-)#{C_IMAG_PAT}i"
|
38
|
-
|
39
|
-
REAL_NUM = Regexp.new("\\A[+-]?#{REAL_PAT}\\Z")
|
40
|
-
RATIONAL = Regexp.new("\\A[+-]?#{RAT_PAT}\\Z")
|
41
|
-
COMPLEX = Regexp.new("\\A[+-]?#{COMP_PAT}\\Z")
|
42
|
-
PURE_IMAG = Regexp.new("\\A[+-](#{C_IMAG_PAT})?i\\Z")
|
43
|
-
|
44
|
-
# char
|
45
|
-
SINGLE_CHAR_PAT = "."
|
46
|
-
SPACE_PAT = "space"
|
47
|
-
NEWLINE_PAT = "newline"
|
48
|
-
|
49
|
-
CHAR_PREFIX = "\#\\\\"
|
50
|
-
CHAR_PAT = "(#{SINGLE_CHAR_PAT}|#{SPACE_PAT}|#{NEWLINE_PAT})"
|
51
|
-
CHAR = Regexp.new("\\A#{CHAR_PREFIX}#{CHAR_PAT}\\Z")
|
52
|
-
|
53
|
-
# :startdoc:
|
54
|
-
|
55
|
-
class << self
|
56
|
-
|
57
|
-
def new(exp, _ = nil)
|
58
|
-
tokens = tokenize(exp)
|
59
|
-
super(tokens.size) { |y|
|
60
|
-
tokens.each { |tk|
|
61
|
-
y.yield(tk)
|
62
|
-
}
|
63
|
-
}
|
64
|
-
end
|
65
|
-
|
66
|
-
S2R_MAP = { "(" => "[ ", ")" => " ] ", "'" => " ' " } # :nodoc:
|
67
|
-
|
68
|
-
def tokenize(exp)
|
69
|
-
source = exp.gsub(/[()']/, S2R_MAP)
|
70
|
-
|
71
|
-
source.split(" ").map { |literal|
|
72
|
-
case literal
|
73
|
-
when "["
|
74
|
-
Token.new(:lparen, literal)
|
75
|
-
when "]"
|
76
|
-
Token.new(:rparen, literal)
|
77
|
-
when "."
|
78
|
-
Token.new(:dot, literal)
|
79
|
-
when "'"
|
80
|
-
Token.new(:quotation, literal)
|
81
|
-
when "#["
|
82
|
-
Token.new(:vec_lparen, literal)
|
83
|
-
when BOOLEAN
|
84
|
-
Token.new(:boolean, literal)
|
85
|
-
when IDENTIFIER
|
86
|
-
Token.new(:identifier, literal)
|
87
|
-
when CHAR
|
88
|
-
Token.new(:character, literal)
|
89
|
-
when STRING
|
90
|
-
Token.new(:string, literal)
|
91
|
-
when ARITHMETIC_OPS, COMPARISON_OPS
|
92
|
-
Token.new(:op_proc, literal)
|
93
|
-
when REAL_NUM, RATIONAL, COMPLEX, PURE_IMAG
|
94
|
-
Token.new(:number, literal)
|
95
|
-
else
|
96
|
-
Token.new(:illegal, literal)
|
97
|
-
end
|
98
|
-
}
|
99
|
-
end
|
100
|
-
|
101
|
-
end
|
102
|
-
|
103
|
-
end
|
104
|
-
end
|
data/lib/rus3/parser.rb
DELETED
@@ -1,87 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "readline"
|
4
|
-
|
5
|
-
module Rus3
|
6
|
-
|
7
|
-
module Parser
|
8
|
-
|
9
|
-
# Indicates the version of the parser module.
|
10
|
-
VERSION = "0.2.0"
|
11
|
-
|
12
|
-
# A base class to derived a parser.
|
13
|
-
class Parser
|
14
|
-
|
15
|
-
# Holds a prompt string. It is intended to be set in the REPL
|
16
|
-
# loop.
|
17
|
-
attr_reader :prompt
|
18
|
-
|
19
|
-
# Constructs the version string.
|
20
|
-
|
21
|
-
def version
|
22
|
-
"parser-module :version #{VERSION}"
|
23
|
-
end
|
24
|
-
|
25
|
-
def initialize
|
26
|
-
@prompt = ""
|
27
|
-
end
|
28
|
-
|
29
|
-
def prompt=(str)
|
30
|
-
index = str.index(">")
|
31
|
-
class_name = self.class.name.split("::")[-1]
|
32
|
-
parser_name = class_name.delete_suffix("Parser").downcase
|
33
|
-
@prompt = str[0...index] + "(#{parser_name})" + str[index..-1]
|
34
|
-
end
|
35
|
-
|
36
|
-
# Reads program source from the passed IO instance, then returns
|
37
|
-
# the AST (abstract syntax tree). Returns nil when reaches to
|
38
|
-
# EOF.
|
39
|
-
|
40
|
-
def read(io = STDIN)
|
41
|
-
program_source = nil
|
42
|
-
if io == STDIN
|
43
|
-
program_source = Readline::readline(@prompt, true)
|
44
|
-
else
|
45
|
-
program_source = io.readlines(chomp: true).join(" ")
|
46
|
-
end
|
47
|
-
program_source.nil? ? nil : parse(program_source)
|
48
|
-
end
|
49
|
-
|
50
|
-
protected
|
51
|
-
|
52
|
-
# Parses the passed program source, then returns the AST to be
|
53
|
-
# evaluated by an evaluator. How to process depends on each
|
54
|
-
# derived parser class.
|
55
|
-
|
56
|
-
def parse(program_source)
|
57
|
-
nil
|
58
|
-
end
|
59
|
-
|
60
|
-
end
|
61
|
-
|
62
|
-
require_relative "parser/scheme_parser"
|
63
|
-
|
64
|
-
# :stopdoc:
|
65
|
-
|
66
|
-
class PassthroughParser < Parser
|
67
|
-
PARSER_VERSION = "0.2.0"
|
68
|
-
|
69
|
-
def version
|
70
|
-
vmsg = "(pass-through-parser version: #{PARSER_VERSION})"
|
71
|
-
vmsg += " #{Lexer.version}"
|
72
|
-
super + " (#{vmsg})"
|
73
|
-
end
|
74
|
-
|
75
|
-
def parse(program_source)
|
76
|
-
[Lexer.new(program_source).map {|tk| tk.to_s}]
|
77
|
-
end
|
78
|
-
|
79
|
-
end
|
80
|
-
|
81
|
-
# :startdoc:
|
82
|
-
|
83
|
-
DEFAULT_PARSER = SchemeParser # :nodoc:
|
84
|
-
|
85
|
-
end
|
86
|
-
|
87
|
-
end
|
@@ -1,657 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Rus3
|
4
|
-
|
5
|
-
module Parser
|
6
|
-
|
7
|
-
# A simple parser to read a s-expression for Scheme.
|
8
|
-
class SchemeParser < Parser
|
9
|
-
|
10
|
-
# Indicates the version of the parser class
|
11
|
-
PARSER_VERSION = "0.2.0"
|
12
|
-
|
13
|
-
# Constructs the version string.
|
14
|
-
|
15
|
-
def version
|
16
|
-
vmsg = "(scheme-parser :version #{PARSER_VERSION})"
|
17
|
-
vmsg += " #{Lexer.version}"
|
18
|
-
super + " (#{vmsg})"
|
19
|
-
end
|
20
|
-
|
21
|
-
def initialize
|
22
|
-
super
|
23
|
-
@lexer = nil
|
24
|
-
@curr_token = @peek_token = nil
|
25
|
-
end
|
26
|
-
|
27
|
-
# Parses a portion of or the whole program source then returns a
|
28
|
-
# AST structure.
|
29
|
-
|
30
|
-
def parse(program_source)
|
31
|
-
@lexer = Lexer.new(program_source)
|
32
|
-
parse_program
|
33
|
-
end
|
34
|
-
|
35
|
-
# :stopdoc:
|
36
|
-
|
37
|
-
private
|
38
|
-
|
39
|
-
def next_token
|
40
|
-
if @peek_token
|
41
|
-
@curr_token = @peek_token
|
42
|
-
@peek_token = nil
|
43
|
-
else
|
44
|
-
@curr_token = @lexer.next
|
45
|
-
end
|
46
|
-
@curr_token
|
47
|
-
end
|
48
|
-
|
49
|
-
def peek_token
|
50
|
-
if @peek_token.nil?
|
51
|
-
@peek_token = @lexer.next
|
52
|
-
end
|
53
|
-
@peek_token
|
54
|
-
end
|
55
|
-
|
56
|
-
def current_token
|
57
|
-
@curr_token
|
58
|
-
end
|
59
|
-
|
60
|
-
def push_back_token(token)
|
61
|
-
@peek_token = token
|
62
|
-
end
|
63
|
-
|
64
|
-
# <program> -> <expression>*
|
65
|
-
def parse_program
|
66
|
-
program = Rus3::AST.instantiate(:program)
|
67
|
-
Kernel.loop {
|
68
|
-
node = parse_expression
|
69
|
-
program << node
|
70
|
-
}
|
71
|
-
program
|
72
|
-
end
|
73
|
-
|
74
|
-
TOKEN_START_DELIMITERS = [ # :nodoc:
|
75
|
-
:lparen, # list: ( ... )
|
76
|
-
:vec_lparen, # vector: #( ... )
|
77
|
-
:bytevec_lparen, # bytevector: #u8( ... )
|
78
|
-
:quotation, # quotation: '<something>
|
79
|
-
:backquote, # quasiquote: `<something>
|
80
|
-
:comma, # used in quasiquote
|
81
|
-
:comma_at, # used in quasiquote
|
82
|
-
:comment_lparen, # comment start
|
83
|
-
]
|
84
|
-
|
85
|
-
def start_delimiter?(token)
|
86
|
-
TOKEN_START_DELIMITERS.include?(token.type)
|
87
|
-
end
|
88
|
-
|
89
|
-
# <expression> -> <simple expression> | <compound expression>
|
90
|
-
# <compound expression> -> <start delimiter> <expression>* <end delimiter>
|
91
|
-
# <start delimiter> -> <lparen> | <vec lparen> | <bytevec lparen> |
|
92
|
-
# <quotation> |
|
93
|
-
# <backquote> | <comma> | <comma at> |
|
94
|
-
# <comment lparen>
|
95
|
-
# <end delimier> -> <rparen> | <comment_rparen>
|
96
|
-
def parse_expression
|
97
|
-
if start_delimiter?(peek_token)
|
98
|
-
parse_compound_expression
|
99
|
-
else
|
100
|
-
parse_simple_expression
|
101
|
-
end
|
102
|
-
end
|
103
|
-
|
104
|
-
# <simple expression> -> <identifier> | <self evaluating>
|
105
|
-
# <self evaluating> -> <boolean> | <number> | <character> | <string>
|
106
|
-
def parse_simple_expression
|
107
|
-
type, literal = *next_token
|
108
|
-
type = :peculiar_identifier if type == :op_proc
|
109
|
-
Rus3::AST.instantiate(type, literal)
|
110
|
-
end
|
111
|
-
|
112
|
-
def parse_identifier
|
113
|
-
Rus3::AST.instantiate(:identifier, next_token.literal)
|
114
|
-
end
|
115
|
-
|
116
|
-
# <compound expression> -> <quotation> |
|
117
|
-
# <vector> |
|
118
|
-
# <list expression>
|
119
|
-
def parse_compound_expression
|
120
|
-
node = nil
|
121
|
-
token = peek_token
|
122
|
-
case token.type
|
123
|
-
when :vec_lparen
|
124
|
-
node = parse_vector
|
125
|
-
when :lparen
|
126
|
-
node = parse_list_expression
|
127
|
-
when :quotation
|
128
|
-
node = parse_quotation
|
129
|
-
else
|
130
|
-
raise Rus3::SchemeSynaxError, token.to_a
|
131
|
-
end
|
132
|
-
node
|
133
|
-
end
|
134
|
-
|
135
|
-
# <list expression> ->
|
136
|
-
# <procedure call> |
|
137
|
-
# <lambda expression> |
|
138
|
-
# <conditional> |
|
139
|
-
# <assignment> |
|
140
|
-
# <macro use> |
|
141
|
-
# <macro block> |
|
142
|
-
# <definition> |
|
143
|
-
# <derived expression> |
|
144
|
-
# <includer>
|
145
|
-
def parse_list_expression
|
146
|
-
node = nil
|
147
|
-
next_token # read :lparen
|
148
|
-
case peek_token.type
|
149
|
-
when :rparen
|
150
|
-
# an empty list
|
151
|
-
node = Rus3::AST.instantiate(:list)
|
152
|
-
next_token # skip :rparen
|
153
|
-
when :identifier
|
154
|
-
case peek_token.literal
|
155
|
-
when "lambda" # lambda expression
|
156
|
-
node = parse_lambda_expression
|
157
|
-
when "if" # conditional
|
158
|
-
node = parse_conditional
|
159
|
-
when "set!" # assignment
|
160
|
-
node = parse_assignment
|
161
|
-
when "let-syntax", "letrec-syntax" # macro block
|
162
|
-
node = parse_macro_block
|
163
|
-
when "define", "define-syntax", "define-values", "define-record-type", "begin"
|
164
|
-
node = parse_definition
|
165
|
-
else
|
166
|
-
node = parse_derived_expression
|
167
|
-
node = parse_macro_use if node.nil?
|
168
|
-
end
|
169
|
-
end
|
170
|
-
node || parse_procedure_call
|
171
|
-
end
|
172
|
-
|
173
|
-
def parse_macro_use
|
174
|
-
nil
|
175
|
-
end
|
176
|
-
|
177
|
-
# <procedure call> -> ( <operator> <operand>* )
|
178
|
-
def parse_procedure_call
|
179
|
-
proc_call_node = Rus3::AST.instantiate(:procedure_call,
|
180
|
-
current_token.literal)
|
181
|
-
proc_call_node.operator = parse_operator
|
182
|
-
|
183
|
-
Kernel.loop {
|
184
|
-
if peek_token.type == :rparen
|
185
|
-
next_token # skip :rparen
|
186
|
-
break
|
187
|
-
end
|
188
|
-
proc_call_node.add_operand(parse_operand)
|
189
|
-
}
|
190
|
-
proc_call_node
|
191
|
-
end
|
192
|
-
|
193
|
-
# <operator> -> <expression>
|
194
|
-
def parse_operator
|
195
|
-
parse_expression
|
196
|
-
end
|
197
|
-
|
198
|
-
# <operand> -> <expression>
|
199
|
-
def parse_operand
|
200
|
-
parse_expression
|
201
|
-
end
|
202
|
-
|
203
|
-
# <lambda expression> -> ( lambda <formals> <body> )
|
204
|
-
# <sequence> -> <command>* <expression>
|
205
|
-
# <command> -> <expression>
|
206
|
-
# <definition> ... see parse_definition
|
207
|
-
def parse_lambda_expression
|
208
|
-
lambda_node = Rus3::AST.instantiate(:lambda_expression,
|
209
|
-
next_token.literal)
|
210
|
-
lambda_node.formals = parse_formals
|
211
|
-
lambda_node.body = read_body
|
212
|
-
next_token # skip :rparen
|
213
|
-
lambda_node
|
214
|
-
end
|
215
|
-
|
216
|
-
# <formals> -> ( <identifier>* ) | <identifier> |
|
217
|
-
# ( <identifier>+ . <identifier> )
|
218
|
-
def parse_formals
|
219
|
-
token = next_token
|
220
|
-
formals = nil
|
221
|
-
if token.type == :lparen
|
222
|
-
formals = Rus3::AST.instantiate(:list)
|
223
|
-
Kernel.loop {
|
224
|
-
if peek_token.type == :rparen
|
225
|
-
next_token
|
226
|
-
break
|
227
|
-
end
|
228
|
-
formals << Rus3::AST.instantiate(:identifier, next_token.literal)
|
229
|
-
}
|
230
|
-
else
|
231
|
-
formals = Rus3::AST.instantiate(:identifier, token.literal)
|
232
|
-
end
|
233
|
-
formals
|
234
|
-
end
|
235
|
-
|
236
|
-
# <body> -> <definition>* <sequence>
|
237
|
-
def read_body
|
238
|
-
body = []
|
239
|
-
Kernel.loop {
|
240
|
-
break if peek_token.type == :rparen # end of <lambda expression>
|
241
|
-
body << parse_expression
|
242
|
-
}
|
243
|
-
body
|
244
|
-
end
|
245
|
-
|
246
|
-
# <conditional> -> ( if <test> <consequent> <alternamte> )
|
247
|
-
def parse_conditional
|
248
|
-
if_node = Rus3::AST.instantiate(:conditional, next_token.literal)
|
249
|
-
if_node.test = parse_test
|
250
|
-
if_node.consequent = parse_consequent
|
251
|
-
if peek_token.type != :rparen
|
252
|
-
if_node.alternate = parse_alternate
|
253
|
-
end
|
254
|
-
next_token # skip :rparen
|
255
|
-
if_node
|
256
|
-
end
|
257
|
-
|
258
|
-
# <test> -> <expression>
|
259
|
-
def parse_test
|
260
|
-
parse_expression
|
261
|
-
end
|
262
|
-
|
263
|
-
# <consequent> -> <expression>
|
264
|
-
def parse_consequent
|
265
|
-
parse_expression
|
266
|
-
end
|
267
|
-
|
268
|
-
# <alternate> -> <expression> | <empty>
|
269
|
-
# <empty> -> ""
|
270
|
-
def parse_alternate
|
271
|
-
parse_expression
|
272
|
-
end
|
273
|
-
|
274
|
-
# <assignment> -> ( set! <identifier> <expression> )
|
275
|
-
def parse_assignment
|
276
|
-
assignment_node = Rus3::AST.instantiate(:assignment, next_token.literal)
|
277
|
-
assignment_node.identifier = parse_identifier
|
278
|
-
assignment_node.expression = parse_expression
|
279
|
-
next_token # skip :rparen
|
280
|
-
assignment_node
|
281
|
-
end
|
282
|
-
|
283
|
-
def parse_macro_block
|
284
|
-
nil
|
285
|
-
end
|
286
|
-
|
287
|
-
# <definition> -> ( define <identifier> <expression> ) |
|
288
|
-
# ( define ( <identifier> <def formals> ) <body> ) |
|
289
|
-
# <syntax definition> |
|
290
|
-
# ( define-values <formals> <body> ) |
|
291
|
-
# ( define-record-type <identifier>
|
292
|
-
# <constructor> <identifier> <field spec>* ) |
|
293
|
-
# ( begin <definition>* )
|
294
|
-
#
|
295
|
-
# <def formals> -> <identifier>* |
|
296
|
-
# <identifier>* . <identifier>
|
297
|
-
# <constructor> -> ( <identifier> <field name>* )
|
298
|
-
# <field spec> -> ( <field name> <accessor> ) |
|
299
|
-
# ( <field name> <accessor> <mutator> )
|
300
|
-
# <field name> -> <identifier>
|
301
|
-
# <accessor> -> <identifier>
|
302
|
-
# <mutator> -> <identifier>
|
303
|
-
# <syntax definition> -> ( define-syntax <keyword> <transformer spec> )
|
304
|
-
# <transformer spec> -> ...
|
305
|
-
# :
|
306
|
-
def parse_definition
|
307
|
-
case peek_token.literal
|
308
|
-
when "define"
|
309
|
-
parse_identifier_definition
|
310
|
-
when "define-syntax"
|
311
|
-
nil # not implemented yet
|
312
|
-
when "define-values"
|
313
|
-
nil # not implemented yet
|
314
|
-
when "define-record-type"
|
315
|
-
nil # not implemented yet
|
316
|
-
when "begin"
|
317
|
-
nil # not implemented yet
|
318
|
-
else
|
319
|
-
raise Rus3::SchemeSynaxError, token.to_a
|
320
|
-
end
|
321
|
-
end
|
322
|
-
|
323
|
-
# ( define <identifier> <expression> )
|
324
|
-
# ( define ( <identifier> <def formals> ) <body> )
|
325
|
-
#
|
326
|
-
# ( define foo 3 )
|
327
|
-
# ( define bar ( lambda ( x y ) ( + x y )))
|
328
|
-
# ( deifne ( hoge n m ) ( * n m ))
|
329
|
-
|
330
|
-
def parse_identifier_definition
|
331
|
-
token = next_token # define
|
332
|
-
define_node = Rus3::AST.instantiate(:identifier_definition, token.literal)
|
333
|
-
case peek_token.type
|
334
|
-
when :lparen
|
335
|
-
next_token # skip :lparen
|
336
|
-
# procedure name
|
337
|
-
define_node.identifier = parse_identifier
|
338
|
-
|
339
|
-
def_formals = Rus3::AST.instantiate(:list)
|
340
|
-
Kernel.loop {
|
341
|
-
if peek_token.type == :rparen
|
342
|
-
next_token
|
343
|
-
break
|
344
|
-
end
|
345
|
-
def_formals << parse_identifier
|
346
|
-
}
|
347
|
-
|
348
|
-
lambda_node = Rus3::AST.instantiate(:lambda_expression, nil)
|
349
|
-
lambda_node.formals = def_formals
|
350
|
-
lambda_node.body = read_body
|
351
|
-
next_token # skip :rparen
|
352
|
-
|
353
|
-
define_node.expression = lambda_node
|
354
|
-
when :identifier
|
355
|
-
define_node.identifier = parse_identifier
|
356
|
-
define_node.expression = parse_expression
|
357
|
-
next_token
|
358
|
-
else
|
359
|
-
raise Rus3::SchemeSynaxError, current_token.to_a
|
360
|
-
end
|
361
|
-
define_node
|
362
|
-
end
|
363
|
-
|
364
|
-
# <quotation> -> '<datum> | ( quote <datum> )
|
365
|
-
def parse_quotation
|
366
|
-
token = next_token
|
367
|
-
quote_node = Rus3::AST.instantiate(:quotation, token.literal)
|
368
|
-
quote_node << parse_datum
|
369
|
-
quote_node
|
370
|
-
end
|
371
|
-
|
372
|
-
# <vetor> -> #( <datum>* )
|
373
|
-
def parse_vector
|
374
|
-
parse_data_to_rparen
|
375
|
-
end
|
376
|
-
|
377
|
-
def parse_data_to_rparen
|
378
|
-
token = next_token
|
379
|
-
ast_type = nil
|
380
|
-
case token.type
|
381
|
-
when :lparen
|
382
|
-
ast_type = :list
|
383
|
-
when :vec_lparen
|
384
|
-
ast_type = :vector
|
385
|
-
else
|
386
|
-
ast_type = :list
|
387
|
-
end
|
388
|
-
node = Rus3::AST.instantiate(ast_type, nil)
|
389
|
-
raise Rus3::SchemeSyntaxError, token.to_a unless node.branch?
|
390
|
-
Kernel.loop {
|
391
|
-
token = peek_token
|
392
|
-
break if token.type == :rparen
|
393
|
-
node << parse_datum
|
394
|
-
}
|
395
|
-
next_token # skip :rparen
|
396
|
-
node
|
397
|
-
end
|
398
|
-
|
399
|
-
# <datum> -> <simple datum> | <compound datum>
|
400
|
-
def parse_datum
|
401
|
-
if start_delimiter?(peek_token)
|
402
|
-
parse_compound_datum
|
403
|
-
else
|
404
|
-
parse_simple_datum
|
405
|
-
end
|
406
|
-
end
|
407
|
-
|
408
|
-
# <simple datum> -> <boolean> | <number> | <character> |
|
409
|
-
# <string> | <symbol>
|
410
|
-
# <symbol> -> <identifier>
|
411
|
-
#
|
412
|
-
# See `parse_simple_expression`.
|
413
|
-
def parse_simple_datum
|
414
|
-
parse_simple_expression
|
415
|
-
end
|
416
|
-
|
417
|
-
# <compound datum> -> <list> | <vector> | <bytevector> | <abbreviation>
|
418
|
-
# <abbreviation> -> <abbrev prefix> <datum>
|
419
|
-
def parse_compound_datum
|
420
|
-
case peek_token.type
|
421
|
-
when :lparen
|
422
|
-
parse_list
|
423
|
-
when :vec_lparen
|
424
|
-
parse_vector
|
425
|
-
else
|
426
|
-
raise Rus3::SchemeSyntaxError, peek_token.to_a
|
427
|
-
end
|
428
|
-
end
|
429
|
-
|
430
|
-
# <list> -> ( <datum>* ) | ( <datum>+ . <datum> )
|
431
|
-
def parse_list
|
432
|
-
parse_data_to_rparen
|
433
|
-
end
|
434
|
-
|
435
|
-
DERIVED_IDENTIFIERS = [
|
436
|
-
"cond", "case", "and", "or", "when", "unless",
|
437
|
-
"let", "let*", "letrec", "letrec*",
|
438
|
-
"let-values", "let*-values",
|
439
|
-
"begin", "do",
|
440
|
-
"delay", "delay-force",
|
441
|
-
"parameterize",
|
442
|
-
"guard",
|
443
|
-
"case-lambda",
|
444
|
-
]
|
445
|
-
|
446
|
-
# <derived expression> ->
|
447
|
-
# ( cond <cond clause>+ ) |
|
448
|
-
# ( cond <cond cluase>* ( else <sequence> ) ) |
|
449
|
-
# ( case <expression> <case caluse>+ ) |
|
450
|
-
# ( case <expression> <case caluse>* ( else <sequence> ) ) |
|
451
|
-
# ( case <expression> <case caluse>* ( else => <recipient> ) ) |
|
452
|
-
# ( and <test>* ) |
|
453
|
-
# ( or <test>* ) |
|
454
|
-
# ( when <test> <sequence> ) |
|
455
|
-
# ( unless <test> <sequence> ) |
|
456
|
-
# ( let ( <binding spec>* ) <body> ) |
|
457
|
-
# ( let <identifier> ( <binding spec>* ) <body> ) |
|
458
|
-
# ( let* ( <binding spec>* ) <body> ) |
|
459
|
-
# ( letrec ( <binding spec>* ) <body> ) |
|
460
|
-
# ( letrec* ( <binding spec>* ) <body> ) |
|
461
|
-
# ( let-values ( <my binding spec>* ) <body> ) |
|
462
|
-
# ( let*-values ( <my binding spec>* ) <body> ) |
|
463
|
-
# ( begin <sequence> ) |
|
464
|
-
# ( do ( <iteration spec>* ) ( <test> <do result> ) <command>* ) |
|
465
|
-
# ( delay <expression> ) |
|
466
|
-
# ( delay-force <expression> ) |
|
467
|
-
# ( parameterize ( ( <expression> <expression> )* ) <body> ) |
|
468
|
-
# ( guard ( <identifier> <cond clause>* ) <body> ) |
|
469
|
-
# ( case-lambda <case-lambda clause>* ) |
|
470
|
-
# <quasiquotation>
|
471
|
-
def parse_derived_expression
|
472
|
-
node = nil
|
473
|
-
token = next_token
|
474
|
-
if token.type == :identifier
|
475
|
-
if DERIVED_IDENTIFIERS.include?(token.literal)
|
476
|
-
method_name = compose_method_name("parse_", token.literal).intern
|
477
|
-
method = self.method(method_name)
|
478
|
-
node = method.call
|
479
|
-
else
|
480
|
-
node = parse_quasiquotation
|
481
|
-
end
|
482
|
-
end
|
483
|
-
push_back_token(token) if node.nil?
|
484
|
-
node
|
485
|
-
end
|
486
|
-
|
487
|
-
SCM_CHAR_TO_RB_MAP = {
|
488
|
-
"*" => "_star",
|
489
|
-
"-" => "_",
|
490
|
-
}
|
491
|
-
|
492
|
-
def compose_method_name(prefix, type_name)
|
493
|
-
converted_name = type_name.gsub(/[*\-]/, SCM_CHAR_TO_RB_MAP)
|
494
|
-
prefix + converted_name
|
495
|
-
end
|
496
|
-
|
497
|
-
def not_implemented_yet(feature)
|
498
|
-
raise Rus3::NotImplementedYetError, feature
|
499
|
-
end
|
500
|
-
|
501
|
-
# ( cond <cond clause>+ )
|
502
|
-
# ( cond <cond cluase>* ( else <sequence> ) )
|
503
|
-
def parse_cond
|
504
|
-
cond_node = Rus3::AST.instantiate(:cond, current_token.literal)
|
505
|
-
|
506
|
-
Kernel.loop {
|
507
|
-
if peek_token.type == :rparen
|
508
|
-
next_token # skip :rparen
|
509
|
-
break
|
510
|
-
end
|
511
|
-
cond_node.add_clause(parse_cond_clause)
|
512
|
-
}
|
513
|
-
cond_node
|
514
|
-
end
|
515
|
-
|
516
|
-
# <cond cluase> -> ( <test> <sequence> ) |
|
517
|
-
# ( <test> ) |
|
518
|
-
# ( <test> => <recipient> )
|
519
|
-
# <test> -> <expression>
|
520
|
-
# <recipient> -> <expression>
|
521
|
-
# <sequence> -> <command>* <expression>
|
522
|
-
# <command> -> <expression>
|
523
|
-
def parse_cond_clause
|
524
|
-
clause_node = Rus3::AST.instantiate(:cond_clause)
|
525
|
-
next_token # skip :lparen
|
526
|
-
|
527
|
-
clause_node.test = parse_test
|
528
|
-
|
529
|
-
Kernel.loop {
|
530
|
-
if peek_token.type == :rparen
|
531
|
-
next_token
|
532
|
-
break
|
533
|
-
end
|
534
|
-
clause_node.add_expression(parse_expression)
|
535
|
-
}
|
536
|
-
clause_node
|
537
|
-
end
|
538
|
-
|
539
|
-
def prase_test
|
540
|
-
parse_expression
|
541
|
-
end
|
542
|
-
|
543
|
-
def parse_case
|
544
|
-
not_implemented_yet("case")
|
545
|
-
end
|
546
|
-
|
547
|
-
def parse_and
|
548
|
-
not_implemented_yet("and")
|
549
|
-
end
|
550
|
-
|
551
|
-
def parse_or
|
552
|
-
not_implemented_yet("or")
|
553
|
-
end
|
554
|
-
|
555
|
-
def parse_when
|
556
|
-
not_implemented_yet("when")
|
557
|
-
end
|
558
|
-
|
559
|
-
def parse_unless
|
560
|
-
not_implemented_yet("unless")
|
561
|
-
end
|
562
|
-
|
563
|
-
# ( let ( <binding spec>* ) <body> ) |
|
564
|
-
# <bind spec> -> ( <identifier> <expression> )
|
565
|
-
#
|
566
|
-
# `Named let` has not supported yet.
|
567
|
-
# ( let <identifier> ( <binding spec>* ) <body> )
|
568
|
-
def parse_let
|
569
|
-
let_node = Rus3::AST.instantiate(:let, current_token.literal)
|
570
|
-
|
571
|
-
let_node.bind_specs = parse_bind_specs
|
572
|
-
let_node.body = read_body
|
573
|
-
next_token # skip :rparen
|
574
|
-
|
575
|
-
let_node
|
576
|
-
end
|
577
|
-
|
578
|
-
def parse_bind_specs
|
579
|
-
specs_node = Rus3::AST.instantiate(:list)
|
580
|
-
next_token # skip :lparen
|
581
|
-
|
582
|
-
Kernel.loop {
|
583
|
-
if peek_token.type == :rparen
|
584
|
-
next_token # skip :rparen
|
585
|
-
break
|
586
|
-
end
|
587
|
-
specs_node << parse_bind_spec
|
588
|
-
}
|
589
|
-
specs_node
|
590
|
-
end
|
591
|
-
|
592
|
-
def parse_bind_spec
|
593
|
-
spec_node = Rus3::AST::instantiate(:bind_spec)
|
594
|
-
next_token # skip :lpraren
|
595
|
-
spec_node.identifier = parse_identifier
|
596
|
-
spec_node.expression = parse_expression
|
597
|
-
next_token # skip :rparen
|
598
|
-
spec_node
|
599
|
-
end
|
600
|
-
|
601
|
-
def parse_let_star
|
602
|
-
not_implemented_yet("let*")
|
603
|
-
end
|
604
|
-
|
605
|
-
def parse_letrec
|
606
|
-
not_implemented_yet("letrec")
|
607
|
-
end
|
608
|
-
|
609
|
-
def parse_letrec_star
|
610
|
-
not_implemented_yet("letrec*")
|
611
|
-
end
|
612
|
-
|
613
|
-
def parse_let_values
|
614
|
-
not_implemented_yet("let-values")
|
615
|
-
end
|
616
|
-
|
617
|
-
def parse_let_star_values
|
618
|
-
not_implemented_yet("let*-values")
|
619
|
-
end
|
620
|
-
|
621
|
-
def parse_begin
|
622
|
-
not_implemented_yet("begin")
|
623
|
-
end
|
624
|
-
|
625
|
-
def parse_do
|
626
|
-
not_implemented_yet("do")
|
627
|
-
end
|
628
|
-
|
629
|
-
def parse_delay
|
630
|
-
not_implemented_yet("delay")
|
631
|
-
end
|
632
|
-
|
633
|
-
def parse_delay_force
|
634
|
-
not_implemented_yet("delay-force")
|
635
|
-
end
|
636
|
-
|
637
|
-
def parse_parameterize
|
638
|
-
not_implemented_yet("parameterize")
|
639
|
-
end
|
640
|
-
|
641
|
-
def parse_guard
|
642
|
-
not_implemented_yet("guard")
|
643
|
-
end
|
644
|
-
|
645
|
-
def parse_case_lambda
|
646
|
-
not_implemented_yet("case-lambda")
|
647
|
-
end
|
648
|
-
|
649
|
-
def parse_quasiquotation
|
650
|
-
nil
|
651
|
-
end
|
652
|
-
|
653
|
-
# :startdoc:
|
654
|
-
|
655
|
-
end
|
656
|
-
end
|
657
|
-
end
|