rusa 0.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.
Files changed (54) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +21 -0
  3. data/README.md +175 -0
  4. data/Rakefile +26 -0
  5. data/Steepfile +9 -0
  6. data/examples/calc.rb +29 -0
  7. data/examples/json.rb +55 -0
  8. data/examples/mini_lang.rb +52 -0
  9. data/exe/rusa +6 -0
  10. data/lib/rusa/analysis/automaton.rb +60 -0
  11. data/lib/rusa/analysis/conflict_resolver.rb +211 -0
  12. data/lib/rusa/analysis/first_follow.rb +106 -0
  13. data/lib/rusa/analysis/item.rb +51 -0
  14. data/lib/rusa/analysis/item_set.rb +64 -0
  15. data/lib/rusa/analysis/lalr_table.rb +460 -0
  16. data/lib/rusa/analysis/parse_action.rb +81 -0
  17. data/lib/rusa/cli.rb +188 -0
  18. data/lib/rusa/errors.rb +12 -0
  19. data/lib/rusa/generator/code_generator.rb +334 -0
  20. data/lib/rusa/grammar/action_capture.rb +128 -0
  21. data/lib/rusa/grammar/dsl.rb +123 -0
  22. data/lib/rusa/grammar/grammar.rb +212 -0
  23. data/lib/rusa/grammar/precedence.rb +29 -0
  24. data/lib/rusa/grammar/rule.rb +55 -0
  25. data/lib/rusa/grammar/symbol.rb +71 -0
  26. data/lib/rusa/version.rb +5 -0
  27. data/lib/rusa.rb +31 -0
  28. data/sig/generated/rusa/analysis/automaton.rbs +25 -0
  29. data/sig/generated/rusa/analysis/conflict_resolver.rbs +57 -0
  30. data/sig/generated/rusa/analysis/first_follow.rbs +33 -0
  31. data/sig/generated/rusa/analysis/item.rbs +35 -0
  32. data/sig/generated/rusa/analysis/item_set.rbs +31 -0
  33. data/sig/generated/rusa/analysis/lalr_table.rbs +182 -0
  34. data/sig/generated/rusa/analysis/parse_action.rbs +58 -0
  35. data/sig/generated/rusa/cli.rbs +68 -0
  36. data/sig/generated/rusa/errors.rbs +24 -0
  37. data/sig/generated/rusa/generator/code_generator.rbs +82 -0
  38. data/sig/generated/rusa/grammar/action_capture.rbs +46 -0
  39. data/sig/generated/rusa/grammar/dsl.rbs +62 -0
  40. data/sig/generated/rusa/grammar/grammar.rbs +103 -0
  41. data/sig/generated/rusa/grammar/precedence.rbs +23 -0
  42. data/sig/generated/rusa/grammar/rule.rbs +35 -0
  43. data/sig/generated/rusa/grammar/symbol.rbs +51 -0
  44. data/sig/generated/rusa/version.rbs +5 -0
  45. data/sig/generated/rusa.rbs +6 -0
  46. data/test/test_automaton.rb +27 -0
  47. data/test/test_code_generator.rb +74 -0
  48. data/test/test_dsl.rb +77 -0
  49. data/test/test_e2e.rb +134 -0
  50. data/test/test_first_follow.rb +70 -0
  51. data/test/test_grammar_model.rb +60 -0
  52. data/test/test_helper.rb +6 -0
  53. data/test/test_lalr_table.rb +64 -0
  54. metadata +96 -0
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "test_helper"
4
+
5
+ class LalrTableTest < Minitest::Test
6
+ def test_resolves_precedence_and_associativity_for_arithmetic_grammar
7
+ grammar = Rusa.grammar do
8
+ token :NUMBER,(/\d+/)
9
+ token :PLUS, "+"
10
+ token :STAR, "*"
11
+ token :LPAREN, "("
12
+ token :RPAREN, ")"
13
+ skip(/\s+/)
14
+
15
+ left :PLUS
16
+ left :STAR
17
+
18
+ start :expr
19
+
20
+ rule :expr do
21
+ alt(:expr, :PLUS, :expr) { |left, _, right| [:add, left, right] }
22
+ alt(:expr, :STAR, :expr) { |left, _, right| [:mul, left, right] }
23
+ alt(:LPAREN, :expr, :RPAREN) { |_, expression, _| expression }
24
+ alt(:NUMBER) { |number| number.to_i }
25
+ end
26
+ end
27
+
28
+ table = Rusa::Analysis::LALRTable.new(grammar)
29
+
30
+ refute_empty table.action_table
31
+ refute_empty table.goto_table
32
+ assert(table.conflicts.any? { |conflict| conflict.message.include?("left associativity") })
33
+ assert(table.conflicts.any? { |conflict| conflict.message.include?("higher token precedence") })
34
+ assert(
35
+ table.action_table.values.any? do |actions|
36
+ actions[:PLUS].is_a?(Rusa::Analysis::Reduce) && actions[:STAR].is_a?(Rusa::Analysis::Shift)
37
+ end
38
+ )
39
+ end
40
+
41
+ def test_prefers_shift_for_dangling_else
42
+ grammar = Rusa.grammar do
43
+ token :IF, "if"
44
+ token :THEN, "then"
45
+ token :ELSE, "else"
46
+ token :ID,(/[a-z]+/)
47
+ skip(/\s+/)
48
+
49
+ start :stmt
50
+
51
+ rule :stmt do
52
+ alt(:IF, :ID, :THEN, :stmt, :ELSE, :stmt)
53
+ alt(:IF, :ID, :THEN, :stmt)
54
+ alt(:ID)
55
+ end
56
+ end
57
+
58
+ table = Rusa::Analysis::LALRTable.new(grammar)
59
+ conflict = table.conflicts.find { |entry| entry.lookahead == :ELSE }
60
+
61
+ refute_nil conflict
62
+ assert_includes conflict.message, "default shift"
63
+ end
64
+ end
metadata ADDED
@@ -0,0 +1,96 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rusa
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Yudai Takada
8
+ bindir: exe
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies: []
12
+ description: Rusa generates standalone Ruby parsers from Ruby-defined grammars without
13
+ external runtime dependencies.
14
+ email:
15
+ - t.yudai92@gmail.com
16
+ executables:
17
+ - rusa
18
+ extensions: []
19
+ extra_rdoc_files: []
20
+ files:
21
+ - LICENSE.txt
22
+ - README.md
23
+ - Rakefile
24
+ - Steepfile
25
+ - examples/calc.rb
26
+ - examples/json.rb
27
+ - examples/mini_lang.rb
28
+ - exe/rusa
29
+ - lib/rusa.rb
30
+ - lib/rusa/analysis/automaton.rb
31
+ - lib/rusa/analysis/conflict_resolver.rb
32
+ - lib/rusa/analysis/first_follow.rb
33
+ - lib/rusa/analysis/item.rb
34
+ - lib/rusa/analysis/item_set.rb
35
+ - lib/rusa/analysis/lalr_table.rb
36
+ - lib/rusa/analysis/parse_action.rb
37
+ - lib/rusa/cli.rb
38
+ - lib/rusa/errors.rb
39
+ - lib/rusa/generator/code_generator.rb
40
+ - lib/rusa/grammar/action_capture.rb
41
+ - lib/rusa/grammar/dsl.rb
42
+ - lib/rusa/grammar/grammar.rb
43
+ - lib/rusa/grammar/precedence.rb
44
+ - lib/rusa/grammar/rule.rb
45
+ - lib/rusa/grammar/symbol.rb
46
+ - lib/rusa/version.rb
47
+ - sig/generated/rusa.rbs
48
+ - sig/generated/rusa/analysis/automaton.rbs
49
+ - sig/generated/rusa/analysis/conflict_resolver.rbs
50
+ - sig/generated/rusa/analysis/first_follow.rbs
51
+ - sig/generated/rusa/analysis/item.rbs
52
+ - sig/generated/rusa/analysis/item_set.rbs
53
+ - sig/generated/rusa/analysis/lalr_table.rbs
54
+ - sig/generated/rusa/analysis/parse_action.rbs
55
+ - sig/generated/rusa/cli.rbs
56
+ - sig/generated/rusa/errors.rbs
57
+ - sig/generated/rusa/generator/code_generator.rbs
58
+ - sig/generated/rusa/grammar/action_capture.rbs
59
+ - sig/generated/rusa/grammar/dsl.rbs
60
+ - sig/generated/rusa/grammar/grammar.rbs
61
+ - sig/generated/rusa/grammar/precedence.rbs
62
+ - sig/generated/rusa/grammar/rule.rbs
63
+ - sig/generated/rusa/grammar/symbol.rbs
64
+ - sig/generated/rusa/version.rbs
65
+ - test/test_automaton.rb
66
+ - test/test_code_generator.rb
67
+ - test/test_dsl.rb
68
+ - test/test_e2e.rb
69
+ - test/test_first_follow.rb
70
+ - test/test_grammar_model.rb
71
+ - test/test_helper.rb
72
+ - test/test_lalr_table.rb
73
+ homepage: https://github.com/ydah/rusa
74
+ licenses:
75
+ - MIT
76
+ metadata:
77
+ homepage_uri: https://github.com/ydah/rusa
78
+ source_code_uri: https://github.com/ydah/rusa
79
+ rdoc_options: []
80
+ require_paths:
81
+ - lib
82
+ required_ruby_version: !ruby/object:Gem::Requirement
83
+ requirements:
84
+ - - ">="
85
+ - !ruby/object:Gem::Version
86
+ version: 3.1.0
87
+ required_rubygems_version: !ruby/object:Gem::Requirement
88
+ requirements:
89
+ - - ">="
90
+ - !ruby/object:Gem::Version
91
+ version: '0'
92
+ requirements: []
93
+ rubygems_version: 4.0.6
94
+ specification_version: 4
95
+ summary: Pure Ruby LALR(1) parser generator with a Ruby DSL.
96
+ test_files: []