rparsec-ruby19 1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/rparsec.rb +3 -0
- data/rparsec/context.rb +83 -0
- data/rparsec/error.rb +28 -0
- data/rparsec/expressions.rb +184 -0
- data/rparsec/functors.rb +274 -0
- data/rparsec/id_monad.rb +17 -0
- data/rparsec/keywords.rb +114 -0
- data/rparsec/locator.rb +40 -0
- data/rparsec/misc.rb +130 -0
- data/rparsec/monad.rb +62 -0
- data/rparsec/operators.rb +103 -0
- data/rparsec/parser.rb +894 -0
- data/rparsec/parser_monad.rb +23 -0
- data/rparsec/parsers.rb +623 -0
- data/rparsec/token.rb +43 -0
- data/test/src/expression_test.rb +124 -0
- data/test/src/full_parser_test.rb +95 -0
- data/test/src/functor_test.rb +66 -0
- data/test/src/import.rb +5 -0
- data/test/src/keyword_test.rb +28 -0
- data/test/src/operator_test.rb +21 -0
- data/test/src/parser_test.rb +53 -0
- data/test/src/perf_benchmark.rb +25 -0
- data/test/src/s_expression_test.rb +33 -0
- data/test/src/scratch.rb +41 -0
- data/test/src/simple_monad_test.rb +22 -0
- data/test/src/simple_parser_test.rb +423 -0
- data/test/src/sql.rb +268 -0
- data/test/src/sql_parser.rb +258 -0
- data/test/src/sql_test.rb +128 -0
- data/test/src/tests.rb +13 -0
- metadata +95 -0
data/test/src/sql.rb
ADDED
@@ -0,0 +1,268 @@
|
|
1
|
+
require 'import'
|
2
|
+
import :misc
|
3
|
+
|
4
|
+
include RParsec
|
5
|
+
class Module
|
6
|
+
include DefHelper
|
7
|
+
end
|
8
|
+
class Expr
|
9
|
+
def self.binary(*ops)
|
10
|
+
ops.each do |op|
|
11
|
+
define_method(op) do |other|
|
12
|
+
BinaryExpr.new(self, op, other)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
binary :+,:-,:*,:/,:%
|
17
|
+
def -@
|
18
|
+
PrefixExpr.new(:-, self)
|
19
|
+
end
|
20
|
+
def self.compare(*ops)
|
21
|
+
ops.each do |op|
|
22
|
+
define_method(op) do |other|
|
23
|
+
ComparePredicate.new(self, op, other)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
compare :'==', :'>', :'<', :'>=', :'<='
|
28
|
+
end
|
29
|
+
class LiteralExpr < Expr
|
30
|
+
def_readable :lit
|
31
|
+
def to_s
|
32
|
+
@lit.to_s
|
33
|
+
end
|
34
|
+
end
|
35
|
+
class VarExpr < Expr
|
36
|
+
def_readable :name
|
37
|
+
def to_s
|
38
|
+
"$#{name}"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
class WordExpr < Expr
|
42
|
+
def_readable :name
|
43
|
+
def to_s
|
44
|
+
name
|
45
|
+
end
|
46
|
+
end
|
47
|
+
class QualifiedColumnExpr < Expr
|
48
|
+
def_readable :owner, :col
|
49
|
+
def to_s
|
50
|
+
"#{owner}.#{col}"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
class WildcardExpr < Expr
|
54
|
+
Instance = WildcardExpr.new
|
55
|
+
def to_s
|
56
|
+
'*'
|
57
|
+
end
|
58
|
+
end
|
59
|
+
class BinaryExpr < Expr
|
60
|
+
def_readable :left, :op, :right
|
61
|
+
def to_s
|
62
|
+
"(#{left} #{op} #{right})"
|
63
|
+
end
|
64
|
+
end
|
65
|
+
class PostfixExpr < Expr
|
66
|
+
def_readable :expr, :op
|
67
|
+
def to_s
|
68
|
+
"(#{expr} #{op})"
|
69
|
+
end
|
70
|
+
end
|
71
|
+
class PrefixExpr < Expr
|
72
|
+
def_readable :op, :expr
|
73
|
+
def to_s
|
74
|
+
"(#{op} #{expr})"
|
75
|
+
end
|
76
|
+
end
|
77
|
+
def cases_string cases, default, result
|
78
|
+
cases.each do |cond, val|
|
79
|
+
result << " when #{cond}: #{val}"
|
80
|
+
end
|
81
|
+
unless default.nil?
|
82
|
+
result << " else #{default}"
|
83
|
+
end
|
84
|
+
result << " end"
|
85
|
+
result
|
86
|
+
end
|
87
|
+
class SimpleCaseExpr < Expr
|
88
|
+
def_readable :expr, :cases, :default
|
89
|
+
def to_s
|
90
|
+
cases_string cases, default, "case #{expr}"
|
91
|
+
end
|
92
|
+
end
|
93
|
+
class CaseExpr < Expr
|
94
|
+
def_readable :cases, :default
|
95
|
+
def to_s
|
96
|
+
cases_string cases, default, 'case'
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
|
101
|
+
############Predicate########################
|
102
|
+
class Predicate
|
103
|
+
end
|
104
|
+
|
105
|
+
class ComparePredicate < Predicate
|
106
|
+
def_readable :left, :op, :right
|
107
|
+
def to_s
|
108
|
+
"#{left} #{op_name} #{right}"
|
109
|
+
end
|
110
|
+
def op_name
|
111
|
+
case op when :"!=": "<>" else op.to_s end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
class CompoundPredicate < Predicate
|
115
|
+
def_readable :left, :op, :right
|
116
|
+
def to_s
|
117
|
+
"(#{left} #{op} #{right})"
|
118
|
+
end
|
119
|
+
end
|
120
|
+
class NotPredicate < Predicate
|
121
|
+
def_readable :predicate
|
122
|
+
def to_s
|
123
|
+
"(not #{predicate})"
|
124
|
+
end
|
125
|
+
end
|
126
|
+
class ExistsPredicate < Predicate
|
127
|
+
def_readable :relation
|
128
|
+
def to_s
|
129
|
+
"exists(#{relation})"
|
130
|
+
end
|
131
|
+
end
|
132
|
+
class NotExistsPredicate < Predicate
|
133
|
+
def_readable :relation
|
134
|
+
def to_s
|
135
|
+
"not exists(#{relation})"
|
136
|
+
end
|
137
|
+
end
|
138
|
+
class InRelationPredicate < Predicate
|
139
|
+
def_readable :expr, :relation
|
140
|
+
def to_s
|
141
|
+
"#{expr} in (#{relation})"
|
142
|
+
end
|
143
|
+
end
|
144
|
+
class NotInRelationPredicate < Predicate
|
145
|
+
def_readable :expr, :relation
|
146
|
+
def to_s
|
147
|
+
"#{expr} not in (#{relation})"
|
148
|
+
end
|
149
|
+
end
|
150
|
+
class InPredicate < Predicate
|
151
|
+
def_readable :expr, :vals
|
152
|
+
def to_s
|
153
|
+
"#{expr} in (#{vals.join(', ')})"
|
154
|
+
end
|
155
|
+
end
|
156
|
+
class NotInPredicate < Predicate
|
157
|
+
def_readable :expr, :vals
|
158
|
+
def to_s
|
159
|
+
"#{expr} not in (#{vals.join(', ')})"
|
160
|
+
end
|
161
|
+
end
|
162
|
+
class BetweenPredicate < Predicate
|
163
|
+
def_readable :expr, :from, :to
|
164
|
+
def to_s
|
165
|
+
"#{expr} between #{from} and #{to}"
|
166
|
+
end
|
167
|
+
end
|
168
|
+
class NotBetweenPredicate < Predicate
|
169
|
+
def_readable :expr, :from, :to
|
170
|
+
def to_s
|
171
|
+
"#{expr} not between #{from} and #{to}"
|
172
|
+
end
|
173
|
+
end
|
174
|
+
class GroupComparisonPredicate < Predicate
|
175
|
+
def_readable :group1, :op, :group2
|
176
|
+
def to_s
|
177
|
+
"#{list_exprs group1} #{op} #{list_exprs group2}"
|
178
|
+
end
|
179
|
+
def list_exprs exprs
|
180
|
+
"(#{exprs.join(', ')})"
|
181
|
+
end
|
182
|
+
end
|
183
|
+
#############Relations######################
|
184
|
+
|
185
|
+
class OrderElement
|
186
|
+
def_readable :expr, :asc
|
187
|
+
def to_s
|
188
|
+
result = "#{expr}"
|
189
|
+
unless asc
|
190
|
+
result << ' desc'
|
191
|
+
end
|
192
|
+
result
|
193
|
+
end
|
194
|
+
end
|
195
|
+
class GroupByClause
|
196
|
+
def_readable :exprs, :having
|
197
|
+
def to_s
|
198
|
+
result = exprs.join(', ')
|
199
|
+
unless having.nil?
|
200
|
+
result << " having #{having}"
|
201
|
+
end
|
202
|
+
result
|
203
|
+
end
|
204
|
+
end
|
205
|
+
class Relation
|
206
|
+
def as_inner
|
207
|
+
to_s
|
208
|
+
end
|
209
|
+
end
|
210
|
+
class TableRelation < Relation
|
211
|
+
def_readable :table
|
212
|
+
def to_s
|
213
|
+
table
|
214
|
+
end
|
215
|
+
end
|
216
|
+
class SelectRelation < Relation
|
217
|
+
def_readable :select, :distinct, :from, :where, :groupby, :orderby
|
218
|
+
def to_s
|
219
|
+
result = "select "
|
220
|
+
if distinct
|
221
|
+
result << 'distinct '
|
222
|
+
end
|
223
|
+
result << "#{select.join(', ')} from #{from.as_inner}"
|
224
|
+
unless where.nil?
|
225
|
+
result << " where #{where}"
|
226
|
+
end
|
227
|
+
unless groupby.nil?
|
228
|
+
result << " group by #{groupby}"
|
229
|
+
end
|
230
|
+
unless orderby.nil?
|
231
|
+
result << " order by #{orderby.join(', ')}"
|
232
|
+
end
|
233
|
+
result
|
234
|
+
end
|
235
|
+
def as_inner
|
236
|
+
"(#{self})"
|
237
|
+
end
|
238
|
+
end
|
239
|
+
class LimitRelation < Relation
|
240
|
+
def_readable :rel, :limit
|
241
|
+
def to_s
|
242
|
+
"#{rel} limit #{limit}"
|
243
|
+
end
|
244
|
+
end
|
245
|
+
class JoinRelation < Relation
|
246
|
+
def_readable :kind, :left, :right, :on
|
247
|
+
def to_s
|
248
|
+
"#{left} #{kind} join #{right} on #{on}"
|
249
|
+
end
|
250
|
+
end
|
251
|
+
class CrossJoinRelation < Relation
|
252
|
+
def_readable :left, :right
|
253
|
+
def to_s
|
254
|
+
"#{left} cross join #{right}"
|
255
|
+
end
|
256
|
+
end
|
257
|
+
class AliasRelation < Relation
|
258
|
+
def_readable :relation, :name
|
259
|
+
def to_s
|
260
|
+
"#{relation.as_inner} AS #{name}"
|
261
|
+
end
|
262
|
+
end
|
263
|
+
class UnionRelation < Relation
|
264
|
+
def_readable :left, :all, :right
|
265
|
+
def to_s
|
266
|
+
"#{left} union #{case when all: 'all ' else '' end}#{right}"
|
267
|
+
end
|
268
|
+
end
|
@@ -0,0 +1,258 @@
|
|
1
|
+
require 'import'
|
2
|
+
import :parsers, :keywords, :operators, :functors, :expressions
|
3
|
+
|
4
|
+
include RParsec
|
5
|
+
|
6
|
+
class Method
|
7
|
+
include FunctorMixin
|
8
|
+
end
|
9
|
+
class Proc
|
10
|
+
include FunctorMixin
|
11
|
+
end
|
12
|
+
module SqlParser
|
13
|
+
include Functors
|
14
|
+
include Parsers
|
15
|
+
extend Parsers
|
16
|
+
MyKeywords = Keywords.case_insensitive(%w{
|
17
|
+
select from where group by having order desc asc
|
18
|
+
inner left right full outer inner join on cross
|
19
|
+
union all distinct as exists in between limit
|
20
|
+
case when else end and or not true false
|
21
|
+
})
|
22
|
+
MyOperators = Operators.new(%w{+ - * / % = > < >= <= <> != : ( ) . ,})
|
23
|
+
def self.operators(*ops)
|
24
|
+
result = []
|
25
|
+
ops.each do |op|
|
26
|
+
result << (MyOperators[op] >> op.to_sym)
|
27
|
+
end
|
28
|
+
sum(*result)
|
29
|
+
end
|
30
|
+
Comparators = operators(*%w{= > < >= <= <> !=})
|
31
|
+
StringLiteral = (char(?') >> (not_char(?')|str("''")).many_.fragment << char(?')).
|
32
|
+
map do |raw|
|
33
|
+
raw.gsub!(/''/,"'")
|
34
|
+
end
|
35
|
+
QuotedName = char(?[) >> not_char(?]).many_.fragment << char(?])
|
36
|
+
Variable = char(?$) >> word
|
37
|
+
MyLexer = number.token(:number) | StringLiteral.token(:string) | Variable.token(:var) | QuotedName.token(:word) |
|
38
|
+
MyKeywords.lexer | MyOperators.lexer
|
39
|
+
MyLexeme = MyLexer.lexeme(whitespaces | comment_line('#')) << eof
|
40
|
+
|
41
|
+
|
42
|
+
######################################### utilities #########################################
|
43
|
+
def keyword
|
44
|
+
MyKeywords
|
45
|
+
end
|
46
|
+
def operator
|
47
|
+
MyOperators
|
48
|
+
end
|
49
|
+
def comma
|
50
|
+
operator[',']
|
51
|
+
end
|
52
|
+
def list expr
|
53
|
+
paren(expr.delimited(comma))
|
54
|
+
end
|
55
|
+
def word(&block)
|
56
|
+
if block.nil?
|
57
|
+
token(:word, &Id)
|
58
|
+
else
|
59
|
+
token(:word, &block)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
def paren parser
|
63
|
+
operator['('] >> parser << operator[')']
|
64
|
+
end
|
65
|
+
def ctor cls
|
66
|
+
cls.method :new
|
67
|
+
end
|
68
|
+
def rctor cls, arity=2
|
69
|
+
ctor(cls).reverse_curry arity
|
70
|
+
end
|
71
|
+
################################### predicate parser #############################
|
72
|
+
def logical_operator op
|
73
|
+
proc{|a,b|CompoundPredicate.new(a,op,b)}
|
74
|
+
end
|
75
|
+
def make_predicate expr, rel
|
76
|
+
expr_list = list expr
|
77
|
+
comparison = make_comparison_predicate expr, rel
|
78
|
+
group_comparison = sequence(expr_list, Comparators, expr_list, &ctor(GroupComparisonPredicate))
|
79
|
+
bool = nil
|
80
|
+
lazy_bool = lazy{bool}
|
81
|
+
bool_term = keyword[:true] >> true | keyword[:false] >> false |
|
82
|
+
comparison | group_comparison | paren(lazy_bool) |
|
83
|
+
make_exists(rel) | make_not_exists(rel)
|
84
|
+
bool_table = OperatorTable.new.
|
85
|
+
infixl(keyword[:or] >> logical_operator(:or), 20).
|
86
|
+
infixl(keyword[:and] >> logical_operator(:and), 30).
|
87
|
+
prefix(keyword[:not] >> ctor(NotPredicate), 40)
|
88
|
+
bool = Expressions.build(bool_term, bool_table)
|
89
|
+
end
|
90
|
+
def make_exists rel
|
91
|
+
keyword[:exists] >> rel.map(&ctor(ExistsPredicate))
|
92
|
+
end
|
93
|
+
def make_not_exists rel
|
94
|
+
keyword[:not] >> keyword[:exists] >> rel.map(&ctor(NotExistsPredicate))
|
95
|
+
end
|
96
|
+
def make_in expr
|
97
|
+
keyword[:in] >> list(expr) >> map(&rctor(InPredicate))
|
98
|
+
end
|
99
|
+
def make_not_in expr
|
100
|
+
keyword[:not] >> keyword[:in] >> list(expr) >> map(&rctor(NotInPredicate))
|
101
|
+
end
|
102
|
+
def make_in_relation rel
|
103
|
+
keyword[:in] >> rel.map(&rctor(InRelationPredicate))
|
104
|
+
end
|
105
|
+
def make_not_in_relation rel
|
106
|
+
keyword[:not] >> keyword[:in] >> rel.map(&rctor(NotInRelationPredicate))
|
107
|
+
end
|
108
|
+
def make_between expr
|
109
|
+
make_between_clause(expr, &ctor(BetweenPredicate))
|
110
|
+
end
|
111
|
+
def make_not_between expr
|
112
|
+
keyword[:not] >> make_between_clause(expr, &ctor(NotBetweenPredicate))
|
113
|
+
end
|
114
|
+
def make_comparison_predicate expr, rel
|
115
|
+
comparison = sequence(Comparators, expr) do |op,e2|
|
116
|
+
proc{|e1|ComparePredicate.new(e1, op, e2)}
|
117
|
+
end
|
118
|
+
in_clause = make_in expr
|
119
|
+
not_in_clause = make_not_in expr
|
120
|
+
in_relation = make_in_relation rel
|
121
|
+
not_in_relation = make_not_in_relation rel
|
122
|
+
between = make_between expr
|
123
|
+
not_between = make_not_between expr
|
124
|
+
compare_with = comparison | in_clause | not_in_clause |
|
125
|
+
in_relation | not_in_relation | between | not_between
|
126
|
+
sequence(expr, compare_with, &Feed)
|
127
|
+
end
|
128
|
+
def make_between_clause expr, &maker
|
129
|
+
factory = proc do |a,_,b|
|
130
|
+
proc {|v|maker.call(v,a,b)}
|
131
|
+
end
|
132
|
+
variant1 = keyword[:between] >> paren(sequence(expr, comma, expr, &factory))
|
133
|
+
variant2 = keyword[:between] >> sequence(expr, keyword[:and], expr, &factory)
|
134
|
+
variant1 | variant2
|
135
|
+
end
|
136
|
+
|
137
|
+
################################ expression parser ###############################
|
138
|
+
def calculate_simple_cases(val, cases, default)
|
139
|
+
SimpleCaseExpr.new(val, cases, default)
|
140
|
+
end
|
141
|
+
def calculate_full_cases(cases, default)
|
142
|
+
CaseExpr.new(cases, default)
|
143
|
+
end
|
144
|
+
def make_expression predicate, rel
|
145
|
+
expr = nil
|
146
|
+
lazy_expr = lazy{expr}
|
147
|
+
simple_case = sequence(keyword[:when], lazy_expr, operator[':'], lazy_expr) do |_,cond,_,val|
|
148
|
+
[cond, val]
|
149
|
+
end
|
150
|
+
full_case = sequence(keyword[:when], predicate, operator[':'], lazy_expr) do |_,cond,_,val|
|
151
|
+
[cond, val]
|
152
|
+
end
|
153
|
+
default_case = (keyword[:else] >> lazy_expr).optional
|
154
|
+
simple_when_then = sequence(lazy_expr, simple_case.many, default_case,
|
155
|
+
keyword[:end]) do |val, cases, default, _|
|
156
|
+
calculate_simple_cases(val, cases, default)
|
157
|
+
end
|
158
|
+
full_when_then = sequence(full_case.many, default_case, keyword[:end]) do |cases, default, _|
|
159
|
+
calculate_full_cases(cases, default)
|
160
|
+
end
|
161
|
+
case_expr = keyword[:case] >> (simple_when_then | full_when_then)
|
162
|
+
wildcard = operator[:*] >> WildcardExpr::Instance
|
163
|
+
lit = token(:number, :string, &ctor(LiteralExpr)) | token(:var, &ctor(VarExpr))
|
164
|
+
atom = lit | wildcard |
|
165
|
+
sequence(word, operator['.'], word|wildcard) {|owner, _, col| QualifiedColumnExpr.new owner, col} |
|
166
|
+
word(&ctor(WordExpr))
|
167
|
+
term = atom | (operator['('] >> lazy_expr << operator[')']) | case_expr
|
168
|
+
table = OperatorTable.new.
|
169
|
+
infixl(operator['+'] >> Plus, 20).
|
170
|
+
infixl(operator['-'] >> Minus, 20).
|
171
|
+
infixl(operator['*'] >> Mul, 30).
|
172
|
+
infixl(operator['/'] >> Div, 30).
|
173
|
+
infixl(operator['%'] >> Mod, 30).
|
174
|
+
prefix(operator['-'] >> Neg, 50)
|
175
|
+
expr = Expressions.build(term, table)
|
176
|
+
end
|
177
|
+
|
178
|
+
################################ relation parser ###############################
|
179
|
+
def make_relation expr, pred
|
180
|
+
exprs = expr.delimited1(comma)
|
181
|
+
relation = nil
|
182
|
+
lazy_relation = lazy{relation}
|
183
|
+
term_relation = word {|w|TableRelation.new w} | operator['('] >> lazy_relation << operator[')']
|
184
|
+
sub_relation = sequence(term_relation, (keyword[:as].optional >> word).optional) do |rel, name|
|
185
|
+
case when name.nil?: rel else AliasRelation.new(rel, name) end
|
186
|
+
end
|
187
|
+
joined_relation = sub_relation.postfix(join_maker(lazy{joined_relation}, pred))
|
188
|
+
where_clause = keyword[:where] >> pred
|
189
|
+
order_element = sequence(expr, (keyword[:asc] >> true | keyword[:desc] >> false).optional(true),
|
190
|
+
&ctor(OrderElement))
|
191
|
+
order_elements = order_element.separated1(comma)
|
192
|
+
exprs = expr.separated1(comma)
|
193
|
+
order_by_clause = keyword[:order] >> keyword[:by] >> order_elements
|
194
|
+
group_by = keyword[:group] >> keyword[:by] >> exprs
|
195
|
+
group_by_clause = sequence(group_by, (keyword[:having] >> pred).optional, &ctor(GroupByClause))
|
196
|
+
relation = sub_relation | sequence(keyword[:select],
|
197
|
+
keyword[:distinct].optional(false), exprs,
|
198
|
+
keyword[:from], joined_relation,
|
199
|
+
where_clause.optional, group_by_clause.optional, order_by_clause.optional
|
200
|
+
) do |_, distinct, projected, _, from, where, groupby, orderby|
|
201
|
+
SelectRelation.new(projected, distinct, from, where, groupby, orderby)
|
202
|
+
end
|
203
|
+
relation = sequence(relation, (keyword[:limit] >> token(:number, &To_i)).optional) do |rel, limit|
|
204
|
+
case when limit.nil?: rel else LimitRelation.new(rel, limit) end
|
205
|
+
end
|
206
|
+
relation = relation.infixl(union_maker)
|
207
|
+
end
|
208
|
+
def union_maker
|
209
|
+
keyword[:union] >> (keyword[:all]>>true|false).map do |all|
|
210
|
+
proc {|r1, r2|UnionRelation.new(r1, all, r2)}
|
211
|
+
end
|
212
|
+
end
|
213
|
+
def join_maker rel, pred
|
214
|
+
crossjoin = keyword[:cross] >> keyword[:join] >> rel.map(&rctor(CrossJoinRelation))
|
215
|
+
leftjoin = outer_join :left
|
216
|
+
rightjoin = outer_join :right
|
217
|
+
fulljoin = outer_join :full
|
218
|
+
innerjoin = keyword[:inner].optional >> keyword[:join] >> :inner
|
219
|
+
join_with_condition = sequence(sum(leftjoin, rightjoin, innerjoin), rel,
|
220
|
+
keyword[:on], pred) do |kind, r, _, on|
|
221
|
+
proc{|r0|JoinRelation.new(kind, r0, r, on)}
|
222
|
+
end
|
223
|
+
sum(crossjoin, join_with_condition)
|
224
|
+
end
|
225
|
+
def outer_join kind
|
226
|
+
keyword[kind] >> keyword[:outer].optional >> keyword[:join] >> kind
|
227
|
+
end
|
228
|
+
|
229
|
+
|
230
|
+
|
231
|
+
########################## put together ###############################
|
232
|
+
def expression
|
233
|
+
assemble[0]
|
234
|
+
end
|
235
|
+
|
236
|
+
def relation
|
237
|
+
assemble[2]
|
238
|
+
end
|
239
|
+
def predicate
|
240
|
+
assemble[1]
|
241
|
+
end
|
242
|
+
|
243
|
+
def assemble
|
244
|
+
pred = nil
|
245
|
+
rel = nil
|
246
|
+
lazy_predicate = lazy{pred}
|
247
|
+
lazy_rel = lazy{rel}
|
248
|
+
expr = make_expression lazy_predicate, lazy_rel
|
249
|
+
pred = make_predicate expr, lazy_rel
|
250
|
+
rel = make_relation expr, pred
|
251
|
+
return expr, pred, rel
|
252
|
+
end
|
253
|
+
|
254
|
+
|
255
|
+
def make parser
|
256
|
+
MyLexeme.nested(parser << eof)
|
257
|
+
end
|
258
|
+
end
|