oakproof 0.7.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,439 @@
1
+ def grammar_rules
2
+ [
3
+ [:start, :ending, :end], # needed to preserve line numbers
4
+ [:start, :begin_assume, :start5],
5
+ [:start, :end_assume, :start5],
6
+ [:start, :marker, :start5],
7
+ [:start, :include, :start5],
8
+ [:start, :now, :start5],
9
+ [:start, :end, :start5],
10
+ [:start, :exit, :start5],
11
+ [:start, :tie_in, :start3],
12
+ [:start, :label, :start2],
13
+ [:start, :else, :start2],
14
+
15
+ # things that can have labels
16
+ [:start2, :assume, :start4],
17
+ [:start2, :axiom, :start5],
18
+ [:start2, :suppose, :start5],
19
+ [:start2, :take, :start5],
20
+ [:start2, :so, :start3],
21
+ [:start2, :derive, :start3],
22
+
23
+ [:start3, :by, :start5],
24
+ [:start3, :proof, :start5],
25
+ [:start3, :else, :start5],
26
+ [:start4, :by, :start5],
27
+ [:start4, :else, :start5],
28
+ [:start5, :ending, :end],
29
+
30
+ [:label, [:label_name, /\s*:/], :end, :catch],
31
+
32
+ [:label_same_line, [:label_name_same_line, /\s*:/], :end, :catch],
33
+
34
+ [:include, /\s*include\b/i, :filename],
35
+
36
+ [:begin_assume, /\s*begin assume\b/i, :end],
37
+
38
+ [:end_assume, /\s*end assume\b/i, :end],
39
+
40
+ [:marker, /\s*marker\b/i, :end],
41
+
42
+ [:filename, [/\s*"/, /[^"\n]+/, /"/], :end],
43
+
44
+ [:tie_in, /\s*tie-in\b/i, :tie_in2],
45
+ [:tie_in2, [:quote, :with, :quote], :tie_in3],
46
+ [:tie_in3, /\s*for (all|any|each|every)\b/i, :tie_in4],
47
+ [:tie_in3, :else, :end],
48
+ [:tie_in4, :atom_list_adjacent, :end],
49
+
50
+ [:assume, /\s*assume\b/i, :assume2],
51
+ [:assume2, :tie_in, :end],
52
+ [:assume2, :else, :label_schema],
53
+
54
+ [:axiom, /\s*axiom\b/i, :label_schema],
55
+
56
+ [:label_schema, :label_same_line, :label_schema2],
57
+ [:label_schema, :else, :label_schema2],
58
+ [:label_schema2, :schema, :end],
59
+ [:label_schema2, :define, :end],
60
+ [:label_schema2, :exp, :end],
61
+
62
+ [:schema, [/\s*schema\b/i, :universal_meta], :end],
63
+
64
+ [:suppose, /\s*suppose\b/i, :suppose2],
65
+ [:suppose2, :label_same_line, :suppose3],
66
+ [:suppose2, :else, :suppose3],
67
+ [:suppose3, :exp, :end],
68
+
69
+ [:take, :take_label, :post_quantifier],
70
+ [:take_label, /\s*take any\b/i, :end],
71
+ [:take_label, [/\s*take\b/i, :label_same_line, /\s*any\b/i], :end],
72
+
73
+ [:so, /\s*so\b/i, :so2],
74
+ [:so2, :assume, :end],
75
+ [:so2, :label_same_line, :so3],
76
+ [:so2, :else, :so3],
77
+ [:so3, :define, :end],
78
+ [:so3, :exp, :end],
79
+
80
+ [:now, /\s*now\b/i, :end],
81
+
82
+ [:end, /\s*end\b/i, :end],
83
+
84
+ [:derive, :exp, :end],
85
+ [:derive, :let, :end],
86
+ [:derive, :define, :end],
87
+
88
+ [:exit, /\s*exit\b/i, :end],
89
+
90
+ [:by, /\s*(by|from)\b/i, :by2],
91
+ [:by2, :question_mark, :by3],
92
+ [:by2, :label_name, :by3],
93
+ [:by3, /\s*,/, :by2],
94
+ [:by3, /\s*and\b/i, :by2],
95
+ [:by3, :else, :end],
96
+
97
+ [:question_mark, /\s*\?/, :end],
98
+
99
+ [:proof, /\s*proof\b/i, :end],
100
+
101
+ [:ending, /\s*\.\s|\s*\.\z/, :end],
102
+ [:ending, /\s*;/, :end],
103
+ [:ending, /\s*\n/, :end],
104
+ [:ending, /\s*\z/, :end],
105
+
106
+ # prefix can have any prefix under it
107
+ # prefix can have any infix of higher level under it
108
+
109
+ # infix can have any prefix of higher level to left of it
110
+ # infix can have any infix of higher level to left of it
111
+
112
+ # infix can have any prefix to right of it
113
+ # infix can have any infix of higher level to right of it
114
+
115
+ [:exp, :exp_, :end],
116
+
117
+ [:prefix_, :universal, :end],
118
+ [:prefix_, :for_at_most_one, :end],
119
+ [:prefix_, :no_existential, :end],
120
+ [:prefix_, :existential, :end],
121
+
122
+ # no infix at this level
123
+ [:exp_, :prefix_, :end],
124
+ [:exp_, :exp0, :end],
125
+
126
+ [:prefix0, :if, :end],
127
+
128
+ [:exp0, :prefix0, :end],
129
+ [:exp0, :exp1, :exp0a],
130
+ [:exp0a, /\s*(iff|if and only if)\b/i, :exp0b],
131
+ [:exp0a, /\s*implies( that)?\b/i, :exp0b],
132
+ [:exp0a, :else, :end],
133
+ [:exp0b, :exp1, :end],
134
+ [:exp0b, :prefix0, :end],
135
+ [:exp0b, :prefix_, :end],
136
+
137
+ [:prefix1, :not, :end],
138
+
139
+ [:exp1, :prefix1, :end],
140
+ [:exp1, :exp2, :exp1a],
141
+ [:exp1a, :and, :and1],
142
+ [:and, /\s*and\b/i, :end],
143
+ [:and1, :exp2, :and2],
144
+ [:and1, :else, :exp1c],
145
+ [:and2, :and, :and1],
146
+ [:and2, :else, :end],
147
+ [:exp1a, :or, :or1],
148
+ [:or, /\s*or\b/i, :end],
149
+ [:or1, :exp2, :or2],
150
+ [:or1, :else, :exp1c],
151
+ [:or2, :or, :or1],
152
+ [:or2, :else, :end],
153
+ [:exp1a, :else, :end],
154
+ [:exp1b, :exp2, :end],
155
+ [:exp1b, :else, :exp1c],
156
+ [:exp1c, :prefix1, :end],
157
+ [:exp1c, :prefix0, :end],
158
+ [:exp1c, :prefix_, :end],
159
+
160
+ [:prefix2, :every, :end],
161
+ [:prefix2, :no, :end],
162
+ [:prefix2, :some, :end],
163
+ [:prefix2, :at_most_one, :end],
164
+
165
+ [:exp2, :prefix2, :end],
166
+ [:exp2, :exp3, :exp2a],
167
+ [:exp2a, /\s*=/i, :exp2b],
168
+ [:exp2a, :not_equal, :exp2b],
169
+ [:exp2a, :inequality, :exp2b],
170
+ [:exp2a, :is_in, :exp2b],
171
+ [:exp2a, :is_not_in, :exp2b],
172
+ [:exp2a, :is_not, :is_predicate],
173
+ [:exp2a, :is, :is_predicate],
174
+ [:exp2a, :set_relation, :exp2b],
175
+ [:exp2a, :custom, :exp2b], # not sure about this, move or remove?
176
+ [:exp2a, :else, :end],
177
+ [:exp2b, :exp3, :end],
178
+
179
+ # addition, subtraction, union, and intersection
180
+ [:exp3, :exp4, :exp3a],
181
+ [:exp3a, :plus, :plus1],
182
+ [:plus, /\s*\+/i, :end],
183
+ [:plus1, :exp4, :plus2],
184
+ [:plus2, :plus, :plus1],
185
+ [:plus2, :else, :end],
186
+ [:exp3a, /\s*\-/i, :exp3b],
187
+ [:exp3a, :union, :union1],
188
+ [:union, /\s*\∪/i, :end],
189
+ [:union1, :exp4, :union2],
190
+ [:union2, :union, :union1],
191
+ [:union2, :else, :end],
192
+ [:exp3a, :intersection, :intersection1],
193
+ [:intersection, /\s*\∩/i, :end],
194
+ [:intersection1, :exp4, :intersection2],
195
+ [:intersection2, :intersection, :intersection1],
196
+ [:intersection2, :else, :end],
197
+ [:exp3a, :else, :end],
198
+ [:exp3b, :exp4, :end],
199
+
200
+ # multiplication and division
201
+ [:exp4, :exp5, :exp4a],
202
+ [:exp4a, :times, :times1],
203
+ [:times, /\s*\*/i, :end],
204
+ [:times1, :exp5, :times2],
205
+ [:times2, :times, :times1],
206
+ [:times2, :else, :end],
207
+ [:exp4a, /\s*\//i, :exp4b],
208
+ [:exp4a, /\s*÷/i, :exp4b],
209
+ [:exp4a, :else, :end],
210
+ [:exp4b, :exp5, :end],
211
+
212
+ # exponentiation
213
+ [:exp5, :exp6, :exp5a],
214
+ [:exp5a, /\s*\^/i, :exp5b],
215
+ [:exp5a, /\s*\*\*/i, :exp5b],
216
+ [:exp5a, :else, :end],
217
+ [:exp5b, :exp6, :end],
218
+
219
+ [:exp6, :operand, :end],
220
+
221
+ [:if, [/\s*if\b/i, :exp, /\s*,?\s*then\b/i], :exp0b],
222
+
223
+ [:not, /\s*not\b/i, :exp1b],
224
+
225
+ [:atom_list, :atom_block, :atom_list2],
226
+ [:atom_list2, [/\s*and\b/i, :atom_block], :atom_list2],
227
+ [:atom_list2, :else, :end],
228
+
229
+ [:atom_block, :word, :atom_block2],
230
+ [:atom_block, :else, :atom_list_adjacent],
231
+ [:atom_block2, :word_same_line, :atom_block2],
232
+ [:atom_block2, :condition, :end, :catch],
233
+ [:atom_block2, :definable_same_line, :atom_list_adjacent2],
234
+ [:atom_block2, :else, :atom_list_adjacent2],
235
+
236
+ [:atom_list_adjacent, :definable, :atom_list_adjacent2],
237
+ [:atom_list_adjacent2, [/,/, :definable_raw,], :atom_list_adjacent2, :catch],
238
+ [:atom_list_adjacent2, :condition, :end],
239
+ [:atom_list_adjacent2, :else, :end],
240
+
241
+ [:universal, /\s*for (all|any|each|every) meta\b/i, :null],
242
+ [:universal, /\s*for (all|any|each|every)\b/i, :post_quantifier_exp],
243
+
244
+ [:universal_meta, /\s*for (all|any|each|every) meta\b/i, :universal_meta2],
245
+ [:universal_meta2, [:list_with_such, /,\s/, :quote], :end],
246
+
247
+ [:existential, /\s*for (at least one|some)\b/i, :post_quantifier_exp],
248
+ [:existential, /\s*there (exist|exists|is|are)( (a|an|at least one|some))?\b/i, :post_quantifier],
249
+ [:for_at_most_one, /\s*for at most one\b/i, :post_quantifier_exp],
250
+ [:for_at_most_one, /\s*there (exist|exists|is|are) at most one\b/i, :post_quantifier],
251
+ [:no_existential, /\s*for no\b/i, :post_quantifier_exp],
252
+ [:no_existential, /\s*there (exist|exists|is|are) no\b/i, :post_quantifier],
253
+
254
+ [:post_quantifier_exp, :list_with_such, :post_quantifier_exp2],
255
+ [:post_quantifier_exp2, [/,\s/, :exp], :end],
256
+
257
+ [:post_quantifier, :list_with_such, :end],
258
+
259
+ [:list_with_such, :atom_list, :list_with_such2],
260
+ [:list_with_such2, [:with, :exp], :list_with_such3],
261
+ [:list_with_such2, :else, :list_with_such3],
262
+ [:list_with_such3, [:such_that, :exp], :end],
263
+ [:list_with_such3, :else, :end],
264
+
265
+ [:with, /\s*with\b/i, :end],
266
+
267
+ [:such_that, /\s*(such that|where)\b/i, :end],
268
+
269
+ [:let, /\s*let\b/i, :let2],
270
+ [:let2, :definable, :let3],
271
+ [:let3, /\s*=/i, :let4],
272
+ [:let4, :exp, :end],
273
+
274
+ [:define, /\s*define\b/i, :post_quantifier],
275
+
276
+ [:condition, [/\s*in\b/i, :exp3], :end],
277
+ [:condition, [/\s*not in\b/i, :exp3], :end],
278
+ [:condition, [:inequality, :exp3], :end],
279
+ [:condition, [:set_relation, :exp3], :end],
280
+ [:condition, [:not_equal, :exp3], :end],
281
+
282
+ [:inequality, /\s*<=/i, :end],
283
+ [:inequality, /\s*≤/i, :end],
284
+ [:inequality, /\s*</i, :end],
285
+ [:inequality, /\s*>=/i, :end],
286
+ [:inequality, /\s*≥/i, :end],
287
+ [:inequality, /\s*>/i, :end],
288
+
289
+ [:set_relation, /\s*\⊆/i, :end],
290
+ [:set_relation, /\s*\⊊/i, :end],
291
+ [:set_relation, /\s*\⊇/i, :end],
292
+ [:set_relation, /\s*\⊋/i, :end],
293
+ [:set_relation, /\s*\⊂/i, :end],
294
+ [:set_relation, /\s*\⊃/i, :end],
295
+
296
+ [:not_equal, /\s*!=/i, :end],
297
+ [:not_equal, /\s*≠/i, :end],
298
+
299
+ [:custom, [:word_same_line, /[ \t]/], :end],
300
+
301
+ [:is, /\s*is\b/i, :end],
302
+ [:is_not, /\s*is not\b/i, :end],
303
+
304
+ [:is_in, /\s*is in\b/i, :end],
305
+ [:is_not_in, /\s*is not in\b/i, :end],
306
+
307
+ [:preposition, /\s*(of|on)\b/i, :end],
308
+
309
+ [:category, :word, :category2],
310
+ [:category2, [:preposition, :exp3], :end],
311
+ [:category2, :word_same_line, :category2],
312
+ [:category2, :else, :end],
313
+
314
+ [:article, /\s*(a|an)\b/i, :end],
315
+
316
+ [:quantified, [:article, :category], :end],
317
+
318
+ [:is_predicate, :quantified, :end],
319
+ [:is_predicate, :word, :end],
320
+
321
+ [:every, /\s*every\b/i, :category_is],
322
+
323
+ [:no, /\s*no\b/i, :category_is],
324
+
325
+ [:some, /\s*(some|at least one)\b/i, :category_is_with_not],
326
+
327
+ [:at_most_one, /\s*at most one\b/i, :category_is_with_not],
328
+
329
+ [:category_is, :category, :category_is2],
330
+ [:category_is2, :is_in, :exp2b],
331
+ [:category_is2, :is, :is_predicate],
332
+
333
+ [:category_is_with_not, :category, :category_is_with_not2],
334
+ [:category_is_with_not2, :is_in, :exp2b],
335
+ [:category_is_with_not2, :is_not_in, :exp2b],
336
+ [:category_is_with_not2, :is_not, :is_predicate],
337
+ [:category_is_with_not2, :is, :is_predicate],
338
+
339
+ [:boolean, /\s*(true|false|contradiction)\b/i, :end],
340
+
341
+ [:thesis, /\s*thesis\b/i, :end],
342
+
343
+ # [:meta, [/\$/, :operand_base], :end],
344
+
345
+ [:quote, [/\s*`/, :exp, /\s*`/], :end],
346
+
347
+ [:string, /\s*"/, :string2],
348
+ [:string2, /"/, :end],
349
+ # [:string2, :meta, :string2],
350
+ # [:string2, /[^"$]*/, :string2],
351
+ [:string2, /[^"]*/, :string2],
352
+
353
+ [:negative, /\s*-/, :negative2],
354
+ [:negative2, :atom, :end],
355
+ [:negative2, [/\[/, :exp, /\s*\]/], :end],
356
+
357
+ [:square_root, /\s*√/, :square_root2],
358
+ [:square_root2, :atom, :end],
359
+ # [:square_root2, [/\[/, :exp, /\s*\]/], :end],
360
+
361
+ [:operand, :boolean, :end],
362
+ [:operand, :thesis, :end],
363
+ [:operand, :string, :end],
364
+ [:operand, :negative, :end],
365
+ [:operand, :square_root, :end, :catch],
366
+ [:operand, :operand_base, :operand2],
367
+ [:operand2, :subst, :operand3],
368
+ [:operand2, :else, :operand3],
369
+ [:operand3, :params, :operand3],
370
+ [:operand3, :else, :end],
371
+
372
+ [:operand_base, [/\s*\(/, :exp, /\s*\)/], :end],
373
+ [:operand_base, [/\s*\|/, :exp, /\s*\|/], :end],
374
+ [:operand_base, :list, :end],
375
+ [:operand_base, :set, :end],
376
+ [:operand_base, :word, :end],
377
+
378
+ [:list, /\s*\[/, :list1a],
379
+ [:list1a, /\s*\]/, :end],
380
+ [:list1a, :else, :list2],
381
+ [:list2, :exp, :list3],
382
+ [:list3, /,/, :list2],
383
+ [:list3, :else, :list4],
384
+ [:list4, /\s*\]/, :end],
385
+
386
+ [:params, /\[/, :list2],
387
+ [:params, /\(/, :params2],
388
+ [:params2, :exp, :params3],
389
+ [:params3, /,/, :params2],
390
+ [:params3, :else, :params4],
391
+ [:params4, /\s*\)/, :end],
392
+
393
+ [:set, /\s*{/, :set1a],
394
+ [:set1a, /\s*}/, :end],
395
+ [:set1a, :else, :set2],
396
+ [:set2, :exp, :set3],
397
+ [:set3, /,/, :set2],
398
+ [:set3, :else, :set4],
399
+ [:set4, /\s*}/, :end],
400
+
401
+ [:map, /\s*{/, :map2],
402
+ [:map2, [:word, /\s*:/, :exp], :map3],
403
+ [:map3, /\s*,/, :map2],
404
+ [:map3, /\s*}/, :end],
405
+
406
+ [:subst, /{/, :map2],
407
+
408
+ [:word, [/\s*/, :atom], :end, :catch],
409
+
410
+ [:word_same_line, [/[ \t]*/, :atom], :end, :catch],
411
+
412
+ [:label_name, [/\s*/, :atom], :label_name2],
413
+ [:label_name2, [/ ?/, :atom], :label_name2, :catch],
414
+ [:label_name2, :else, :end],
415
+
416
+ [:label_name_same_line, [/[ \t]*/, :atom], :label_name2, :catch],
417
+
418
+ [:definable, [/\s*/, :definable_raw], :end, :catch],
419
+
420
+ [:definable_same_line, [/[ \t]*/, :definable_raw], :end, :catch],
421
+
422
+ [:definable_raw, /\+|\-|\*|\÷|\/|\^|⊆|⊊|⊂|\|\||{}|\[\]|∪|∩|</, :end],
423
+ [:definable_raw, :atom, :end],
424
+
425
+ [:atom, /for (all|any|at least one|at most one)\b/i, :null],
426
+ [:atom, /for (each|every|no|some)\b/i, :null],
427
+ [:atom, /there (are|exist|exists|is)\b/i, :null],
428
+ [:atom, /(at least one|at most one|every|some|no)\b/i, :null],
429
+ [:atom, /(and|any|define|if|iff|implies|in|is|let|not|of|on|or)\b/i, :null],
430
+ [:atom, /(such that|then|where|with)\b/i, :null],
431
+ [:atom, /(assume|axiom|begin assume|by|end|exit|from|include)\b/i, :null],
432
+ [:atom, /(marker|now|proof|schema|so|suppose|take)\b/i, :null],
433
+ [:atom, /(contradiction|false|thesis|true)\b/i, :null],
434
+ [:atom, /((?!
435
+ \(|\)|\[|\]|,|;|\.\s|\.\z|=|!=|≠|\+|\-|\*|÷|\^
436
+ |<=|≤|<|>=|≥|>|:|"|`|{|}|\$|\||⊆|⊇|⊊|⊋|⊂|⊃|\/
437
+ )\S)+/x, :end],
438
+ ]
439
+ end
data/src/grammar.rb ADDED
@@ -0,0 +1,218 @@
1
+ require 'set'
2
+ require 'strscan'
3
+
4
+ class Grammar
5
+ attr_reader :non_terminals, :start_symbol
6
+
7
+ class Rule
8
+ attr_reader :state, :input, :next_state, :catch, :multiple
9
+
10
+ def initialize state, input, next_state, catch, multiple = nil
11
+ @state, @input, @next_state, @catch, @multiple =
12
+ state, input, next_state, catch, multiple
13
+ @input = Regexp.new Regexp.escape(@input) if @input.is_a? String
14
+ end
15
+ end
16
+
17
+ def initialize rules
18
+ @rules = []
19
+ rules.each {|rule|
20
+ state, inputs, next_state, catch = rule
21
+ raise "bad rule format: #{rule}" if not state or (catch and catch != :catch)
22
+ if not inputs.is_a? Array
23
+ @rules << Rule.new(state, inputs, next_state, catch)
24
+ else
25
+ # make a dummy state which can be used to catch errors from the real inputs
26
+ dummy = @rules.size.to_s.to_sym
27
+ @rules << Rule.new(state, dummy, next_state, catch, :multiple)
28
+ inputs.each_with_index {|input, index|
29
+ # here we generate symbols for implicit states in input arrays
30
+ this_state = (index == 0) ? dummy : @rules.size.to_s.to_sym
31
+ if index == inputs.size - 1
32
+ this_next_state = :end
33
+ else
34
+ this_next_state = (@rules.size + 1).to_s.to_sym
35
+ end
36
+ @rules << Rule.new(this_state, input, this_next_state, catch)
37
+ }
38
+ end
39
+ }
40
+ @non_terminals = @rules.collect {|rule| rule.state}.to_set
41
+ inputs = @rules.collect {|rule| rule.input}
42
+ symbol_inputs = inputs.select {|input| input.is_a? Symbol}
43
+ unrecognized = symbol_inputs - @non_terminals.to_a - [:else, :eof]
44
+ raise "unrecognized inputs: #{unrecognized}" unless unrecognized.empty?
45
+ @start_symbol = @rules[0].state
46
+ @rules = @rules.group_by {|rule| rule.state}
47
+ end
48
+
49
+ def [] non_terminal
50
+ @rules[non_terminal] or []
51
+ end
52
+ end
53
+
54
+ class GrammarParser
55
+ def initialize grammar
56
+ @grammar = grammar
57
+ end
58
+
59
+ def match input
60
+ if input == :else
61
+ true
62
+ elsif input == :eof
63
+ @scanner.eos?
64
+ elsif @grammar.non_terminals.include? input
65
+ parse_from input
66
+ elsif match_string = @scanner.scan(input)
67
+ @tree.bloom match_string
68
+ true
69
+ else
70
+ false
71
+ end
72
+ end
73
+
74
+ def parse program
75
+ @scanner = StringScanner.new program
76
+ @tree = GrammarTree.new
77
+ parse_from @grammar.start_symbol, true
78
+ @tree
79
+ end
80
+
81
+ def parse_each program
82
+ @scanner = StringScanner.new program
83
+ last_pos = @scanner.charpos
84
+ until @scanner.eos?
85
+ @tree = GrammarTree.new
86
+ parse_from @grammar.start_symbol, true
87
+ yield @tree, program[last_pos...@scanner.charpos], last_pos
88
+ last_pos = @scanner.charpos
89
+ end
90
+ end
91
+
92
+ def parse_from state, top = false
93
+ top ? @tree.root(state) : @tree.branch(state)
94
+ parsed = while true
95
+ last_pos = @scanner.pos
96
+ last_active = @tree.active
97
+ found = @grammar[state].find {|rule|
98
+ begin
99
+ match rule.input
100
+ rescue GrammarParseException => exception
101
+ unless rule.catch
102
+ if rule.multiple
103
+ # remove dummy branch which was just added, replacing it with its children
104
+ last_active.branches[-1..-1] = last_active.branches[-1].branches
105
+ # take responsibility for exception if exception state is a dummy value
106
+ if exception.state.to_s.to_i.to_s == exception.state.to_s
107
+ exception.state = state
108
+ end
109
+ end
110
+ raise
111
+ end
112
+ @scanner.pos = last_pos
113
+ @tree.prune until @tree.active == last_active
114
+ false
115
+ end
116
+ }
117
+ break false if not found
118
+ if found.multiple
119
+ # remove dummy branch which was just added, replacing it with its children
120
+ last_active.branches[-1..-1] = last_active.branches[-1].branches
121
+ end
122
+ break true if found.next_state == :end
123
+ state = found.next_state
124
+ end
125
+ committed = (not @tree.active.branches.empty?)
126
+ @tree.retract if parsed
127
+ @tree.prune if not parsed and not committed
128
+ return parsed if parsed or (not top and not committed)
129
+ raise GrammarParseException.new @tree, state, @scanner
130
+ end
131
+ end
132
+
133
+ class GrammarParseException < StandardError
134
+ attr_reader :scanner, :tree
135
+ attr_accessor :state
136
+
137
+ def initialize tree, state, scanner
138
+ @tree = tree
139
+ @state = state
140
+ @scanner = scanner
141
+ end
142
+
143
+ def position
144
+ @scanner.charpos
145
+ end
146
+
147
+ def to_s
148
+ rest_to_show = @scanner.rest.inspect[0..80]
149
+ "\n#{@tree}parse failed in #{@state.inspect} at #{rest_to_show}"
150
+ end
151
+ end
152
+
153
+ class GrammarTree
154
+ attr_reader :active
155
+
156
+ class Node
157
+ attr_accessor :branches, :parent, :value
158
+
159
+ def initialize value, parent, leaf = nil
160
+ @value, @parent = value, parent
161
+ @branches = [] unless leaf
162
+ end
163
+
164
+ def text
165
+ return @value if not @branches
166
+ @branches.collect {|branch| branch.text}.join
167
+ end
168
+
169
+ def to_s prefix = '1'
170
+ result = prefix + ' ' + @value.inspect + "\n"
171
+ if @branches
172
+ @branches.each_with_index {|branch, index|
173
+ new_prefix = prefix + '.' + (index + 1).to_s
174
+ result << branch.to_s(new_prefix)
175
+ }
176
+ end
177
+ result
178
+ end
179
+
180
+ # def to_s indent = 0
181
+ # result = ' ' * indent + @value.inspect + "\n"
182
+ # @branches.each {|branch| result << branch.to_s(indent + 1)} if @branches
183
+ # result
184
+ # end
185
+ end
186
+
187
+ def bloom string
188
+ @active.branches << Node.new(string, @active, :leaf)
189
+ end
190
+
191
+ def branch symbol
192
+ @active.branches << Node.new(symbol, @active)
193
+ @active = @active.branches[-1]
194
+ end
195
+
196
+ def prune
197
+ if @active == @root
198
+ @active, @root = nil, nil
199
+ else
200
+ @active.parent.branches.delete @active
201
+ @active = @active.parent
202
+ end
203
+ end
204
+
205
+ def retract
206
+ @active = @active.parent
207
+ end
208
+
209
+ def root value = nil
210
+ return @root if not value
211
+ @root = Node.new value, nil
212
+ @active = @root
213
+ end
214
+
215
+ def to_s
216
+ @root.to_s
217
+ end
218
+ end
data/src/oak.rb ADDED
@@ -0,0 +1,56 @@
1
+ require_relative 'proof.rb'
2
+
3
+ name_version = 'Oak version 0.7.1'
4
+ issues_url = 'https://github.com/timlabs/oak/issues'
5
+
6
+ options = {}
7
+
8
+ if ARGV.delete '-v'
9
+ puts name_version
10
+ exit if ARGV.size == 0
11
+ end
12
+
13
+ if ARGV.delete '-c'
14
+ options[:reduce] = true
15
+ end
16
+
17
+ if ARGV.delete '-f'
18
+ options[:fix] = true
19
+ end
20
+
21
+ if ARGV.delete '-m'
22
+ options[:marker] = true
23
+ end
24
+
25
+ if ARGV.delete '-w'
26
+ options[:wait] = true
27
+ end
28
+
29
+ if options[:fix] and options[:wait]
30
+ puts 'error: options -f and -w cannot be used together'
31
+ exit
32
+ end
33
+
34
+ if ARGV.size != 1 or ARGV[0].start_with? '-'
35
+ puts 'usage: oak [-v] [-c] [-f] [-m] [-w] <filename>'
36
+ puts ' -v print the version number of Oak'
37
+ puts ' -c check for unneeded citations'
38
+ puts ' -f look for a fix'
39
+ puts ' -m assume until marker'
40
+ puts ' -w wait for validity (does not change proof outcome)'
41
+ exit
42
+ end
43
+
44
+ begin
45
+ Proof.process_file ARGV[0], options
46
+ rescue ProofException
47
+ # already printed
48
+ rescue Interrupt
49
+ puts "\naborted due to ctrl-c"
50
+ rescue => e
51
+ puts "\n\n#{e.message} (#{e.class}) [#{name_version}]"
52
+ puts "\tfrom #{e.backtrace.join "\n\tfrom "}"
53
+ puts "\nBUG: You have found a bug in the proof checker! It would be " \
54
+ "greatly appreciated if you could report it at #{issues_url} so that " \
55
+ "it can be fixed."
56
+ end