Class: Calyx::Registry

Inherits:
Object
  • Object
show all
Defined in:
lib/calyx/registry.rb

Overview

Lookup table of all the available rules in the grammar.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeRegistry

Construct an empty registry.



7
8
9
10
11
12
# File 'lib/calyx/registry.rb', line 7

def initialize
  @options = Options.new({})
  @rules = {}
  @transforms = {}
  @modifiers = Modifiers.new
end

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.

Parameters:

  • name (Symbol)
  • productions (Array)


53
54
55
# File 'lib/calyx/registry.rb', line 53

def method_missing(name, *productions)
  define_rule(name, caller_locations.first, productions)
end

Instance Attribute Details

#modifiersObject (readonly)

Returns the value of attribute modifiers.



4
5
6
# File 'lib/calyx/registry.rb', line 4

def modifiers
  @modifiers
end

#rulesObject (readonly)

Returns the value of attribute rules.



4
5
6
# File 'lib/calyx/registry.rb', line 4

def rules
  @rules
end

#transformsObject (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.

Parameters:



148
149
150
# File 'lib/calyx/registry.rb', line 148

def combine(registry)
  @rules = rules.merge(registry.rules)
end

#define_context_rule(name, trace, productions) ⇒ Object

Defines a rule in the temporary evaluation context.

Parameters:

  • name (Symbol)
  • productions (Array)


77
78
79
80
# File 'lib/calyx/registry.rb', line 77

def define_context_rule(name, trace, productions)
  productions = [productions] unless productions.is_a?(Enumerable)
  context[name.to_sym] = Rule.new(name.to_sym, construct_rule(productions), trace)
end

#define_rule(name, trace, productions) ⇒ Object

Defines a static rule in the grammar.

Parameters:

  • name (Symbol)
  • productions (Array)


69
70
71
# File 'lib/calyx/registry.rb', line 69

def define_rule(name, trace, productions)
  rules[name.to_sym] = Rule.new(name.to_sym, construct_rule(productions), trace)
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.

Parameters:

  • start_symbol (Symbol) (defaults to: :start)
  • rules_map (Hash) (defaults to: {})

Returns:

  • (Array)


160
161
162
163
164
165
166
167
168
169
170
171
172
# File 'lib/calyx/registry.rb', line 160

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

#expand(symbol) ⇒ Calyx::Rule

Expands the given symbol to its rule.

Parameters:

  • symbol (Symbol)

Returns:



86
87
88
89
90
91
92
93
94
95
96
97
98
99
# File 'lib/calyx/registry.rb', line 86

def expand(symbol)
  expansion = rules[symbol] || context[symbol]

  if expansion.nil?
    if @options.strict?
      raise Errors::UndefinedRule.new(@last_expansion, symbol)
    else
      expansion = Production::Terminal.new('')
    end
  end

  @last_expansion = expansion
  expansion
end

#filter(name, callable = nil) {|String| ... } ⇒ Object

Registers the given block as a string filter.

Parameters:

  • name (Symbol)

Yields:

  • (String)

Yield Returns:

  • (String)


41
42
43
44
45
46
47
# File 'lib/calyx/registry.rb', line 41

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.

Parameters:

  • name (Symbol)
  • pairs (Hash<Regex,String>)


32
33
34
# File 'lib/calyx/registry.rb', line 32

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.

Parameters:

  • symbol (Symbol)


118
119
120
# File 'lib/calyx/registry.rb', line 118

def memoize_expansion(symbol)
  memos[symbol] ||= expand(symbol).evaluate(@options)
end

#modifier(name) ⇒ Object

Attaches a modifier module to this instance.

Parameters:

  • name (Module)


24
25
26
# File 'lib/calyx/registry.rb', line 24

def modifier(name)
  modifiers.extend(name)
end

#options(opts) ⇒ Object

Applies additional config options to this instance.

Parameters:



17
18
19
# File 'lib/calyx/registry.rb', line 17

def options(opts)
  @options = @options.merge(opts)
end

#rule(name, *productions) ⇒ Object

Registers a new grammar rule.

Parameters:

  • name (Symbol)
  • productions (Array)


61
62
63
# File 'lib/calyx/registry.rb', line 61

def rule(name, *productions)
  define_rule(name, caller_locations.first, productions)
end

#transform(name, value) ⇒ String

Applies the given modifier function to the given value to transform it.

Parameters:

  • name (Symbol)
  • value (String)

Returns:

  • (String)


106
107
108
109
110
111
112
# File 'lib/calyx/registry.rb', line 106

def transform(name, value)
  if transforms.key?(name)
    transforms[name].call(value)
  else
    modifiers.transform(name, value)
  end
end

#unique_expansion(symbol) ⇒ Object

Expands a unique rule symbol by evaluating it and checking that it hasn’t previously been selected.

Parameters:

  • symbol (Symbol)


126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
# File 'lib/calyx/registry.rb', line 126

def unique_expansion(symbol)
  pending = true
  uniques[symbol] = [] if uniques[symbol].nil?

  while pending
    result = expand(symbol).evaluate(@options)

    unless uniques[symbol].include?(result)
      uniques[symbol] << result
      pending = false
    end
  end

  result
end