module Mapper

  # The atomic part of the rule. 
  # If :type is :symbol, then :data means the string representing a nonterminal symbol.
  # If :type is :literal, then :data means the string representing terminal symbol(s).
  # The depth attribute is reserved for purposes of the mapper.
  # The :track is used only when Mapper#track_support_on == true 
  Token = Struct.new( :type, :data, :depth, :track )
  
  # The internal representation of the language syntax, used for the genotype->phenotype mapping of 
  # Grammatical Evolution. The genotype is basically the array of fixnums, the phenotype is the source
  # code in some programming language, or, in general, any construct following the syntax.  
  # See http://www.grammatical-evolution.org/ 
  # 
  # A Grammar instance is created by the parser (e.g. Abnf::Parser) and passed as a main constructor 
  # argument of objects subclassing Mapper::Base.
  # The instance of the Grammar class is basically a Hash of { symbol1 => Rule1, symbol2 => Rule2 ... } 
  # assignments. each_pair of the hash maps the nonterminal symbol[i] to RuleAlt[i]. The Mapper::RuleAlt 
  # object is the array of all rule alternatives expanding the given symbol).
  # 
  # The Grammar has to define a start_symbol for successful mapping. 
  # 
  class Grammar < Hash

    # Initialize a Grammar. 
    # The src argument is the instance of any Hash subclass (for deep copying), the start argument is 
    # the start symbol definition.
    def initialize( src=nil, start=nil )
      super()
      update src unless src.nil?

      if start.nil? 
        @start_symbol = src.start_symbol if src.kind_of? Grammar
      else
        @start_symbol = start
      end
    end

    # Return a deep copy of the instance.
    def deep_copy
      copy = Grammar.new( nil, @start_symbol )
      each_pair {|symb, alt| copy[symb] = alt.deep_copy }
      copy 
    end

    # Return the array of all defined the symbols, sorted.
    def symbols
      keys.sort
    end

    # Start symbol of the genotype-phenotype mapping.
    attr_accessor :start_symbol

  end

  # One rule alternative. Mapper::RuleAlt is, in fact, an array of Mapper::Token structures.
  # For instance:
  #   <expr> ::= X*Y  
  #   
  # defines the Mapper::Rule of one RuleAlt alternative for the symbol <expr>. 
  # The first and only RuleAlt consists of this sequence:
  #   Mapper::Token.new( :symbol, 'X' )
  #   Mapper::Token.new( :literal, '*' )
  #   Mapper::Token.new( :symbol, 'Y' ) 
  # 
  class RuleAlt < Array

    # Initialize the array of the rules.
    # The src argument is the instance of an array of Mapper::Token instances. 
    # The recursive argument will be copied into self.recursivity attribute.
    # The arity argument will be copied into self.arity attribute. 
    # The min_depth will be copied into self.min_depth attribute.
    def initialize( ary=nil, recursive=nil, arity=nil, min_depth=nil )
      super ary unless ary.nil? 
      @recursivity = recursive
      @arity = arity
      @min_depth = min_depth
    end 

    # Return a deep copy of the instance.   
    def deep_copy
      alt = map {|t| Token.new( t.type, t.data, t.depth ) } 
      RuleAlt.new( alt, @recursivity, @arity, @min_depth )
    end

    # The RuleAlt recursivity used in Validator.analyze_recursivity process (see), based on nonterminal :symbol-ic Token-s.
    # Allowed values are: 
    #   :infinite ... the RuleAlt contains at least one :infinite :symbol, 
    #   :cyclic ... the RuleAlt contains no :infinite symbol and contains at least one :cyclic :symbol, 
    #   :terminating .. the RuleAlt does not contain :infinite nor :cyclic :symbol-s (ie. contains only :literal-s). 
    #   
    attr_accessor :recursivity

    # The RuleAlt arity used in Validator.analyze_arity process (see). 
    # 'arity' is the number of tokens with type == :symbol in the RuleAlt 
    attr_accessor :arity

    #  The RuleAlt min_depth used in Validator.analyze_min_depth process (see).
    #  This is a minimal number of mapping steps required by the generator to finish the mapping process.
    attr_accessor :min_depth

  end
 
  # Right-hand side of the syntactic rule, composed from logical aternatives.
  # Rule contains one or more Mapper::RuleAlt objects, for GE Mapper::Base to select from.
  #
  # For instance:
  #   <expr> ::= X | X+Y | X*Y  
  #   
  # defines the Rule of three RuleAlts for the symbol "<expr>". 
  # 
  class Rule < Array
    
    # Initialize the Rule from the ary argument (ie. from the Enumerable of RuleAlts).
    # The recursive, sn_altering and min_depth arguments will be copied into self.recursivity, 
    # self.sn_altering and self.min_depth attribute, respectively. 
    #  
    def initialize( ary=nil, recursive=nil, sn_altering=nil, min_depth=nil )
      super ary unless ary.nil?
      @recursivity = recursive
      @sn_altering = sn_altering
      @min_depth = min_depth     
    end 

    # Return a deep copy of the instance.     
    def deep_copy
      rule = map {|r| r.deep_copy } 
      Rule.new( rule, @recursivity, @sn_altering, @min_depth )
    end

    # The Rule (symbol) recursivity used in Validator.analyze_min_depth process (see).
    # Allowed values are: 
    #   :infinite ... the Rule contains only :infinite RuleAlts, 
    #   :cyclic ... the Rule contains at least one :cyclic RuleAlt, 
    #   :terminating .. the Rule contains only :terminating RuleAlts. 
    #   
    attr_accessor :recursivity   

    # The sn_altering (structural/nodal altering) attribute is used in Validator.analyze_sn_altering process (see).
    # Allowed values are:
    #   :structural ... the mutation on this position can result in the structural change of the phenotype.
    #   :nodal ... the mutation on this position cannot result in the structural change (the decision tree is unchanged).
    #
    attr_accessor :sn_altering

    #  The min_depth attribute used in Validator.analyze_recursivity process (see).
    #  This is a minimal number of mapping steps required by the generator to finish the mapping process.
    attr_accessor :min_depth
   
  end

end