Class: Calyx::Registry
- Inherits:
-
Object
- Object
- Calyx::Registry
- Defined in:
- lib/calyx/registry.rb
Overview
Lookup table of all the available rules in the grammar.
Instance Attribute Summary collapse
-
#dicts ⇒ Object
readonly
Returns the value of attribute dicts.
-
#modifiers ⇒ Object
readonly
Returns the value of attribute modifiers.
-
#rules ⇒ Object
readonly
Returns the value of attribute rules.
-
#transforms ⇒ Object
readonly
Returns the value of attribute transforms.
Instance Method Summary collapse
-
#combine(registry) ⇒ Object
Merges the given registry instance with the target registry.
-
#define_context_rule(name, trace, productions) ⇒ Object
Defines a rule in the temporary evaluation context.
-
#define_rule(name, trace, productions) ⇒ Object
Defines a static rule in the grammar.
-
#evaluate(start_symbol = :start, rules_map = {}) ⇒ Array
Evaluates the grammar defined in this registry, combining it with rules from the passed in context.
-
#expand(symbol) ⇒ Calyx::Rule
Expands the given symbol to its rule.
-
#expand_filter(name, value) ⇒ String
Applies the given modifier function to the given value to filter it.
-
#expand_map(name, value, direction) ⇒ String
Applies a modifier to substitute the value with a bidirectional map lookup.
-
#filter(name, callable = nil) {|String| ... } ⇒ Object
Registers the given block as a string filter.
-
#initialize ⇒ Registry
constructor
Construct an empty registry.
-
#mapping(name, pairs) ⇒ Object
Registers a paired mapping regex.
-
#memoize_expansion(symbol) ⇒ Object
Expands a memoized rule symbol by evaluating it and storing the result for later.
-
#method_missing(name, *productions) ⇒ Object
Registers a new grammar rule without explicitly calling the ‘#rule` method.
-
#modifier(name) ⇒ Object
Attaches a modifier module to this instance.
-
#options(opts) ⇒ Object
Applies additional config options to this instance.
-
#rule(name, *productions) ⇒ Object
Registers a new grammar rule.
-
#unique_expansion(symbol) ⇒ Object
Expands a unique rule symbol by evaluating it and checking that it hasn’t previously been selected.
Constructor Details
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(name, *productions) ⇒ Object
Registers a new grammar rule without explicitly calling the ‘#rule` method.
54 55 56 |
# File 'lib/calyx/registry.rb', line 54 def method_missing(name, *productions) define_rule(name, caller_locations.first, productions) end |
Instance Attribute Details
#dicts ⇒ Object (readonly)
Returns the value of attribute dicts.
4 5 6 |
# File 'lib/calyx/registry.rb', line 4 def dicts @dicts end |
#modifiers ⇒ Object (readonly)
Returns the value of attribute modifiers.
4 5 6 |
# File 'lib/calyx/registry.rb', line 4 def modifiers @modifiers end |
#rules ⇒ Object (readonly)
Returns the value of attribute rules.
4 5 6 |
# File 'lib/calyx/registry.rb', line 4 def rules @rules end |
#transforms ⇒ Object (readonly)
Returns the value of attribute transforms.
4 5 6 |
# File 'lib/calyx/registry.rb', line 4 def transforms @transforms end |
Instance Method Details
#combine(registry) ⇒ Object
Merges the given registry instance with the target registry.
This is only needed at compile time, so that child classes can easily inherit the set of rules decared by their parent.
181 182 183 |
# File 'lib/calyx/registry.rb', line 181 def combine(registry) @rules = rules.merge(registry.rules) end |
#define_context_rule(name, trace, productions) ⇒ Object
Defines a rule in the temporary evaluation context.
88 89 90 91 |
# File 'lib/calyx/registry.rb', line 88 def define_context_rule(name, trace, productions) productions = [productions] unless productions.is_a?(Enumerable) context[name.to_sym] = Rule.new(name.to_sym, Rule.build_ast(productions, self), trace) end |
#define_rule(name, trace, productions) ⇒ Object
Defines a static rule in the grammar.
70 71 72 73 74 75 76 77 78 79 80 81 82 |
# File 'lib/calyx/registry.rb', line 70 def define_rule(name, trace, productions) symbol = name.to_sym # TODO: this could be tidied up by consolidating parsing in a single class branch = Rule.build_ast(productions, self) # If the static rule is a map of k=>v pairs then add it to the lookup dict if branch.is_a?(Production::AffixTable) dicts[symbol] = branch else rules[symbol] = Rule.new(symbol, branch, trace) end end |
#evaluate(start_symbol = :start, rules_map = {}) ⇒ Array
Evaluates the grammar defined in this registry, combining it with rules from the passed in context.
Produces a syntax tree of nested list nodes.
193 194 195 196 197 198 199 200 201 202 203 204 205 |
# File 'lib/calyx/registry.rb', line 193 def evaluate(start_symbol=:start, rules_map={}) reset_evaluation_context rules_map.each do |key, value| if rules.key?(key.to_sym) raise Errors::DuplicateRule.new(key) end define_context_rule(key, caller_locations.last, value) end [start_symbol, (start_symbol).evaluate(@options)] end |
#expand(symbol) ⇒ Calyx::Rule
Expands the given symbol to its rule.
97 98 99 100 101 102 103 104 105 106 107 108 109 110 |
# File 'lib/calyx/registry.rb', line 97 def (symbol) expansion = rules[symbol] || context[symbol] if expansion.nil? if @options.strict? raise Errors::UndefinedRule.new(@last_expansion, symbol) else expansion = Syntax::Terminal.new('') end end @last_expansion = expansion expansion end |
#expand_filter(name, value) ⇒ String
Applies the given modifier function to the given value to filter it.
117 118 119 120 121 122 123 |
# File 'lib/calyx/registry.rb', line 117 def (name, value) if transforms.key?(name) transforms[name].call(value) else modifiers.transform(name, value) end end |
#expand_map(name, value, direction) ⇒ String
Applies a modifier to substitute the value with a bidirectional map lookup.
132 133 134 135 136 137 138 139 140 |
# File 'lib/calyx/registry.rb', line 132 def (name, value, direction) map_lookup = dicts[name] if direction == :left map_lookup.key_for(value) else map_lookup.value_for(value) end end |
#filter(name, callable = nil) {|String| ... } ⇒ Object
Registers the given block as a string filter.
42 43 44 45 46 47 48 |
# File 'lib/calyx/registry.rb', line 42 def filter(name, callable=nil, &block) if block_given? transforms[name.to_sym] = block else transforms[name.to_sym] = callable end end |
#mapping(name, pairs) ⇒ Object
Registers a paired mapping regex.
33 34 35 |
# File 'lib/calyx/registry.rb', line 33 def mapping(name, pairs) transforms[name.to_sym] = construct_mapping(pairs) end |
#memoize_expansion(symbol) ⇒ Object
Expands a memoized rule symbol by evaluating it and storing the result for later.
146 147 148 |
# File 'lib/calyx/registry.rb', line 146 def memoize_expansion(symbol) memos[symbol] ||= (symbol).evaluate(@options) end |
#modifier(name) ⇒ Object
Attaches a modifier module to this instance.
25 26 27 |
# File 'lib/calyx/registry.rb', line 25 def modifier(name) modifiers.extend(name) end |
#options(opts) ⇒ Object
Applies additional config options to this instance.
18 19 20 |
# File 'lib/calyx/registry.rb', line 18 def (opts) @options = @options.merge(opts) end |
#rule(name, *productions) ⇒ Object
Registers a new grammar rule.
62 63 64 |
# File 'lib/calyx/registry.rb', line 62 def rule(name, *productions) define_rule(name, caller_locations.first, productions) end |
#unique_expansion(symbol) ⇒ Object
Expands a unique rule symbol by evaluating it and checking that it hasn’t previously been selected.
154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 |
# File 'lib/calyx/registry.rb', line 154 def unique_expansion(symbol) pending = true uniques[symbol] = [] if uniques[symbol].nil? while pending if uniques[symbol].size == (symbol).size uniques[symbol] = [] pending = false end result = (symbol).evaluate(@options) unless uniques[symbol].include?(result) uniques[symbol] << result pending = false end end result end |