lib/antelope/generator/templates/ruby.ant in antelope-0.2.0 vs lib/antelope/generator/templates/ruby.ant in antelope-0.2.2
- old
+ new
@@ -1,146 +1,178 @@
-
-# This file assumes that the output of the generator will be placed
-# within a module or a class. However, the module/class requires a
-# `type` method, which takes a terminal and gives its type, as a
-# symbol. These types should line up with the terminals that were
-# defined in the original grammar.
-
-# The actions to take during parsing. In every state, there are a
-# set of acceptable peek tokens; this table tells the parser what
-# to do on each acceptable peek token. The possible actions include
-# `:accept`, `:reduce`, and `:state`; `:accept` means to accept the
-# input and return the value of the pasing. `:reduce` means to
-# reduce the top of the stack into a given nonterminal. `:state`
-# means to transition to another state.
-#
-# @return [Array<Hash<(Symbol, Array<(Symbol, Numeric)>)>>]
-ACTION_TABLE = {{= generate_action_table }}.freeze
-
-# A list of all of the productions. Only includes the left-hand side,
-# the number of tokens on the right-hand side, and the block to call
-# on reduction.
-#
-# @return [Array<Array<(Symbol, Numeric, Proc)>>]
-PRODUCTIONS = {{= generate_productions_list }}.freeze
-
-# Runs the parser.
-#
-# @param input [Array<Object>] the input to run the parser over.
-# @return [Object] the result of the accept.
-def parse(input)
- stack = []
- stack.push([nil, 0])
- input = input.dup
- last = nil
-
- until stack.empty? do
- last = parse_action(stack, input)
- end
-
- last
-
-end
-
-# Actually performs the parsing action on the given stack on input.
-# If you want to implement a push parser, than messing with this
-# method is probably the way to go.
-#
-# @param stack [Array<Array<(Object, Numeric)>>] the stack of the
-# parser. The actual order of the stack is important.
-# @param input [Array<Object>] the input to run the parser over.
-# The elements of this may be passed to the `type` method.
-# @return [Object] the result of the last accepting reduction.
-def parse_action(stack, input)
- last = nil
- peek_token = if input.empty?
- :$end
- else
- type(input.first)
- end
-
- action = ACTION_TABLE[stack.last.last].fetch(peek_token) do
- ACTION_TABLE[stack.last.last].fetch(:$default)
- end
- case action.first
- when :accept
- production = PRODUCTIONS[action.last]
- last = stack.pop(production[1]).first.first
- stack.pop
- when :reduce
- production = PRODUCTIONS[action.last]
- removing = stack.pop(production[1])
- value = instance_exec(*removing.map(&:first), &production[2])
- goto = ACTION_TABLE[stack.last.last][production[0]]
- stack.push([value, goto.last])
- when :state
- stack.push([input.shift, action.last])
- else
- raise NotImplementedError, "Unknown action #{action.first}"
- end
-
- last
-
-rescue KeyError => e
- if handle_error(
- { :stack => stack,
- :peek => peek_token,
- :remaining => input,
- :error => e,
- :expected => ACTION_TABLE[stack.last.last].keys
- })
- retry
- end
-end
-
-{{ if define_own_handler? }}
-def handle_error(data, _ = false)
-{{ if panic_mode? }}
- if _ || data[:peek] == :$end # we can't recover if
- # we're at the end
-{{ end }}
- raise {{= error_class }},
- "Unexpected token #{data[:peek]}; " \
- "expected one of #{data[:expected].join(', ')}",
- data[:error].backtrace
-{{ if panic_mode? }}
- end
-
- new_peek = :$error
- acceptable_state = false
- state = nil
-
- until data[:stack].empty? or acceptable_state
- state = data[:stack].last.last
-
- if ACTION_TABLE[state].key?(new_peek)
- acceptable_state = true
- else
- data[:stack].pop # discard
- end
- end
-
- return handle_error(data, true) unless acceptable_state
-
- action = ACTION_TABLE[state][new_peek]
- lookaheads = nil
-
- until lookaheads
- if action[0] == :state
- lookaheads = ACTION_TABLE[action.last].keys
- elsif action[0] == :reduce
- rule = PRODUCTIONS[action.last]
- action = ACTION_TABLE[stack[-rule[1]].last][rule[0]]
- end
- end
-
- until data[:remaining].empty? || lookaheads.
- include?(data[:remaining][0].first)
- data[:remaining].shift
- end
-
- data[:remaining].unshift([new_peek, data[:error]])
- true
-
-{{ end }}
-end
-{{ end }}
+
+# This file assumes that the output of the generator will be placed
+# within a module or a class. However, the module/class requires a
+# `type` method, which takes a terminal and gives its type, as a
+# symbol. These types should line up with the terminals that were
+# defined in the original grammar.
+
+# The actions to take during parsing. In every state, there are a
+# set of acceptable peek tokens; this table tells the parser what
+# to do on each acceptable peek token. The possible actions include
+# `:accept`, `:reduce`, and `:state`; `:accept` means to accept the
+# input and return the value of the pasing. `:reduce` means to
+# reduce the top of the stack into a given nonterminal. `:state`
+# means to transition to another state.
+#
+# @return [Array<Hash<(Symbol, Array<(Symbol, Numeric)>)>>]
+ACTION_TABLE = {{= generate_action_table }}.freeze
+
+# The default action that is taken for most reductions.
+#
+# @return [Proc]
+DEFAULT_PROC = proc { |_| _ }
+# A list of all of the productions. Only includes the left-hand side,
+# the number of tokens on the right-hand side, and the block to call
+# on reduction.
+#
+# @return [Array<Array<(Symbol, Numeric, Proc)>>]
+PRODUCTIONS = {{= generate_productions_list }}.freeze
+
+# Runs the parser.
+#
+# @param input [Array] the input to run the parser over.
+# @return [Object] the result of the accept.
+def parse(input)
+ stack = []
+ stack.push([nil, 0])
+ last = nil
+ input = input.to_a.dup
+
+ until stack.empty? do
+ last = parse_action(stack, input)
+ end
+
+ last
+
+end
+
+# Actually performs the parsing action on the given stack on input.
+# If you want to implement a push parser, than messing with this
+# method is probably the way to go.
+#
+# @param stack [Array<Array<(Object, Numeric)>>] the stack of the
+# parser. The actual order of the stack is important.
+# @param input [Array<Object>] the input to run the parser over.
+# The elements of this may be passed to the `type` method.
+# @return [Object] the result of the last accepting reduction.
+def parse_action(stack, input)
+ last = nil
+ peek_token = if input.empty?
+ :$end
+ else
+ type(input.first)
+ end
+
+ action = ACTION_TABLE[stack.last.last].fetch(peek_token) do
+ ACTION_TABLE[stack.last.last].fetch(:$default)
+ end
+
+ case action.first
+ when :accept
+ production = PRODUCTIONS[action.last]
+ last = stack.pop(production[1]).first.first
+ stack.pop
+ when :reduce
+ production = PRODUCTIONS[action.last]
+ removing = stack.pop(production[1])
+ value = instance_exec(*removing.map(&:first), &production[2])
+ goto = ACTION_TABLE[stack.last.last][production[0]]
+ stack.push([value, goto.last])
+ when :state
+ stack.push([input.shift, action.last])
+ else
+ raise NotImplementedError, "Unknown action #{action.first}"
+ end
+
+ last
+
+rescue KeyError => e
+ peek = input.first
+
+ if handle_error({
+ :stack => stack,
+ :peek => peek_token,
+ :remaining => input,
+ :error => e,
+ :line => line_of(peek),
+ :column => column_of(peek),
+ :expected => ACTION_TABLE[stack.last.last].keys
+ })
+ retry
+ else
+ raise
+ end
+end
+
+private
+
+def line_of(peek)
+ if peek.respond_to?(:line)
+ peek.line
+ else
+ 0
+ end
+end
+
+def column_of(peek)
+ if peek.respond_to?(:column)
+ peek.column
+ else
+ 0
+ end
+end
+
+{{ if define_own_handler? }}
+def handle_error(data, _ = false)
+{{ if panic_mode? }}
+ if _ || data[:peek] == :$end # we can't recover if
+ # we're at the end
+{{ end }}
+ raise {{= error_class }},
+ "Unexpected token #{data[:peek]} on line #{data[:line]}, " \
+ "column #{data[:column]}; expected one of " \
+ "#{data[:expected].join(', ')}",
+ data[:error].backtrace
+{{ if panic_mode? }}
+ end
+
+ new_peek = :$error
+ acceptable_state = false
+ state = nil
+
+ until data[:stack].empty? or acceptable_state
+ state = data[:stack].last.last
+
+ if ACTION_TABLE[state].key?(new_peek)
+ acceptable_state = true
+ else
+ data[:stack].pop # discard
+ end
+ end
+
+ return handle_error(data, true) unless acceptable_state
+
+ action = ACTION_TABLE[state][new_peek]
+ lookaheads = nil
+
+ until lookaheads
+ if action[0] == :state
+ lookaheads = ACTION_TABLE[action.last].keys
+ elsif action[0] == :reduce
+ rule = PRODUCTIONS[action.last]
+ action = ACTION_TABLE[stack[-rule[1]].last][rule[0]]
+ end
+ end
+
+ begin
+ until lookaheads.include?(data[:remaining][0].peek)
+ data[:remaining].next
+ end
+ rescue StopIteration
+ end
+
+ data[:remaining].unshift([new_peek, data[:error]])
+ true
+
+{{ end }}
+end
+{{ end }}