rparsec-ruby19 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/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
|