class Calyx::Registry
Lookup table of all the available rules in the grammar.
Attributes
Public Class Methods
Construct an empty registry.
# File lib/calyx/registry.rb, line 7 def initialize @options = Options.new({}) @rules = {} @dicts = {} @transforms = {} @modifiers = Modifiers.new end
Public Instance Methods
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.
@param [Calyx::Registry] registry
# File lib/calyx/registry.rb, line 181 def combine(registry) @rules = rules.merge(registry.rules) end
Defines a rule in the temporary evaluation context.
@param [Symbol] name @param [Array] productions
# 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
Defines a static rule in the grammar.
@param [Symbol] name @param [Array] productions
# 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
Evaluates the grammar defined in this registry, combining it with rules from the passed in context.
Produces a syntax tree of nested list nodes.
@param [Symbol] start_symbol @param [Hash] rules_map @return [Array]
# 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, expand(start_symbol).evaluate(@options)] end
Expands the given symbol to its rule.
@param [Symbol] symbol @return [Calyx::Rule]
# File lib/calyx/registry.rb, line 97 def expand(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
Applies the given modifier function to the given value to filter it.
@param [Symbol] name @param [String] value @return [String]
# File lib/calyx/registry.rb, line 117 def expand_filter(name, value) if transforms.key?(name) transforms[name].call(value) else modifiers.transform(name, value) end end
Applies a modifier to substitute the value with a bidirectional map lookup.
@param [Symbol] name @param [String] value @param [Symbol] direction :left or :right @return [String]
# File lib/calyx/registry.rb, line 132 def expand_map(name, value, direction) map_lookup = dicts[name] if direction == :left map_lookup.key_for(value) else map_lookup.value_for(value) end end
Registers the given block as a string filter.
@param [Symbol] name @yield [String] @yieldreturn [String]
# 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
Registers a paired mapping regex.
@param [Symbol] name @param [Hash<Regex,String>] pairs
# File lib/calyx/registry.rb, line 33 def mapping(name, pairs) transforms[name.to_sym] = construct_mapping(pairs) end
Expands a memoized rule symbol by evaluating it and storing the result for later.
@param [Symbol] symbol
# File lib/calyx/registry.rb, line 146 def memoize_expansion(symbol) memos[symbol] ||= expand(symbol).evaluate(@options) end
Registers a new grammar rule without explicitly calling the `#rule` method.
@param [Symbol] name @param [Array] productions
# File lib/calyx/registry.rb, line 54 def method_missing(name, *productions) define_rule(name, caller_locations.first, productions) end
Attaches a modifier module to this instance.
@param [Module] name
# File lib/calyx/registry.rb, line 25 def modifier(name) modifiers.extend(name) end
Applies additional config options to this instance.
@param [Options] opts
# File lib/calyx/registry.rb, line 18 def options(opts) @options = @options.merge(opts) end
Registers a new grammar rule.
@param [Symbol] name @param [Array] productions
# File lib/calyx/registry.rb, line 62 def rule(name, *productions) define_rule(name, caller_locations.first, productions) end
Expands a unique rule symbol by evaluating it and checking that it hasn't previously been selected.
@param [Symbol] symbol
# 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 == expand(symbol).size uniques[symbol] = [] pending = false end result = expand(symbol).evaluate(@options) unless uniques[symbol].include?(result) uniques[symbol] << result pending = false end end result end
Private Instance Methods
# File lib/calyx/registry.rb, line 217 def construct_mapping(pairs) mapper = -> (input) { match, target = pairs.detect { |match, target| input =~ match } if match && target input.gsub(match, target) else input end } end
# File lib/calyx/registry.rb, line 211 def reset_evaluation_context @context = {} @memos = {} @uniques = {} end