lib/antelope/generation/recognizer/rule.rb in antelope-0.0.1 vs lib/antelope/generation/recognizer/rule.rb in antelope-0.1.0
- old
+ new
@@ -1,28 +1,76 @@
# encoding: utf-8
+require "securerandom"
+
module Antelope
module Generation
class Recognizer
+
+ # Defines a rule. A rule has a corresponding production, and a
+ # position in that production. It also contains extra
+ # information for other reasons.
class Rule
+ # The left-hand side of the rule.
+ #
+ # @return [Ace::Token::Nonterminal]
attr_reader :left
+
+ # The right-hand side of the rule.
+ #
+ # @return [Ace::Token]
attr_reader :right
+
+ # The current position inside of the rule.
+ #
+ # @return [Numeric]
attr_reader :position
+
+ # The block to be executed on production match.
+ #
+ # @deprecated Use {Ace::Grammar::Production#block} instead.
+ # @return [String]
attr_reader :block
+
+ # The lookahead set for this specific rule. Contains nothing
+ # unless {#final?} returns true.
+ #
+ # @return [Set<Symbol>]
attr_accessor :lookahead
+
+ # The id for this rule. Initialy, this is set to a string of
+ # hexadecimal characters; after construction of all states,
+ # however, it is a number.
+ #
+ # @return [String, Numeric]
attr_accessor :id
- attr_accessor :presidence
+
+ # The precedence for this rule.
+ #
+ # @return [Ace::Precedence]
+ attr_accessor :precedence
+
+ # The associated production.
+ #
+ # @return [Ace::Grammar::Production]
attr_reader :production
include Comparable
+ # Initialize the rule.
+ #
+ # @param production [Ace::Grammar::Production] the production
+ # that this rule is based off of.
+ # @param position [Numeric] the position that this rule is in
+ # the production.
+ # @param inherited [nil] do not use.
def initialize(production, position, inherited = false)
- @left = production.label
+ @left = production.label.dup
@position = position
@lookahead = Set.new
- @presidence = production.prec
+ @precedence = production.prec
@production = production
@block = production.block
@id = SecureRandom.hex
if inherited
@@ -30,61 +78,113 @@
else
@right = production.items.map(&:dup).freeze
end
end
+ # Give a nice representation of the rule as a string.
+ #
+ # @return [String]
def inspect
- "#<#{self.class} id=#{id} left=#{left} right=[#{right.join(" ")}] position=#{position}>"
+ "#<#{self.class} id=#{id} left=#{left} " \
+ "right=[#{right.join(" ")}] position=#{position}>"
end
+ # Give a nicer representation of the rule as a string. Shows
+ # the id of the rule, the precedence, and the actual
+ # production; if the given argument is true, it will show a
+ # dot to show the position of the rule.
+ #
+ # @param dot [Boolean] show the current position of the rule.
+ # @return [String]
def to_s(dot = true)
- "#{id}/#{presidence.type.to_s[0]}#{presidence.level}: #{left} → #{right[0, position].join(" ")}#{" • " if dot}#{right[position..-1].join(" ")}"
+ "#{id}/#{precedence.type.to_s[0]}#{precedence.level}: " \
+ "#{left} → #{right[0, position].join(" ")}" \
+ "#{" • " if dot}#{right[position..-1].join(" ")}"
end
+ # Returns the active token. If there is no active token, it
+ # returns a blank {Ace::Token}.
+ #
+ # @return [Ace::Token]
def active
right[position] or Ace::Token.new(nil)
end
+ # Creates the rule after this one by incrementing the position
+ # by one. {#succ?} should be called to make sure that this
+ # rule exists.
+ #
+ # @return [Rule]
def succ
Rule.new(production, position + 1)
end
+ # Checks to see if a rule can exist after this one; i.e. the
+ # position is not equal to the size of the right side of the
+ # rule.
+ #
+ # @return [Boolean]
def succ?
- right.size > (position)
+ right.size > position
end
+ # Checks to see if this is the final rule, as in no rule can
+ # exist after this one; i.e. the position is equal to the
+ # size of the right side.
+ #
+ # @return [Boolean]
def final?
!succ?
end
+ # Compares this rule to another object. If the other object
+ # is not a rule, it delegates the comparison. Otherwise, it
+ # converts both this and the other rule into arrays and
+ # compares the result.
+ #
+ # @param other [Object] the object to compare.
+ # @return [Numeric]
def <=>(other)
if other.is_a? Rule
to_a <=> other.to_a
else
super
end
end
- def without_transitions
- @_without_transitions ||=
- Rule.new(production, position)
- end
-
+ # Fuzzily compares this object to another object. If the
+ # other object is not a rule, it delegates the comparison.
+ # Otherwise, it fuzzily compares the left and right sides.
+ #
+ # @param other [Object] the object to compare.
+ # @return [Numeric]
def ===(other)
if other.is_a? Rule
left === other.left and right.each_with_index.
all? { |e, i| e === other.right[i] }
else
super
end
end
+ # Generates a hash for this class.
+ #
+ # @note This is not intended for use. It is only defined to be
+ # compatible with Hashs (and by extension, Sets).
+ # @private
+ # @return [Object]
def hash
to_a.hash
end
alias_method :eql?, :==
+ # Creates an array representation of this class.
+ #
+ # @note This is not intended for use. It is only defined to
+ # make equality checking easier, and to create a hash.
+ # @private
+ # @return [Array<(Ace::Token::Nonterminal, Array<Ace::Token>, Numeric)>]
def to_a
[left, right, position]
end
end
end