Class: Whittle::Rule
- Inherits:
-
Object
- Object
- Whittle::Rule
- Defined in:
- lib/whittle/rule.rb
Overview
Represents an individual Rule, forming part of an overall RuleSet.
Direct Known Subclasses
Constant Summary collapse
- NULL_ACTION =
Proc.new { }
- DUMP_ACTION =
Proc.new { |input| input }
Instance Attribute Summary collapse
-
#action ⇒ Object
readonly
Returns the value of attribute action.
-
#assoc ⇒ Object
readonly
Returns the value of attribute assoc.
-
#components ⇒ Object
readonly
Returns the value of attribute components.
-
#name ⇒ Object
readonly
Returns the value of attribute name.
-
#prec ⇒ Object
readonly
Returns the value of attribute prec.
Instance Method Summary collapse
-
#%(assoc) ⇒ Rule
Set the associativity of this Rule.
-
#^(prec) ⇒ Object
Set the precedence of this Rule, as an Integer.
-
#as(preset = nil, &block) ⇒ Rule
Specify how this Rule should be reduced.
-
#build_parse_table(table, parser, context) ⇒ Object
Walks all possible branches from the given rule, building a parse table.
-
#initialize(name, *components) ⇒ Rule
constructor
Create a new Rule for the RuleSet named
name
. -
#skip! ⇒ Rule
Alias for as(:nothing).
-
#terminal? ⇒ Boolean
Predicate check for whether or not the Rule represents a terminal symbol.
Constructor Details
#initialize(name, *components) ⇒ Rule
Create a new Rule for the RuleSet named name
.
The components can either be names of other Rules, or for a terminal Rule, a single pattern to match in the input string.
27 28 29 30 31 32 33 34 35 36 37 38 39 |
# File 'lib/whittle/rule.rb', line 27 def initialize(name, *components) @components = components @action = DUMP_ACTION @name = name @assoc = :right @prec = 0 @components.each do |c| unless Regexp === c || String === c || Symbol === c raise ArgumentError, "Unsupported rule component #{c.class}" end end end |
Instance Attribute Details
#action ⇒ Object (readonly)
Returns the value of attribute action.
12 13 14 |
# File 'lib/whittle/rule.rb', line 12 def action @action end |
#assoc ⇒ Object (readonly)
Returns the value of attribute assoc.
14 15 16 |
# File 'lib/whittle/rule.rb', line 14 def assoc @assoc end |
#components ⇒ Object (readonly)
Returns the value of attribute components.
13 14 15 |
# File 'lib/whittle/rule.rb', line 13 def components @components end |
#name ⇒ Object (readonly)
Returns the value of attribute name.
11 12 13 |
# File 'lib/whittle/rule.rb', line 11 def name @name end |
#prec ⇒ Object (readonly)
Returns the value of attribute prec.
15 16 17 |
# File 'lib/whittle/rule.rb', line 15 def prec @prec end |
Instance Method Details
#%(assoc) ⇒ Rule
Set the associativity of this Rule.
Accepts values of :left, :right (default) or :nonassoc.
186 187 188 189 190 191 |
# File 'lib/whittle/rule.rb', line 186 def %(assoc) raise ArgumentError, "Invalid associativity #{assoc.inspect}" \ unless [:left, :right, :nonassoc].include?(assoc) tap { @assoc = assoc } end |
#^(prec) ⇒ Object
Set the precedence of this Rule, as an Integer.
The higher the number, the higher the precedence.
199 200 201 202 203 204 |
# File 'lib/whittle/rule.rb', line 199 def ^(prec) raise ArgumentError, "Invalid precedence level #{prec.inspect}" \ unless prec.respond_to?(:to_i) tap { @prec = prec.to_i } end |
#as(preset = nil, &block) ⇒ Rule
Specify how this Rule should be reduced.
Given a block, the Rule will be reduced by passing the result of reducing all inputs as arguments to the block.
The default action is to return the leftmost input unchanged.
Given the Symbol :value, the matched input will be returned verbatim. Given the Symbol :nothing, nil will be returned; you can use this to skip whitesapce and comments, for example.
155 156 157 158 159 160 161 162 163 164 165 166 167 |
# File 'lib/whittle/rule.rb', line 155 def as(preset = nil, &block) tap do case preset when :value then @action = DUMP_ACTION when :nothing then @action = NULL_ACTION when nil raise ArgumentError, "Rule#as expected a block, not none given" unless block_given? @action = block else raise ArgumentError, "Invalid preset #{preset.inspect} to Rule#as" end end end |
#build_parse_table(table, parser, context) ⇒ Object
Walks all possible branches from the given rule, building a parse table.
The parse table is a list of instructions (transitions) that can be looked up, given the current parser state and the current lookahead token.
65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 |
# File 'lib/whittle/rule.rb', line 65 def build_parse_table(table, parser, context) state = table[context[:state]] ||= {} sym = components[context[:offset]] rule = parser.rules[sym] new_offset = context[:offset] + 1 new_state = if state.key?(sym) state[sym][:state] end || [self, new_offset].hash if sym.nil? assert_reducible!(state, sym) state[sym] = { :action => :reduce, :rule => self, :prec => context[:prec] } if context[:initial] state[:$end] = { :action => :accept, :rule => self } end else raise GrammarError, "Unreferenced rule #{sym.inspect}" if rule.nil? new_prec = if rule.terminal? rule.prec else context[:prec] end if rule.terminal? state[sym] = { :action => :shift, :state => new_state, :prec => new_prec, :assoc => rule.assoc } else state[sym] = { :action => :goto, :state => new_state } rule.build_parse_table( table, parser, { :state => context[:state], :seen => context[:seen], :offset => 0, :prec => 0 } ) end build_parse_table( table, parser, { :initial => context[:initial], :state => new_state, :seen => context[:seen], :offset => new_offset, :prec => new_prec } ) end resolve_conflicts(state) end |
#skip! ⇒ Rule
Alias for as(:nothing).
173 174 175 |
# File 'lib/whittle/rule.rb', line 173 def skip! as(:nothing) end |
#terminal? ⇒ Boolean
Predicate check for whether or not the Rule represents a terminal symbol.
A terminal symbol is effectively any rule that directly matches some pattern in the input string and references no other rules.
48 49 50 |
# File 'lib/whittle/rule.rb', line 48 def terminal? raise "Must be implemented by subclass" end |