package org.reldb.rel.v0.interpreter;
import java.util.*;
import org.reldb.rel.exceptions.*;
import org.reldb.rel.v0.generator.*;
import org.reldb.rel.v0.generator.Generator.Summarize.SummarizeItem;
import org.reldb.rel.v0.languages.tutoriald.BaseASTNode;
import org.reldb.rel.v0.languages.tutoriald.parser.*;
import org.reldb.rel.v0.storage.BuiltinTypeBuilder;
import org.reldb.rel.v0.storage.relvars.RelvarHeading;
import org.reldb.rel.v0.storage.relvars.RelvarMetadata;
import org.reldb.rel.v0.storage.relvars.RelvarRealMetadata;
import org.reldb.rel.v0.types.*;
import org.reldb.rel.v0.types.builtin.TypeBoolean;
import org.reldb.rel.v0.types.builtin.TypeCharacter;
import org.reldb.rel.v0.types.builtin.TypeInteger;
import org.reldb.rel.v0.types.builtin.TypeRational;
import org.reldb.rel.v0.types.userdefined.*;
import org.reldb.rel.v0.values.*;
import org.reldb.rel.v0.vm.Context;
import org.reldb.rel.v0.vm.NativeFunction;
import org.reldb.rel.v0.vm.Operator;
import org.reldb.rel.v0.vm.VirtualMachine;
import org.reldb.rel.v0.vm.instructions.core.OpLte;
public class TutorialDParser implements TutorialDVisitor {
// Code generator
private Generator generator;
// Current node (for error reporting)
private BaseASTNode currentNode;
// False if operatorsAreStorable > 0
private int operatorsAreStorable = 0;
/** Ctor */
public TutorialDParser(Generator generator) {
this.generator = generator;
generator.setParser(this);
}
public void beginOperatorsNonStorable() {
operatorsAreStorable++;
}
public void endOperatorsNonStorable() {
operatorsAreStorable--;
}
public BaseASTNode getCurrentNode() {
return currentNode;
}
// Obtain the source code of a given node
private String getSourceCodeOf(BaseASTNode node) {
StringBuffer source = new StringBuffer();
Token currentToken = node.first_token;
while (currentToken != null) {
source.append(currentToken);
if (currentToken == node.last_token)
break;
source.append(' ');
currentToken = currentToken.next;
}
return source.toString().trim();
}
// Obtain the source code of a child of a given node
private String getSourceCodeOfChild(SimpleNode node, int childIndex) {
return getSourceCodeOf(getChild(node, childIndex));
}
// Compile a given child of the given node
private Object compileChild(SimpleNode node, int childIndex, Object data) {
return node.jjtGetChild(childIndex).jjtAccept(this, data);
}
// Compile all children of the given node
private void compileChildren(SimpleNode node, Object data) {
node.childrenAccept(this, data);
}
// Get the ith child as a BaseASTNode
private static BaseASTNode getChild(SimpleNode node, int childIndex) {
return (BaseASTNode)node.jjtGetChild(childIndex);
}
// Get the token value of the ith child of a given node.
private static String getTokenOfChild(SimpleNode node, int childIndex) {
return getChild(node, childIndex).tokenValue;
}
// Get the count of children of a given node.
private static int getChildCount(SimpleNode node) {
return node.jjtGetNumChildren();
}
// Get the count of children of a given child.
private static int getChildCountOfChild(SimpleNode node, int childIndex) {
return ((SimpleNode)getChild(node, childIndex)).jjtGetNumChildren();
}
public Object visit(SimpleNode node, Object data) {
System.out.println(node + ": acceptor not implemented in subclass?");
return data;
}
//
// Type definition
//
public Object visit(ASTTypeDef node, Object data) {
currentNode = node;
// Child 0 - type name
String typeName = getTokenOfChild(node, 0);
// Compile remaining children
for (int i=1; i<getChildCount(node); i++)
compileChild(node, i, typeName);
return null;
}
public Object visit(ASTTypeDefExternal node, Object data) {
currentNode = node;
// data - type name
String typeName = (String)data;
// Child 0 - external language name
String language = getTokenOfChild(node, 0);
// node.tokenValue - external source code
String source = node.tokenValue;
generator.createTypeExternal(typeName, language, source, new References());
return null;
}
/*
* Possrep nodes
*/
public Object visit(ASTTypeDefInternal node, Object data) {
currentNode = node;
References references = new References();
generator.setGlobalReferenceCollector(references);
// data - type name
String typeName = (String)data;
// Create new type
TypeAlpha typedef = new TypeAlpha(typeName);
generator.createTypeInternalForwardReference(typedef);
// Compile children
for (int i=0; i<getChildCount(node); i++)
compileChild(node, i, typedef);
generator.setGlobalReferenceCollector(null);
generator.createTypeInternal(typedef, getSourceCodeOf(node), references);
return data;
}
public Object visit(ASTTypeDefInternalOptOrdinal node, Object data) {
currentNode = node;
((TypeAlpha)data).setOrdinal(true);
return null;
}
public Object visit(ASTTypeDefInternalOptOrdered node, Object data) {
currentNode = node;
((TypeAlpha)data).setOrdered(true);
return null;
}
public Object visit(ASTTypeDefInternalOptUnion node, Object data) {
currentNode = node;
((TypeAlpha)data).setUnion(true);
return null;
}
public Object visit(ASTSingleInheritanceIsDef node, Object data) {
currentNode = node;
// Data = TypeUserdefined
TypeAlpha udt = (TypeAlpha)data;
// Child 0 - parent type identifier
String supertypeName = getTokenOfChild(node, 0);
Type supertype = generator.findType(supertypeName);
if (!(supertype instanceof TypeAlpha))
throw new ExceptionSemantic("RS0099: IS must specify a user-defined TYPE as a supertype. " + supertype.getSignature() + " is not a user-defined TYPE.");
udt.setSupertype((TypeAlpha)supertype);
// Child 1 - n - PossrepOrSpecializationDetails
for (int i=1; i<getChildCount(node); i++)
compileChild(node, i, udt);
return null;
}
public Object visit(ASTMultipleInheritanceIsDef node, Object data) {
currentNode = node;
// Data = TypeUserdefined
MultipleInheritance mi = new MultipleInheritance();
// Child 0 - scalar_type_name_commalist
compileChild(node, 0, mi);
// Child 1 - derived_possrep_def_list
compileChild(node, 1, mi);
// Set this type definition to be multiple inheritance
((TypeAlpha)data).setMultipleInheritance(mi);
return null;
}
public Object visit(ASTScalarTypeName node, Object data) {
currentNode = node;
// Data = MultipleInheritance
String identifier = getTokenOfChild(node, 0);
// Add type name to MultipleInheritance
((MultipleInheritance)data).addScalarTypeName(identifier);
return null;
}
public Object visit (ASTPossrepInitialiser node, Object data) {
// Data = TypeUserdefined
compileChildren(node, data);
if (getChildCount(node) > 0)
((TypeAlpha)data).checkPossrepInitialisation();
return null;
}
// Not per TTM
public Object visit(ASTPossrepInitialiserAssignments node, Object data) {
currentNode = node;
// Data = TypeUserdefined
// Child 0 = identifier() = possrep name
String identifier = getTokenOfChild(node, 0);
Generator.PossrepInitialisation possrepInit = generator.new PossrepInitialisation(((TypeAlpha)data), identifier);
// Child 1 = assignment()
compileChild(node, 1, data);
possrepInit.endPossrepInitialisation();
return null;
}
public Object visit(ASTPossrepDef node, Object data) {
currentNode = node;
// Data = TypeUserdefined
TypeAlpha udt = (TypeAlpha)data;
// Child 0 - PossrepDefIdentifier
String possrepName = (String)compileChild(node, 0, data);
Possrep possrep = new Possrep(udt, possrepName);
// Child 1 - PossrepDefComponentCommalist
compileChild(node, 1, possrep);
// Child 2 - PossrepDefConstraintDef
compileChild(node, 2, possrep);
return data;
}
public Object visit(ASTPossrepDefIdentifier node, Object data) {
currentNode = node;
// Data = TypeUserdefined
// Child 0 - optional identifier
if (getChildCount(node) > 0)
return getTokenOfChild(node, 0);
else
return ((TypeAlpha)data).getTypeName();
}
public Object visit(ASTPossrepDefConstraintDef node, Object data) {
currentNode = node;
// Data = Possrep
if (getChildCount(node) > 0) {
Possrep possrep = (Possrep)data;
Generator.PossrepConstraint constraint = generator.new PossrepConstraint(possrep);
// Compile <boolexpr>
compileChildren(node, data);
// End constraint
constraint.endPossrepConstraint();
}
return data;
}
public Object visit(ASTPossrepDefComponentCommalist node, Object data) {
currentNode = node;
// Data = Possrep
compileChildren(node, data);
return data;
}
public Object visit(ASTPossrepDefComponent node, Object data) {
currentNode = node;
// Data = Possrep
// Child 0 - Identifier
String componentName = getTokenOfChild(node, 0);
// Child 1 - Type
Type componentType = (Type)compileChild(node, 1, data);
// Add this component to the Possrep
new PossrepComponent((Possrep)data, componentName, componentType);
return data;
}
public Object visit(ASTPossrepConstraintDef node, Object data) {
currentNode = node;
// Data = Possrep
compileChildren(node, data);
return data;
}
public Object visit(ASTSpecialisationConstraintDef node, Object data) {
currentNode = node;
// Data = TypeUserdefined
TypeAlpha udt = (TypeAlpha)data;
Generator.SpecialisationConstraint constraint = generator.new SpecialisationConstraint(udt);
// Compile <boolexpr>
compileChildren(node, data);
// End constraint
constraint.endSpecialisationConstraint();
return data;
}
public Object visit(ASTDerivedPossrepDef node, Object data) {
currentNode = node;
// Data = TypeUserdefined
// Child 0 = possrep name
String possrepName = (String)compileChild(node, 0, data);
TypeAlpha udt = (TypeAlpha)data;
Possrep possrep = new DerivedPossrep(udt, possrepName);
for (int i=1; i<getChildCount(node); i++)
compileChild(node, i, possrep);
return data;
}
public Object visit(ASTDerivedPossrepDefOptIdentifier node, Object data) {
currentNode = node;
// Data = TypeUserdefined
// Child 0 - optional identifier
if (getChildCount(node) > 0)
return getTokenOfChild(node, 0);
else
return ((TypeAlpha)data).getTypeName();
}
public Object visit(ASTDerivedPossrepComponentDef node, Object data) {
currentNode = node;
// Data = DerivedPossrep
// Child 0 - new identifier
String newIdentifier = getTokenOfChild(node, 0);
// Child 1 - old identifier in the form THE_x
String oldIdentifier = getTokenOfChild(node, 1);
// Child 2 - supertype identifier
String supertypeName = getTokenOfChild(node, 2);
((DerivedPossrep)data).addDerivation(newIdentifier, oldIdentifier, supertypeName);
return data;
}
/*
* End possrep nodes
*/
//
// End type definition
//
// Compile a Rel program. Return the main operator definition as a RelOperatorDefinition.
public Object visit(ASTCode node, Object data) {
currentNode = node;
generator.beginCompilation();
// Compile all children of this node, which compiles the whole program.
compileChildren(node, data);
return generator.endCompilation();
}
// Evaluate a Rel expression. Return the main operator definition as a RelOperatorDefinition.
public Object visit(ASTEvaluate node, Object data) {
currentNode = node;
generator.beginCompilation();
// Compile children of this node, which compiles the whole expression.
Type type = null;
for (int i=0; i<getChildCount(node); i++)
type = (Type)compileChild(node, i, data);
generator.setDeclaredReturnType(type);
generator.compileReturnValue(type);
return generator.endCompilation();
}
// Statement list
public Object visit(ASTStatementList node, Object data) {
currentNode = node;
compileChildren(node, data);
return null;
}
// Statement
public Object visit(ASTStatement node, Object data) {
currentNode = node;
compileChildren(node, data);
return null;
}
// Obtain operator return type
public Object visit(ASTGetOperatorReturnType node, Object data) {
currentNode = node;
generator.setCompilingOff();
try {
// Child 1 - return definition (Type)
return compileChild(node, 1, data);
} finally {
generator.setCompilingOn();
}
}
// Obtain heading
public Object visit(ASTGetHeading node, Object data) {
currentNode = node;
generator.setCompilingOff();
try {
// Child 0 - return definition (Heading)
return compileChild(node, 0, data);
} finally {
generator.setCompilingOn();
}
}
// Obtain operator signature
public Object visit(ASTGetSignature node, Object data) {
currentNode = node;
generator.setCompilingOff();
try {
// Child 0 - return OperatorSignature
OperatorSignature sig = (OperatorSignature)compileChild(node, 0, data);
// Child 1 - get RETURN type
compileChild(node, 1, data);
sig.setReturnType(generator.getDeclaredReturnType());
return sig;
} finally {
generator.setCompilingOn();
}
}
public Object visit(ASTBackup node, Object data) {
generator.backup();
return null;
}
public Object visit(ASTWrite node, Object data) {
// Child 0 - expression
generator.compileWrite((Type)compileChild(node, 0, data));
return null;
}
public Object visit(ASTWriteln node, Object data) {
if (getChildCount(node) > 0) {
// Child 0 - expression
generator.compileWriteln((Type)compileChild(node, 0, data));
} else
generator.compileWritelnNoExpression();
return null;
}
public Object visit(ASTOutput node, Object data) {
// Child 0 - expression
generator.compileOutput((Type)compileChild(node, 0, data));
return null;
}
public Object visit(ASTAnnounce node, Object data) {
// Child 0 - string_literal
generator.announce(getTokenOfChild(node, 0));
return null;
}
public Object visit(ASTExecute node, Object data) {
// Child 0 - expression - should be TypeCharacter
Type exprType = (Type)compileChild(node, 0, data);
if (!(exprType instanceof TypeCharacter))
throw new ExceptionSemantic("RS0100: Expected expression of type CHARACTER but got " + exprType);
generator.compileExecute();
return null;
}
public Object visit(ASTSet node, Object data) {
// Child 0 - attribute
// Child 1 - value
generator.set(getTokenOfChild(node, 0), getTokenOfChild(node, 1));
return null;
}
public Object visit(ASTTransactionBegin node, Object data) {
currentNode = node;
generator.compileTransactionBegin();
return null;
}
public Object visit(ASTTransactionCommit node, Object data) {
currentNode = node;
generator.compileTransactionCommit();
return null;
}
public Object visit(ASTTransactionRollback node, Object data) {
currentNode = node;
generator.compileTransactionRollback();
return null;
}
// Update statement optional WHERE clause.
public Object visit(ASTUpdateWhere node, Object data) {
currentNode = node;
Type type = (Type)compileChild(node, 0, data);
if (!(type instanceof TypeBoolean))
throw new ExceptionSemantic("RS0101: Expected BOOLEAN in WHERE of UPDATE, but got " + type);
return null;
}
// Expression
public Object visit(ASTExpression node, Object data) {
currentNode = node;
Type returnType = null;
for (int i=0; i<getChildCount(node); i++)
returnType = (Type)compileChild(node, i, data);
return returnType;
}
// Update expression assignment statements
public Object visit(ASTUpdateAssignment node, Object data) {
currentNode = node;
compileChildren(node, data);
return null;
}
// Substitute implementation for both infix and prefix syntax.
private Object substitute(SimpleNode node, Object data) {
currentNode = node;
// Child 0 - expression
Type exprType = (Type)compileChild(node, 0, data);
if (exprType instanceof TypeTuple) {
Generator.TupleSubstitute tupleSubstitute = generator.new TupleSubstitute((TypeTuple)exprType);
// Child 1 - update assignment statements
compileChild(node, 1, data);
return tupleSubstitute.endTupleSubstitute();
} else if (exprType instanceof TypeRelation) {
Generator.RelationSubstitute relationSubstitute = generator.new RelationSubstitute((TypeRelation)exprType);
// Child 1 - update assignment statements
compileChild(node, 1, data);
return relationSubstitute.endRelationSubstitute();
} else
throw new ExceptionSemantic("RS0102: Expected TUPLE or RELATION, but got " + exprType);
}
// Substitute
public Object visit(ASTSubstitute node, Object data) {
return substitute(node, data);
}
// DIVIDEBY
public Object visit(ASTAlgDivide node, Object data) {
currentNode = node;
// Child0 - r1
Type r1Type = (Type)compileChild(node, 0, data);
if (!(r1Type instanceof TypeRelation))
throw new ExceptionSemantic("RS0103: DIVIDEBY expected RELATION as first operand, but got " + r1Type);
// Child1 - r2
Type r2Type = (Type)compileChild(node, 1, data);
if (!(r2Type instanceof TypeRelation))
throw new ExceptionSemantic("RS0104: DIVIDEBY expected RELATION as second operand, but got " + r2Type);
// Child3 - r3
Type r3Type = (Type)compileChild(node, 2, data);
if (!(r3Type instanceof TypeRelation))
throw new ExceptionSemantic("RS0105: DIVIDEBY expected RELATION as third operand, but got " + r3Type);
// Child4 - AlgDividePerOptional - if not null, it's r4
Type r4Type = (Type)compileChild(node, 3, data);
if (r4Type == null)
return generator.compileSmallDivide((TypeRelation)r1Type, (TypeRelation)r2Type, (TypeRelation)r3Type);
else {
if (!(r4Type instanceof TypeRelation))
throw new ExceptionSemantic("RS0106: DIVIDEBY expected RELATION as fourth operand, but got " + r4Type);
return generator.compileGreatDivide((TypeRelation)r1Type, (TypeRelation)r2Type, (TypeRelation)r3Type, (TypeRelation)r4Type);
}
}
// DIVIDEBY 'per' optional term
public Object visit(ASTAlgDividePerOptional node, Object data) {
currentNode = node;
// Child0 if present, is r4
if (getChildCount(node) > 0)
return compileChild(node, 0, data);
return null;
}
// Tuple attribute from
public Object visit(ASTAttributeFrom node, Object data) {
currentNode = node;
// Child 0 - attribute name
String name = getTokenOfChild(node, 0);
// Child 1 - tuple expression
Type tupleExpression = (Type)compileChild(node, 1, data);
if (!(tupleExpression instanceof TypeTuple))
throw new ExceptionSemantic("RS0107: Expected TUPLE, but got " + tupleExpression);
return generator.compileTupleGetAttribute((TypeTuple)tupleExpression, name);
}
// Tuple from
public Object visit(ASTTupleFrom node, Object data) {
currentNode = node;
// Child 0 - relation expression
Type relationExpression = (Type)compileChild(node, 0, data);
if (!(relationExpression instanceof TypeRelation))
throw new ExceptionSemantic("RS0108: Expected RELATION, but got " + relationExpression);
return generator.compileRelationGetTuple((TypeRelation)relationExpression);
}
private abstract class NadicDefinition {
abstract TypeTuple compileTupleOperation(TypeTuple left, TypeTuple right);
abstract TypeRelation compileRelationOperation(TypeRelation left, TypeRelation right);
abstract TypeHeading compileNadicEmptyList();
void checkNoExpressionsAllowed() {}
}
private abstract class NadicDefinitionWithoutHeading extends NadicDefinition {
TypeHeading compileNadicEmptyList() {
generator.compilePush(ValueRelation.getDee(generator));
return TypeRelation.getEmptyRelationType();
}
}
private abstract class NadicDefinitionWithOptionalHeading extends NadicDefinition {
TypeHeading compileNadicEmptyList() {
generator.compilePush(ValueTuple.getEmptyTuple(generator));
return TypeTuple.getEmptyTupleType();
}
}
// n-adic relation/tuple operator definer without heading
private Type defineNadicWithoutHeading(SimpleNode node, NadicDefinition nadic) {
// Child 0 - HeadingExpCommalist of TUPLE or RELATION expressions
Type[] types = (Type[])compileChild(node, 0, null);
if (types.length == 0) {
nadic.checkNoExpressionsAllowed();
return nadic.compileNadicEmptyList();
} else {
Type returnType = types[types.length - 1];
if (returnType instanceof TypeTuple) {
for (int i=types.length - 1; i > 0; i--)
returnType = nadic.compileTupleOperation((TypeTuple)types[i - 1], (TypeTuple)returnType);
} else if (returnType instanceof TypeRelation) {
for (int i=types.length - 1; i > 0; i--)
returnType = nadic.compileRelationOperation((TypeRelation)types[i - 1], (TypeRelation)returnType);
}
return returnType;
}
}
// n-adic relation/tuple operator definer with optional heading
private Type defineNadicWithOptionalHeading(SimpleNode node, NadicDefinition nadic) {
if (getChildCount(node) == 2) {
// Child 0 - NadicHeading
Heading heading = (Heading)compileChild(node, 0, null);
// Child 1 - HeadingExpCommalist of RELATION expressions
Type[] types = (Type[])compileChild(node, 1, heading);
if (types.length == 0) {
nadic.checkNoExpressionsAllowed();
Generator.RelationDefinition relationDefinition = generator.new RelationDefinition(heading);
relationDefinition.endRelation();
return new TypeRelation(heading);
} else {
Type returnType = types[types.length - 1];
if (!(returnType instanceof TypeRelation))
throw new ExceptionSemantic("RS0109: Expected expression(s) of type RELATION, but got " + returnType);
for (int i=types.length - 1; i > 0; i--)
returnType = nadic.compileRelationOperation((TypeRelation)types[i - 1], (TypeRelation)returnType);
return returnType;
}
} else
return defineNadicWithoutHeading(node, nadic);
}
// optional n-adic relation operator heading. Return Heading if present.
public Object visit(ASTNadicHeading node, Object data) {
currentNode = node;
return (Heading)compileChild(node, 0, data);
}
// Heading expression commalist. Return Vector of expression TypeS.
public Object visit(ASTHeadingExpCommalist node, Object data) {
currentNode = node;
// data is optional Heading. If not null, all expressions must be of RELATION type
// and match the heading. If null, all expressions must be of TUPLE type or RELATION
// type but not both.
Heading heading = null;
if (data != null)
heading = (Heading)data;
Type firstType = null;
Type types[] = new Type[getChildCount(node)];
for (int i = 0; i < types.length; i++) {
Type type = (Type)compileChild(node, i, data);
if (i == 0) {
firstType = type;
if (!(type instanceof TypeHeading))
throw new ExceptionSemantic("RS0110: Expected expression of type TUPLE or RELATION, but got " + type);
}
else if (firstType instanceof TypeTuple && !(type instanceof TypeTuple))
throw new ExceptionSemantic("RS0111: Expected TUPLE, but got " + type);
else if (firstType instanceof TypeRelation && !(type instanceof TypeRelation))
throw new ExceptionSemantic("RS0112: Expected expression of type " + firstType + " but got " + type);
if (heading != null) {
if (!(type instanceof TypeRelation) || !heading.canAccept(((TypeRelation)type).getHeading()))
throw new ExceptionSemantic("RS0113: Expected expression of type RELATION " + heading + " but got " + type);
}
types[i] = type;
}
return types;
}
// n-adic UNION
public Object visit(ASTNadicUnion node, Object data) {
currentNode = node;
return defineNadicWithOptionalHeading(node, new NadicDefinitionWithOptionalHeading() {
TypeTuple compileTupleOperation(TypeTuple left, TypeTuple right) {
return generator.compileTupleJoin(left, right);
}
TypeRelation compileRelationOperation(TypeRelation left, TypeRelation right) {
return generator.compileRelationUnion(left, right);
}
});
}
// n-adic XUNION
public Object visit(ASTNadicXunion node, Object data) {
currentNode = node;
return defineNadicWithOptionalHeading(node, new NadicDefinitionWithOptionalHeading() {
TypeTuple compileTupleOperation(TypeTuple left, TypeTuple right) {
return generator.compileTupleCompose(left, right);
}
TypeRelation compileRelationOperation(TypeRelation left, TypeRelation right) {
return generator.compileRelationXunion(left, right);
}
});
}
// n-adic D_UNION
public Object visit(ASTNadicDUnion node, Object data) {
currentNode = node;
return defineNadicWithOptionalHeading(node, new NadicDefinitionWithOptionalHeading() {
TypeTuple compileTupleOperation(TypeTuple left, TypeTuple right) {
return generator.compileTupleDUnion(left, right);
}
TypeRelation compileRelationOperation(TypeRelation left, TypeRelation right) {
return generator.compileRelationDUnion(left, right);
}
});
}
// n-adic INTERSECT
public Object visit(ASTNadicIntersect node, Object data) {
currentNode = node;
return defineNadicWithOptionalHeading(node, new NadicDefinitionWithOptionalHeading() {
TypeTuple compileTupleOperation(TypeTuple left, TypeTuple right) {
return generator.compileTupleIntersect(left, right);
}
TypeRelation compileRelationOperation(TypeRelation left, TypeRelation right) {
return generator.compileRelationIntersect(left, right);
}
void checkNoExpressionsAllowed() {
throw new ExceptionSemantic("RS0114: Expression list for n-adic INTERSECT cannot be empty.");
}
});
}
// n-adic JOIN
public Object visit(ASTNadicJoin node, Object data) {
currentNode = node;
return defineNadicWithoutHeading(node, new NadicDefinitionWithoutHeading() {
TypeTuple compileTupleOperation(TypeTuple left, TypeTuple right) {
return generator.compileTupleJoin(left, right);
}
TypeRelation compileRelationOperation(TypeRelation left, TypeRelation right) {
return generator.compileRelationJoin(left, right);
}
});
}
// n-adic TIMES
public Object visit(ASTNadicTimes node, Object data) {
currentNode = node;
return defineNadicWithoutHeading(node, new NadicDefinitionWithoutHeading() {
TypeTuple compileTupleOperation(TypeTuple left, TypeTuple right) {
return generator.compileTupleJoin(left, right);
}
TypeRelation compileRelationOperation(TypeRelation left, TypeRelation right) {
return generator.compileRelationTimes(left, right);
}
});
}
// n-adic COMPOSE
public Object visit(ASTNadicCompose node, Object data) {
currentNode = node;
return defineNadicWithoutHeading(node, new NadicDefinitionWithoutHeading() {
TypeTuple compileTupleOperation(TypeTuple left, TypeTuple right) {
return generator.compileTupleCompose(left, right);
}
TypeRelation compileRelationOperation(TypeRelation left, TypeRelation right) {
return generator.compileRelationCompose(left, right);
}
});
}
private abstract class BinaryDefinition {
abstract String getName();
abstract TypeTuple compileTupleOperation(TypeTuple left, TypeTuple right);
abstract TypeRelation compileRelationOperation(TypeRelation left, TypeRelation right);
}
// Binary relation/tuple operator definer.
private Type defineBinary(SimpleNode node, BinaryDefinition binary) {
currentNode = node;
// Child 0 - left hand operand
Type leftType = (Type)compileChild(node, 0, null);
// Child 1 - right hand operand
Type rightType = (Type)compileChild(node, 1, null);
if (leftType instanceof TypeTuple && rightType instanceof TypeTuple) {
return binary.compileTupleOperation((TypeTuple)leftType, (TypeTuple)rightType);
} else if (leftType instanceof TypeRelation && rightType instanceof TypeRelation) {
return binary.compileRelationOperation((TypeRelation)leftType, (TypeRelation)rightType);
} else
throw new ExceptionSemantic("RS0115: Cannot perform " + binary.getName() + " on " + leftType + " with " + rightType);
}
// D_UNION
public Object visit(ASTAlgDUnion node, Object data) {
currentNode = node;
return defineBinary(node, new BinaryDefinition() {
String getName() {return "D_UNION";}
TypeTuple compileTupleOperation(TypeTuple left, TypeTuple right) {
return generator.compileTupleDUnion(left, right);
}
TypeRelation compileRelationOperation(TypeRelation left, TypeRelation right) {
return generator.compileRelationDUnion(left, right);
}
});
}
// Semijoin
public Object visit(ASTAlgSemijoin node, Object data) {
currentNode = node;
return defineBinary(node, new BinaryDefinition() {
String getName() {return "SEMIJOIN";}
TypeTuple compileTupleOperation(TypeTuple left, TypeTuple right) {
return generator.compileTupleSemijoin(left, right);
}
TypeRelation compileRelationOperation(TypeRelation left, TypeRelation right) {
return generator.compileRelationSemijoin(left, right);
}
});
}
// Semiminus
public Object visit(ASTAlgSemiminus node, Object data) {
currentNode = node;
return defineBinary(node, new BinaryDefinition() {
String getName() {return "SEMIMINUS";}
TypeTuple compileTupleOperation(TypeTuple left, TypeTuple right) {
return generator.compileTupleSemiminus(left, right);
}
TypeRelation compileRelationOperation(TypeRelation left, TypeRelation right) {
return generator.compileRelationSemiminus(left, right);
}
});
}
// Compose
public Object visit(ASTAlgCompose node, Object data) {
currentNode = node;
return defineBinary(node, new BinaryDefinition() {
String getName() {return "COMPOSE";}
TypeTuple compileTupleOperation(TypeTuple left, TypeTuple right) {
return generator.compileTupleCompose(left, right);
}
TypeRelation compileRelationOperation(TypeRelation left, TypeRelation right) {
return generator.compileRelationCompose(left, right);
}
});
}
// Minus
public Object visit(ASTAlgMinus node, Object data) {
currentNode = node;
return defineBinary(node, new BinaryDefinition() {
String getName() {return "MINUS";}
TypeTuple compileTupleOperation(TypeTuple left, TypeTuple right) {
return generator.compileTupleMinus(left, right);
}
TypeRelation compileRelationOperation(TypeRelation left, TypeRelation right) {
return generator.compileRelationMinus(left, right);
}
});
}
// I_MINUS
public Object visit(ASTAlgIMinus node, Object data) {
currentNode = node;
return defineBinary(node, new BinaryDefinition() {
String getName() {return "I_MINUS";}
TypeTuple compileTupleOperation(TypeTuple left, TypeTuple right) {
return generator.compileTupleIMinus(left, right);
}
TypeRelation compileRelationOperation(TypeRelation left, TypeRelation right) {
return generator.compileRelationIMinus(left, right);
}
});
}
// Intersect
public Object visit(ASTAlgIntersect node, Object data) {
currentNode = node;
return defineBinary(node, new BinaryDefinition() {
String getName() {return "INTERSECT";}
TypeTuple compileTupleOperation(TypeTuple left, TypeTuple right) {
return generator.compileTupleIntersect(left, right);
}
TypeRelation compileRelationOperation(TypeRelation left, TypeRelation right) {
return generator.compileRelationIntersect(left, right);
}
});
}
// Union
public Object visit(ASTAlgUnion node, Object data) {
currentNode = node;
return defineBinary(node, new BinaryDefinition() {
String getName() {return "UNION";}
TypeTuple compileTupleOperation(TypeTuple left, TypeTuple right) {
return generator.compileTupleJoin(left, right);
}
TypeRelation compileRelationOperation(TypeRelation left, TypeRelation right) {
return generator.compileRelationUnion(left, right);
}
});
}
// Xunion
public Object visit(ASTAlgXunion node, Object data) {
currentNode = node;
return defineBinary(node, new BinaryDefinition() {
String getName() {return "XUNION";}
TypeTuple compileTupleOperation(TypeTuple left, TypeTuple right) {
return generator.compileTupleCompose(left, right);
}
TypeRelation compileRelationOperation(TypeRelation left, TypeRelation right) {
return generator.compileRelationXunion(left, right);
}
});
}
// Join
public Object visit(ASTAlgJoin node, Object data) {
currentNode = node;
return defineBinary(node, new BinaryDefinition() {
String getName() {return "JOIN";}
TypeTuple compileTupleOperation(TypeTuple left, TypeTuple right) {
return generator.compileTupleJoin(left, right);
}
TypeRelation compileRelationOperation(TypeRelation left, TypeRelation right) {
return generator.compileRelationJoin(left, right);
}
});
}
// Times
public Object visit(ASTAlgTimes node, Object data) {
currentNode = node;
return defineBinary(node, new BinaryDefinition() {
String getName() {return "TIMES";}
TypeTuple compileTupleOperation(TypeTuple left, TypeTuple right) {
return generator.compileTupleJoin(left, right);
}
TypeRelation compileRelationOperation(TypeRelation left, TypeRelation right) {
return generator.compileRelationTimes(left, right);
}
});
}
private abstract class UnaryDefinition {
abstract String getName();
abstract TypeTuple compileTupleOperation(TypeTuple operand);
abstract TypeRelation compileRelationOperation(TypeRelation operand);
}
// Unary relation/tuple operator definer.
private Type defineUnary(SimpleNode node, UnaryDefinition unary) {
currentNode = node;
// Child 0 - source expression
Type sourceType = (Type)compileChild(node, 0, null);
if (sourceType instanceof TypeTuple) {
return unary.compileTupleOperation((TypeTuple)sourceType);
} else if (sourceType instanceof TypeRelation) {
return unary.compileRelationOperation((TypeRelation)sourceType);
} else
throw new ExceptionSemantic("RS0116: Cannot perform " + unary.getName() + " on " + sourceType);
}
// Unwrap
public Object visit(final ASTAlgUnwrap node, Object data) {
currentNode = node;
return defineUnary(node, new UnaryDefinition() {
String getName() {return "UNWRAP";}
TypeTuple compileTupleOperation(TypeTuple operand) {
// Child 1 - identifier
String name = getTokenOfChild(node, 1);
return generator.compileTupleUnwrap(operand, name);
}
TypeRelation compileRelationOperation(TypeRelation operand) {
// Child 1 - identifier
String name = getTokenOfChild(node, 1);
return generator.compileRelationUnwrap(operand, name);
}
});
}
// Wrap
public Object visit(final ASTAlgWrap node, Object data) {
currentNode = node;
return defineUnary(node, new UnaryDefinition() {
String getName() {return "WRAP";}
TypeTuple compileTupleOperation(TypeTuple operand) {
// Child 1 - wrapping list
return (TypeTuple)compileChild(node, 1, operand);
}
TypeRelation compileRelationOperation(TypeRelation operand) {
// Child 1 - wrapping list
return (TypeRelation)compileChild(node, 1, operand);
}
});
}
// Wrapping item
public Object visit(ASTWrappingItem node, Object data) {
currentNode = node;
// data is Type of expression that will be available on the stack
Type sourceType = (Type)data;
// Child 0 - AttributeNameList -- compilation returns AttributeSelection
SelectAttributes selection = (SelectAttributes)compileChild(node, 0, data);
// Child 1 - identifier -- name of new attribute
String name = getTokenOfChild(node, 1);
if (sourceType instanceof TypeTuple)
return generator.compileTupleWrap((TypeTuple)sourceType, selection, name);
else if (sourceType instanceof TypeRelation)
return generator.compileRelationWrap((TypeRelation)sourceType, selection, name);
else
throw new ExceptionSemantic("RS0309: Unable to WRAP " + sourceType);
}
// Group
public Object visit(ASTGroup node, Object data) {
currentNode = node;
// Child 0 - source
Type sourceType = (Type)compileChild(node, 0, data);
// Child 1 - AttributeNameList -- compilation returns AttributeSelection
SelectAttributes selection = (SelectAttributes)compileChild(node, 1, data);
// Child 2 - identifier -- name of new attribute
String name = getTokenOfChild(node, 2);
if (!(sourceType instanceof TypeRelation))
throw new ExceptionSemantic("RS0310: Unable to GROUP " + sourceType);
return generator.compileRelationGroup((TypeRelation)sourceType, selection, name);
}
// Ungroup
public Object visit(ASTAlgUngroup node, Object data) {
currentNode = node;
// Child 0 - source
Type sourceType = (Type)compileChild(node, 0, data);
// Child 1 - attribute name
String name = getTokenOfChild(node, 1);
if (!(sourceType instanceof TypeRelation))
throw new ExceptionSemantic("RS0311: Unable to UNGROUP " + sourceType);
return generator.compileRelationUngroup((TypeRelation)sourceType, name);
}
// LOAD ... FROM ...
public Object visit(ASTRelationArrayLoad node, Object data) {
currentNode = node;
// Child 0 - identifier
String identifier = getTokenOfChild(node, 0);
// Child 1 - expression
Type expressionType = (Type)compileChild(node, 1, data);
generator.compileLoad(identifier, expressionType);
return null;
}
// ORDER
public Object visit(ASTAlgOrder node, Object data) {
currentNode = node;
// Child 0 - source
Type sourceType = (Type)compileChild(node, 0, data);
// Child 1 - SelectOrder via ASTOrderItemCommalist
SelectOrder orderItems = (SelectOrder)compileChild(node, 1, data);
if (sourceType instanceof TypeRelation || sourceType instanceof TypeArray)
return generator.compileOrder((TypeHeading)sourceType, orderItems);
else
throw new ExceptionSemantic("RS0117: Unable to perform ORDER on " + sourceType + "; expected a RELATION or ARRAY.");
}
// UNORDER
public Object visit(ASTAlgUnorder node, Object data) {
currentNode = node;
// Child 0 - source
Type sourceType = (Type)compileChild(node, 0, data);
if (!(sourceType instanceof TypeArray))
throw new ExceptionSemantic("RS0444: Unable to perform UNORDER on " + sourceType + "; expected an ARRAY.");
return generator.compileArrayUnorder((TypeArray)sourceType);
}
// ORDER item commalist
public Object visit(ASTOrderItemCommalist node, Object data) {
currentNode = node;
SelectOrder orderItems = new SelectOrder();
compileChildren(node, orderItems);
return orderItems;
}
public Object visit(ASTOrderItemAsc node, Object data) {
currentNode = node;
// data is OrderItems
SelectOrder orderItems = (SelectOrder)data;
// Child 0 - attribute identifier
String identifier = getTokenOfChild(node, 0);
orderItems.add(identifier, SelectOrder.Order.ASC);
return null;
}
public Object visit(ASTOrderItemDesc node, Object data) {
currentNode = node;
// data is OrderItems
SelectOrder orderItems = (SelectOrder)data;
// Child 0 - attribute identifier
String identifier = getTokenOfChild(node, 0);
orderItems.add(identifier, SelectOrder.Order.DESC);
return null;
}
// Extend implementation for both prefix and infix syntax
private Object extend(final SimpleNode node, Object data) {
currentNode = node;
return defineUnary(node, new UnaryDefinition() {
String getName() {return "EXTEND";}
TypeTuple compileTupleOperation(TypeTuple operand) {
Generator.Extend extend = generator.new Extend(operand.getHeading());
// Child 1 - ExtendList
compileChild(node, 1, extend);
return generator.endTupleExtend(extend);
}
TypeRelation compileRelationOperation(TypeRelation operand) {
Generator.Extend extend = generator.new Extend(operand.getHeading());
// Child 1 - ExtendList
compileChild(node, 1, extend);
return generator.endRelationExtend(extend);
}
});
}
// Extend
public Object visit(final ASTExtend node, Object data) {
return extend(node, data);
}
// Extend list.
public Object visit(ASTExtendList node, Object data) {
currentNode = node;
compileChildren(node, data);
return null;
}
// Extend item
public Object visit(ASTExtendItem node, Object data) {
currentNode = node;
// data is either Generator.TupleExtend or Generator.RelationExtend
// Child 0 - identifier
String identifier = getTokenOfChild(node, 0);
// Child 1 - expression
Type expressionType = (Type)compileChild(node, 1, data);
((Generator.Extend)data).addExtendItem(identifier, expressionType);
return null;
}
// RANK implementation for both prefix and infix syntax.
private Object rank(SimpleNode node, Object data) {
currentNode = node;
// Child 0 - source
Type sourceType = (Type)compileChild(node, 0, data);
if (!(sourceType instanceof TypeRelation))
throw new ExceptionSemantic("RS0499: Unable to perform RANK on " + sourceType + "; expected a RELATION.");
TypeRelation sourceRelationType = (TypeRelation)sourceType;
// Child 1 - SelectOrder via ASTOrderItemCommalist
SelectOrder orderItems = (SelectOrder)compileChild(node, 1, data);
// Child 2 - identifier
String identifier = getTokenOfChild(node, 2);
return generator.compileRank(sourceRelationType, orderItems, identifier);
}
// RANK
public Object visit(ASTRank node, Object data) {
return rank(node, data);
}
// Project. Return Type of projection.
public Object visit(final ASTAlgProject node, Object data) {
currentNode = node;
return defineUnary(node, new UnaryDefinition() {
String getName() {return "projection";}
TypeTuple compileTupleOperation(TypeTuple operand) {
// Child 1 - AttributeNameList
SelectAttributes attributes = (SelectAttributes)compileChild(node, 1, null);
return generator.compileTupleProject(operand, attributes);
}
TypeRelation compileRelationOperation(TypeRelation operand) {
// Child 1 - AttributeNameList
SelectAttributes attributes = (SelectAttributes)compileChild(node, 1, null);
return generator.compileRelationProject(operand, attributes);
}
});
}
// WHERE
public Object visit(final ASTAlgWhere node, Object data) {
currentNode = node;
return defineUnary(node, new UnaryDefinition() {
String getName() {return "WHERE";}
TypeTuple compileTupleOperation(TypeTuple operand) {
throw new ExceptionSemantic("RS0118: WHERE expected relation, but got " + operand);
}
TypeRelation compileRelationOperation(TypeRelation operand) {
Generator.Where where = generator.new Where(operand);
// Child 1 - boolean expression
Type expressionType = (Type)compileChild(node, 1, null);
if (!(expressionType instanceof TypeBoolean))
throw new ExceptionSemantic("RS0119: WHERE expression expected boolean, but got " + expressionType);
return where.endWhere();
}
});
}
// infix EXTEND
public Object visit(ASTAlgExtend node, Object data) {
return extend(node, data);
}
// infix RANK
public Object visit(ASTAlgRank node, Object data) {
return rank(node, data);
}
// infix SUMMARIZE
public Object visit(ASTAlgSummarize node, Object data) {
return summarize(node, data);
}
// infix UPDATE expression
public Object visit(ASTAlgUpdate node, Object data) {
return substitute(node, data);
}
// Rename. Return Type of rename.
public Object visit(final ASTAlgRename node, Object data) {
currentNode = node;
return defineUnary(node, new UnaryDefinition() {
String getName() {return "RENAME";}
TypeTuple compileTupleOperation(TypeTuple operand) {
// Child 1 - renaming list
Heading newHeading = new Heading(operand);
compileChild(node, 1, newHeading);
return new TypeTuple(newHeading);
}
TypeRelation compileRelationOperation(TypeRelation operand) {
// Child 1 - renaming list
Heading newHeading = new Heading(operand);
compileChild(node, 1, newHeading);
return new TypeRelation(newHeading);
}
});
}
// Renaming list
public Object visit(ASTRenamingList node, Object data) {
currentNode = node;
Heading newHeading = (Heading)data;
for (int i = 0; i < getChildCount(node); i++)
compileChild(node, i, newHeading);
return null;
}
// Simple rename element
public Object visit(ASTRenamingSimple node, Object data) {
currentNode = node;
// data is Heading
Heading newHeading = (Heading)data;
// Child 0 - name from
String nameFrom = getTokenOfChild(node, 0);
// Child 1 - name to
String nameTo = getTokenOfChild(node, 1);
if (!newHeading.rename(nameFrom, nameTo))
throw new ExceptionSemantic("RS0120: Rename from " + nameFrom + " to " + nameTo + " found no matching attributes.");
return null;
}
// Prefix rename element
public Object visit(ASTRenamingPrefix node, Object data) {
currentNode = node;
// data is Heading
Heading newHeading = (Heading)data;
// Child 0 - name from
String nameFrom = (String)compileChild(node, 0, data);
// Child 1 - name to
String nameTo = (String)compileChild(node, 1, data);
if (!newHeading.renamePrefix(nameFrom, nameTo))
throw new ExceptionSemantic("RS0121: Rename from prefix " + nameFrom + " to " + nameTo + " found no matching attributes.");
return null;
}
// Suffix rename element
public Object visit(ASTRenamingSuffix node, Object data) {
currentNode = node;
// data is Heading
Heading newHeading = (Heading)data;
// Child 0 - name from
String nameFrom = (String)compileChild(node, 0, data);
// Child 1 - name to
String nameTo = (String)compileChild(node, 1, data);
if (!newHeading.renameSuffix(nameFrom, nameTo))
throw new ExceptionSemantic("RS0122: Rename from suffix " + nameFrom + " to " + nameTo + " found no matching attributes.");
return null;
}
// Attribute name list. Return an AttributeSelection.
public Object visit(ASTAttributeNameList node, Object data) {
currentNode = node;
SelectAttributes attributes = new SelectAttributes();
compileChildren(node, attributes);
return attributes;
}
// ALL BUT
public Object visit(ASTAllBut node, Object data) {
currentNode = node;
if (getChildCount(node) == 0)
return null;
// data is AttributeSelection
SelectAttributes attributes = (SelectAttributes)data;
attributes.setAllBut(true);
return null;
}
// ATTRIBUTES_OF(r)
public Object visit(ASTAttributeNameCommalistListAttributesOf node, Object data) {
currentNode = node;
// data is AttributeSelection
SelectAttributes attributes = (SelectAttributes)data;
try {
generator.setCompilingOff();
Type type = (Type)compileChild(node, 0, data);
if (!(type instanceof TypeHeading))
throw new ExceptionSemantic("RS0448: Expected RELATION, TUPLE or ARRAY as ATTRIBUTES_OF operand, but got " + type);
TypeHeading typeHeading = (TypeHeading)type;
attributes.add(typeHeading.getHeading().getAttributes());
} finally {
generator.setCompilingOn();
}
return null;
}
// name1, name2, ..., nameN
public Object visit(ASTAttributeNameCommalistList node, Object data) {
currentNode = node;
// data is AttributeSelection
SelectAttributes attributes = (SelectAttributes)data;
for (int i=0; i<getChildCount(node); i++)
attributes.add(getTokenOfChild(node, i));
return null;
}
// Var def
public Object visit(ASTVarDef node, Object data) {
currentNode = node;
// Child 0 - identifier
String varName = getTokenOfChild(node, 0);
// Child 1 - pass var name to remainder of var definition
compileChild(node, 1, varName);
return null;
}
// Scalar or TUPLE variable definition
public Object visit(ASTVarScalarOrTuple node, Object data) {
currentNode = node;
// data is varName
String varName = (String)data;
// Child - VarTypeOrInitValue
Type varType = (Type)compileChild(node, 0, data);
if (varType instanceof TypeRelation)
throw new ExceptionSemantic("RS0123: Relation-valued variable definition requires REAL, BASE, PUBLIC, or PRIVATE and a KEY specification.");
else
generator.defineVariable(varName, varType);
return null;
}
private RelvarHeading relvarDefinition(SimpleNode node) {
currentNode = node;
// Child 0 - VarTypeOrInitValue (or in the case of a PUBLIC relvar, just a TypeRef)
Type varType = (Type)compileChild(node, 0, null);
if (!(varType instanceof TypeRelation))
throw new ExceptionSemantic("RS0124: Relation-valued variable definition expected initialization of RELATION type, but got " + varType);
Heading heading = ((TypeRelation)varType).getHeading();
// Child 1 - KeyDefList
return (RelvarHeading)compileChild(node, 1, new RelvarHeading(heading));
}
// Relvar definition
public Object visit(ASTVarRelvarReal node, Object data) {
currentNode = node;
// data is varName
String varName = (String)data;
References references = new References();
generator.setGlobalReferenceCollector(references);
RelvarHeading definition = relvarDefinition(node);
generator.setGlobalReferenceCollector(null);
generator.defineRelvarReal(varName, definition, references);
return null;
}
// Relvar definition
public Object visit(ASTVarRelvarPublic node, Object data) {
currentNode = node;
// data is varName
String varName = (String)data;
RelvarHeading definition = relvarDefinition(node);
generator.defineRelvarPublic(varName, definition);
return null;
}
// Relvar definition
public Object visit(ASTVarRelvarPrivate node, Object data) {
currentNode = node;
// data is varName
String varName = (String)data;
RelvarHeading definition = relvarDefinition(node);
generator.defineRelvarPrivate(varName, definition);
return null;
}
public Object visit(ASTVarRelvarVirtual node, Object data) {
currentNode = node;
// data is varName
String varName = (String)data;
// Child 0 - expression
String sourceCode = getSourceCodeOfChild(node, 0);
References references = new References();
generator.setGlobalReferenceCollector(references);
generator.setPersistentOnlyOn();
Type varType = (Type)compileChild(node, 0, null);
generator.setPersistentOnlyOff();
generator.setGlobalReferenceCollector(null);
if (!(varType instanceof TypeRelation))
throw new ExceptionSemantic("RS0125: Virtual relation-valued variable definition expected expression of RELATION type, but got " + varType);
Heading heading = ((TypeRelation)varType).getHeading();
// Child 1 - KeyDefList
RelvarHeading keydef = (RelvarHeading)compileChild(node, 1, new RelvarHeading(heading));
generator.defineRelvarVirtual(varName, sourceCode, keydef, references);
return varType;
}
public Object visit(ASTVarRelvarExternal node, Object data) {
currentNode = node;
// data is varName
String varName = (String)data;
// Child 0 - identifier -- type of EXTERNAL relvar
String externalRelvarType = getTokenOfChild(node, 0);
// Child 1 - string literal -- string specifying EXTERNAL relvar
String externalRelvarSpecification = ValueCharacter.stripDelimitedString(getTokenOfChild(node, 1));
// Child 2 - identifier -- duplicates or no duplicates
String duplicates = "AUTOKEY";
if (getChildCount(node) > 2)
duplicates = getTokenOfChild(node, 2);
generator.defineRelvarExternal(varName, externalRelvarType, externalRelvarSpecification, duplicates);
return null;
}
public Object visit(ASTKeyDefList node, Object data) {
currentNode = node;
// data is RelvarHeading
RelvarHeading keydef = (RelvarHeading)data;
for (int i=0; i<getChildCount(node); i++)
keydef.addKey((SelectAttributes)compileChild(node, i, (RelvarHeading)data));
return keydef;
}
public Object visit(ASTKeyDef node, Object data) {
currentNode = node;
// Child 0 - SelectAttributes
return compileChild(node, 0, data);
}
// Compile INIT (init value is on stack at run-time) and return variable Type
public Object visit(ASTVarTypeAndOptionalInit node, Object data) {
currentNode = node;
// Child 0 - Type
Type varType = (Type)compileChild(node, 0, data);
// Child 1 (optional) - init expression
if (getChildCount(node) > 1) {
Type expressionType = (Type)compileChild(node, 1, data);
if (!varType.canAccept(expressionType))
throw new ExceptionSemantic("RS0126: Variable of type " + varType + " cannot be initialised with an expression of type " + expressionType);
generator.compileReformat(varType, expressionType);
} else
generator.compilePush(varType.getDefaultValue(generator));
return varType;
}
// Compile INIT (init value is on stack at run-time) and return variable Type
public Object visit(ASTVarInit node, Object data) {
currentNode = node;
// Child 0 - init expression
return compileChild(node, 0, data);
}
// Var DROP
public Object visit(ASTDropRelvar node, Object data) {
currentNode = node;
// Child 0 - identifier
String varName = getTokenOfChild(node, 0);
generator.dropRelvar(varName);
return null;
}
public Object visit(ASTDatabaseConstraint node, Object data) {
currentNode = node;
// Child 0 - identifier
String constraintName = getTokenOfChild(node, 0);
// Child 1 - boolean expression
References references = new References();
generator.setGlobalReferenceCollector(references);
Operator constraintOperator = generator.beginConstraintDefinition();
Type expressionType = (Type)compileChild(node, 1, data);
if (!(expressionType instanceof TypeBoolean))
throw new ExceptionSemantic("RS0127: Constraint definition expected expression of type BOOLEAN, but got " + expressionType);
generator.compileReturnValue(TypeBoolean.getInstance());
generator.endConstraintDefinition();
generator.setGlobalReferenceCollector(null);
generator.createConstraint(constraintName, getSourceCodeOfChild(node, 1), constraintOperator, references);
return null;
}
public Object visit(ASTDropConstraint node, Object data) {
currentNode = node;
// Child 0 - identifier
String constraintName = getTokenOfChild(node, 0);
generator.dropConstraint(constraintName);
return null;
}
public Object visit(ASTDropType node, Object data) {
currentNode = node;
// Child 0 - identifier
String typeName = getTokenOfChild(node, 0);
generator.dropType(typeName);
return null;
}
private class Alteration {
private String varname;
private RelvarHeading relvarHeading;
public Alteration(String varname, RelvarHeading relvarHeading) {
this.varname = varname;
this.relvarHeading = relvarHeading;
}
public String getVarname() {
return varname;
}
public RelvarHeading getRelvarHeading() {
return relvarHeading;
}
public void setRelvarHeading(RelvarHeading relvarHeading) {
this.relvarHeading = relvarHeading;
}
}
@Override
public Object visit(ASTAlterVar node, Object data) {
currentNode = node;
// Child 0 - identifier
String varname = getTokenOfChild(node, 0);
RelvarMetadata rawMetadata = generator.getDatabase().getRelvarMetadata(varname);
if (rawMetadata == null)
throw new ExceptionSemantic("RS0439: REAL VAR '" + varname + "' does not exist.");
if (!(rawMetadata instanceof RelvarRealMetadata))
throw new ExceptionSemantic("RS0440: '" + varname + "' is not a REAL VAR.");
RelvarRealMetadata metadata = (RelvarRealMetadata)rawMetadata;
RelvarHeading relvarHeading = metadata.getHeadingDefinition(generator.getDatabase());
Alteration alteration = new Alteration(varname, relvarHeading);
// Child 1 - AlterVarActionOptional
alteration = (Alteration)compileChild(node, 1, alteration);
// If there is a Child 2, it's an AlterVarActionKey
if (getChildCount(node) == 3)
compileChild(node, 2, alteration);
return null;
}
@Override
public Object visit(ASTAlterVarActionKey node, Object data) {
currentNode = node;
// data is an Alteration
Alteration alteration = (Alteration)data;
String varname = alteration.getVarname();
// child 0 is ASTKeyDefList; pass and return RelvarHeading
RelvarHeading keydef = (RelvarHeading)compileChild(node, 0, new RelvarHeading(alteration.getRelvarHeading().getHeading()));
generator.alterVarRealAlterKey(varname, keydef);
return null;
}
@Override
public Object visit(ASTAlterVarActionOptional node, Object data) {
// Child 0 to n: all AlterVarAction*
// 'data' is an Alteration
for (int i=0; i<getChildCount(node); i++)
data = compileChild(node, i, data);
return data;
}
@Override
public Object visit(ASTAlterVarActionRename node, Object data) {
currentNode = node;
// data is an Alteration
Alteration alteration = (Alteration)data;
String varname = alteration.getVarname();
// child 0 is old attribute name
String oldName = getTokenOfChild(node, 0);
// child 1 is new attribute name
String newName = getTokenOfChild(node, 1);
alteration.setRelvarHeading(generator.alterVarRealRename(varname, alteration.getRelvarHeading(), oldName, newName));
return alteration;
}
@Override
public Object visit(ASTAlterVarActionChangeType node, Object data) {
currentNode = node;
// data is an Alteration
Alteration alteration = (Alteration)data;
String varname = alteration.getVarname();
// child 0 is attribute name
String attributeName = getTokenOfChild(node, 0);
// child 1 is new type
Type newType = (Type)compileChild(node, 1, data);
alteration.setRelvarHeading(generator.alterVarRealChangeType(varname, alteration.getRelvarHeading(), attributeName, newType));
return alteration;
}
@Override
public Object visit(ASTAlterVarActionInsert node, Object data) {
currentNode = node;
// data is an Alteration
Alteration alteration = (Alteration)data;
String varname = alteration.getVarname();
// child 0 is ASTAttributeSpec; heading will contain new attribute name and type
Heading heading = new Heading();
compileChild(node, 0, heading);
alteration.setRelvarHeading(generator.alterVarRealInsertAttributes(varname, alteration.getRelvarHeading(), heading));
return alteration;
}
@Override
public Object visit(ASTAlterVarActionDrop node, Object data) {
currentNode = node;
// data is an Alteration
Alteration alteration = (Alteration)data;
String varname = alteration.getVarname();
// child 0 is attribute name
String attributeName = getTokenOfChild(node, 0);
alteration.setRelvarHeading(generator.alterVarRealDropAttribute(varname, alteration.getRelvarHeading(), attributeName));
return alteration;
}
// Type specification
public Object visit(ASTType node, Object data) {
currentNode = node;
// Child 0 - type name
String typeName = getTokenOfChild(node, 0);
return generator.findType(typeName);
}
public Object visit(ASTTypeArray node, Object data) {
currentNode = node;
// Child 0 - Type
Type maybeArrayType = (Type)compileChild(node, 0, data);
if (!(maybeArrayType instanceof TypeTuple))
throw new ExceptionSemantic("RS0128: ARRAY expected type TUPLE, but got " + maybeArrayType);
return new TypeArray(((TypeTuple)maybeArrayType).getHeading());
}
// TYPE_OF pseudo-operator. Return TypeInfo for given expression.
public Object visit(ASTTypeOf node, Object data) {
currentNode = node;
// don't emit code, because the expression isn't evaluated
generator.setCompilingOff();
Type typeOfExpression = null;
try {
// Child 0 - expression
typeOfExpression = (Type)compileChild(node, 0, data);
} finally {
generator.setCompilingOn();
}
Type typeInfo = generator.findType("TypeInfo");
generator.compilePush(generator.getTypeOf(typeOfExpression));
return typeInfo;
}
// IMAGE_IN pseudo-operator
public Object visit(ASTImageIn node, Object data) {
currentNode = node;
// Child 0 - relational expression
Type maybeRelationType = (Type)compileChild(node, 0, data);
if (!(maybeRelationType instanceof TypeRelation))
throw new ExceptionSemantic("RS0445: IMAGE_IN or !! expected first operand of type RELATION, but got " + maybeRelationType);
TypeRelation leftType = (TypeRelation)maybeRelationType;
Generator.RelationDefinition relation = generator.new RelationDefinition(null);
// Child 1 - optional tuple expression. If absent, it's TUPLE {*}
if (getChildCount(node) == 2) {
Type maybeTupleType = (Type)compileChild(node, 1, data);
if (!(maybeTupleType instanceof TypeTuple))
throw new ExceptionSemantic("RS0446: IMAGE_IN or !! expected second operand of type TUPLE, but got " + maybeTupleType);
relation.addTupleToRelation((TypeTuple)maybeTupleType);
} else {
Generator.TupleDefinition tuple = generator.new TupleDefinition();
tuple.setWildcard();
relation.addTupleToRelation(tuple.endTuple());
}
TypeRelation rightType = relation.endRelation();
TypeRelation joinType = generator.compileRelationJoin(leftType, rightType);
SelectAttributes attributes = new SelectAttributes();
attributes.setAllBut(true);
attributes.add(rightType.getHeading().getAttributes());
return generator.compileRelationProject(joinType, attributes);
}
// !! alias for IMAGE_IN
public Object visit(ASTImageBangBang node, Object data) {
currentNode = node;
compileChild(node, 0, data);
String relvarname = getTokenOfChild(node, 0);
Slot referencedSlot = generator.findReference(relvarname);
if (!(referencedSlot.getType() instanceof TypeRelation))
throw new ExceptionSemantic("RS0479: !! expected operand of type RELATION, but got " + referencedSlot.getType());
referencedSlot.compileGet(generator);
TypeRelation leftType = (TypeRelation)referencedSlot.getType();
Generator.RelationDefinition relation = generator.new RelationDefinition(null);
Generator.TupleDefinition tuple = generator.new TupleDefinition();
tuple.setWildcard();
relation.addTupleToRelation(tuple.endTuple());
TypeRelation rightType = relation.endRelation();
TypeRelation joinType = generator.compileRelationJoin(leftType, rightType);
SelectAttributes attributes = new SelectAttributes();
attributes.setAllBut(true);
attributes.add(rightType.getHeading().getAttributes());
return generator.compileRelationProject(joinType, attributes);
}
// SAME TYPE AS. Return Type.
public Object visit(ASTTypeSameTypeAs node, Object data) {
currentNode = node;
// don't emit code for what is essentially a type generator
generator.setCompilingOff();
try {
// Child 0 - expression
return (Type)compileChild(node, 0, data);
} finally {
generator.setCompilingOn();
}
}
// SAME HEADING AS. Return Heading.
public Object visit(ASTSameHeadingAs node, Object data) {
currentNode = node;
// don't emit code for what is essentially a heading generator
generator.setCompilingOff();
try {
// Child 0 - expression
Type exprType = (Type)compileChild(node, 0, data);
if (exprType instanceof TypeHeading)
return ((TypeHeading)exprType).getHeading();
else
throw new ExceptionSemantic("RS0129: SAME_HEADING_AS is only applicable to tuple and relation expressions, not " + exprType);
} finally {
generator.setCompilingOn();
}
}
// TypeOperator. Return TypeOperator.
public Object visit(ASTOpType node, Object data) {
currentNode = node;
// Child 0 - type_ref_commalist
OperatorSignature signature = (OperatorSignature)compileChild(node, 0, null);
// Child 1 - optional return type
if (getChildCount(node) > 1) {
Type returnType = (Type)compileChild(node, 1, null);
signature.setReturnType(returnType);
}
return new TypeOperator(signature);
}
// TypeRelation. Return TypeRelation.
public Object visit(ASTTypeRelation node, Object data) {
currentNode = node;
// Child 0 - heading
return new TypeRelation((Heading)compileChild(node, 0, data));
}
// TypeTuple. Return TypeTuple.
public Object visit(ASTTypeTuple node, Object data) {
currentNode = node;
// Child 0 - Heading
return new TypeTuple((Heading)compileChild(node, 0, data));
}
// Heading. Return Heading.
public Object visit(ASTHeading node, Object data) {
currentNode = node;
Heading heading = new Heading();
// Children are AttributeSpecS
compileChildren(node, heading);
return heading;
}
// Attribute specification
public Object visit(ASTAttributeSpec node, Object data) {
currentNode = node;
// data is Heading
Heading heading = (Heading)data;
// Child 0 - Identifier
String attributeName = getTokenOfChild(node, 0);
// Child 1 - Type
Type attributeType = (Type)compileChild(node, 1, data);
heading.add(attributeName, attributeType);
return null;
}
private OperatorDefinition lastPersistentOperatorDefinition;
public void addOperator(OperatorDefinition operator) {
// persist it, if appropriate
if (operatorsAreStorable == 0)
generator.persistOperator(operator);
lastPersistentOperatorDefinition = operator;
}
// External operator definition
public Object visit(ASTExternalOpDef node, Object data) {
// Child 0 - identifier (fn name)
compileChild(node, 0, data);
String fnname = getTokenOfChild(node, 0);
Generator.ExternalOperator operator = generator.new ExternalOperator(fnname);
// Child 1 - parameter def commalist
compileChild(node, 1, data);
// Child 2 - optional return definition -- UserOpReturns
compileChild(node, 2, data);
// Child 3 - external language identifier
String externalLanguage = getTokenOfChild(node, 3);
// node.tokenValue - source code
String sourcecode = node.tokenValue;
// done
operator.endExternalOperator(externalLanguage, sourcecode);
return null;
}
// Operator definition
public Object visit(ASTUserOpDef node, Object data) {
currentNode = node;
// Child 0 - identifier (fn name)
compileChild(node, 0, data);
String fnname = getTokenOfChild(node, 0);
References references = new References();
generator.setGlobalReferenceCollector(references);
generator.setPersistentOnlyOn();
generator.beginOperator(fnname);
OperatorDefinition operator = generator.getCurrentOperatorDefinition();
try {
// Child 1 - parameter def commalist
compileChild(node, 1, data);
// Child 2 - optional return definition -- UserOpReturns
compileChild(node, 2, data);
// Child 3 - optional updates definition
compileChild(node, 3, data);
// Child 4 - optional synonym definition
compileChild(node, 4, data);
// Child 5 - optional version definition
compileChild(node, 5, data);
// Child 6 - body
compileChild(node, 6, data);
// done
generator.endOperator();
} finally {
generator.setPersistentOnlyOff();
}
generator.setGlobalReferenceCollector(null);
// capture source and persist it, if appropriate
if (generator.isTopLevelOperator(operator)) {
if (operatorsAreStorable == 0) {
operator.setSourceCode(operator.getSignature().getOperatorDeclaration() + getSourceCodeOf(node) + " ;");
operator.setReferences(references);
generator.persistOperator(operator);
}
lastPersistentOperatorDefinition = operator;
}
return null;
}
// Get most recent persistent operator definition
public OperatorDefinition getLastPersistentOperatorDefinition() {
return lastPersistentOperatorDefinition;
}
// Parameter definition list
public Object visit(ASTUserOpParameters node, Object data) {
currentNode = node;
generator.beginParameterDefinitions();
compileChildren(node, data);
generator.endParameterDefinitions();
return null;
}
// Parameter definition
public Object visit(ASTParmDef node, Object data) {
currentNode = node;
// Child 0 - identifier
String parmName = getTokenOfChild(node, 0);
// Child 1 - parameter type
Type parmType = (Type)compileChild(node, 1, data);
// Define parm
generator.defineOperatorParameter(parmName, parmType);
return null;
}
// Operator's return definition
public Object visit(ASTUserOpReturns node, Object data) {
currentNode = node;
if (getChildCount(node) == 0)
return null;
Type returnType = (Type)compileChild(node, 0, data);
generator.setDeclaredReturnType(returnType);
return returnType;
}
// Operator's updates definition
public Object visit(ASTUserOpUpdates node, Object data) {
currentNode = node;
// TODO - mutually exclusive with return definition
if (getChildCount(node) == 0)
return null;
compileChildren(node, data);
return null;
}
// Operator's synonym definition
public Object visit(ASTUserOpSynonym node, Object data) {
currentNode = node;
// TODO - User Op Synonym
if (getChildCount(node) == 0)
return null;
compileChildren(node, data);
return null;
}
// Operator's version definition
public Object visit(ASTUserOpVersion node, Object data) {
currentNode = node;
// TODO - User Op Version
if (getChildCount(node) == 0)
return null;
compileChildren(node, data);
return null;
}
// Operator body
public Object visit(ASTUserOpBody node, Object data) {
currentNode = node;
compileChildren(node, data);
return null;
}
// Operator return, with optional expression
public Object visit(ASTReturnExpression node, Object data) {
currentNode = node;
// Child 0 - optional return expression
if (getChildCount(node) > 0) {
Type expressionType = (Type)compileChild(node, 0, data);
if (generator.getDeclaredReturnType() == null)
throw new ExceptionSemantic("RS0130: Operator " + generator.getCurrentDefinitionSignature() + " has not declared a return type but has defined a return expression.");
if (!generator.getDeclaredReturnType().canAccept(expressionType))
throw new ExceptionSemantic("RS0131: Operator " + generator.getCurrentDefinitionSignature() + " has declared return type " + generator.getDeclaredReturnType() + " but attempted to return " + expressionType);
generator.compileReturnValue(generator.getDeclaredReturnType());
} else
generator.compileReturn();
return null;
}
public Object visit(ASTDropOperator node, Object data) {
// Child 0 - OpSignature
OperatorSignature signature = (OperatorSignature)compileChild(node, 0, data);
generator.dropOperator(signature);
return null;
}
public Object visit(ASTOpSignature node, Object data) {
// Child 0 - identifier
String identifier = getTokenOfChild(node, 0);
// Child 1 - type_ref_commalist
return (OperatorSignature)compileChild(node, 1, identifier);
}
public Object visit(ASTTypeRefCommalist node, Object data) {
// data is String - operator name
OperatorSignature signature = new OperatorSignature((String)data);
for (int i=0; i<getChildCount(node); i++)
signature.addParameterType((Type)compileChild(node, i, data));
return signature;
}
// Operator invocation argument list. Returns an OperatorSignature.
public Object visit(ASTArgList node, Object data) {
currentNode = node;
// data is operator name
String operatorName = (String)data;
OperatorSignature signature = new OperatorSignature(operatorName);
for (int i=0; i<getChildCount(node); i++)
signature.setParameterType(i, (Type)compileChild(node, i, data));
return signature;
}
// Operator call statement
public Object visit(ASTCall node, Object data) {
currentNode = node;
// Child 0 - identifier (fn name)
String opName = getTokenOfChild(node, 0);
// Child 1 - arglist
OperatorSignature signature = (OperatorSignature)compileChild(node, 1, opName);
generator.compileCall(signature);
return null;
}
// Operator evaluation in an expression
public Object visit(ASTFnInvoke node, Object data) {
currentNode = node;
// Child 0 - identifier (fn name)
String opName = getTokenOfChild(node, 0);
// Child 1 - arglist
OperatorSignature signature = (OperatorSignature)compileChild(node, 1, opName);
return generator.compileEvaluate(signature);
}
// Compile an IF
public Object visit(ASTIfStatement node, Object data) {
currentNode = node;
// Child 0 - test expression
Type expressionType = (Type)compileChild(node, 0, data);
if (!(expressionType instanceof TypeBoolean))
throw new ExceptionSemantic("RS0132: IF expression must be boolean.");
Generator.IfStatement ifStatement = generator.new IfStatement();
// Child 1 - if statement
compileChild(node, 1, data);
// Child 2 - ElseStatement -- pass it the ifStatement
compileChild(node, 2, ifStatement);
// end if
ifStatement.endIf();
return null;
}
// Compile an ELSE
public Object visit(ASTElseStatement node, Object data) {
currentNode = node;
if (getChildCount(node) == 0)
return null;
// data is Generator.IfStatement
Generator.IfStatement ifStatement = (Generator.IfStatement)data;
ifStatement.beginElse();
compileChild(node, 0, data);
return null;
}
public Object visit(ASTIfExpression node, Object data) {
currentNode = node;
// Child 0 - test expression
Type expressionType = (Type)compileChild(node, 0, data);
if (!(expressionType instanceof TypeBoolean))
throw new ExceptionSemantic("RS0133: IF expression must be boolean.");
Generator.IfStatement ifStatement = generator.new IfStatement();
// Child 1 - if's conditionally-executed expression
Type ifType = (Type)compileChild(node, 1, data);
// Child 2 - if's ElseExpression
ifStatement.beginElse();
Type elseType = (Type)compileChild(node, 2, data);
// end if
ifStatement.endIf();
if (!ifType.canAccept(elseType))
throw new ExceptionSemantic("RS0144: IF ... ELSE expected the ELSE expression to be " + ifType + " but got " + elseType);
return ifType;
}
class CaseStatement {
Stack<Generator.IfStatement> ifStatements = new Stack<Generator.IfStatement>();
void beginCaseWhen() {
if (ifStatements.size() > 0)
ifStatements.peek().beginElse();
}
void endCaseWhen() {
ifStatements.push(generator.new IfStatement());
}
void caseElse() {
ifStatements.peek().beginElse();
}
void endCase() {
while (ifStatements.size() > 0)
ifStatements.pop().endIf();
}
}
// CASE statement
public Object visit(ASTCaseStatement node, Object data) {
currentNode = node;
CaseStatement caseStatement = new CaseStatement();
// Child 0 - CaseWhenList
compileChild(node, 0, caseStatement);
// Child 1 - CaseElse
compileChild(node, 1, caseStatement);
caseStatement.endCase();
return null;
}
// CASE WHEN list
public Object visit(ASTCaseWhenList node, Object data) {
currentNode = node;
// data is Generator.CaseStatement
compileChildren(node, data);
return null;
}
// CASE WHEN
public Object visit(ASTCaseWhen node, Object data) {
currentNode = node;
// data is Generator.CaseStatement
CaseStatement caseStatement = (CaseStatement)data;
caseStatement.beginCaseWhen();
// Child 0 - boolean expression
Type expressionType = (Type)compileChild(node, 0, data);
if (!(expressionType instanceof TypeBoolean))
throw new ExceptionSemantic("RS0145: WHEN expression must be boolean.");
caseStatement.endCaseWhen();
// Child 1 - statement
compileChild(node, 1, data);
return null;
}
// CASE ELSE
public Object visit(ASTCaseElse node, Object data) {
currentNode = node;
// data is Generator.CaseStatement
if (getChildCount(node) > 0) {
((CaseStatement)data).caseElse();
compileChild(node, 0, data);
}
return null;
}
class CaseExpression extends CaseStatement {
private Type exprType = null;
public void setExpressionType(Type type) {
if (exprType == null)
exprType = type;
else if (type == null)
throw new ExceptionFatal("RS0312: CASE encountered null type returned from expression compilation");
else
if (!exprType.canAccept(type))
throw new ExceptionSemantic("RS0145: CASE expected " + exprType + " but got " + type);
}
public Type getExpressionType() {
return exprType;
}
}
public Object visit(ASTCaseExpression node, Object data) {
currentNode = node;
CaseExpression caseExpression = new CaseExpression();
// Child 0 - CaseWhenList
compileChild(node, 0, caseExpression);
// Child 1 - CaseElse
caseExpression.caseElse();
caseExpression.setExpressionType((Type)compileChild(node, 1, data));
caseExpression.endCase();
return caseExpression.getExpressionType();
}
public Object visit(ASTCaseWhenListExpression node, Object data) {
currentNode = node;
// data is Generator.CaseExpression
compileChildren(node, data);
return null;
}
public Object visit(ASTCaseWhenExpression node, Object data) {
currentNode = node;
// data is Generator.CaseExpression
CaseExpression caseExpression = (CaseExpression)data;
caseExpression.beginCaseWhen();
// Child 0 - boolean expression
Type expressionType = (Type)compileChild(node, 0, data);
if (!(expressionType instanceof TypeBoolean))
throw new ExceptionSemantic("RS0146: WHEN expression must be boolean.");
caseExpression.endCaseWhen();
// Child 1 - expression
caseExpression.setExpressionType((Type)compileChild(node, 1, data));
return null;
}
// Compile a DO loop
public Object visit(ASTDoLoop node, Object data) {
currentNode = node;
// Child 0 - identifier
String identifier = getTokenOfChild(node, 0);
// Child 1 - initial expression
Type initExprType = (Type)compileChild(node, 1, data);
Slot loopIndex = generator.findReference(identifier);
if (!(loopIndex.getType() instanceof TypeInteger))
throw new ExceptionSemantic("RS0147: DO loop only supports INTEGER iteration. Iterator of type " + loopIndex.getType() + " not supported.");
if (!loopIndex.getType().canAccept(initExprType))
throw new ExceptionSemantic("RS0148: Cannot assign " + initExprType + " to " + identifier + " which is a " + loopIndex.getType());
generator.compileSet(loopIndex);
// begin loop
Generator.DoLoop forLoop = generator.new DoLoop();
// Child 2 - terminal expression ... compile as test
generator.compileGet(loopIndex);
Type termExprType = (Type)compileChild(node, 2, data);
if (!(termExprType.canAccept(TypeInteger.getInstance())))
throw new ExceptionSemantic("RS0149: Expression after TO is " + termExprType + ", expected " + loopIndex.getType());
generator.compileInstruction(new OpLte());
forLoop.testDo();
// compile loop body
compileChild(node, 3, data);
// compile loop increment
generator.compileGet(loopIndex);
generator.compilePush(1);
generator.compilePlus();
generator.compileSet(loopIndex);
forLoop.endDo();
return null;
}
// Compile a WHILE loop
public Object visit(ASTWhileLoop node, Object data) {
currentNode = node;
Generator.DoLoop whileLoop = generator.new DoLoop();
// Child 0 - boolean test expression
Type testExpressionType = (Type)compileChild(node, 0, data);
if (!(testExpressionType instanceof TypeBoolean))
throw new ExceptionSemantic("RS0150: WHILE expression expected boolean, but got " + testExpressionType);
whileLoop.testDo();
// Child 1 - loop body
compileChild(node, 1, data);
whileLoop.endDo();
return null;
}
// Compile a FOR loop
public Object visit(ASTForLoop node, Object data) {
// Child 0 - expression
Type expressionType = (Type)compileChild(node, 0, data);
if (!(expressionType instanceof TypeArray)) {
if (expressionType instanceof TypeRelation)
throw new ExceptionSemantic("RS0151: FOR expected ARRAY, but got " + expressionType + ". Use ORDER() to convert a relation to an ARRAY.");
else
throw new ExceptionSemantic("RS0152: FOR expected ARRAY, but got " + expressionType);
}
Generator.ForLoop forLoop = generator.new ForLoop();
forLoop.beginForLoop((TypeArray)expressionType);
// Child 1 - statement
compileChild(node, 1, data);
forLoop.endForLoop();
return null;
}
// Process an identifier
// This doesn't do anything, but needs to be here because we need an ASTIdentifier node in order to get an identifier's token.
public Object visit(ASTIdentifier node, Object data) {
currentNode = node;
return null;
}
// Execute a group of comma-separated assignment statements
//
// The evaluation of all expressions as a unit, followed by assigning expression evaluation
// results as a unit, ensures assignment conforms to TTM multiple-assignment requirements.
public Object visit(ASTAssignment node, Object data) {
currentNode = node;
generator.beginAssignment();
// Compile expression evaluations.
for (int i = getChildCount(node) - 1; i >= 0; i--)
compileChild(node, i, new Integer(1));
// Compile slot assignments.
for (int i = 0; i < getChildCount(node); i++)
compileChild(node, i, new Integer(2));
generator.endAssignment();
return null;
}
// Assignment statement.
//
// If data is Integer(1), compile the expression evaluation.
//
// If data is Integer(2), compile the assignment.
//
public Object visit(ASTAssign node, Object data) {
currentNode = node;
switch (((Integer)data).intValue()) {
case 1:
compileChild(node, 1, data);
break;
case 2:
generator.setCompilingOff();
Type expressionType = (Type)compileChild(node, 1, data);
generator.setCompilingOn();
String refName = getTokenOfChild(node, 0);
Slot reference = generator.findReference(refName);
if (!reference.getType().canAccept(expressionType))
throw new ExceptionSemantic("RS0153: Cannot assign " + expressionType + " to '" + refName + "' which is a " + reference.getType());
if (reference.isParameter())
throw new ExceptionSemantic("RS0403: Parameter is not updateable.");
generator.compileReformat(reference.getType(), expressionType);
generator.compileSet(reference);
}
return null;
}
// Insert into Relvar
//
// If data is Integer(1), compile the expression evaluation.
//
// If data is Integer(2), compile the assignment.
//
public Object visit(ASTInsert node, Object data) {
currentNode = node;
switch (((Integer)data).intValue()) {
case 1:
break;
case 2:
Type expressionType = (Type)compileChild(node, 1, data);
String refName = getTokenOfChild(node, 0);
Slot reference = generator.findReference(refName);
if (!(expressionType instanceof TypeRelation))
throw new ExceptionSemantic("RS0154: Expected expression of type relation, but got " + expressionType);
if (!reference.getType().canAccept(expressionType))
throw new ExceptionSemantic("RS0155: Cannot insert " + expressionType + " into '" + refName + "' because it is a " + reference.getType());
Type resultType = generator.compileReformat(reference.getType(), expressionType);
generator.compileRelvarInsert(reference, refName, (TypeRelation)resultType);
break;
}
return null;
}
// Insert into Relvar. Throw exception if tuples already exist.
//
// If data is Integer(1), compile the expression evaluation.
//
// If data is Integer(2), compile the assignment.
//
public Object visit(ASTDInsert node, Object data) {
currentNode = node;
switch (((Integer)data).intValue()) {
case 1:
break;
case 2:
Type expressionType = (Type)compileChild(node, 1, data);
String refName = getTokenOfChild(node, 0);
Slot reference = generator.findReference(refName);
if (!(expressionType instanceof TypeRelation))
throw new ExceptionSemantic("RS0156: Expected expression of type relation, but got " + expressionType);
if (!reference.getType().canAccept(expressionType))
throw new ExceptionSemantic("RS0157: Cannot insert " + expressionType + " into '" + refName + "' because it is a " + reference.getType());
Type resultType = generator.compileReformat(reference.getType(), expressionType);
generator.compileRelvarInsertNoDuplicates(reference, refName, (TypeRelation)resultType);
break;
}
return null;
}
// UPDATE statement
//
// If data is Integer(1), exit
//
// If data is Integer(2), compile the assignment.
//
// TODO - ensure UPDATE in multiple-assignment conforms to TTM.
public Object visit(ASTUpdateStatement node, Object data) {
currentNode = node;
if (data != null && data.equals(new Integer(1)))
return null;
// Child 0 - variable name
String identifier = getTokenOfChild(node, 0);
Slot slot = generator.findReference(identifier);
if (slot.isParameter())
throw new ExceptionSemantic("RS0404: Parameter is not updateable.");
Type slotType = slot.getType();
if (slotType instanceof TypeTuple) {
if (getChildCountOfChild(node, 1) > 0)
throw new ExceptionSemantic("RS0158: WHERE clause is not appropriate for UPDATE of a tuple.");
generator.compileGet(slot);
Generator.TupleSubstitute tupleUpdate = generator.new TupleSubstitute((TypeTuple)slotType);
// Child 2 - update expression assignment statements
compileChild(node, 2, data);
tupleUpdate.endTupleSubstitute();
generator.compileSet(slot);
return null;
} else if (slotType instanceof TypeRelation) {
Generator.UpdateWhere relvarUpdate = generator.new UpdateWhere(identifier, (TypeRelation)slotType);
if (getChildCountOfChild(node, 1) > 0) {
relvarUpdate.beginRelvarUpdateWhere();
// Child 1 - optional WHERE clause
compileChild(node, 1, data);
relvarUpdate.endRelvarUpdateWhere();
}
relvarUpdate.beginRelvarUpdateAssignment();
// Child 2 - update expression assignment statements
compileChild(node, 2, data);
relvarUpdate.endUpdateWhere();
return null;
} else
throw new ExceptionSemantic("RS0159: Expected TUPLE or RELATION, but got " + slotType);
}
// Delete from Relvar
//
// If data is Integer(1), exit
//
// If data is Integer(2), compile the assignment.
//
// TODO - ensure DELETE in multiple-assignment conforms to TTM.
public Object visit(ASTDelete node, Object data) {
currentNode = node;
if (data != null && data.equals(new Integer(1)))
return null;
// Child 0 - relvar name
String identifier = getTokenOfChild(node, 0);
Slot slot = generator.findReference(identifier);
if (slot.isParameter())
throw new ExceptionSemantic("RS0405: Parameter is not updateable.");
Type slotType = slot.getType();
if (slotType instanceof TypeRelation) {
// is a parameter present?
if (getChildCountOfChild(node, 1) > 0) {
Generator.DeleteHandler deleteHandler = generator.new DeleteHandler(identifier, (TypeRelation)slotType);
// Child 1 - parameter
Type expressionType = (Type)compileChild(node, 1, deleteHandler);
deleteHandler.endDeleteHandler(expressionType);
} else {
generator.compileRelvarPurge(slot, identifier);
}
return null;
} else
throw new ExceptionSemantic("RS0160: Expected relvar or relation-valued attribute in DELETE, but got " + slotType);
}
// Delete from Relvar - optional WHERE expression or expression specifying relation
// data is Generator.DeleteHandler
public Object visit(ASTDeleteParameter node, Object data) {
currentNode = node;
Type type = null;
if (getChildCount(node) == 2) {
// WHERE
compileChild(node, 0, data);
// BOOLEAN expression
type = (Type)compileChild(node, 1, data);
if (!(type instanceof TypeBoolean))
throw new ExceptionSemantic("RS0161: Expected BOOLEAN expression in WHERE, but got " + type);
} else if (getChildCount(node) == 1) {
// RELATION expression
type = (Type)compileChild(node, 0, data);
if (!(type instanceof TypeRelation))
throw new ExceptionSemantic("RS0162: Expected RELATION to specify tuples to DELETE, but got " + type);
}
return type;
}
// Delete from Relvar - WHERE keyword
public Object visit(ASTDeleteWhere node, Object data) {
currentNode = node;
((Generator.DeleteHandler)data).doWhere();
return null;
}
// I_DELETE
//
// If data is Integer(1), exit
//
// If data is Integer(2), compile the assignment.
//
// TODO - ensure DELETE in multiple-assignment conforms to TTM.
public Object visit(ASTIDelete node, Object data) {
currentNode = node;
if (data != null && data.equals(new Integer(1)))
return null;
// Child 0 - relvar name
String identifier = getTokenOfChild(node, 0);
Slot slot = generator.findReference(identifier);
Type slotType = slot.getType();
if (slotType instanceof TypeRelation) {
// Child 1 - expression
Type type = (Type)compileChild(node, 1, null);
if (!(type instanceof TypeRelation))
throw new ExceptionSemantic("RS0163: Expected RELATION to specify tuples to I_DELETE, but got " + type);
if (!slotType.canAccept(type))
throw new ExceptionSemantic("RS0164: Expected expression of type " + slotType + " but got " + type);
generator.compileReformat(slotType, type);
generator.compileRelvarIDelete(slot, identifier);
} else
throw new ExceptionSemantic("RS0165: Expected relvar in I_DELETE, but got " + slotType);
return null;
}
// Dereference an array at a specified subscript, and push its value onto the stack
public Object visit(ASTArrayDereference node, Object data) {
currentNode = node;
// Child0 - expression
Type arrayType = (Type)compileChild(node, 0, data);
if (!(arrayType instanceof TypeArray))
throw new ExceptionSemantic("RS0166: ARRAY dereference expected ARRAY, but got " + arrayType);
Type arrayHoldsType = ((TypeArray)arrayType).getElementType();
// Child1 - subscript expression
Type subscriptExprType = (Type)compileChild(node, 1, data);
if (!(subscriptExprType instanceof TypeInteger))
throw new ExceptionSemantic("RS0167: ARRAY dereference expected subscript of type INTEGER, but got " + subscriptExprType);
generator.compileArrayGet();
return arrayHoldsType;
}
// Invoke a ValueOperator
public Object visit(ASTFnInvokeAnonymous node, Object data) {
currentNode = node;
// Child 1 - arglist
OperatorSignature signature = (OperatorSignature)compileChild(node, 1, null);
// Child 0 - expression evaluating to ValueOperator
Type expressionType = (Type)compileChild(node, 0, data);
if (!(expressionType instanceof TypeOperator))
throw new ExceptionSemantic("RS0168: Expected OPERATOR, but got " + expressionType);
TypeOperator operatorType = (TypeOperator)expressionType;
if (!operatorType.getOperatorSignature().canBeInvokedBy(signature))
throw new ExceptionSemantic("RS0169: Expected invocation of OPERATOR " + operatorType.getOperatorSignature().toRelLookupString() + " but got invocation of OPERATOR " + signature);
generator.compileEvaluateAnonymous();
return operatorType.getOperatorSignature().getReturnType();
}
// Compile a dereference of a variable or parameter. Return variable or parm Type.
public Object visit(ASTDereference node, Object data) {
currentNode = node;
return generator.compileGet(node.tokenValue);
}
// aggregate COUNT invocation
private Type aggInvokeCount(Type exprType) {
OperatorSignature sig = new OperatorSignature("COUNT");
if (exprType instanceof TypeRelation || exprType instanceof TypeArray)
sig.addParameterType(exprType);
else
throw new ExceptionSemantic("RS0170: Aggregate COUNT expected RELATION or ARRAY, but got " + exprType);
return generator.compileEvaluate(sig);
}
// aggregate COUNT
public Object visit(ASTAggCount node, Object data) {
currentNode = node;
// Child 0 - Expression
Type exprType = (Type)compileChild(node, 0, null);
return aggInvokeCount(exprType);
}
// Aggregator result type
private static class AggregateResult {
private Type attributeType;
private Type returnType;
AggregateResult(Type attributeType, Type returnType) {
this.attributeType = attributeType;
this.returnType = returnType;
}
Type getAttributeType() {
return attributeType;
}
Type getReturnType() {
return returnType;
}
}
private static long introducedAttributeNameSerial = 0;
// Aggregate operator handler for SUM, AVG, MAX, MIN, etc.
private abstract class Aggregator {
private String opName;
private Type returnType;
private TypeArray extendedRelationExprType;
protected String introducedAttributeName;
protected Type attributeExprType;
Aggregator(String operatorName) {
opName = operatorName;
}
protected TypeArray extendAndProjectToAggregatable(Type source, String aggregandName) {
final String aggregandAttributeName = "AGGREGAND";
final String aggregationSerialAttributeName = "AGGREGATION_SERIAL";
// sourceRenaming := source RENAME {AGGREGAND AS %random1, AGGREGATION_SERIAL AS %random2}
Heading sourceRenaming = (source instanceof TypeArray) ? ((TypeArray)source).getHeading() : ((TypeRelation)source).getHeading();
sourceRenaming.rename(aggregandAttributeName, sourceRenaming.getRandomFreeAttributeName());
sourceRenaming.rename(aggregationSerialAttributeName, sourceRenaming.getRandomFreeAttributeName());
// extendedType := EXTEND sourceRenaming {AGGREGATION_SERIAL := serial_number()}
Generator.Extend extend = generator.new Extend(sourceRenaming);
extend.addExtendSerialiser(aggregationSerialAttributeName);
TypeArray extendedType = generator.endArrayExtend(extend);
// renamed := extendedType RENAME {aggregandName AS AGGREGAND}
Heading renamed = extendedType.getHeading();
renamed.rename(aggregandName, aggregandAttributeName);
// extendedRelationExprType := renamed {AGGREGAND, AGGREGATION_SERIAL}
SelectAttributes attributes = new SelectAttributes();
attributes.add(aggregandAttributeName);
attributes.add(aggregationSerialAttributeName);
extendedRelationExprType = generator.compileArrayProject(new TypeArray(renamed), attributes);
return extendedRelationExprType;
}
// SUMMARIZE aggregator build !!!
Type buildAggregator(SimpleNode node, Generator.Summarize.SummarizeItem item, boolean distinct, int attributeExpressionNodeNumber) {
// Child attributeExpressionNodeNumber - expression
item.beginSummarizeItemExpression();
attributeExprType = (Type)compileChild(node, attributeExpressionNodeNumber, item);
TypeRelation extendedSourceType = item.endSummarizeItemExpression(attributeExprType, distinct);
// convert to ARRAY ... consider using this to define specific SelectOrder as part of SUMMARIZE syntax
return generator.compileOrder(extendedSourceType, new SelectOrder());
}
// SUMMARIZE aggregator invocation
AggregateResult buildInvocation(Type aggExpType, Generator.Summarize.SummarizeItem item, OperatorDefinition aggregator, SimpleNode node, int initialValueNodeNumber) {
return createAggregator(aggExpType, item.getExtendAttributeName(), aggregator, node, initialValueNodeNumber);
}
// SUMMARIZE aggregator !!!
AggregateResult createAggregator(SimpleNode node, Generator.Summarize.SummarizeItem item, boolean distinct) {
Type aggExpType = buildAggregator(node, item, distinct, 0);
return createAggregator(aggExpType, item.getExtendAttributeName());
}
// extend TupleIteratable source with attribute expression as %AGGn attribute, and result to ARRAY if it isn't already an ARRAY
TypeArray buildAggregator(SimpleNode node, int tupleIteratableExpressionNodeNumber, int attributeExpressionNodeNumber) {
// Child tupleIteratableExpressionNodeNumber - TupleIteratable expression
Type attributeExpressionType = (Type)compileChild(node, tupleIteratableExpressionNodeNumber, null);
if (attributeExpressionType instanceof TypeArray) {
// Child attributeExpressionNodeNumber - Attribute expression
Generator.Extend extend = generator.new Extend(((TypeArray)attributeExpressionType).getHeading());
introducedAttributeName = "%AGG" + introducedAttributeNameSerial++;
attributeExprType = (Type)compileChild(node, attributeExpressionNodeNumber, null);
checkAttributeType(attributeExprType);
extend.addExtendItem(introducedAttributeName, attributeExprType);
extendedRelationExprType = generator.endArrayExtend(extend);
return extendedRelationExprType;
} else if (attributeExpressionType instanceof TypeRelation) {
// Child attributeExpressionNodeNumber - Attribute expression
Generator.Extend extend = generator.new Extend(((TypeRelation)attributeExpressionType).getHeading());
introducedAttributeName = "%AGG" + introducedAttributeNameSerial++;
attributeExprType = (Type)compileChild(node, attributeExpressionNodeNumber, null);
checkAttributeType(attributeExprType);
extend.addExtendItem(introducedAttributeName, attributeExprType);
TypeRelation extendedSourceType = generator.endRelationExtend(extend);
extendedRelationExprType = generator.compileOrder(extendedSourceType, new SelectOrder());
return extendedRelationExprType;
} else
throw new ExceptionSemantic("RS0171: Aggregate " + (opName.startsWith("%") ? "" : opName + " ") + "expected RELATION or ARRAY, but got " + attributeExpressionType);
}
// implement operator invocation
AggregateResult buildInvocation(Type aggExpType, OperatorDefinition aggregator, SimpleNode node, int initialValueNodeNumber) {
return createAggregator(aggExpType, introducedAttributeName, aggregator, node, initialValueNodeNumber);
}
// aggregate operator invocation
AggregateResult createAggregator(SimpleNode node) {
buildAggregator(node, 0, 1);
return createAggregator(extendedRelationExprType, introducedAttributeName);
}
private AggregateResult createAggregator(Type exprType, String attributeName, OperatorDefinition aggregator, SimpleNode initialValueNode, int initialValueNodeNumber) {
extendAndProjectToAggregatable(exprType, attributeName);
if (initialValueNodeNumber >= 0) {
Type initialValueType = (Type)compileChild(initialValueNode, initialValueNodeNumber, null);
if (!getAttributeExpressionType().canAccept(initialValueType))
throw new ExceptionSemantic("RS0442: Expected type of initial value to be " + getAttributeExpressionType() + " but got " + initialValueType);
}
returnType = generator.compileEvaluate(aggregator);
return new AggregateResult(attributeExprType, getReturnType(attributeExprType));
}
// create aggregator !!!
private AggregateResult createAggregator(Type exprType, String attributeName) {
TypeArray aggregatableType = extendAndProjectToAggregatable(exprType, attributeName);
String operatorName = getOpNameForType(attributeExprType);
OperatorSignature sig = new OperatorSignature("AGGREGATE_" + operatorName);
sig.addParameterType(aggregatableType);
returnType = generator.compileEvaluate(sig);
return new AggregateResult(attributeExprType, getReturnType(attributeExprType));
}
void checkAttributeType(Type t) {}
String getOpNameForType(Type attributeType) {
return opName;
}
Type getReturnType(Type attributeType) {
return returnType;
}
Type getAttributeExpressionType() {
return attributeExprType;
}
String getName() {
return opName;
}
}
class AggregatorSum extends Aggregator {
AggregatorSum() {
super("SUM");
}
String getOpNameForType(Type attributeType) {
if (attributeType instanceof TypeInteger)
return "SUM_INTEGER";
else if (attributeType instanceof TypeRational)
return "SUM_RATIONAL";
else
return super.getOpNameForType(attributeType);
}
}
class AggregatorAvg extends Aggregator {
AggregatorAvg() {
super("AVG");
}
String getOpNameForType(Type attributeType) {
if (attributeType instanceof TypeInteger)
return "AVG_INTEGER";
else if (attributeType instanceof TypeRational)
return "AVG_RATIONAL";
else
return super.getOpNameForType(attributeType);
}
}
class AggregatorMax extends Aggregator {
AggregatorMax() {
super("MAX");
}
Type getReturnType(Type attributeType) {
return attributeType;
}
}
class AggregatorMin extends Aggregator {
AggregatorMin() {
super("MIN");
}
Type getReturnType(Type attributeType) {
return attributeType;
}
}
class AggregatorAnd extends Aggregator {
AggregatorAnd() {
super("AND");
}
}
class AggregatorOr extends Aggregator {
AggregatorOr() {
super("OR");
}
}
class AggregatorXor extends Aggregator {
AggregatorXor() {
super("XOR");
}
}
class AggregatorEquiv extends Aggregator {
AggregatorEquiv() {
super("EQUIV");
}
}
class AggregatorUnion extends Aggregator {
AggregatorUnion() {
super("UNION");
}
Type getReturnType(Type attributeType) {
return attributeType;
}
void checkAttributeType(Type t) {
if (!(t instanceof TypeRelation))
throw new ExceptionSemantic("RS0173: Aggregate UNION expected attribute of type RELATION; got " + t);
}
}
class AggregatorXunion extends Aggregator {
AggregatorXunion() {
super("XUNION");
}
Type getReturnType(Type attributeType) {
return attributeType;
}
void checkAttributeType(Type t) {
if (!(t instanceof TypeRelation))
throw new ExceptionSemantic("RS0174: Aggregate XUNION expected attribute of type RELATION; got " + t);
}
}
class AggregatorDUnion extends Aggregator {
AggregatorDUnion() {
super("D_UNION");
}
Type getReturnType(Type attributeType) {
return attributeType;
}
void checkAttributeType(Type t) {
if (!(t instanceof TypeRelation))
throw new ExceptionSemantic("RS0175: Aggregate D_UNION expected attribute of type RELATION; got " + t);
}
}
class AggregatorIntersect extends Aggregator {
AggregatorIntersect() {
super("INTERSECT");
}
Type getReturnType(Type attributeType) {
return attributeType;
}
void checkAttributeType(Type t) {
if (!(t instanceof TypeRelation))
throw new ExceptionSemantic("RS0176: Aggregate INTERSECT expected attribute of type RELATION; got " + t);
}
}
private static long introducedAggregateOperatorNameSerial = 0;
class AggregatorAggregate extends Aggregator {
AggregatorAggregate() {
super("%AGGREGATE" + introducedAggregateOperatorNameSerial++);
}
Type getReturnType(Type attributeType) {
return attributeType;
}
private OperatorDefinition buildGenericAggregator(SimpleNode node, Type aggExpType, int initialValueNodeNumber) {
final OperatorDefinition attributeFold = generator.beginAnonymousOperator();
attributeFold.defineParameter("VALUE1", getAttributeExpressionType());
attributeFold.defineParameter("VALUE2", getAttributeExpressionType());
attributeFold.setDeclaredReturnType(getAttributeExpressionType());
// last child - aggregator's op_body()
compileChild(node, getChildCount(node) - 1, null);
generator.endOperator();
VirtualMachine vm = new VirtualMachine(generator, generator.getDatabase(), generator.getPrintStream());
Context context = new Context(generator, vm);
Operator attributeFoldOperator = attributeFold.getOperator();
NativeFunction aggregatorFunction;
if (initialValueNodeNumber < 0)
aggregatorFunction = new NativeFunction() {
@Override
public Value evaluate(Value[] arguments) {
TupleIteratable tupleIteratable = (TupleIteratable)arguments[0];
TupleFoldFirstIsIdentity folder = new TupleFoldFirstIsIdentity("AGGREGATE requires at least one tuple.", tupleIteratable.iterator(), 0) {
@Override
public Value fold(Value left, Value right) {
context.push(left);
context.push(right);
context.call(attributeFoldOperator);
return context.pop();
}
};
folder.run();
return folder.getResult();
}
};
else
aggregatorFunction = new NativeFunction() {
@Override
public Value evaluate(Value[] arguments) {
TupleIteratable tupleIteratable = (TupleIteratable)arguments[0];
Value initialValue = arguments[1];
TupleFold folder = new TupleFold(tupleIteratable.iterator(), 0) {
@Override
public Value fold(Value left, Value right) {
context.push(left);
context.push(right);
context.call(attributeFoldOperator);
return context.pop();
}
@Override
public Value getIdentity() {
return initialValue;
}
};
folder.run();
return folder.getResult();
}
};
Type[] parms;
String docs = "";
if (initialValueNodeNumber < 0) {
parms = new Type[] {aggExpType};
docs = getName() + "(p " + aggExpType.getSignature() + ") RETURNS " + getAttributeExpressionType().getSignature();
} else {
parms = new Type[] {getAttributeExpressionType(), aggExpType};
docs = getName() + "(a " + getAttributeExpressionType().getSignature() + ", p " + aggExpType.getSignature() + ") RETURNS " + getAttributeExpressionType().getSignature();
}
return new OperatorDefinitionNativeFunction(
getName(),
docs,
parms,
getAttributeExpressionType(),
aggregatorFunction);
}
// node assumed to have two or three children.
// if two:
// child 0 - expression
// child 1 - AGGREGATE body
// if three:
// child 0 - expression
// child 1 - initial accumulator
// child 2 - AGGREGATE body
public AggregateResult makeAggregator(SimpleNode node, SummarizeItem summarizeItem, boolean distinct) {
Type aggExpType = buildAggregator(node, summarizeItem, distinct, 0);
int initialValueNodeNumber = getChildCount(node) == 3 ? 1 : -1;
OperatorDefinition aggregator = buildGenericAggregator(node, aggExpType, initialValueNodeNumber);
return buildInvocation(aggExpType, summarizeItem, aggregator, node, initialValueNodeNumber);
}
// node assumed to have three or four children.
// if three:
// child 0 - relation
// child 1 - expression
// child 2 - AGGREGATE body
// if four:
// child 0 - relation
// child 1 - expression
// child 2 - initial accumulator
// child 3 - AGGREGATE body
public AggregateResult makeAggregator(SimpleNode node) {
Type aggExpType = buildAggregator(node, 0, 1);
int initialValueNodeNumber = getChildCount(node) == 4 ? 2 : -1;
OperatorDefinition aggregator = buildGenericAggregator(node, aggExpType, initialValueNodeNumber);
return buildInvocation(aggExpType, aggregator, node, initialValueNodeNumber);
}
}
class AggregatorUserdefined extends Aggregator {
AggregatorUserdefined(String opName) {
super(opName);
}
Type getReturnType(Type attributeType) {
return attributeType;
}
public AggregateResult makeAggregator(SimpleNode node, SummarizeItem summarizeItem, boolean distinct) {
// Child 2 - expression
Type aggExpType = buildAggregator(node, summarizeItem, distinct, 2);
// Child 3 - [optional] initial value
int initialValueNodeNumber = getChildCount(node) == 4 ? 3 : -1;
introducedAttributeName = summarizeItem.getExtendAttributeName();
return createOperatorInvocation(node, aggExpType, initialValueNodeNumber);
}
public AggregateResult makeAggregator(SimpleNode node) {
// Child 1 - relation expression
// Child 2 - attribute expression
Type aggExpType = buildAggregator(node, 1, 2);
// Child 3 - initial value (optional)
int initialValueNodeNumber = getChildCount(node) == 4 ? 3 : -1;
return createOperatorInvocation(node, aggExpType, initialValueNodeNumber);
}
private AggregateResult createOperatorInvocation(SimpleNode node, Type aggExpType, int initialValueNodeNumber) {
Type aggregatableType = extendAndProjectToAggregatable(aggExpType, introducedAttributeName);
Type initialValueType = null;
if (initialValueNodeNumber >= 0) {
initialValueType = (Type)compileChild(node, initialValueNodeNumber, null);
if (!getAttributeExpressionType().canAccept(initialValueType))
throw new ExceptionSemantic("RS0443: Expected type of initial value to be " + getAttributeExpressionType() + " but got " + initialValueType);
}
String operatorName = getOpNameForType(attributeExprType);
OperatorSignature sig = new OperatorSignature("AGGREGATE_" + operatorName);
sig.addParameterType(aggregatableType);
if (initialValueType != null)
sig.addParameterType(initialValueType);
Type returnType = generator.compileEvaluate(sig);
return new AggregateResult(attributeExprType, returnType);
}
}
// aggregate SUM
public Object visit(ASTAggSum node, Object data) {
currentNode = node;
return new AggregatorSum().createAggregator(node).getReturnType();
}
// aggregate AVG
public Object visit(ASTAggAvg node, Object data) {
currentNode = node;
return new AggregatorAvg().createAggregator(node).getReturnType();
}
// aggregate MAX
public Object visit(ASTAggMax node, Object data) {
currentNode = node;
return new AggregatorMax().createAggregator(node).getReturnType();
}
// aggregate MIN
public Object visit(ASTAggMin node, Object data) {
currentNode = node;
return new AggregatorMin().createAggregator(node).getReturnType();
}
// aggregate AND
public Object visit(ASTAggAnd node, Object data) {
currentNode = node;
return new AggregatorAnd().createAggregator(node).getReturnType();
}
// aggregate OR
public Object visit(ASTAggOr node, Object data) {
currentNode = node;
return new AggregatorOr().createAggregator(node).getReturnType();
}
// aggregate XOR
public Object visit(ASTAggXor node, Object data) {
currentNode = node;
return new AggregatorXor().createAggregator(node).getReturnType();
}
// aggregate EQUIV
public Object visit(ASTAggEquiv node, Object data) {
currentNode = node;
return new AggregatorEquiv().createAggregator(node).getReturnType();
}
// aggregate UNION
public Object visit(ASTAggUnion node, Object data) {
currentNode = node;
return new AggregatorUnion().createAggregator(node).getAttributeType();
}
// aggregate XUNION
public Object visit(ASTAggXunion node, Object data) {
currentNode = node;
return new AggregatorXunion().createAggregator(node).getAttributeType();
}
// aggregate D_UNION
public Object visit(ASTAggDUnion node, Object data) {
currentNode = node;
return new AggregatorDUnion().createAggregator(node).getAttributeType();
}
// aggregate INTERSECT
public Object visit(ASTAggIntersect node, Object data) {
currentNode = node;
return new AggregatorIntersect().createAggregator(node).getAttributeType();
}
// aggregate AGGREGATE (generic aggregation)
public Object visit(ASTAggAggregate node, Object data) {
currentNode = node;
return new AggregatorAggregate().makeAggregator(node).getReturnType();
}
// aggregate AGGREGATE (invoke user-defined aggregate operator)
public Object visit(ASTAggAggregateUserdefined node, Object data) {
currentNode = node;
// Child 0 - operator name
String aggOpName = getTokenOfChild(node, 0);
return new AggregatorUserdefined(aggOpName).makeAggregator(node).getReturnType();
}
// EXACTLY. Return TypeBoolean.
public Object visit(ASTExactly node, Object data) {
currentNode = node;
int booleanExpressionCount = 0;
if (getChildCount(node) >= 2) {
Type firstExprType = (Type)compileChild(node, 1, data);
if (firstExprType instanceof TypeRelation) {
if (getChildCount(node) != 3)
throw new ExceptionSemantic("RS0177: Aggregate EXACTLY expected three arguments, but got " + getChildCount(node));
String attributeName = getTokenOfChild((SimpleNode)getChild(node, 2), 0);
Heading source = ((TypeRelation)firstExprType).getHeading();
// Get index of attribute in relation's tuples
int attributeIndex = source.getIndexOf(attributeName);
if (attributeIndex < 0)
throw new ExceptionSemantic("RS0178: Attribute " + attributeName + " not found in " + firstExprType);
Type attributeType = source.getAttributes().get(attributeIndex).getType();
if (!(attributeType instanceof TypeBoolean))
throw new ExceptionSemantic("RS0179: Aggregate EXACTLY expected attribute of type BOOLEAN, but got " + attributeType);
generator.compilePush(ValueInteger.select(generator, attributeIndex));
// Child 0 - ValueInteger n
Type exactlyNType = (Type)compileChild(node, 0, data);
if (!(exactlyNType instanceof TypeInteger))
throw new ExceptionSemantic("RS0180: First parameter to EXACTLY expected INTEGER, but got " + exactlyNType);
OperatorSignature sig = new OperatorSignature("EXACTLY");
sig.addParameterType(firstExprType);
sig.addParameterType(TypeInteger.getInstance());
sig.addParameterType(TypeInteger.getInstance());
return generator.compileEvaluate(sig);
} else if (firstExprType instanceof TypeBoolean) {
booleanExpressionCount++;
for (int i=2; i<getChildCount(node); i++) {
Type exprType = (Type)compileChild(node, i, data);
if (!(exprType instanceof TypeBoolean))
throw new ExceptionSemantic("RS0181: n-adic EXACTLY expected BOOLEAN for argument " + (i + 1) + ", but got " + exprType);
booleanExpressionCount++;
}
} else
throw new ExceptionSemantic("RS0182: n-adic EXACTLY expected BOOLEAN for the second argument, but got " + firstExprType);
}
// Child 0 - ValueInteger n
Type exactlyNType = (Type)compileChild(node, 0, data);
if (!(exactlyNType instanceof TypeInteger))
throw new ExceptionSemantic("RS0183: First parameter to EXACTLY expected INTEGER, but got " + exactlyNType);
generator.compileExactly(booleanExpressionCount);
return TypeBoolean.getInstance();
}
// SUMMARIZE implementation for both prefix and infix SUMMARIZE.
private Object summarize(SimpleNode node, Object data) {
currentNode = node;
// Child 0 - source expression
Type sourceType = (Type)compileChild(node, 0, data);
if (!(sourceType instanceof TypeRelation))
throw new ExceptionSemantic("RS0184: Expected RELATION for first operand of SUMMARIZE, but got " + sourceType);
// Child 1 - SummarizePerOrBy
TypeRelation perType = (TypeRelation)compileChild(node, 1, sourceType);
Generator.Summarize summarize = generator.new Summarize((TypeRelation)sourceType, perType);
// Child 2 - SummarizeItems
compileChild(node, 2, summarize);
return summarize.endSummarize();
}
// SUMMARIZE
public Object visit(ASTSummarize node, Object data) {
return summarize(node, data);
}
// SUMMARIZE optional 'PER' or 'BY'
public Object visit(ASTSummarizePerOrBy node, Object data) {
currentNode = node;
// data is Type of source
if (getChildCount(node) == 0) {
// PER TABLE_DEE
generator.compilePush(ValueRelation.getDee(generator));
return TypeRelation.getEmptyRelationType();
} else
// Compile PER or BY
return compileChild(node, 0, data);
}
// SUMMARIZE 'PER'
public Object visit(ASTSummarizePer node, Object data) {
currentNode = node;
// data is Type of source
// Child 0 - 'per' expression
Type perType = (Type)compileChild(node, 0, data);
if (!(perType instanceof TypeRelation))
throw new ExceptionSemantic("RS0185: Expected RELATION for second operand of SUMMARIZE, but got " + perType);
return perType;
}
// SUMMARIZE 'BY'
public Object visit(ASTSummarizeBy node, Object data) {
currentNode = node;
// data is Type of source
// Child 0 - AttributeNameList
SelectAttributes nameList = (SelectAttributes)compileChild(node, 0, data);
// DUP expression, and project it by the given AttributeNameList
generator.compileDuplicate();
return generator.compileRelationProject((TypeRelation)data, nameList);
}
// SUMMARIZE items
public Object visit(ASTSummarizeItems node, Object data) {
currentNode = node;
// data is Generator.Summarize
compileChildren(node, data);
return null;
}
// SUMMARIZE item
public Object visit(ASTSummarizeItem node, Object data) {
currentNode = node;
// data is Generator.Summarize
Generator.Summarize.SummarizeItem item = ((Generator.Summarize)data).new SummarizeItem();
// Child 0 - identifier
String itemIntroducedName = getTokenOfChild(node, 0);
// Child 1 - summarize aggregation
Type aggReturnType = (Type)compileChild(node, 1, item);
item.endSummarizeItem(aggReturnType, itemIntroducedName);
return null;
}
// SUMMARIZE - COUNT
public Object visit(ASTSummarizeCount node, Object data) {
currentNode = node;
// data is Generator.SummarizeItem
Generator.Summarize.SummarizeItem item = (Generator.Summarize.SummarizeItem)data;
OperatorSignature signature = new OperatorSignature("COUNT");
signature.addParameterType(item.getTypeOfY());
return generator.compileEvaluate(signature);
}
// SUMMARIZE - COUNTD
public Object visit(ASTSummarizeCountDistinct node, Object data) {
currentNode = node;
// data is Generator.SummarizeItem
Generator.Summarize.SummarizeItem item = (Generator.Summarize.SummarizeItem)data;
// Child 0 - expression
item.beginSummarizeItemExpression();
Type exprType = (Type)compileChild(node, 0, data);
item.endSummarizeItemExpression(exprType, true);
OperatorSignature signature = new OperatorSignature("COUNT");
signature.addParameterType(item.getTypeOfY());
return generator.compileEvaluate(signature);
}
// SUMMARIZE - SUM
public Object visit(ASTSummarizeSum node, Object data) {
currentNode = node;
return new AggregatorSum().createAggregator(node, (Generator.Summarize.SummarizeItem)data, false).getReturnType();
}
// SUMMARIZE - SUMD
public Object visit(ASTSummarizeSumDistinct node, Object data) {
currentNode = node;
return new AggregatorSum().createAggregator(node, (Generator.Summarize.SummarizeItem)data, true).getReturnType();
}
// SUMMARIZE - AVG
public Object visit(ASTSummarizeAvg node, Object data) {
currentNode = node;
return new AggregatorAvg().createAggregator(node, (Generator.Summarize.SummarizeItem)data, false).getReturnType();
}
// SUMMARIZE - AVGD
public Object visit(ASTSummarizeAvgDistinct node, Object data) {
currentNode = node;
return new AggregatorAvg().createAggregator(node, (Generator.Summarize.SummarizeItem)data, true).getReturnType();
}
// SUMMARIZE - MAX
public Object visit(ASTSummarizeMax node, Object data) {
currentNode = node;
return new AggregatorMax().createAggregator(node, (Generator.Summarize.SummarizeItem)data, false).getReturnType();
}
// SUMMARIZE - MIN
public Object visit(ASTSummarizeMin node, Object data) {
currentNode = node;
return new AggregatorMin().createAggregator(node, (Generator.Summarize.SummarizeItem)data, false).getReturnType();
}
// SUMMARIZE - AND
public Object visit(ASTSummarizeAnd node, Object data) {
currentNode = node;
return new AggregatorAnd().createAggregator(node, (Generator.Summarize.SummarizeItem)data, false).getReturnType();
}
// SUMMARIZE - OR
public Object visit(ASTSummarizeOr node, Object data) {
currentNode = node;
return new AggregatorOr().createAggregator(node, (Generator.Summarize.SummarizeItem)data, false).getReturnType();
}
// SUMMARIZE - XOR
public Object visit(ASTSummarizeXor node, Object data) {
currentNode = node;
return new AggregatorXor().createAggregator(node, (Generator.Summarize.SummarizeItem)data, false).getReturnType();
}
// SUMMARIZE - EQUIV
public Object visit(ASTSummarizeEquiv node, Object data) {
currentNode = node;
return new AggregatorEquiv().createAggregator(node, (Generator.Summarize.SummarizeItem)data, false).getReturnType();
}
// SUMMARIZE - UNION
public Object visit(ASTSummarizeUnion node, Object data) {
currentNode = node;
return new AggregatorUnion().createAggregator(node, (Generator.Summarize.SummarizeItem)data, false).getAttributeType();
}
// SUMMARIZE - XUNION
public Object visit(ASTSummarizeXunion node, Object data) {
currentNode = node;
return new AggregatorXunion().createAggregator(node, (Generator.Summarize.SummarizeItem)data, false).getAttributeType();
}
// SUMMARIZE - D_UNION
public Object visit(ASTSummarizeDUnion node, Object data) {
currentNode = node;
return new AggregatorDUnion().createAggregator(node, (Generator.Summarize.SummarizeItem)data, false).getAttributeType();
}
// SUMMARIZE - INTERSECT
public Object visit(ASTSummarizeIntersect node, Object data) {
currentNode = node;
return new AggregatorIntersect().createAggregator(node, (Generator.Summarize.SummarizeItem)data, false).getAttributeType();
}
// SUMMARIZE - AGGREGATE
public Object visit(ASTSummarizeAggregate node, Object data) {
currentNode = node;
return new AggregatorAggregate().makeAggregator(node, (Generator.Summarize.SummarizeItem)data, false).getReturnType();
}
// SUMMARIZE - AGGREGATED
public Object visit(ASTSummarizeAggregateDistinct node, Object data) {
currentNode = node;
return new AggregatorAggregate().makeAggregator(node, (Generator.Summarize.SummarizeItem)data, true).getReturnType();
}
// SUMMARIZE - user-defined aggregation operator
public Object visit(ASTSummarizeUserdefined node, Object data) {
currentNode = node;
// Child 0 - identifier
String aggOpName = getTokenOfChild(node, 0);
// Child 1 - SummarizeUserdefinedDistinct
compileChild(node, 1, data);
// Child 2 - expression
// Child 3 - [optional] initial value
Generator.Summarize.SummarizeItem summarizeItem = (Generator.Summarize.SummarizeItem)data;
return new AggregatorUserdefined(aggOpName).makeAggregator(node, summarizeItem, summarizeItem.isDistinct()).getReturnType();
}
// SUMMARIZE aggregation - user-defined aggregation operator invocation optional DISTINCT keyword
public Object visit(ASTSummarizeUserdefinedDistinct node, Object data) {
compileChildren(node, data); // SummarizeUserDefinedDistinctTrue, if it's there
return null;
}
// SUMMARIZE aggregation - user-defined aggregation operator invocation specified DISTINCT keyword
public Object visit(ASTSummarizeUserdefinedDistinctTrue node, Object data) {
Generator.Summarize.SummarizeItem summarizeItem = (Generator.Summarize.SummarizeItem)data;
summarizeItem.setDistinct(true);
return null;
}
private class SummarizeExactlyAggregator extends Aggregator {
SummarizeExactlyAggregator() {
super("EXACTLY");
}
AggregateResult createAggregator(SimpleNode node, Object data, boolean distinct) {
currentNode = node;
// data is Generator.SummarizeItem
Generator.Summarize.SummarizeItem item = (Generator.Summarize.SummarizeItem)data;
// Child 1 - expression
item.beginSummarizeItemExpression();
Type exprType = (Type)compileChild(node, 1, data);
if (!(exprType instanceof TypeBoolean))
throw new ExceptionSemantic("RS0186: Aggregate EXACTLY expected BOOLEAN, but got " + exprType);
TypeRelation aggExpType = item.endSummarizeItemExpression(exprType, distinct);
// Child 0 - n
Type exactlyNType = (Type)compileChild(node, 0, data);
if (!(exactlyNType instanceof TypeInteger))
throw new ExceptionSemantic("RS0187: First parameter to EXACTLY expected INTEGER, but got " + exactlyNType);
Heading source = ((TypeRelation)aggExpType).getHeading();
// Get index of attribute in relation's tuples
int attributeIndex = source.getIndexOf(item.getExtendAttributeName());
if (attributeIndex < 0)
throw new ExceptionFatal("RS0313: Attribute " + item.getExtendAttributeName() + " not found in " + aggExpType);
generator.compilePush(ValueInteger.select(generator, attributeIndex));
OperatorSignature sig = new OperatorSignature("EXACTLY");
sig.addParameterType(aggExpType);
sig.addParameterType(TypeInteger.getInstance());
sig.addParameterType(TypeInteger.getInstance());
return new AggregateResult(null, generator.compileEvaluate(sig));
}
void checkAttributeType(Type t) {}
}
// SUMMARIZE - EXACTLY
public Object visit(ASTSummarizeExactly node, Object data) {
currentNode = node;
return (new SummarizeExactlyAggregator()).createAggregator(node, data, false).getReturnType();
}
// SUMMARIZE - EXACTLYD
public Object visit(ASTSummarizeExactlyDistinct node, Object data) {
currentNode = node;
return (new SummarizeExactlyAggregator()).createAggregator(node, data, true).getReturnType();
}
// construct n-adic boolean operation handler
private class NadicBooleanOperation {
private String opName;
private String opOperatorName;
NadicBooleanOperation(SimpleNode node, String opName, String opOperatorName) {
currentNode = node;
this.opName = opName;
this.opOperatorName = opOperatorName;
// Child 0 - BooleanExpressionCommalist
int opCount = ((Integer)compileChild(node, 0, null)).intValue();
if (opCount == 0)
compileEmptyListResult();
else if (opCount > 1)
for (int i=0; i<opCount - 1; i++)
compileOperation();
}
void compileOperation() {
OperatorSignature signature = new OperatorSignature(getOpOperatorName());
signature.addParameterType(TypeBoolean.getInstance());
signature.addParameterType(TypeBoolean.getInstance());
signature.setReturnType(TypeBoolean.getInstance());
generator.compileEvaluate(signature);
}
String getOpOperatorName() {return opOperatorName;}
void compileEmptyListResult() {
throw new ExceptionSemantic("RS0188: n-adic " + opName + " was specified with no operands. You must specify at least one operand.");
}
}
// n-adic OR. Return TypeBoolean.
public Object visit(ASTNadicOr node, Object data) {
currentNode = node;
// TODO - optimise by exiting on encountering first OR that returns true.
new NadicBooleanOperation(node, "OR", BuiltinTypeBuilder.OR) {
void compileEmptyListResult() {
generator.compilePush(false);
}
};
return TypeBoolean.getInstance();
}
// n-adic AND. Return TypeBoolean.
public Object visit(ASTNadicAnd node, Object data) {
currentNode = node;
// TODO - optimise by exiting on encountering first AND that returns false.
new NadicBooleanOperation(node, "AND", BuiltinTypeBuilder.AND) {
void compileEmptyListResult() {
generator.compilePush(true);
}
};
return TypeBoolean.getInstance();
}
// n-adic XOR. Return TypeBoolean.
public Object visit(ASTNadicXor node, Object data) {
currentNode = node;
new NadicBooleanOperation(node, "XOR", BuiltinTypeBuilder.XOR) {
void compileEmptyListResult() {
generator.compilePush(false);
}
};
return TypeBoolean.getInstance();
}
// n-adic EQUIV. Return TypeBoolean.
public Object visit(ASTNadicEquiv node, Object data) {
currentNode = node;
new NadicBooleanOperation(node, "EQUIV", BuiltinTypeBuilder.EQUALS) {
void compileEmptyListResult() {
generator.compilePush(true);
}
};
return TypeBoolean.getInstance();
}
private class NadicOperation {
private ExpressionCommalist commalist;
private String opName;
private String opOperatorName;
NadicOperation(SimpleNode node, String opName, String opOperatorName) {
currentNode = node;
this.opName = opName;
this.opOperatorName = opOperatorName;
// Child 0 - ExpressionCommalist
commalist = (ExpressionCommalist)compileChild(node, 0, null);
if (commalist.count == 0)
commalist.exprType = compileEmptyListResult();
else if (commalist.count > 1)
for (int i=0; i<commalist.count - 1; i++)
compileOperation();
}
void compileOperation() {
OperatorSignature signature = new OperatorSignature(getOperatorName());
signature.addParameterType(getFirstOperandType());
signature.addParameterType(getFirstOperandType());
signature.setReturnType(getFirstOperandType());
generator.compileEvaluate(signature);
}
String getOperatorName() {return opOperatorName;}
Type compileEmptyListResult() {
throw new ExceptionSemantic("RS0189: n-adic " + opName + " was specified with no operands. You must specify at least one operand.");
}
Type getFirstOperandType() {
return commalist.exprType;
}
}
// n-adic COUNT
public Object visit(ASTNadicCount node, Object data) {
currentNode = node;
// Child 0 - ExpressionCommalist
ExpressionCommalist commalist = (ExpressionCommalist)compileChild(node, 0, null);
for (int i=0; i<commalist.count; i++)
generator.compilePop();
generator.compilePush(ValueInteger.select(generator, commalist.count));
return TypeInteger.getInstance();
}
// n-adic SUM. Return type of first operand.
public Object visit(ASTNadicSum node, Object data) {
currentNode = node;
return (new NadicOperation(node, "SUM", BuiltinTypeBuilder.PLUS) {
Type compileEmptyListResult() {
generator.compilePush(0);
return TypeInteger.getInstance();
}
}).getFirstOperandType();
}
// n-adic MAX. Return type of first operand.
public Object visit(ASTNadicMax node, Object data) {
currentNode = node;
return (new NadicOperation(node, "MAX", BuiltinTypeBuilder.MAX)).getFirstOperandType();
}
// n-adic MIN. Return type of first operand.
public Object visit(ASTNadicMin node, Object data) {
currentNode = node;
return (new NadicOperation(node, "MIN", BuiltinTypeBuilder.MIN)).getFirstOperandType();
}
// n-adic AVG. Return rational.
public Object visit(ASTNadicAvg node, Object data) {
currentNode = node;
// Child 0 - ExpressionCommalist
ExpressionCommalist commalist = (ExpressionCommalist)compileChild(node, 0, null);
generator.compileNadicAverage(commalist.count);
return TypeRational.getInstance();
}
private static class ExpressionCommalist {
int count;
Type exprType;
}
// Comma-separated expression list. Return ExpressionCommalist.
public Object visit(ASTExpressionCommalist node, Object data) {
currentNode = node;
ExpressionCommalist commalist = new ExpressionCommalist();
commalist.count = getChildCount(node);
commalist.exprType = null;
for (int i=0; i<getChildCount(node); i++) {
Type t = (Type)compileChild(node, i, data);
if (commalist.exprType == null)
commalist.exprType = t;
else if (commalist.exprType != t)
throw new ExceptionSemantic("RS0190: Argument " + i + " of an n-adic expression list is " + t + " but " + commalist.exprType + " was expected.");
}
return commalist;
}
// Comma-separated boolean expression list. Compile the list and
// return the number of compiled nodes. Check to ensure all operands are TypeBoolean.
public Object visit(ASTBooleanExpressionCommalist node, Object data) {
currentNode = node;
int count = getChildCount(node);
for (int i=0; i<getChildCount(node); i++) {
Type t = (Type)compileChild(node, i, data);
if (!(t instanceof TypeBoolean))
throw new ExceptionSemantic("RS0191: Argument " + i + " of an n-adic boolean expression list is " + t + " but BOOLEAN was expected.");
}
return new Integer(count);
}
// IN
public Object visit(ASTTupleIn node, Object data) {
currentNode = node;
Type leftType = (Type)compileChild(node, 0, data);
if (!(leftType instanceof TypeTuple))
throw new ExceptionSemantic("RS0192: Expected TUPLE on left side of IN, but got " + leftType);
Type rightType = (Type)compileChild(node, 1, data);
if (!(rightType instanceof TypeRelation))
throw new ExceptionSemantic("RS0193: Expected RELATION on right side of IN, but got " + rightType);
if (!(new TypeRelation(((TypeTuple)leftType).getHeading()).canAccept(rightType)))
throw new ExceptionSemantic("RS0194: " + leftType + " does not have the same heading as " + rightType);
return generator.compileTupleIn((TypeTuple)leftType, (TypeRelation)rightType);
}
// Concatenate (||)
public Object visit(ASTConcatenate node, Object data) {
currentNode = node;
compileChild(node, 0, data);
compileChild(node, 1, data);
generator.compileConcatenate();
return TypeCharacter.getInstance();
}
// ==
public Object visit(ASTCompEqual node, Object data) {
currentNode = node;
Type leftType = (Type)compileChild(node, 0, data);
Type rightType = (Type)compileChild(node, 1, data);
return generator.compileEQ(leftType, rightType);
}
// !=
public Object visit(ASTCompNequal node, Object data) {
currentNode = node;
Type leftType = (Type)compileChild(node, 0, data);
Type rightType = (Type)compileChild(node, 1, data);
return generator.compileNEQ(leftType, rightType);
}
// >=
public Object visit(ASTCompGTE node, Object data) {
currentNode = node;
Type leftType = (Type)compileChild(node, 0, data);
Type rightType = (Type)compileChild(node, 1, data);
return generator.compileGTE(leftType, rightType);
}
// <=
public Object visit(ASTCompLTE node, Object data) {
currentNode = node;
Type leftType = (Type)compileChild(node, 0, data);
Type rightType = (Type)compileChild(node, 1, data);
return generator.compileLTE(leftType, rightType);
}
// >
public Object visit(ASTCompGT node, Object data) {
currentNode = node;
Type leftType = (Type)compileChild(node, 0, data);
Type rightType = (Type)compileChild(node, 1, data);
return generator.compileGT(leftType, rightType);
}
// <
public Object visit(ASTCompLT node, Object data) {
currentNode = node;
Type leftType = (Type)compileChild(node, 0, data);
Type rightType = (Type)compileChild(node, 1, data);
return generator.compileLT(leftType, rightType);
}
// Subset
public Object visit(ASTCompSubset node, Object data) {
currentNode = node;
Type leftType = (Type)compileChild(node, 0, data);
Type rightType = (Type)compileChild(node, 1, data);
return generator.compileSubset(leftType, rightType);
}
// Subset or equal
public Object visit(ASTCompSubsetEqual node, Object data) {
currentNode = node;
Type leftType = (Type)compileChild(node, 0, data);
Type rightType = (Type)compileChild(node, 1, data);
return generator.compileSubsetOrEqual(leftType, rightType);
}
// Superset
public Object visit(ASTCompSuperset node, Object data) {
currentNode = node;
Type leftType = (Type)compileChild(node, 0, data);
Type rightType = (Type)compileChild(node, 1, data);
return generator.compileSuperset(leftType, rightType);
}
// Superset or equal
public Object visit(ASTCompSupersetEqual node, Object data) {
currentNode = node;
Type leftType = (Type)compileChild(node, 0, data);
Type rightType = (Type)compileChild(node, 1, data);
return generator.compileSupersetOrEqual(leftType, rightType);
}
// XOR
public Object visit(ASTXor node, Object data) {
currentNode = node;
Type leftType = (Type)compileChild(node, 0, data);
Type rightType = (Type)compileChild(node, 1, data);
return generator.compileOperatorInvocation(BuiltinTypeBuilder.XOR, leftType, rightType, TypeBoolean.getInstance());
}
// EQUIV
public Object visit(ASTEquiv node, Object data) {
currentNode = node;
Type leftType = (Type)compileChild(node, 0, data);
Type rightType = (Type)compileChild(node, 1, data);
return generator.compileOperatorInvocation(BuiltinTypeBuilder.EQUALS, leftType, rightType, TypeBoolean.getInstance());
}
// OR
public Object visit(ASTOr node, Object data) {
currentNode = node;
Type leftType = (Type)compileChild(node, 0, data);
Type rightType = (Type)compileChild(node, 1, data);
return generator.compileOperatorInvocation(BuiltinTypeBuilder.OR, leftType, rightType, TypeBoolean.getInstance());
}
// AND
public Object visit(ASTAnd node, Object data) {
currentNode = node;
Type leftType = (Type)compileChild(node, 0, data);
Type rightType = (Type)compileChild(node, 1, data);
return generator.compileOperatorInvocation(BuiltinTypeBuilder.AND, leftType, rightType, TypeBoolean.getInstance());
}
// NOT Return Type of expression.
public Object visit(ASTUnaryNot node, Object data) {
currentNode = node;
Type opType = (Type)compileChild(node, 0, data);
return generator.compileOperatorInvocation(BuiltinTypeBuilder.NOT, opType, TypeBoolean.getInstance());
}
// +
public Object visit(ASTAdd node, Object data) {
currentNode = node;
Type leftType = (Type)compileChild(node, 0, data);
Type rightType = (Type)compileChild(node, 1, data);
return generator.compileOperatorInvocation(BuiltinTypeBuilder.PLUS, leftType, rightType, rightType);
}
// -
public Object visit(ASTSubtract node, Object data) {
currentNode = node;
Type leftType = (Type)compileChild(node, 0, data);
Type rightType = (Type)compileChild(node, 1, data);
return generator.compileOperatorInvocation(BuiltinTypeBuilder.MINUS, leftType, rightType, rightType);
}
// *
public Object visit(ASTTimes node, Object data) {
currentNode = node;
Type leftType = (Type)compileChild(node, 0, data);
Type rightType = (Type)compileChild(node, 1, data);
return generator.compileOperatorInvocation(BuiltinTypeBuilder.TIMES, leftType, rightType, rightType);
}
// /
public Object visit(ASTDivide node, Object data) {
currentNode = node;
Type leftType = (Type)compileChild(node, 0, data);
Type rightType = (Type)compileChild(node, 1, data);
return generator.compileOperatorInvocation(BuiltinTypeBuilder.DIVIDE, leftType, rightType, rightType);
}
// % (modulo)
public Object visit(ASTMod node, Object data) {
currentNode = node;
Type leftType = (Type)compileChild(node, 0, data);
Type rightType = (Type)compileChild(node, 1, data);
return generator.compileOperatorInvocation(BuiltinTypeBuilder.MODULO, leftType, rightType, rightType);
}
// + (unary) Return Type of expression.
public Object visit(ASTUnaryPlus node, Object data) {
currentNode = node;
Type opType = (Type)compileChild(node, 0, data);
return generator.compileOperatorInvocation(BuiltinTypeBuilder.UNARY_PLUS, opType, opType);
}
// - (unary) Return Type of expression.
public Object visit(ASTUnaryMinus node, Object data) {
currentNode = node;
Type opType = (Type)compileChild(node, 0, data);
return generator.compileOperatorInvocation(BuiltinTypeBuilder.UNARY_MINUS, opType, opType);
}
// WITH
public Object visit(ASTWith node, Object data) {
currentNode = node;
Generator.With with = generator.new With();
// Child 0 - WITH name introduction list
compileChild(node, 0, with);
// Child 1 - WITH expression
Type expressionType = (Type)compileChild(node, 1, data);
return with.endWith(expressionType);
}
// WITH name introduction list
public Object visit(ASTWithNameIntroCommalist node, Object data) {
currentNode = node;
// data is With
compileChildren(node, data);
return null;
}
// WITH name introduction
public Object visit(ASTWithNameIntro node, Object data) {
currentNode = node;
// data is With
// Child 0 - identifier
String introducedName = getTokenOfChild(node, 0);
// Child 1 - expression
Type expressionType = (Type)compileChild(node, 1, data);
((Generator.With)data).addWithItem(expressionType, introducedName);
return null;
}
// TCLOSE
public Object visit(ASTTClose node, Object data) {
// Child 0 - expression
return generator.compileTClose((Type)compileChild(node, 0, data));
}
private OperatorDefinition lastAnonymousOperatorDefinition;
// Compile and push anonymous operator
public Object visit(ASTLambda node, Object data) {
currentNode = node;
//
OperatorDefinition operator = generator.beginAnonymousOperator();
// Child 0 - parameter def commalist
compileChild(node, 0, data);
// Child 1 - RETURNS type_ref
Type returnType = (Type)compileChild(node, 1, data);
generator.setDeclaredReturnType(returnType);
// Child 2 - body
compileChild(node, 2, data);
// done
generator.endOperator();
// push operator as value
operator.setSourceCode(getSourceCodeOf(node));
generator.compilePush(new ValueOperator(generator, operator.getOperator(), operator.getSourceCode()));
lastAnonymousOperatorDefinition = operator;
return new TypeOperator(operator.getSignature());
}
// Return most recent anonymous operator definition
public OperatorDefinition getLastAnonymousOperatorDefinition() {
return lastAnonymousOperatorDefinition;
}
// Compile literal RELATION. Return TypeRelation.
public Object visit(ASTRelation node, Object data) {
currentNode = node;
// Child 0 - optional heading specification
Heading heading = (Heading)compileChild(node, 0, data);
// Compile literal relation
Generator.RelationDefinition relation = generator.new RelationDefinition(heading);
// Child 1 - HeadingExpCommalist
compileChild(node, 1, relation);
return relation.endRelation();
}
// Optional RELATION heading specification. Return Heading if specified, null otherwise.
public Object visit(ASTRelationHeading node, Object data) {
currentNode = node;
if (getChildCount(node) > 0)
return compileChild(node, 0, data);
return null;
}
// Tuple expression list
public Object visit(ASTTupleExpressionCommalist node, Object data) {
currentNode = node;
// data is Generator.RelationDefinition
Generator.RelationDefinition relation = (Generator.RelationDefinition)data;
// Every child should be a ValueTuple
for (int i=0; i<getChildCount(node); i++) {
Type exprType = (Type)compileChild(node, i, data);
if (!(exprType instanceof TypeTuple))
throw new ExceptionSemantic("RS0195: Expected TUPLE in literal relation; got " + exprType);
relation.addTupleToRelation((TypeTuple)exprType);
}
return null;
}
// TABLE_DUM
public Object visit(ASTRelationDum node, Object data) {
currentNode = node;
generator.compilePush(ValueRelation.getDum(generator));
return TypeRelation.getEmptyRelationType();
}
// TABLE_DEE
public Object visit(ASTRelationDee node, Object data) {
currentNode = node;
generator.compilePush(ValueRelation.getDee(generator));
return TypeRelation.getEmptyRelationType();
}
// Compile literal TUPLE. Return TypeTuple.
public Object visit(ASTTuple node, Object data) {
currentNode = node;
// Compile literal tuple
Generator.TupleDefinition tuple = generator.new TupleDefinition();
// Children - TupleComponent
compileChildren(node, tuple);
return tuple.endTuple();
}
// tuple component
public Object visit(ASTTupleComponent node, Object data) {
currentNode = node;
// data is Generator.TupleDefinition
Generator.TupleDefinition tuple = (Generator.TupleDefinition)data;
// Child 0 - identifier
String identifier = getTokenOfChild(node, 0);
// Child 1 - expression
Type expressionType = (Type)compileChild(node, 1, data);
tuple.setTupleAttribute(identifier, expressionType);
return null;
}
// tuple wildcard, i.e., TUPLE {*}
public Object visit(ASTTupleComponentWildcard node, Object data) {
currentNode = node;
// data is Generator.TupleDefinition
Generator.TupleDefinition tuple = (Generator.TupleDefinition)data;
tuple.setWildcard();
return null;
}
// Capture string literal. Return String.
public Object visit(ASTStringLiteral node, Object data) {
currentNode = node;
return ValueCharacter.stripDelimitedString(node.tokenValue);
}
// Compile literal delimited string. Return TypeCharacter.
public Object visit(ASTCharacter node, Object data) {
currentNode = node;
generator.compilePushDelimitedString(node.tokenValue);
return TypeCharacter.getInstance();
}
// Compile literal integer. Return TypeInteger.
public Object visit(ASTInteger node, Object data) {
currentNode = node;
try {
generator.compilePush(Long.parseLong(node.tokenValue));
} catch (java.lang.NumberFormatException nfe) {
throw new ExceptionSemantic("RS0196: Invalid INTEGER '" + node.tokenValue + "'");
}
return TypeInteger.getInstance();
}
// Compile literal rational. Return TypeRational.
public Object visit(ASTRational node, Object data) {
currentNode = node;
try {
generator.compilePush(Double.parseDouble(node.tokenValue));
} catch (java.lang.NumberFormatException nfe) {
throw new ExceptionSemantic("RS0197: Invalid RATIONAL '" + node.tokenValue + "'");
}
return TypeRational.getInstance();
}
// Compile literal boolean true. Return TypeBoolean.
public Object visit(ASTTrue node, Object data) {
currentNode = node;
generator.compilePush(true);
return TypeBoolean.getInstance();
}
// Compile literal boolean false. Return TypeBoolean.
public Object visit(ASTFalse node, Object data) {
currentNode = node;
generator.compilePush(false);
return TypeBoolean.getInstance();
}
}