367 lines
6.8 KiB
Plaintext
Raw Normal View History

%{
//
// Parser.jay
//
// Author:
// Juraj Skripsky (juraj@hotfeet.ch)
//
// (C) 2004 HotFeet GmbH (http://www.hotfeet.ch)
// Copyright 2011 Xamarin Inc (http://www.xamarin.com)
//
using System;
using System.Collections;
using System.Data;
namespace Mono.Data.SqlExpressions {
internal class Parser {
static Parser ()
{
if (Environment.GetEnvironmentVariable ("MONO_DEBUG_SQLEXPRESSIONS") != null)
yacc_verbose_flag = 2;
}
bool cacheAggregationResults = false;
DataRow[] aggregationRows = null;
static int yacc_verbose_flag;
//called by DataTable.Select
//called by DataColumn.set_Expression //FIXME: enable cache in this case?
public Parser () {
ErrorOutput = System.IO.TextWriter.Null;
cacheAggregationResults = true;
}
//called by DataTable.Compute
public Parser (DataRow[] aggregationRows)
{
ErrorOutput = System.IO.TextWriter.Null;
this.aggregationRows = aggregationRows;
}
public IExpression Compile (string sqlExpr)
{
try {
Tokenizer tokenizer = new Tokenizer (sqlExpr);
if (yacc_verbose_flag > 1)
return (IExpression) yyparse (tokenizer,
new yydebug.yyDebugSimple ());
else
return (IExpression) yyparse (tokenizer);
} catch (yyParser.yyException) {
throw new SyntaxErrorException (String.Format ("Expression '{0}' is invalid.", sqlExpr));
}
}
%}
%token PAROPEN PARCLOSE
%token AND OR
%token NOT
%token TRUE FALSE
%token NULL
%token PARENT CHILD
%token EQ LT GT
%token PLUS MINUS
%token MUL DIV MOD
%token DOT COMMA
%token IS IN NOT_IN LIKE NOT_LIKE
%token COUNT SUM AVG MAX MIN STDEV VAR
%token IIF SUBSTRING ISNULL LEN TRIM CONVERT
%token StringLiteral NumberLiteral DateLiteral
%token Identifier
%token FunctionName
%start Expr
%left OR
%left AND
%left NOT
%left EQ LT GT
%left PLUS MINUS
%left MUL DIV MOD
%left UMINUS
%%
Expr
: BoolExpr
| ArithExpr
;
BoolExpr
: PAROPEN BoolExpr PARCLOSE
{
$$ = (IExpression)$2;
}
| BoolExpr AND BoolExpr
{
$$ = new BoolOperation (Operation.AND, (IExpression)$1, (IExpression)$3);
}
| BoolExpr OR BoolExpr
{
$$ = new BoolOperation (Operation.OR, (IExpression)$1, (IExpression)$3);
}
| NOT BoolExpr
{
$$ = new Negation ((IExpression)$2);
}
| Predicate
;
Predicate
: CompPredicate
| IsPredicate
| LikePredicate
| InPredicate
;
CompPredicate
: ArithExpr CompOp ArithExpr
{
$$ = new Comparison ((Operation)$2, (IExpression)$1, (IExpression)$3);
}
;
CompOp
: EQ { $$ = Operation.EQ; }
| NE { $$ = Operation.NE; }
| LT { $$ = Operation.LT; }
| GT { $$ = Operation.GT; }
| LE { $$ = Operation.LE; }
| GE { $$ = Operation.GE; }
;
LE : LT EQ; // <=
NE : LT GT; // <>
GE : GT EQ; // >=
ArithExpr
: PAROPEN ArithExpr PARCLOSE
{
$$ = (IExpression)$2;
}
| ArithExpr MUL ArithExpr
{
$$ = new ArithmeticOperation (Operation.MUL, (IExpression)$1, (IExpression)$3);
}
| ArithExpr DIV ArithExpr
{
$$ = new ArithmeticOperation (Operation.DIV, (IExpression)$1, (IExpression)$3);
}
| ArithExpr MOD ArithExpr
{
$$ = new ArithmeticOperation (Operation.MOD, (IExpression)$1, (IExpression)$3);
}
| ArithExpr PLUS ArithExpr
{
$$ = new ArithmeticOperation (Operation.ADD, (IExpression)$1, (IExpression)$3);
}
| ArithExpr MINUS ArithExpr
{
$$ = new ArithmeticOperation (Operation.SUB, (IExpression)$1, (IExpression)$3);
}
| MINUS ArithExpr %prec UMINUS
{
$$ = new Negative ((IExpression)$2);
}
| Function
| Value
;
Value
: LiteralValue
| SingleColumnValue
;
LiteralValue
: StringLiteral { $$ = new Literal ($1); }
| NumberLiteral { $$ = new Literal ($1); }
| DateLiteral { $$ = new Literal ($1); }
| BoolLiteral
| NULL { $$ = new Literal (null); }
;
BoolLiteral
: TRUE { $$ = new Literal (true); }
| FALSE { $$ = new Literal (false); }
;
SingleColumnValue
: LocalColumnValue
| ParentColumnValue
;
MultiColumnValue
: LocalColumnValue
| ChildColumnValue
;
LocalColumnValue
: ColumnName
{
$$ = new ColumnReference ((string)$1);
}
;
ParentColumnValue
: PARENT DOT ColumnName
{
$$ = new ColumnReference (ReferencedTable.Parent, null, (string)$3);
}
| PARENT PAROPEN RelationName PARCLOSE DOT ColumnName
{
$$ = new ColumnReference (ReferencedTable.Parent, (string)$3, (string)$6);
}
;
ChildColumnValue
: CHILD DOT ColumnName
{
$$ = new ColumnReference (ReferencedTable.Child, null, (string)$3);
}
| CHILD PAROPEN RelationName PARCLOSE DOT ColumnName
{
$$ = new ColumnReference (ReferencedTable.Child, (string)$3, (string)$6);
}
;
ColumnName
: Identifier
| ColumnName DOT Identifier
{
$$ = (string)$1 + "." + (string)$3;
}
;
RelationName
: Identifier;
Function
: CalcFunction
| AggFunction
| StringFunction
;
AggFunction
: AggFunctionName PAROPEN MultiColumnValue PARCLOSE
{
$$ = new Aggregation (cacheAggregationResults, aggregationRows, (AggregationFunction)$1, (ColumnReference)$3);
}
;
AggFunctionName
: COUNT { $$ = AggregationFunction.Count; }
| SUM { $$ = AggregationFunction.Sum; }
| AVG { $$ = AggregationFunction.Avg; }
| MAX { $$ = AggregationFunction.Max; }
| MIN { $$ = AggregationFunction.Min; }
| STDEV { $$ = AggregationFunction.StDev; }
| VAR { $$ = AggregationFunction.Var; }
;
StringExpr
: SingleColumnValue
| StringLiteral { $$ = new Literal ($1); }
| Function
;
StringFunction
: TRIM PAROPEN ArithExpr PARCLOSE
{
$$ = new TrimFunction ((IExpression)$3);
}
| SUBSTRING PAROPEN ArithExpr COMMA ArithExpr COMMA ArithExpr PARCLOSE
{
$$ = new SubstringFunction ((IExpression)$3, (IExpression)$5, (IExpression)$7);
}
;
CalcFunction
: IIF PAROPEN Expr COMMA Expr COMMA Expr PARCLOSE
{
$$ = new IifFunction ((IExpression)$3, (IExpression)$5, (IExpression)$7);
}
| ISNULL PAROPEN Expr COMMA Expr PARCLOSE
{
$$ = new IsNullFunction ((IExpression)$3, (IExpression)$5);
}
| LEN PAROPEN Expr PARCLOSE
{
$$ = new LenFunction ((IExpression)$3);
}
| CONVERT PAROPEN Expr COMMA TypeSpecifier PARCLOSE
{
$$ = new ConvertFunction ((IExpression)$3, (string)$5);
}
;
TypeSpecifier
: StringLiteral
| Identifier
;
IsPredicate
: ArithExpr IS NULL
{
$$ = new Comparison (Operation.EQ, (IExpression)$1, new Literal (null));
}
| ArithExpr IS NOT NULL
{
$$ = new Comparison (Operation.NE, (IExpression)$1, new Literal (null));
}
;
LikePredicate
: StringExpr LIKE StringExpr
{
$$ = new Like ((IExpression)$1, (IExpression)$3);
}
| StringExpr NOT_LIKE StringExpr
{
$$ = new Negation (new Like ((IExpression)$1, (IExpression)$3));
}
;
InPredicate
: ArithExpr IN InPredicateValue
{
$$ = new In ((IExpression)$1, (IList)$3);
}
| ArithExpr NOT_IN InPredicateValue
{
$$ = new Negation (new In ((IExpression)$1, (IList)$3));
}
;
InPredicateValue
: PAROPEN InValueList PARCLOSE { $$ = $2; }
;
InValueList
: LiteralValue
{
$$ = new ArrayList();
((IList)$$).Add ($1);
}
| InValueList COMMA LiteralValue
{
((IList)($$ = $1)).Add ($3);
}
;
%%
}