oakproof 0.7.1

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,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