module OracleSqlParser::Grammar

grammar Grammar
  include OracleSqlParser::Grammar::ReservedWord
  include OracleSqlParser::Grammar::Condition
  include OracleSqlParser::Grammar::Expression
  include OracleSqlParser::Grammar::Select
  include OracleSqlParser::Grammar::Update
  include OracleSqlParser::Grammar::Insert
  include OracleSqlParser::Grammar::Delete
  rule sql
    q:(
      select_statement /
      update_statement /
      insert_statement /
      delete_statement
    ) {
      def ast
        q.ast
      end
    }
  end

  rule ident
    !keyword
    i:(
      c:ident_content_with_double_quote /
      c:ident_content
    ) {
      def ast
        i.c.ast
      end
    }
  end

  rule ident_content
    [a-zA-Z] [a-zA-Z0-9_]* {
      def ast
        OracleSqlParser::Ast::Identifier[:name => text_value]
      end
    }
  end

  rule ident_content_with_double_quote
    '"' name:[^"]* '"' {
      def ast
        OracleSqlParser::Ast::Identifier[:name => name.text_value, :quoted => true]
      end
    }
  end

  rule space
    [ \n]+
  end

  rule hint # not implemented
    '/*+' '*/' {
      def ast
        nil
      end
    }
  end

  rule t_alias
    ident {
      def ast
        super
      end
    }
  end

  rule c_alias
    ident {
      def ast
        super
      end
    }
  end

  rule table_name
    ident {
      def ast
        super
      end
    }
  end

  rule column_name
    ident {
      def ast
        super
      end
    }
  end

  rule schema_name
    ident {
      def ast
        super
      end
    }
  end

  rule number_literal
    '-'? [0-9]+ ([.] [0-9]+)? {
      def ast
        OracleSqlParser::Ast::NumberLiteral.new(:value => text_value)
      end
    }
  end

  rule position
    integer {
      def ast
        super
      end
    }
  end

  rule integer
    '-'? [0-9]+ {
      def ast
        OracleSqlParser::Ast::NumberLiteral.new(:value => text_value)
      end
    }
  end

  rule text_literal
    "'" ("\\'" / !"'" .)* "'" {
      def ast
        OracleSqlParser::Ast::TextLiteral.new(:value => text_value[1..-2])
      end
    }
  end

  rule table_reference
    t:(
      &'(' space? subquery /
      schema_name:schema_name '.' table_name:table_name /
      table_name:table_name
    ) l:('@' dblink)? a:(space t_alias)? {
      def ast
        OracleSqlParser::Ast::TableReference[
          :schema_name => t.try(:schema_name).ast,
          :table_name => t.try(:table_name).ast,
          :dblink => l.try(:dblink).ast,
          :subquery => t.try(:subquery).ast,
          :table_alias => a.try(:t_alias).ast,
        ]
      end
    }
  end

  rule current_of
    current_of_keyword space? cursor_name {
      def ast
        OracleSqlParser::Ast::CurrentOf[
          :cursor => cursor_name.ast
        ]
      end
    }
  end

  rule dblink
    ident {
      def ast
        super
      end
    }
  end

  rule cursor_name
    ident {
      def ast
        super
      end
    }
  end

  rule sequence
    ident space? '.' space? n:(currval_keyword / nextval_keyword) {
      def ast
        OracleSqlParser::Ast::Identifier[:name => text_value]
      end
    }
  end

  rule package_name
    ident {
      def ast
        super
      end
    }
  end

  rule procedure_name
    ident {
      def ast
        super
      end
    }
  end
end

end