rltk 2.0.0 → 2.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.
- data/README.md +46 -2
- data/Rakefile +10 -1
- data/lib/rltk/ast.rb +48 -3
- data/lib/rltk/cfg.rb +90 -21
- data/lib/rltk/cg/bindings.rb +37 -5
- data/lib/rltk/cg/execution_engine.rb +11 -12
- data/lib/rltk/cg/generated_bindings.rb +2 -8
- data/lib/rltk/cg/generated_extended_bindings.rb +244 -0
- data/lib/rltk/cg/llvm.rb +64 -6
- data/lib/rltk/cg/module.rb +80 -2
- data/lib/rltk/cg/pass_manager.rb +28 -15
- data/lib/rltk/cg/support.rb +2 -0
- data/lib/rltk/cg/target.rb +100 -0
- data/lib/rltk/cg/triple.rb +58 -0
- data/lib/rltk/cg/type.rb +7 -7
- data/lib/rltk/cg/value.rb +25 -1
- data/lib/rltk/cg.rb +1 -1
- data/lib/rltk/parser.rb +91 -43
- data/lib/rltk/util/monkeys.rb +8 -4
- data/lib/rltk/version.rb +1 -1
- data/test/tc_ast.rb +62 -8
- data/test/tc_parser.rb +137 -0
- metadata +4 -2
@@ -0,0 +1,58 @@
|
|
1
|
+
# Author: Chris Wailes <chris.wailes@gmail.com>
|
2
|
+
# Project: Ruby Language Toolkit
|
3
|
+
# Date: 2012/06/13
|
4
|
+
# Description: This file defines the Triple class.
|
5
|
+
|
6
|
+
############
|
7
|
+
# Requires #
|
8
|
+
############
|
9
|
+
|
10
|
+
# Ruby Language Toolkit
|
11
|
+
require 'rltk/cg/bindings'
|
12
|
+
|
13
|
+
#######################
|
14
|
+
# Classes and Modules #
|
15
|
+
#######################
|
16
|
+
|
17
|
+
module RLTK::CG # :nodoc:
|
18
|
+
|
19
|
+
# Class binding for the LLVM Triple class.
|
20
|
+
class Triple
|
21
|
+
include BindingClass
|
22
|
+
|
23
|
+
#################
|
24
|
+
# Class Methods #
|
25
|
+
#################
|
26
|
+
|
27
|
+
# @return [Triple] Object representing the host architecture, vendor, OS, and environment.
|
28
|
+
def self.host
|
29
|
+
@host ||= self.new(Bindings.get_host_triple)
|
30
|
+
end
|
31
|
+
|
32
|
+
# @return [String] String representation of the host architecture, vendor, OS, and environment.
|
33
|
+
def self.host_string
|
34
|
+
@host_string ||= Bindings.get_host_triple_string
|
35
|
+
end
|
36
|
+
|
37
|
+
####################
|
38
|
+
# Instance Methods #
|
39
|
+
####################
|
40
|
+
|
41
|
+
# Create a new triple describing the host architecture, vendor, OS,
|
42
|
+
# and (optionally) environment.
|
43
|
+
#
|
44
|
+
# @param [FFI::Pointer, String] overloaded
|
45
|
+
def initialize(overloaded)
|
46
|
+
@ptr =
|
47
|
+
case overloaded
|
48
|
+
when FFI::Pointer then overloaded
|
49
|
+
when String then Bindings.triple_create(overloaded)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# @return [String] String representation of this triple.
|
54
|
+
def to_s
|
55
|
+
Bindings.get_triple_string(@ptr)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
data/lib/rltk/cg/type.rb
CHANGED
@@ -442,7 +442,7 @@ end
|
|
442
442
|
# @param [String] blame Variable name to blame for failed type checks.
|
443
443
|
# @param [Boolean] strict Strict or non-strict checking. Uses `instance_of?` and `is_a?` respectively.
|
444
444
|
#
|
445
|
-
# @raise [
|
445
|
+
# @raise [ArgumentError] An error is raise if a class is passed in parameter *o*
|
446
446
|
# that hasn't included the Singleton class, if the class passed in parameter
|
447
447
|
# *type* isn't a sub-class of {RLTK::CG::Type Type}, or if the type check
|
448
448
|
# fails.
|
@@ -456,10 +456,10 @@ def check_cg_type(o, type = RLTK::CG::Type, blame = 'type', strict = false)
|
|
456
456
|
if o.includes_module?(Singleton)
|
457
457
|
o.instance
|
458
458
|
else
|
459
|
-
raise "The #{o.name} class (passed as parameter #{blame}) must be instantiated directly."
|
459
|
+
raise ArgumentError, "The #{o.name} class (passed as parameter #{blame}) must be instantiated directly."
|
460
460
|
end
|
461
461
|
else
|
462
|
-
raise "The #{o.name} class (passed as parameter #{blame} does not inherit from the #{type.name} class."
|
462
|
+
raise ArgumentError, "The #{o.name} class (passed as parameter #{blame} does not inherit from the #{type.name} class."
|
463
463
|
end
|
464
464
|
else
|
465
465
|
check_type(o, type, blame, strict)
|
@@ -476,7 +476,7 @@ end
|
|
476
476
|
# @param [String] blame Variable name to blame for failed type checks.
|
477
477
|
# @param [Boolean] strict Strict or non-strict checking. Uses `instance_of?` and `is_a?` respectively.
|
478
478
|
#
|
479
|
-
# @raise [
|
479
|
+
# @raise [ArgumentError] An error is raise if a class is passed in *array* that
|
480
480
|
# hasn't included the Singleton class, if the class passed in parameter
|
481
481
|
# *type* isn't a sub-class of {RLTK::CG::Type Type}, or if the type check
|
482
482
|
# fails.
|
@@ -491,10 +491,10 @@ def check_cg_array_type(array, type = RLTK::CG::Type, blame = 'el_types', strict
|
|
491
491
|
if o.includes_module?(Singleton)
|
492
492
|
o.instance
|
493
493
|
else
|
494
|
-
raise "The #{o.name} class (passed in parameter #{blame}) must be instantiated directly."
|
494
|
+
raise ArgumentError, "The #{o.name} class (passed in parameter #{blame}) must be instantiated directly."
|
495
495
|
end
|
496
496
|
else
|
497
|
-
raise "The #{o.name} class (passed in parameter #{blame}) does not inherit from the #{type.name} class."
|
497
|
+
raise ArgumentError, "The #{o.name} class (passed in parameter #{blame}) does not inherit from the #{type.name} class."
|
498
498
|
end
|
499
499
|
|
500
500
|
else
|
@@ -503,7 +503,7 @@ def check_cg_array_type(array, type = RLTK::CG::Type, blame = 'el_types', strict
|
|
503
503
|
if type_ok
|
504
504
|
o
|
505
505
|
else
|
506
|
-
raise "Parameter #{blame} must contain instances of the #{type.name} class."
|
506
|
+
raise ArgumentError, "Parameter #{blame} must contain instances of the #{type.name} class."
|
507
507
|
end
|
508
508
|
end
|
509
509
|
end
|
data/lib/rltk/cg/value.rb
CHANGED
@@ -60,7 +60,11 @@ module RLTK::CG # :nodoc:
|
|
60
60
|
Bindings.is_constant(@ptr).to_bool
|
61
61
|
end
|
62
62
|
|
63
|
-
# Print the LLVM IR representation of this value to standard
|
63
|
+
# Print the LLVM IR representation of this value to standard error.
|
64
|
+
# This function is the debugging version of the more general purpose
|
65
|
+
# {#print} method.
|
66
|
+
#
|
67
|
+
# @see #print
|
64
68
|
#
|
65
69
|
# @return [void]
|
66
70
|
def dump
|
@@ -91,6 +95,26 @@ module RLTK::CG # :nodoc:
|
|
91
95
|
Bindings.is_null(@ptr).to_bool
|
92
96
|
end
|
93
97
|
|
98
|
+
# Print the LLVM IR representation of this value to a file. The file
|
99
|
+
# may be specified via a file name (which will be created or
|
100
|
+
# truncated) or an object that responds to #fileno.
|
101
|
+
#
|
102
|
+
# @LLVMECB
|
103
|
+
#
|
104
|
+
# @param [String, #fileno] io File name or object with a file descriptor to print to.
|
105
|
+
#
|
106
|
+
# @return [void]
|
107
|
+
def print(io = $stdout)
|
108
|
+
case io
|
109
|
+
when String
|
110
|
+
File.open(io, 'w') do |f|
|
111
|
+
Bindings.print_value(@ptr, f.fileno)
|
112
|
+
end
|
113
|
+
else
|
114
|
+
Bindings.print_value(@ptr, io.fileno)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
94
118
|
# Truncate a value to a given type.
|
95
119
|
#
|
96
120
|
# @param [Type] type Type to truncate to.
|
data/lib/rltk/cg.rb
CHANGED
@@ -14,7 +14,7 @@ module RLTK # :nodoc:
|
|
14
14
|
# generation functionality is provided by bindings to
|
15
15
|
# [LLVM](http://llvm.org).
|
16
16
|
module CG
|
17
|
-
autoload :
|
17
|
+
autoload :BasicBlock, 'rltk/cg/basic_block'
|
18
18
|
autoload :Bindings, 'rltk/cg/bindings'
|
19
19
|
autoload :Builder, 'rltk/cg/builder'
|
20
20
|
autoload :Context, 'rltk/cg/context'
|
data/lib/rltk/parser.rb
CHANGED
@@ -100,25 +100,41 @@ module RLTK # :nodoc:
|
|
100
100
|
|
101
101
|
@grammar.callback do |p, type, num|
|
102
102
|
@procs[p.id] =
|
103
|
-
[
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
Proc.new {
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
Proc.new { |o
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
Proc.new {
|
120
|
-
|
121
|
-
|
103
|
+
[
|
104
|
+
case type
|
105
|
+
when :*
|
106
|
+
case num
|
107
|
+
when :first then Proc.new { || [] }
|
108
|
+
else Proc.new { |os, o| os << o }
|
109
|
+
end
|
110
|
+
|
111
|
+
when :+
|
112
|
+
case num
|
113
|
+
when :first then Proc.new { |o| [o] }
|
114
|
+
else Proc.new { |os, o| os << o }
|
115
|
+
end
|
116
|
+
|
117
|
+
when :'?'
|
118
|
+
case num
|
119
|
+
when :first then Proc.new { || nil }
|
120
|
+
else Proc.new { |o| o }
|
121
|
+
end
|
122
|
+
|
123
|
+
when :elp
|
124
|
+
case num
|
125
|
+
when :first then Proc.new { || [] }
|
126
|
+
else Proc.new { |prime| prime }
|
127
|
+
end
|
128
|
+
|
129
|
+
when :nelp
|
130
|
+
case num
|
131
|
+
when :first then Proc.new { |el| [el] }
|
132
|
+
when :second then Proc.new { |els, _, el| els + [el] }
|
133
|
+
else Proc.new { |*el| if el.length == 1 then el.first else el end }
|
134
|
+
end
|
135
|
+
end,
|
136
|
+
p.rhs.length
|
137
|
+
]
|
122
138
|
|
123
139
|
@production_precs[p.id] = p.last_terminal
|
124
140
|
end
|
@@ -163,25 +179,41 @@ module RLTK # :nodoc:
|
|
163
179
|
|
164
180
|
@grammar.callback do |p, type, num|
|
165
181
|
@procs[p.id] =
|
166
|
-
[
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
Proc.new { |v|
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
Proc.new { |v|
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
Proc.new { |v|
|
183
|
-
|
184
|
-
|
182
|
+
[
|
183
|
+
case type
|
184
|
+
when :*
|
185
|
+
case num
|
186
|
+
when :first then Proc.new { |v| [] }
|
187
|
+
else Proc.new { |v| v[0] << v[1] }
|
188
|
+
end
|
189
|
+
|
190
|
+
when :+
|
191
|
+
case num
|
192
|
+
when :first then Proc.new { |v| [v[0]] }
|
193
|
+
else Proc.new { |v| v[0] << v[1] }
|
194
|
+
end
|
195
|
+
|
196
|
+
when :'?'
|
197
|
+
case num
|
198
|
+
when :first then Proc.new { |v| nil }
|
199
|
+
else Proc.new { |v| v[0] }
|
200
|
+
end
|
201
|
+
|
202
|
+
when :elp
|
203
|
+
case num
|
204
|
+
when :first then Proc.new { |v| [] }
|
205
|
+
else Proc.new { |v| v[0] }
|
206
|
+
end
|
207
|
+
|
208
|
+
when :nelp
|
209
|
+
case num
|
210
|
+
when :first then Proc.new { |v| v }
|
211
|
+
when :second then Proc.new { |v| v[0] + [v[2]] }
|
212
|
+
else Proc.new { |v| if v.length == 1 then v.first else v end }
|
213
|
+
end
|
214
|
+
end,
|
215
|
+
p.rhs.length
|
216
|
+
]
|
185
217
|
|
186
218
|
@production_precs[p.id] = p.last_terminal
|
187
219
|
end
|
@@ -365,6 +397,14 @@ module RLTK # :nodoc:
|
|
365
397
|
@states.each { |state| state.clean }
|
366
398
|
end
|
367
399
|
|
400
|
+
# Adds productions and actions for parsing empty lists.
|
401
|
+
#
|
402
|
+
# @see CFG#empty_list_production
|
403
|
+
def empty_list_production(symbol, list_elements, separator)
|
404
|
+
@grammar.empty_list(symbol, list_elements, separator)
|
405
|
+
end
|
406
|
+
alias :empty_list :empty_list_production
|
407
|
+
|
368
408
|
# This function will print a description of the parser to the
|
369
409
|
# provided IO object.
|
370
410
|
#
|
@@ -507,7 +547,9 @@ module RLTK # :nodoc:
|
|
507
547
|
opts = build_finalize_opts(opts)
|
508
548
|
|
509
549
|
# Get the name of the file in which the parser is defined.
|
510
|
-
|
550
|
+
#
|
551
|
+
# FIXME: See why this is failing for the simple ListParser example.
|
552
|
+
def_file = caller()[2].split(':')[0] if opts[:use]
|
511
553
|
|
512
554
|
# Check to make sure we can load the necessary information
|
513
555
|
# from the specified object.
|
@@ -725,6 +767,14 @@ module RLTK # :nodoc:
|
|
725
767
|
end
|
726
768
|
end
|
727
769
|
|
770
|
+
# Adds productions and actions for parsing nonempty lists.
|
771
|
+
#
|
772
|
+
# @see CFG#nonempty_list_production
|
773
|
+
def nonempty_list_production(symbol, list_elements, separator)
|
774
|
+
@grammar.nonempty_list(symbol, list_elements, separator)
|
775
|
+
end
|
776
|
+
alias :nonempty_list :nonempty_list_production
|
777
|
+
|
728
778
|
# This function is where actual parsing takes place. The
|
729
779
|
# _tokens_ argument must be an array of Token objects, the last
|
730
780
|
# of which has type EOS. By default this method will return the
|
@@ -772,9 +822,7 @@ module RLTK # :nodoc:
|
|
772
822
|
tokens.each do |token|
|
773
823
|
# Check to make sure this token was seen in the
|
774
824
|
# grammar definition.
|
775
|
-
if not @symbols.include?(token.type)
|
776
|
-
raise BadToken
|
777
|
-
end
|
825
|
+
raise BadToken if not @symbols.include?(token.type)
|
778
826
|
|
779
827
|
v.puts("Current token: #{token.type}#{if token.value then "(#{token.value})" end}") if v
|
780
828
|
|
@@ -1265,7 +1313,7 @@ module RLTK # :nodoc:
|
|
1265
1313
|
@state_stack << state
|
1266
1314
|
@output_stack << o
|
1267
1315
|
@node_stack << @labels.length
|
1268
|
-
@labels << node0
|
1316
|
+
@labels << if CFG::is_terminal?(node0) and o then node0.to_s + "(#{o})" else node0 end
|
1269
1317
|
@positions << position
|
1270
1318
|
|
1271
1319
|
if CFG::is_nonterminal?(node0)
|
data/lib/rltk/util/monkeys.rb
CHANGED
@@ -18,6 +18,8 @@
|
|
18
18
|
# @param [String, nil] blame Variable name to blame for failed type checks.
|
19
19
|
# @param [Boolean] strict Strict or non-strict checking. Uses `instance_of?` and `is_a?` respectively.
|
20
20
|
#
|
21
|
+
# @raise [ArgumentError] An error is raise if the type checking fails.
|
22
|
+
#
|
21
23
|
# @return [Object] The object passed as parameter o.
|
22
24
|
def check_type(o, type, blame = nil, strict = false)
|
23
25
|
type_ok = if strict then o.instance_of?(type) else o.is_a?(type) end
|
@@ -26,9 +28,9 @@ def check_type(o, type, blame = nil, strict = false)
|
|
26
28
|
o
|
27
29
|
else
|
28
30
|
if blame
|
29
|
-
raise "Parameter #{blame} must be an instance of the #{type.name} class. Received an instance of #{o.class.name}."
|
31
|
+
raise ArgumentError, "Parameter #{blame} must be an instance of the #{type.name} class. Received an instance of #{o.class.name}."
|
30
32
|
else
|
31
|
-
raise "Expected an object of type #{type.name}. Received an instance of #{o.class.name}."
|
33
|
+
raise ArgumentError, "Expected an object of type #{type.name}. Received an instance of #{o.class.name}."
|
32
34
|
end
|
33
35
|
end
|
34
36
|
end
|
@@ -40,6 +42,8 @@ end
|
|
40
42
|
# @param [String, nil] blame Variable name to blame for failed type checks.
|
41
43
|
# @param [Boolean] strict Strict or non-strict checking. Uses `instance_of?` and `is_a?` respectively.
|
42
44
|
#
|
45
|
+
# @raise [ArgumentError] An error is raise if the type checking fails.
|
46
|
+
#
|
43
47
|
# @return [Object] The object passed in parameter o.
|
44
48
|
def check_array_type(array, type, blame = nil, strict = false)
|
45
49
|
array.each do |o|
|
@@ -47,9 +51,9 @@ def check_array_type(array, type, blame = nil, strict = false)
|
|
47
51
|
|
48
52
|
if not type_ok
|
49
53
|
if blame
|
50
|
-
raise "Parameter #{blame} must contain instances of the #{type.name} class."
|
54
|
+
raise ArgumentError, "Parameter #{blame} must contain instances of the #{type.name} class."
|
51
55
|
else
|
52
|
-
raise "Expected an object of type #{type.name}."
|
56
|
+
raise ArgumentError, "Expected an object of type #{type.name}."
|
53
57
|
end
|
54
58
|
end
|
55
59
|
end
|
data/lib/rltk/version.rb
CHANGED
data/test/tc_ast.rb
CHANGED
@@ -29,34 +29,88 @@ class ASTNodeTester < Test::Unit::TestCase
|
|
29
29
|
|
30
30
|
class DNode < RLTK::ASTNode; end
|
31
31
|
|
32
|
+
class SNode < RLTK::ASTNode
|
33
|
+
value :string, String
|
34
|
+
|
35
|
+
child :left, SNode
|
36
|
+
child :right, SNode
|
37
|
+
end
|
38
|
+
|
32
39
|
def setup
|
33
|
-
@leaf0 = CNode.new
|
34
|
-
@tree0 = ANode.new(BNode.new(@leaf0
|
40
|
+
@leaf0 = CNode.new
|
41
|
+
@tree0 = ANode.new(BNode.new(@leaf0), BNode.new)
|
42
|
+
|
43
|
+
@tree1 = ANode.new(BNode.new(CNode.new), BNode.new)
|
44
|
+
@tree2 = ANode.new(BNode.new, BNode.new(CNode.new))
|
35
45
|
|
36
|
-
@
|
37
|
-
|
46
|
+
@tree3 = SNode.new('F',
|
47
|
+
SNode.new('B',
|
48
|
+
SNode.new('A'),
|
49
|
+
SNode.new('D',
|
50
|
+
SNode.new('C'),
|
51
|
+
SNode.new('E')
|
52
|
+
),
|
53
|
+
),
|
54
|
+
SNode.new('G',
|
55
|
+
nil,
|
56
|
+
SNode.new('I',
|
57
|
+
SNode.new('H')
|
58
|
+
)
|
59
|
+
)
|
60
|
+
)
|
38
61
|
end
|
39
62
|
|
40
63
|
def test_children
|
41
|
-
node = ANode.new
|
64
|
+
node = ANode.new
|
42
65
|
|
43
66
|
assert_equal(node.children, [nil, nil])
|
44
67
|
|
45
|
-
node.children = (expected_children = [BNode.new
|
68
|
+
node.children = (expected_children = [BNode.new, CNode.new])
|
46
69
|
|
47
70
|
assert_equal(node.children, expected_children)
|
48
71
|
|
49
72
|
node.map do |child|
|
50
73
|
if child.is_a?(BNode)
|
51
|
-
CNode.new
|
74
|
+
CNode.new
|
52
75
|
else
|
53
|
-
BNode.new
|
76
|
+
BNode.new
|
54
77
|
end
|
55
78
|
end
|
56
79
|
|
57
80
|
assert_equal(node.children, expected_children.reverse)
|
58
81
|
end
|
59
82
|
|
83
|
+
def test_dump
|
84
|
+
tree0_string = @tree0.dump
|
85
|
+
|
86
|
+
reloaded_tree = Marshal.load(tree0_string)
|
87
|
+
|
88
|
+
assert_equal(@tree0, reloaded_tree)
|
89
|
+
end
|
90
|
+
|
91
|
+
def test_each
|
92
|
+
# Test pre-order
|
93
|
+
nodes = []
|
94
|
+
expected = ['F', 'B', 'A', 'D', 'C', 'E', 'G', 'I', 'H']
|
95
|
+
@tree3.each(:pre) { |n| nodes << n.string }
|
96
|
+
|
97
|
+
assert_equal(expected, nodes)
|
98
|
+
|
99
|
+
# Test post-order
|
100
|
+
nodes = []
|
101
|
+
expected = ['A', 'C', 'E', 'D', 'B', 'H', 'I', 'G', 'F']
|
102
|
+
@tree3.each(:post) { |n| nodes << n.string }
|
103
|
+
|
104
|
+
assert_equal(expected, nodes)
|
105
|
+
|
106
|
+
# Test level-order
|
107
|
+
nodes = []
|
108
|
+
expected = ['F', 'B', 'G', 'A', 'D', 'I', 'C', 'E', 'H']
|
109
|
+
@tree3.each(:level) { |n| nodes << n.string }
|
110
|
+
|
111
|
+
assert_equal(expected, nodes)
|
112
|
+
end
|
113
|
+
|
60
114
|
def test_equal
|
61
115
|
assert_equal(@tree0, @tree1)
|
62
116
|
assert_not_equal(@tree0, @tree2)
|
data/test/tc_parser.rb
CHANGED
@@ -31,6 +31,14 @@ class ParserTester < Test::Unit::TestCase
|
|
31
31
|
rule(/\s/)
|
32
32
|
end
|
33
33
|
|
34
|
+
class AlphaLexer < RLTK::Lexer
|
35
|
+
rule(/[A-Za-z]/) { |t| [t.upcase.to_sym, t] }
|
36
|
+
|
37
|
+
rule(/,/) { :COMMA }
|
38
|
+
|
39
|
+
rule(/\s/)
|
40
|
+
end
|
41
|
+
|
34
42
|
class APlusBParser < RLTK::Parser
|
35
43
|
production(:a, 'A+ B') { |a, _| a.length }
|
36
44
|
|
@@ -77,6 +85,44 @@ class ParserTester < Test::Unit::TestCase
|
|
77
85
|
finalize
|
78
86
|
end
|
79
87
|
|
88
|
+
class EmptyListParser0 < RLTK::Parser
|
89
|
+
empty_list('list', :A, :COMMA)
|
90
|
+
|
91
|
+
finalize
|
92
|
+
end
|
93
|
+
|
94
|
+
class EmptyListParser1 < RLTK::Parser
|
95
|
+
array_args
|
96
|
+
|
97
|
+
empty_list('list', ['A', 'B', 'C D'], :COMMA)
|
98
|
+
|
99
|
+
finalize
|
100
|
+
end
|
101
|
+
|
102
|
+
class NonEmptyListParser0 < RLTK::Parser
|
103
|
+
nonempty_list('list', :A, :COMMA)
|
104
|
+
|
105
|
+
finalize
|
106
|
+
end
|
107
|
+
|
108
|
+
class NonEmptyListParser1 < RLTK::Parser
|
109
|
+
nonempty_list('list', [:A, :B], :COMMA)
|
110
|
+
|
111
|
+
finalize
|
112
|
+
end
|
113
|
+
|
114
|
+
class NonEmptyListParser2 < RLTK::Parser
|
115
|
+
nonempty_list('list', ['A', 'B', 'C D'], :COMMA)
|
116
|
+
|
117
|
+
finalize
|
118
|
+
end
|
119
|
+
|
120
|
+
class NonEmptyListParser3 < RLTK::Parser
|
121
|
+
nonempty_list('list', 'A+', :COMMA)
|
122
|
+
|
123
|
+
finalize
|
124
|
+
end
|
125
|
+
|
80
126
|
class DummyError1 < StandardError; end
|
81
127
|
class DummyError2 < StandardError; end
|
82
128
|
|
@@ -193,6 +239,24 @@ class ParserTester < Test::Unit::TestCase
|
|
193
239
|
assert_equal(4, AStarBParser.parse(ABLexer.lex('aaaab')))
|
194
240
|
end
|
195
241
|
|
242
|
+
def test_empty_list
|
243
|
+
####################
|
244
|
+
# EmptyListParser0 #
|
245
|
+
####################
|
246
|
+
|
247
|
+
expected = []
|
248
|
+
actual = EmptyListParser0.parse(AlphaLexer.lex(''))
|
249
|
+
assert_equal(expected, actual)
|
250
|
+
|
251
|
+
####################
|
252
|
+
# EmptyListParser1 #
|
253
|
+
####################
|
254
|
+
|
255
|
+
expected = ['a', 'b', ['c', 'd']]
|
256
|
+
actual = EmptyListParser1.parse(AlphaLexer.lex('a, b, c d'))
|
257
|
+
assert_equal(expected, actual)
|
258
|
+
end
|
259
|
+
|
196
260
|
def test_environment
|
197
261
|
actual = RotatingCalc.parse(RLTK::Lexers::Calculator.lex('+ 1 2'))
|
198
262
|
assert_equal(3, actual)
|
@@ -247,6 +311,79 @@ class ParserTester < Test::Unit::TestCase
|
|
247
311
|
assert_raise(RLTK::BadToken) { RLTK::Parsers::InfixCalc.parse(RLTK::Lexers::EBNF.lex('A B C')) }
|
248
312
|
end
|
249
313
|
|
314
|
+
def test_nonempty_list
|
315
|
+
#######################
|
316
|
+
# NonEmptyListParser0 #
|
317
|
+
#######################
|
318
|
+
|
319
|
+
expected = ['a']
|
320
|
+
actual = NonEmptyListParser0.parse(AlphaLexer.lex('a'))
|
321
|
+
assert_equal(expected, actual)
|
322
|
+
|
323
|
+
expected = ['a', 'a']
|
324
|
+
actual = NonEmptyListParser0.parse(AlphaLexer.lex('a, a'))
|
325
|
+
assert_equal(expected, actual)
|
326
|
+
|
327
|
+
assert_raise(RLTK::NotInLanguage) { NonEmptyListParser0.parse(AlphaLexer.lex('')) }
|
328
|
+
assert_raise(RLTK::NotInLanguage) { NonEmptyListParser0.parse(AlphaLexer.lex(',')) }
|
329
|
+
assert_raise(RLTK::NotInLanguage) { NonEmptyListParser0.parse(AlphaLexer.lex('aa')) }
|
330
|
+
assert_raise(RLTK::NotInLanguage) { NonEmptyListParser0.parse(AlphaLexer.lex('a,')) }
|
331
|
+
assert_raise(RLTK::NotInLanguage) { NonEmptyListParser0.parse(AlphaLexer.lex(',a')) }
|
332
|
+
|
333
|
+
#######################
|
334
|
+
# NonEmptyListParser1 #
|
335
|
+
#######################
|
336
|
+
|
337
|
+
expected = ['a']
|
338
|
+
actual = NonEmptyListParser1.parse(AlphaLexer.lex('a'))
|
339
|
+
assert_equal(expected, actual)
|
340
|
+
|
341
|
+
expected = ['b']
|
342
|
+
actual = NonEmptyListParser1.parse(AlphaLexer.lex('b'))
|
343
|
+
assert_equal(expected, actual)
|
344
|
+
|
345
|
+
expected = ['a', 'b', 'a', 'b']
|
346
|
+
actual = NonEmptyListParser1.parse(AlphaLexer.lex('a, b, a, b'))
|
347
|
+
assert_equal(expected, actual)
|
348
|
+
|
349
|
+
assert_raise(RLTK::NotInLanguage) { NonEmptyListParser1.parse(AlphaLexer.lex('a b')) }
|
350
|
+
|
351
|
+
#######################
|
352
|
+
# NonEmptyListParser2 #
|
353
|
+
#######################
|
354
|
+
|
355
|
+
expected = ['a']
|
356
|
+
actual = NonEmptyListParser2.parse(AlphaLexer.lex('a'))
|
357
|
+
assert_equal(expected, actual)
|
358
|
+
|
359
|
+
expected = ['b']
|
360
|
+
actual = NonEmptyListParser2.parse(AlphaLexer.lex('b'))
|
361
|
+
assert_equal(expected, actual)
|
362
|
+
|
363
|
+
expected = [['c', 'd']]
|
364
|
+
actual = NonEmptyListParser2.parse(AlphaLexer.lex('c d'))
|
365
|
+
assert_equal(expected, actual)
|
366
|
+
|
367
|
+
expected = [['c', 'd'], ['c', 'd']]
|
368
|
+
actual = NonEmptyListParser2.parse(AlphaLexer.lex('c d, c d'))
|
369
|
+
assert_equal(expected, actual)
|
370
|
+
|
371
|
+
expected = ['a', 'b', ['c', 'd']]
|
372
|
+
actual = NonEmptyListParser2.parse(AlphaLexer.lex('a, b, c d'))
|
373
|
+
assert_equal(expected, actual)
|
374
|
+
|
375
|
+
assert_raise(RLTK::NotInLanguage) { NonEmptyListParser2.parse(AlphaLexer.lex('c')) }
|
376
|
+
assert_raise(RLTK::NotInLanguage) { NonEmptyListParser2.parse(AlphaLexer.lex('d')) }
|
377
|
+
|
378
|
+
#######################
|
379
|
+
# NonEmptyListParser3 #
|
380
|
+
#######################
|
381
|
+
|
382
|
+
expected = [['a'], ['a', 'a'], ['a', 'a', 'a']]
|
383
|
+
actual = NonEmptyListParser3.parse(AlphaLexer.lex('a, aa, aaa'))
|
384
|
+
assert_equal(expected, actual)
|
385
|
+
end
|
386
|
+
|
250
387
|
def test_postfix_calc
|
251
388
|
actual = RLTK::Parsers::PostfixCalc.parse(RLTK::Lexers::Calculator.lex('1 2 +'))
|
252
389
|
assert_equal(3, actual)
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rltk
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.1.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-08-01 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: ffi
|
@@ -192,6 +192,8 @@ files:
|
|
192
192
|
- lib/rltk/cg/value.rb
|
193
193
|
- lib/rltk/cg/bindings.rb
|
194
194
|
- lib/rltk/cg/llvm.rb
|
195
|
+
- lib/rltk/cg/target.rb
|
196
|
+
- lib/rltk/cg/triple.rb
|
195
197
|
- lib/rltk/cg/generated_bindings.rb
|
196
198
|
- lib/rltk/parsers/postfix_calc.rb
|
197
199
|
- lib/rltk/parsers/infix_calc.rb
|