lib/antelope/generation/recognizer/rule.rb in antelope-0.2.0 vs lib/antelope/generation/recognizer/rule.rb in antelope-0.2.2

- old
+ new

@@ -1,216 +1,216 @@ -# 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 [Array<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::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 - - # The precedence for this rule. - # - # @return [Ace::Precedence] - attr_accessor :precedence - - # The associated production. - # - # @return [Ace::Production] - attr_reader :production - - include Comparable - - # Initialize the rule. - # - # @param production [Ace::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.dup - @position = position - @lookahead = Set.new - @precedence = production.prec - @production = production - @block = production.block - @id = SecureRandom.hex - - if inherited - @left, @right = inherited - else - @right = production.items.map(&:dup) - 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}>" - 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}/#{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, [left, right]) - 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 - 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 - - # The complete opposite of {#final?} - it checks to see if - # this is the first rule, as in no rule can exist before this - # one; i.e. the position is zero. - # - # @return [Boolean] - def start? - position.zero? - 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 ==(other) - hash == other.hash if other.respond_to?(:hash) - end - - alias_method :eql?, :== - - # 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.size == other.right.size and - right.each_with_index. - all? { |e, i| e === other.right[i] } - else - super - end - end - - # Produces a clone of the rule; any modifications made to the - # contents of that rule do not reflect the contents of this - # rule. - # - # @return [Rule] - def clone - Rule.new(production, position) - 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 - @_hash ||= to_a.hash - end - - # 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 - @_array ||= [left, right, position] - end - end - end - end -end +# 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 [Array<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::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 + + # The precedence for this rule. + # + # @return [Ace::Precedence] + attr_accessor :precedence + + # The associated production. + # + # @return [Ace::Production] + attr_reader :production + + include Comparable + + # Initialize the rule. + # + # @param production [Ace::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.dup + @position = position + @lookahead = Set.new + @precedence = production.prec + @production = production + @block = production.block + @id = "%10x" % object_id + + if inherited + @left, @right = inherited + else + @right = production.items.map(&:dup) + 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}>" + 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}/#{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, [left, right]) + 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 + 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 + + # The complete opposite of {#final?} - it checks to see if + # this is the first rule, as in no rule can exist before this + # one; i.e. the position is zero. + # + # @return [Boolean] + def start? + position.zero? + 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 ==(other) + hash == other.hash if other.respond_to?(:hash) + end + + alias_method :eql?, :== + + # 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.size == other.right.size and + right.each_with_index. + all? { |e, i| e === other.right[i] } + else + super + end + end + + # Produces a clone of the rule; any modifications made to the + # contents of that rule do not reflect the contents of this + # rule. + # + # @return [Rule] + def clone + Rule.new(production, position) + 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 + @_hash ||= to_a.hash + end + + # 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 + @_array ||= [left, right, position] + end + end + end + end +end