rubasteme 0.1.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.
@@ -0,0 +1,123 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SicpScheme
4
+
5
+ # primitive procedure for SICP Scheme
6
+
7
+ module Primitives
8
+ def cons(obj1, obj2)
9
+ [obj1, obj2]
10
+ end
11
+
12
+ def pair?(obj)
13
+ obj.instance_of?(Array)
14
+ end
15
+
16
+ def car(lis)
17
+ lis[0]
18
+ end
19
+
20
+ def cdr(lis)
21
+ lis[1..-1]
22
+ end
23
+
24
+ def list(*args)
25
+ args
26
+ end
27
+
28
+ def append(*args)
29
+ if args.empty?
30
+ []
31
+ else
32
+ args[0] + append(*args[1..-1])
33
+ end
34
+ end
35
+
36
+ def write(obj)
37
+ print obj
38
+ end
39
+
40
+ def display(obj)
41
+ write(obj)
42
+ print "\n"
43
+ end
44
+
45
+ def zero?(obj)
46
+ eqv?(obj, 0)
47
+ end
48
+
49
+ def a_calc(op, *args)
50
+ case args.size
51
+ when 0
52
+ 0
53
+ when 1
54
+ args[0]
55
+ else
56
+ a_calc(op, args[0].send(op, args[1]), *args[2..-1])
57
+ end
58
+ end
59
+
60
+ def add(*args)
61
+ a_calc(:+, *args)
62
+ end
63
+
64
+ def subtract(*args)
65
+ a_calc(:-, *args)
66
+ end
67
+
68
+ def mul(*args)
69
+ a_calc(:*, *args)
70
+ end
71
+
72
+ def div(*args)
73
+ a_calc(:/, *args)
74
+ end
75
+
76
+ def mod(*args)
77
+ a_calc(:%, *args)
78
+ end
79
+
80
+ def scm_true
81
+ [:ast_boolean, "#t"]
82
+ end
83
+
84
+ def scm_false
85
+ [:ast_boolean, "#f"]
86
+ end
87
+
88
+ def c_calc(op, *args)
89
+ case args.size
90
+ when 0, 1
91
+ raise ArgumentError, args.to_s
92
+ when 2
93
+ args[0].send(op, args[1]) ? scm_true : scm_false
94
+ else
95
+ args[0].send(op, args[1]) and c_calc(op, *args[1..-1]) ? scm_true : scm_false
96
+ end
97
+ end
98
+
99
+ def lt?(*args)
100
+ c_calc(:<, *args)
101
+ end
102
+
103
+ def le?(*args)
104
+ c_calc(:<=, *args)
105
+ end
106
+
107
+ def gt?(*args)
108
+ c_calc(:>, *args)
109
+ end
110
+
111
+ def ge?(*args)
112
+ c_calc(:>=, *args)
113
+ end
114
+
115
+ def same_value?(*args)
116
+ c_calc(:==, *args)
117
+ end
118
+
119
+ def eqv?(obj1, obj2)
120
+ obj1 == obj2 ? scm_true : scm_false
121
+ end
122
+ end
123
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SicpScheme
4
+ class Printer
5
+ def initialize
6
+ end
7
+
8
+ def print(scm_obj)
9
+ pp scm_obj
10
+ end
11
+ end
12
+ end
data/exe/rubasteme ADDED
@@ -0,0 +1,88 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "pp"
4
+ require "rubasteme"
5
+
6
+ def version
7
+ "Rubasteme version: #{Rubasteme::VERSION} (#{Rubasteme::RELEASE})"
8
+ end
9
+
10
+ def usage
11
+ puts <<HELP
12
+ usage:
13
+ rubasteme [option] [FILE]
14
+
15
+ Reads the given files as a sequence of tokens, then print AST nodes.
16
+ If no FILE is specified, then tries to read from the standard input.
17
+
18
+ option:
19
+ -o, --output-file OUTPUT_FILE : specify the output file
20
+ -t, --format-type TYPE : specify the output format
21
+ -d, --debug : specify to run verbosely
22
+ -v, --version : print version
23
+ -h, --help : show this message
24
+
25
+ input format:
26
+ Specify one of the following names:
27
+ ast, array
28
+ HELP
29
+ end
30
+
31
+ def opt_parse(args, opts = {})
32
+ files = []
33
+ while args.size > 0
34
+ arg = args.shift
35
+ case arg
36
+ when "-o", "--output-file"
37
+ opts[:output_file] = args.shift
38
+ when "-t", "--format-type"
39
+ format_type = args.shift
40
+ raise ArgumentError, "not specified as format type" if format_type.nil?
41
+ opts[:format_type] = format_type.intern
42
+ when "-d", "--debug"
43
+ opts[:verbose] = true
44
+ when "-v", "--version"
45
+ puts version
46
+ exit 0
47
+ when "-h", "--help"
48
+ puts usage
49
+ exit 0
50
+ else # must be a filename
51
+ files << arg if arg
52
+ end
53
+ end
54
+ args.concat(files)
55
+ opts
56
+ end
57
+
58
+ opts = opt_parse(ARGV)
59
+ if opts[:verbose]
60
+ puts version
61
+ format = opts[:format_type] || "default (token)"
62
+ puts "Input format: #{format}"
63
+ ofname = opts[:output_file] || "STDOUT"
64
+ puts "Output file: #{ofname}"
65
+ end
66
+
67
+ lines = []
68
+ if ARGV.size > 0
69
+ lines = ARGF.entries.map{|s| s.delete_suffix("\n")}
70
+ else
71
+ lines = STDIN.readlines(chomp: true)
72
+ end
73
+
74
+ tokens = lines.map{|e| Kernel.eval(e)}
75
+ lexer = Rubasteme.lexer(tokens)
76
+ parser = Rubasteme.parser(lexer)
77
+ ast = parser.parse
78
+
79
+ output = ""
80
+ PP.pp(ast.to_a, output)
81
+
82
+ form = opts[:format_type] || :token
83
+ of = STDOUT
84
+ of = File.open(opts[:output_file], "w") if opts[:output_file]
85
+
86
+ of.puts(output)
87
+
88
+ of.close
data/lib/rubasteme.rb ADDED
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rbscmlex"
4
+
5
+ module Rubasteme
6
+
7
+ def self.lexer(obj)
8
+ Rbscmlex::Lexer.new(obj)
9
+ end
10
+
11
+ require_relative "rubasteme/error"
12
+ require_relative "rubasteme/utils"
13
+ require_relative "rubasteme/ast"
14
+ require_relative "rubasteme/parser"
15
+ require_relative "rubasteme/version"
16
+ end
@@ -0,0 +1,93 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rubasteme
4
+
5
+ def self.write(ast_node, of = STDOUT)
6
+ of.puts ast_node.to_s
7
+ end
8
+
9
+ module AST
10
+
11
+ AST_NODE_TYPE = [ # :nodoc:
12
+ # leaf
13
+ :ast_empty_list,
14
+ :ast_boolean,
15
+ :ast_identifier,
16
+ :ast_character,
17
+ :ast_string,
18
+ :ast_number,
19
+ :ast_dot,
20
+ # branch
21
+ :ast_program,
22
+ :ast_list,
23
+ :ast_quotation,
24
+ :ast_procedure_call,
25
+ :ast_lambda_expression,
26
+ :ast_formals,
27
+ :ast_conditional,
28
+ :ast_assignment,
29
+ :ast_identifier_definition,
30
+ :ast_cond,
31
+ :ast_cond_clause,
32
+ :ast_case,
33
+ :ast_and,
34
+ :ast_or,
35
+ :ast_when,
36
+ :ast_unless,
37
+ :ast_let,
38
+ :ast_let_star,
39
+ :ast_letrec,
40
+ :ast_letrec_star,
41
+ :ast_bindings,
42
+ :ast_bind_spec,
43
+ :ast_begin,
44
+ :ast_do,
45
+ :ast_iteration_bindings,
46
+ :ast_test_and_do_result,
47
+ :ast_iteration_spec,
48
+ # misc.
49
+ :ast_illegal,
50
+ ]
51
+
52
+ def self.instantiate(ast_node_type, literal)
53
+ type_name = Utils.camel_case(ast_node_type.to_s.delete_prefix("ast_"))
54
+ klass = AST.const_get("#{type_name}Node")
55
+
56
+ if klass.nil? or klass == IllegalNode
57
+ IllegalNode.new(ast_node_type, literal)
58
+ else
59
+ klass.new(literal)
60
+ end
61
+ end
62
+
63
+ class Node
64
+ def initialize(_literal = nil)
65
+ end
66
+
67
+ def type
68
+ klass_name = self.class.name.split("::")[-1]
69
+ type_name = Utils.snake_case(klass_name.delete_suffix("Node"))
70
+ "ast_#{type_name}".intern
71
+ end
72
+
73
+ def to_a; []; end
74
+ def to_s; to_a.to_s; end
75
+ end
76
+
77
+ require_relative "ast/leaf_node"
78
+ require_relative "ast/branch_node"
79
+
80
+ class IllegalNode < Node
81
+ def initialize(type, literal)
82
+ super(literal)
83
+ @given_type = type
84
+ @literal = literal
85
+ end
86
+
87
+ def to_a
88
+ [type, @given_type, @literal]
89
+ end
90
+ end
91
+
92
+ end
93
+ end
@@ -0,0 +1,514 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rubasteme
4
+
5
+ module AST
6
+
7
+ class BranchNode < Node
8
+ def initialize(initial_size = nil)
9
+ super(nil)
10
+ @nodes = initial_size.nil? ? [] : Array.new(initial_size)
11
+ end
12
+
13
+ def size
14
+ @nodes.size
15
+ end
16
+
17
+ def to_a
18
+ [type].concat(@nodes.map(&:to_a))
19
+ end
20
+
21
+ include Enumerable
22
+
23
+ def each(&blk)
24
+ if block_given?
25
+ @nodes.each(&blk)
26
+ self
27
+ else
28
+ @nodes.each
29
+ end
30
+ end
31
+
32
+ def [](index)
33
+ @nodes[index]
34
+ end
35
+
36
+ def []=(index, node)
37
+ @nodes[index] = node
38
+ end
39
+
40
+ def <<(node)
41
+ @nodes << node
42
+ end
43
+ end
44
+
45
+ class ProgramNode < BranchNode
46
+ def initialize(_ = nil)
47
+ super(nil)
48
+ end
49
+ end
50
+
51
+ class VectorNode < BranchNode
52
+ def initialize(_ = nil)
53
+ super(nil)
54
+ end
55
+ end
56
+
57
+ class ListNode < BranchNode
58
+ def initialize(_ = nil)
59
+ super(nil)
60
+ end
61
+ end
62
+
63
+ class QuotationNode < ListNode
64
+ def initialize(_ = nil)
65
+ super(nil)
66
+ end
67
+ end
68
+
69
+ class ProcedureCallNode < ListNode
70
+ def initialize(_ = nil)
71
+ # @nodes = [<operator>, <operand>*]
72
+ super(1)
73
+ end
74
+
75
+ def operator
76
+ @nodes[0]
77
+ end
78
+
79
+ def operator=(node)
80
+ @nodes[0] = node
81
+ end
82
+
83
+ def operands
84
+ @nodes[1..-1]
85
+ end
86
+
87
+ def add_operand(node)
88
+ @nodes << node
89
+ end
90
+ end
91
+
92
+ class LambdaExpressionNode < ListNode
93
+ def initialize(_ = nil)
94
+ # @nodes = [<formals>, <body>, ...]
95
+ super(1)
96
+ end
97
+
98
+ def formals
99
+ @nodes[0]
100
+ end
101
+
102
+ def formals=(node)
103
+ @nodes[0] = node
104
+ end
105
+
106
+ def body
107
+ @nodes[1..-1]
108
+ end
109
+
110
+ def body=(nodes)
111
+ nodes.each_with_index { |node, i|
112
+ @nodes[i + 1] = node
113
+ }
114
+ end
115
+ end
116
+
117
+ class FormalsNode < ListNode
118
+ def initialize(_ = nil)
119
+ # @nodes = [<identifier 1>, <identifier 2>, ... ]
120
+ super(nil)
121
+ end
122
+
123
+ def add_identifier(node)
124
+ @nodes << node
125
+ end
126
+ end
127
+
128
+ class ConditionalNode < ListNode
129
+ def initialize(_ = nil)
130
+ # @nodes = [<test>, <consequent>] or
131
+ # [<test>, <consequent>, <alternate>]
132
+ super(1)
133
+ end
134
+
135
+ def test
136
+ @nodes[0]
137
+ end
138
+
139
+ def test=(node)
140
+ @nodes[0] = node
141
+ end
142
+
143
+ def consequent
144
+ @nodes[1]
145
+ end
146
+
147
+ def consequent=(node)
148
+ @nodes[1] = node
149
+ end
150
+
151
+ def alternate
152
+ @nodes[2]
153
+ end
154
+
155
+ def alternate=(node)
156
+ @nodes[2] = node
157
+ end
158
+
159
+ def alternate?
160
+ !@nodes[2].nil?
161
+ end
162
+ end
163
+
164
+ class AssignmentNode < ListNode
165
+ def initialize(_ = nil)
166
+ # @nodes = [<identifier>, <expression>]
167
+ super(2)
168
+ end
169
+
170
+ def identifier
171
+ @nodes[0]
172
+ end
173
+
174
+ def identifier=(node)
175
+ @nodes[0] = node
176
+ end
177
+
178
+ def expression
179
+ @nodes[1]
180
+ end
181
+
182
+ def expression=(node)
183
+ @nodes[1] = node
184
+ end
185
+ end
186
+
187
+ class IdentifierDefinitionNode < ListNode
188
+ def initialize(_ = nil)
189
+ # @nodes = [<identifier>, <expression>]
190
+ # <expression> might be a lambda expression.
191
+ super(2)
192
+ end
193
+
194
+ def identifier
195
+ @nodes[0]
196
+ end
197
+
198
+ def identifier=(node)
199
+ @nodes[0] = node
200
+ end
201
+
202
+ def expression
203
+ @nodes[1]
204
+ end
205
+
206
+ def expression=(node)
207
+ @nodes[1] = node
208
+ end
209
+
210
+ def def_formals
211
+ lambda? ? expression.formals : nil
212
+ end
213
+
214
+ def body
215
+ lambda? ? expression.body : nil
216
+ end
217
+
218
+ private
219
+
220
+ def lambda?
221
+ expression.type == :ast_lambda_expression
222
+ end
223
+ end
224
+
225
+ class CondNode < ListNode
226
+ def initialize(_ = nil)
227
+ super(nil)
228
+ end
229
+
230
+ def cond_clause
231
+ @nodes[0..-1]
232
+ end
233
+
234
+ def add_clause(node)
235
+ @nodes << node
236
+ end
237
+ end
238
+
239
+ class CondClauseNode < ListNode
240
+ # @nodes = [<test>, <sequence>]
241
+ def initialize(_ = nil)
242
+ super(nil)
243
+ end
244
+
245
+ def test
246
+ @nodes[0]
247
+ end
248
+
249
+ def test=(node)
250
+ @nodes[0] = node
251
+ end
252
+
253
+ def sequence
254
+ @nodes[1..-1]
255
+ end
256
+
257
+ def add_expression(node)
258
+ @nodes << node
259
+ end
260
+ end
261
+
262
+ class AndNode < ListNode
263
+ def initialize(_ = nil)
264
+ # @nodes = [<test>, ...]
265
+ super(nil)
266
+ end
267
+ end
268
+
269
+ class OrNode < ListNode
270
+ def initialize(_ = nil)
271
+ # @nodes = [<test>, ...]
272
+ super(nil)
273
+ end
274
+ end
275
+
276
+ class TestAndSequenceNode < ListNode
277
+ def initialize(_ = nil)
278
+ super(1)
279
+ end
280
+
281
+ def test
282
+ @nodes[0]
283
+ end
284
+
285
+ def test=(node)
286
+ @nodes[0] = node
287
+ end
288
+
289
+ def sequence
290
+ @nodes[1..-1]
291
+ end
292
+
293
+ def add_sequence(node)
294
+ @nodes << node
295
+ end
296
+ end
297
+
298
+ class WhenNode < TestAndSequenceNode
299
+ end
300
+
301
+ class UnlessNode < TestAndSequenceNode
302
+ end
303
+
304
+ class LetNode < ListNode
305
+ def initialize(_ = nil)
306
+ # @nodes = [<bindings>, <body>, ...] or
307
+ # [<identifier>, <bindings>, <body>, ...]
308
+ super(1)
309
+ end
310
+
311
+ def identifier
312
+ named_let? ? @nodes[0] : nil
313
+ end
314
+
315
+ def identifier=(node)
316
+ @nodes.insert(0, node) if node.type == :ast_identifier
317
+ end
318
+
319
+ def bindings
320
+ named_let? ? @nodes[1] : @nodes[0]
321
+ end
322
+
323
+ def bindings=(node)
324
+ if named_let?
325
+ @nodes[1] = node
326
+ else
327
+ @nodes[0] = node
328
+ end
329
+ end
330
+
331
+ def body
332
+ named_let? ? @nodes[2..-1] : @nodes[1..-1]
333
+ end
334
+
335
+ def body=(nodes)
336
+ start_pos = named_let? ? 2 : 1
337
+ nodes.each_with_index { |node, i|
338
+ @nodes[start_pos + i] = node
339
+ }
340
+ end
341
+
342
+ private
343
+
344
+ def named_let?
345
+ @nodes[0].nil? ? false : @nodes[0].type == :ast_identifier
346
+ end
347
+ end
348
+
349
+ class LetBaseNode < ListNode
350
+ def initialize(_ = nil)
351
+ # @nodes = [<bindings>, <body>, ...]
352
+ super(1)
353
+ end
354
+
355
+ def bindings
356
+ @nodes[0]
357
+ end
358
+
359
+ def bindings=(node)
360
+ @nodes[0] = node
361
+ end
362
+
363
+ def body
364
+ @nodes[1..-1]
365
+ end
366
+
367
+ def body=(nodes)
368
+ nodes.each_with_index { |node, i|
369
+ @nodes[1 + i] = node
370
+ }
371
+ end
372
+ end
373
+
374
+ class LetStarNode < LetBaseNode
375
+ end
376
+
377
+ class LetrecNode < LetBaseNode
378
+ end
379
+
380
+ class LetrecStarNode < LetBaseNode
381
+ end
382
+
383
+ class BindingsNode < ListNode
384
+ def initialize(_ = nil)
385
+ # @nodes = [<bind spec 1>, <bind spec 2> , ...]
386
+ super(nil)
387
+ end
388
+
389
+ def add_bind_spec(node)
390
+ @nodes << node
391
+ end
392
+ end
393
+
394
+ class BindSpecNode < ListNode
395
+ def initialize(_ = nil)
396
+ super(2)
397
+ end
398
+
399
+ def identifier
400
+ @nodes[0]
401
+ end
402
+
403
+ def identifier=(node)
404
+ @nodes[0] = node
405
+ end
406
+
407
+ def expression
408
+ @nodes[1]
409
+ end
410
+
411
+ def expression=(node)
412
+ @nodes[1] = node
413
+ end
414
+ end
415
+
416
+ class BeginNode < ListNode
417
+ def initialize(_ = nil)
418
+ super(nil)
419
+ end
420
+ end
421
+
422
+ class DoNode < ListNode
423
+ def initialize(_ = nil)
424
+ # @nodes = [<iteration bindings>, <test and do result>, <command>, ...]
425
+ super(2)
426
+ end
427
+
428
+ def iteration_bindings
429
+ @nodes[0]
430
+ end
431
+
432
+ def iteration_bindings=(node)
433
+ @nodes[0] = node
434
+ end
435
+
436
+ def test_and_do_result
437
+ @nodes[1]
438
+ end
439
+
440
+ def test_and_do_result=(node)
441
+ @nodes[1] = node
442
+ end
443
+
444
+ def commands
445
+ @nodes[2..-1]
446
+ end
447
+
448
+ def add_command(node)
449
+ @nodes << node
450
+ end
451
+ end
452
+
453
+ class IterationBindingsNode < ListNode
454
+ def initialize(_ = nil)
455
+ super(nil)
456
+ end
457
+
458
+ def add_iteration_spec(node)
459
+ @nodes << node
460
+ end
461
+ end
462
+
463
+ class TestAndDoResultNode < ListNode
464
+ def initialize(_ = nil)
465
+ super(1)
466
+ end
467
+
468
+ def test
469
+ @nodes[0]
470
+ end
471
+
472
+ def test=(node)
473
+ @nodes[0] = node
474
+ end
475
+
476
+ def add_expression(node)
477
+ @nodes << node
478
+ end
479
+ end
480
+
481
+ class IterationSpecNode < ListNode
482
+ def initialize(_ = nil)
483
+ # @nodes = [<identifier>, <init>, <step>]
484
+ super(3)
485
+ end
486
+
487
+ def identifier
488
+ @nodes[0]
489
+ end
490
+
491
+ def identifier=(node)
492
+ @nodes[0] = node
493
+ end
494
+
495
+ def init
496
+ @nodes[1]
497
+ end
498
+
499
+ def init=(node)
500
+ @nodes[1] = node
501
+ end
502
+
503
+ def step
504
+ @nodes[2]
505
+ end
506
+
507
+ def step=(node)
508
+ @nodes[2] = node
509
+ end
510
+ end
511
+
512
+ end # end of AST
513
+
514
+ end