Skip to content
adqlGrammar.jj 46 KiB
Newer Older
	(t=<UNSIGNED_INTEGER>
	| t=<UNSIGNED_FLOAT>)
	{return t.image;}
}

String SignedInteger(): {Token sign=null, number;} {
	((sign=<PLUS>|sign=<MINUS>)? number=<UNSIGNED_INTEGER>)
	{return ((sign==null)?"":sign.image)+number.image;}
}

/* *********** */
/* EXPRESSIONS */
/* *********** */
ADQLOperand ValueExpressionPrimary(): {String expr; ADQLColumn column; ADQLOperand op;} {
gmantele's avatar
gmantele committed
	try{
		(// unsigned_value_specification
		  expr=UnsignedNumeric() {return queryFactory.createNumericConstant(expr);}
		// string
		| expr=String() {return queryFactory.createStringConstant(expr);}
		// column_reference
		| column=Column() {return column;}
		// set_function_specification
		| op=SqlFunction() {return op;}
		// LEFT_PAR value_expression RIGHT_PAR
		| (<LEFT_PAR> op=ValueExpression() <RIGHT_PAR>) {return queryFactory.createWrappedOperand(op);})
	}catch(Exception ex){
		throw generateParseException(ex);
	}
ADQLOperand ValueExpression(): {ADQLOperand valueExpr = null; } {
	(valueExpr=GeometryValueFunction()
	| LOOKAHEAD(<PLUS> | <MINUS>) valueExpr=NumericExpression()
	| LOOKAHEAD(<COORDSYS>) valueExpr=StringExpression()
	| LOOKAHEAD(StringFactor() <CONCAT>) valueExpr=StringExpression()
	| valueExpr=NumericExpression())

ADQLOperand NumericExpression(): {Token sign=null; ADQLOperand leftOp, rightOp=null;} {
	(leftOp=NumericTerm() ((sign=<PLUS> | sign=<MINUS>) rightOp=NumericExpression())?)
	{
	if (sign == null)
		return leftOp;
	else{
		try{
			return queryFactory.createOperation(leftOp, OperationType.getOperator(sign.image), rightOp);
		}catch(Exception ex){
			throw generateParseException(ex);
		}
	}
	}
}

ADQLOperand NumericTerm(): {Token sign=null; ADQLOperand leftOp, rightOp=null;} {
	(leftOp=Factor() ((sign=<ASTERISK> | sign=<DIVIDE>) rightOp=NumericTerm())?)
	{
	if (sign == null)
		return leftOp;
	else{
		try{
			return queryFactory.createOperation(leftOp, OperationType.getOperator(sign.image), rightOp);
		}catch(Exception ex){
			throw generateParseException(ex);
		}
	}
	}
}

ADQLOperand Factor(): {boolean negative = false;; ADQLOperand op;} {
	(
		(<PLUS> | (<MINUS> {negative = true;}))?
		(LOOKAHEAD(2) op=NumericFunction() | op=ValueExpressionPrimary())
	)
	
	{
		if (negative){
			try{
				op = queryFactory.createNegativeOperand(op);
			}catch(Exception ex){
				throw generateParseException(ex);
			}
		}
		
		return op;
	}
}

ADQLOperand StringExpression(): {ADQLOperand leftOp; ADQLOperand rightOp = null;} {
	leftOp=StringFactor()
	(
		<CONCAT>
		rightOp=StringFactor()
		{
			if (!(leftOp instanceof Concatenation)){
				try{
					ADQLOperand temp = leftOp;
					leftOp = queryFactory.createConcatenation();
					((Concatenation)leftOp).add(temp);
				}catch(Exception ex){
					throw generateParseException(ex);
				}
			}
			((Concatenation)leftOp).add(rightOp);
		}
	)*

ADQLOperand StringFactor(): {ADQLOperand op;} {
	(op=ExtractCoordSys()
	| LOOKAHEAD(2) op=UserDefinedFunction()
	| op=ValueExpressionPrimary())
	{return op;}
}

GeometryValue<GeometryFunction> GeometryExpression(): {ADQLColumn col = null; GeometryFunction gf = null;} {
	(col=Column() | gf=GeometryValueFunction())
	{
		if (col != null)
			return new GeometryValue<GeometryFunction>(col);
		else
			return new GeometryValue<GeometryFunction>(gf);
	}
}

/* ********************************** */
/* BOOLEAN EXPRESSIONS (WHERE clause) */
/* ********************************** */
ClauseConstraints ConditionsList(ClauseConstraints clause): {ADQLConstraint constraint = null; Token op = null; boolean notOp = false;} {
	try{
		[<NOT> {notOp = true;}]
		constraint=Constraint()
		{
			if (notOp) constraint = queryFactory.createNot(constraint);
			notOp = false;
			if (clause instanceof ADQLConstraint)
				clause.add(constraint);
			else
				clause.add(constraint);
		}
		(
			(op=<AND> | op=<OR>)
			[<NOT> {notOp = true;}]
			constraint=Constraint()
			{
				if (notOp) constraint = queryFactory.createNot(constraint);
				notOp = false;
				if (clause instanceof ADQLConstraint)
					clause.add(op.image, constraint);
				else
					clause.add(op.image, constraint);
			}
		)*
	}catch(Exception ex){
		throw generateParseException(ex);
	}
	{return clause;}
}

ADQLConstraint Constraint(): {ADQLConstraint constraint =  null;} {
	(LOOKAHEAD(Predicate()) constraint=Predicate()
	| (
		<LEFT_PAR>
		{
			try{
				constraint = queryFactory.createGroupOfConstraints();
			}catch(Exception ex){
				throw generateParseException(ex);
			}
		}
		ConditionsList((ConstraintsGroup)constraint)
		<RIGHT_PAR>
	))
	{return constraint;}
}

ADQLConstraint Predicate(): {ADQLQuery q=null; ADQLColumn column=null; ADQLOperand strExpr1=null, strExpr2=null; ADQLOperand op; Token notToken = null; ADQLConstraint constraint = null;} {
	try{
		// exists_predicate
		((<EXISTS> q=SubQueryExpression()) {return queryFactory.createExists(q);}
		// null_predicate
		| LOOKAHEAD(Column() <IS>)(column=Column() <IS> [notToken=<NOT>] <NULL> {return queryFactory.createIsNull((notToken!=null), column);})
		// like_predicate
		| LOOKAHEAD(StringExpression() [<NOT>] <LIKE>) (strExpr1=StringExpression() [notToken=<NOT>] <LIKE> strExpr2=StringExpression() {return queryFactory.createComparison(strExpr1, (notToken==null)?ComparisonOperator.LIKE:ComparisonOperator.NOTLIKE, strExpr2);})
		| (op=ValueExpression()
			(// comparison_predicate
			(constraint=ComparisonEnd(op))
			// between predicate
			| LOOKAHEAD(2) constraint=BetweenEnd(op)
			// in_predicate
			| constraint=InEnd(op)
			)
		))
	}catch(Exception ex){
		throw generateParseException(ex);
	}
	{return constraint;}
}

Comparison ComparisonEnd(ADQLOperand leftOp): {Token comp; ADQLOperand rightOp;} {
	((comp=<EQUAL> | comp=<NOT_EQUAL> | comp=<LESS_THAN> | comp=<LESS_EQUAL_THAN> | comp=<GREATER_THAN> | comp=<GREATER_EQUAL_THAN>) rightOp=ValueExpression())
	{
		try{
			return queryFactory.createComparison(leftOp, ComparisonOperator.getOperator(comp.image), rightOp);
		}catch(Exception ex){
			throw generateParseException(ex);
		}
	}
}

Between BetweenEnd(ADQLOperand leftOp): {Token notToken=null; ADQLOperand min, max;} {
	[notToken=<NOT>] <BETWEEN> min=ValueExpression() <AND> max=ValueExpression()
	{
		try{
			return queryFactory.createBetween((notToken!=null), leftOp, min, max);
		}catch(Exception ex){
			throw generateParseException(ex);
		}
	}
}

In InEnd(ADQLOperand leftOp): {Token not=null; ADQLQuery q = null; ADQLOperand item; Vector<ADQLOperand> items = new Vector<ADQLOperand>();} {
	[not=<NOT>] <IN>
	(LOOKAHEAD(2) q=SubQueryExpression()
	| (<LEFT_PAR> item=ValueExpression() {items.add(item);} (<COMMA> item=ValueExpression() {items.add(item);})* <RIGHT_PAR>))
	{
		try{
			if (q != null)
				return queryFactory.createIn(leftOp, q, not!=null);
			else{
				ADQLOperand[] list = new ADQLOperand[items.size()];
				int i=0;
				for(ADQLOperand op : items)
					list[i++] = op;
				return queryFactory.createIn(leftOp, list, not!=null);
			}
		}catch(Exception ex){
			throw generateParseException(ex);
		}
	}
}


/* ************* */
/* SQL FUNCTIONS */
/* ************* */
SQLFunction SqlFunction(): {Token fct, all=null, distinct=null; ADQLOperand op=null; SQLFunction funct = null;}{
	try{
		(
			(<COUNT> <LEFT_PAR> [distinct=<QUANTIFIER>] (all=<ASTERISK> | op=ValueExpression()) <RIGHT_PAR>
			{ funct = queryFactory.createSQLFunction((all!=null)?SQLFunctionType.COUNT_ALL:SQLFunctionType.COUNT, op, distinct != null && distinct.image.equalsIgnoreCase("distinct")); })
		|
			((fct=<AVG> | fct=<MAX> | fct=<MIN> | fct=<SUM>) <LEFT_PAR> [distinct=<QUANTIFIER>] op=ValueExpression() <RIGHT_PAR> 
			{ funct = queryFactory.createSQLFunction(SQLFunctionType.valueOf(fct.image.toUpperCase()), op, distinct != null && distinct.image.equalsIgnoreCase("distinct")); })
		)
	}catch(Exception ex){
		throw generateParseException(ex);
	}


/* ************** */
/* ADQL FUNCTIONS */
/* ************** */
ADQLOperand[] Coordinates(): {ADQLOperand[] ops = new ADQLOperand[2];} {
	ops[0]=NumericExpression() <COMMA> ops[1]=NumericExpression()
	{return ops;}
}

GeometryFunction GeometryFunction(): {Token t=null; GeometryValue<GeometryFunction> gvf1, gvf2; GeometryValue<PointFunction> gvp1, gvp2; GeometryFunction gf = null; PointFunction p1=null, p2=null; ADQLColumn col1 = null, col2 = null;} {
	try{
		// predicate_geometry_function
		(
			((t=<CONTAINS> | t=<INTERSECTS>) <LEFT_PAR> gvf1=GeometryExpression() <COMMA> gvf2=GeometryExpression() <RIGHT_PAR>
			{
				if (t.image.equalsIgnoreCase("contains"))
					gf = queryFactory.createContains(gvf1, gvf2);
				else
					gf = queryFactory.createIntersects(gvf1, gvf2);
			})
		// non_predicate_geometry_function
		|	(<AREA> <LEFT_PAR> gvf1=GeometryExpression() <RIGHT_PAR>) {gf = queryFactory.createArea(gvf1);}
		|	(<COORD1> <LEFT_PAR> (p1=Point() {gf = queryFactory.createCoord1(p1);} | col1=Column() {gf = queryFactory.createCoord1(col1);}) <RIGHT_PAR>)
		|	(<COORD2> <LEFT_PAR> (p1=Point() {gf = queryFactory.createCoord2(p1);} | col1=Column() {gf = queryFactory.createCoord2(col1);}) <RIGHT_PAR>)
		|	(<DISTANCE>
				<LEFT_PAR>
				(p1=Point()|col1=Column()) 
				{
					if (p1 != null)
						gvp1 = new GeometryValue<PointFunction>(p1);
					else
						gvp1 = new GeometryValue<PointFunction>(col1);
				}
				<COMMA>
				(p2=Point()|col2=Column())
				{
					if (p2 != null)
						gvp2 = new GeometryValue<PointFunction>(p2);
					else
						gvp2 = new GeometryValue<PointFunction>(col2);
				} 
				<RIGHT_PAR>
				{gf = queryFactory.createDistance(gvp1, gvp2);}
			)
		)
	}catch(Exception ex){
		throw generateParseException(ex);
	}
	
	{ return gf; }
}

ADQLOperand CoordinateSystem(): { Token oldToken = token; ADQLOperand coordSys=null;}{
	coordSys=StringExpression()
	{
		if (allowedCoordSys.size() > 0){
			TextPosition position = new TextPosition(oldToken.next, token);
			if (coordSys == null)
				throw new ParseException("A coordinate system must always be provided !", position);
			if (coordSys instanceof StringConstant && !isAllowedCoordSys(((StringConstant)coordSys).getValue()))
				throw new ParseException("\""+coordSys.toADQL()+"\" is not an allowed coordinate systems !", position);
		}
			
		return coordSys;
	}
}

GeometryFunction GeometryValueFunction(): {ADQLOperand coordSys; ADQLOperand width, height; ADQLOperand[] coords, tmp; Vector<ADQLOperand> vCoords; ADQLOperand op=null; GeometryValue<GeometryFunction> gvf = null; GeometryFunction gf = null;} {
	try{
		// BOX:
		((<BOX> <LEFT_PAR> coordSys=CoordinateSystem() // coord_sys
				<COMMA> coords=Coordinates() // coordinates
				<COMMA> width=NumericExpression() <COMMA> height=NumericExpression() <RIGHT_PAR>)
		 {gf = queryFactory.createBox(coordSys, coords[0], coords[1], width, height);}
		 
		// CENTROID:
		| (<CENTROID> <LEFT_PAR> gvf=GeometryExpression() <RIGHT_PAR>) {gf = queryFactory.createCentroid(gvf);}
		
		// CIRCLE:
		| (<CIRCLE> <LEFT_PAR> coordSys=CoordinateSystem() // coord_sys
				<COMMA> coords=Coordinates() // coordinates
				<COMMA> width=NumericExpression() <RIGHT_PAR>) // radius
		 {gf = queryFactory.createCircle(coordSys, coords[0], coords[1], width);}
		
		// POINT: 
		| gf=Point()
		
		// POLYGON:
		| (<POLYGON> <LEFT_PAR> coordSys=CoordinateSystem() // coord_sys
				{ vCoords = new Vector<ADQLOperand>(); } // coordinates
				<COMMA> tmp=Coordinates() {vCoords.add(tmp[0]); vCoords.add(tmp[1]);}
				<COMMA> tmp=Coordinates() {vCoords.add(tmp[0]); vCoords.add(tmp[1]);}
				<COMMA> tmp=Coordinates() {vCoords.add(tmp[0]); vCoords.add(tmp[1]);}
				(<COMMA> tmp=Coordinates() {vCoords.add(tmp[0]); vCoords.add(tmp[1]);})*
				<RIGHT_PAR>)
		  { gf = queryFactory.createPolygon(coordSys, vCoords); }
		  
		// REGION:
		| (<REGION> <LEFT_PAR> op=StringExpression() <RIGHT_PAR>) {gf = queryFactory.createRegion(op);})
	}catch(Exception ex){
		throw generateParseException(ex);
	}
	
	{return gf;}
}

PointFunction Point(): {ADQLOperand coordSys; ADQLOperand[] coords;} {
	<POINT> <LEFT_PAR> coordSys=CoordinateSystem() // coord_sys
			<COMMA> coords=Coordinates() <RIGHT_PAR> // coordinates
	{
		try{
			return queryFactory.createPoint(coordSys, coords[0], coords[1]);
		}catch(Exception ex){
			throw generateParseException(ex);
		}
	}
}

GeometryFunction ExtractCoordSys(): {GeometryValue<GeometryFunction> gvf;} {
	<COORDSYS> <LEFT_PAR> gvf=GeometryExpression() <RIGHT_PAR>
	{
		try{
			return queryFactory.createExtractCoordSys(gvf);
		}catch(Exception ex){
			throw generateParseException(ex);
		}
	}
}

/* ***************** */
/* NUMERIC FUNCTIONS */
/* ***************** */
ADQLFunction NumericFunction(): {ADQLFunction fct;} {
	(fct=MathFunction()
	| fct=TrigFunction()
	| fct=GeometryFunction()
	| fct=UserDefinedFunction())
	{return fct;}
}

MathFunction MathFunction(): {Token fct=null; ADQLOperand param1=null, param2=null; String integerValue = null;} {
	try{
		((fct=<ABS> <LEFT_PAR> param1=NumericExpression() <RIGHT_PAR>)
		| (fct=<CEILING> <LEFT_PAR> param1=NumericExpression() <RIGHT_PAR>)
		| (fct=<DEGREES> <LEFT_PAR> param1=NumericExpression() <RIGHT_PAR>)
		| (fct=<EXP> <LEFT_PAR> param1=NumericExpression() <RIGHT_PAR>)
		| (fct=<FLOOR> <LEFT_PAR> param1=NumericExpression() <RIGHT_PAR>)
		| (fct=<LOG> <LEFT_PAR> param1=NumericExpression() <RIGHT_PAR>)
		| (fct=<LOG10> <LEFT_PAR> param1=NumericExpression() <RIGHT_PAR>)
		| (fct=<MOD> <LEFT_PAR> param1=NumericExpression() <COMMA> param2=NumericExpression() <RIGHT_PAR>)
		| (fct=<PI> <LEFT_PAR><RIGHT_PAR>)
		| (fct=<POWER> <LEFT_PAR> param1=NumericExpression() <COMMA> param2=NumericExpression() <RIGHT_PAR>)
		| (fct=<RADIANS> <LEFT_PAR> param1=NumericExpression() <RIGHT_PAR>)
		| (fct=<RAND> <LEFT_PAR> (param1=NumericExpression())? <RIGHT_PAR>)
gmantele's avatar
gmantele committed
		| (fct=<ROUND> <LEFT_PAR> param1=NumericExpression() (<COMMA> integerValue=SignedInteger() {param2 = queryFactory.createNumericConstant(integerValue);})? <RIGHT_PAR>)
		| (fct=<SQRT> <LEFT_PAR> param1=NumericExpression() <RIGHT_PAR>)
gmantele's avatar
gmantele committed
		| (fct=<TRUNCATE> <LEFT_PAR> param1=NumericExpression() (<COMMA> integerValue=SignedInteger() {param2 = queryFactory.createNumericConstant(integerValue);})? <RIGHT_PAR>))
		{
			if (param1 != null)
				return queryFactory.createMathFunction(MathFunctionType.valueOf(fct.image.toUpperCase()), param1, param2);
			else
				return null;
		}
	}catch(Exception ex){
		throw generateParseException(ex);
	}
}

MathFunction TrigFunction(): {Token fct=null; ADQLOperand param1=null, param2=null;} {
	((fct=<ACOS> <LEFT_PAR> param1=NumericExpression() <RIGHT_PAR>)
	| (fct=<ASIN> <LEFT_PAR> param1=NumericExpression() <RIGHT_PAR>)
	| (fct=<ATAN> <LEFT_PAR> param1=NumericExpression() <RIGHT_PAR>)
	| (fct=<ATAN2> <LEFT_PAR> param1=NumericExpression() <COMMA> param2=NumericExpression() <RIGHT_PAR>)
	| (fct=<COS> <LEFT_PAR> param1=NumericExpression() <RIGHT_PAR>)
	| (fct=<COT> <LEFT_PAR> param1=NumericExpression() <RIGHT_PAR>)
	| (fct=<SIN> <LEFT_PAR> param1=NumericExpression() <RIGHT_PAR>)
	| (fct=<TAN> <LEFT_PAR> param1=NumericExpression() <RIGHT_PAR>))
	{
		try{
			if (param1 != null)
				return queryFactory.createMathFunction(MathFunctionType.valueOf(fct.image.toUpperCase()), param1, param2);
			else
				return null;
		}catch(Exception ex){
			throw generateParseException(ex);
		}
	}
}

/* /!\ WARNING: The function name may be prefixed by "udf_" but there is no way to check it here ! */
UserDefinedFunction UserDefinedFunction(): {Token fct; Vector<ADQLOperand> params = new Vector<ADQLOperand>(); ADQLOperand op;} {
	fct=<REGULAR_IDENTIFIER> <LEFT_PAR> (op=ValueExpression() {params.add(op);} (<COMMA> op=ValueExpression() {params.add(op);})*)? <RIGHT_PAR>
	{
		//System.out.println("INFO [ADQLParser]: \""+fct.image+"\" (from line "+fct.beginLine+" and column "+fct.beginColumn+" to line "+token.endLine+" and column "+(token.endColumn+1)+") is considered as an user defined function !");
		try{
			ADQLOperand[] parameters = new ADQLOperand[params.size()];
			for(int i=0; i<params.size(); i++)
				parameters[i] = params.get(i);
			return queryFactory.createUserDefinedFunction(fct.image, parameters);
		}catch(UnsupportedOperationException uoe){
			throw new ParseException(uoe.getMessage(), new TextPosition(fct, token));
		}catch(Exception ex){
			throw generateParseException(ex);
		}
	}
}