astra.ast.core.ASTRAParser Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of astra-compiler Show documentation
Show all versions of astra-compiler Show documentation
Core compiler artifact for the ASTRA Language
The newest version!
package astra.ast.core;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Stack;
import astra.ast.definition.FormulaDefinition;
import astra.ast.definition.TypeDefinition;
import astra.ast.element.ConstantElement;
import astra.ast.element.FunctionElement;
import astra.ast.element.GRuleElement;
import astra.ast.element.InferenceElement;
import astra.ast.element.InitialElement;
import astra.ast.element.ModuleElement;
import astra.ast.element.PackageElement;
import astra.ast.element.RuleElement;
import astra.ast.element.TypesElement;
import astra.ast.event.MessageEvent;
import astra.ast.event.ModuleEvent;
import astra.ast.event.UpdateEvent;
import astra.ast.formula.AndFormula;
import astra.ast.formula.BindFormula;
import astra.ast.formula.BooleanTermElement;
import astra.ast.formula.BracketFormula;
import astra.ast.formula.ComparisonFormula;
import astra.ast.formula.FormulaVariable;
import astra.ast.formula.GoalFormula;
import astra.ast.formula.IsDoneFormula;
import astra.ast.formula.ModuleFormula;
import astra.ast.formula.NOTFormula;
import astra.ast.formula.OrFormula;
import astra.ast.formula.PredicateFormula;
import astra.ast.formula.ScopedGoalFormula;
import astra.ast.formula.TestGoalFormula;
import astra.ast.statement.AssignmentStatement;
import astra.ast.statement.BlockStatement;
import astra.ast.statement.DeclarationStatement;
import astra.ast.statement.DoneStatement;
import astra.ast.statement.ForAllStatement;
import astra.ast.statement.ForEachStatement;
import astra.ast.statement.IfStatement;
import astra.ast.statement.MaintainBlockStatement;
import astra.ast.statement.MinusMinusStatement;
import astra.ast.statement.ModuleCallStatement;
import astra.ast.statement.PlanCallStatement;
import astra.ast.statement.PlusPlusStatement;
import astra.ast.statement.QueryStatement;
import astra.ast.statement.ScopedStatement;
import astra.ast.statement.SendStatement;
import astra.ast.statement.SpawnGoalStatement;
import astra.ast.statement.SubGoalStatement;
import astra.ast.statement.SynchronizedBlockStatement;
import astra.ast.statement.TRStatement;
import astra.ast.statement.TestGoalStatement;
import astra.ast.statement.TryRecoverStatement;
import astra.ast.statement.UpdateStatement;
import astra.ast.statement.WaitStatement;
import astra.ast.statement.WhileStatement;
import astra.ast.term.AtIndexTerm;
import astra.ast.term.Brackets;
import astra.ast.term.CountFormulaeTerm;
import astra.ast.term.CountTerm;
import astra.ast.term.Function;
import astra.ast.term.HeadTerm;
import astra.ast.term.InlineVariableDeclaration;
import astra.ast.term.ListSplitterTerm;
import astra.ast.term.ListTerm;
import astra.ast.term.Literal;
import astra.ast.term.ModuleTerm;
import astra.ast.term.NotTerm;
import astra.ast.term.Operator;
import astra.ast.term.QueryTerm;
import astra.ast.term.TailTerm;
import astra.ast.term.VariableElement;
import astra.ast.tr.FunctionCallAction;
import astra.ast.tr.TRModuleCallAction;
import astra.ast.tr.TRRuleElement;
import astra.ast.tr.UpdateAction;
import astra.ast.type.BasicType;
import astra.ast.type.ObjectType;
public class ASTRAParser {
private static final int[] OPERATOR_PRECEDENCE = { Token.MULTIPLY, Token.DIVIDE, Token.MODULO, Token.PLUS, Token.MINUS };
private static final int[] BOOLEAN_OPERATOR_PRECEDENCE = { Token.AND, Token.OR };
private static final int[][] COMPARISON_OPERATOR_PRECEDENCE = {
new int[] {Token.ASSIGNMENT, Token.ASSIGNMENT},
new int[] {Token.NOT, Token.ASSIGNMENT},
new int[] {Token.GREATER_THAN, Token.ASSIGNMENT},
new int[] {Token.GREATER_THAN},
new int[] {Token.LESS_THAN, Token.ASSIGNMENT},
new int[] {Token.LESS_THAN}
};
static Map BRACKET_PAIRINGS = new HashMap<>();
static {
BRACKET_PAIRINGS.put(Token.LEFT_BRACKET, Token.RIGHT_BRACKET);
BRACKET_PAIRINGS.put(Token.LEFT_BRACE, Token.RIGHT_BRACE);
BRACKET_PAIRINGS.put(Token.LEFT_SQ_BRACKET, Token.RIGHT_SQ_BRACKET);
}
static Map BRACKET_STRINGS = new HashMap<>();
static {
BRACKET_STRINGS.put(Token.LEFT_BRACE, "{");
BRACKET_STRINGS.put(Token.LEFT_BRACKET, "(");
BRACKET_STRINGS.put(Token.LEFT_SQ_BRACKET, "[");
BRACKET_STRINGS.put(Token.RIGHT_SQ_BRACKET, "]");
BRACKET_STRINGS.put(Token.RIGHT_BRACKET, ")");
BRACKET_STRINGS.put(Token.RIGHT_BRACE, "}");
}
private ADTTokenizer tokenizer;
public ASTRAParser(ADTTokenizer tokenizer) {
this.tokenizer = tokenizer;
}
public List readTo(int type) throws ParseException {
List list = new ArrayList<>();
Token token = tokenizer.nextToken();
Token first = token;
boolean finished = false;
Stack bracketStack = new Stack<>();
while ( token.type != Token.EOF && !finished) {
if (BRACKET_PAIRINGS.containsKey(token.type)) {
bracketStack.push(token);
if (token.type == type && bracketStack.size() == 1 ) {
finished = true;
}
} else if (BRACKET_PAIRINGS.containsValue(token.type)) {
if (bracketStack.isEmpty()) {
throw new ParseException("Too many brackets", token, token);
}
Token t = bracketStack.pop();
if (BRACKET_PAIRINGS.get(t.type) != token.type) {
// System.out.println("Tokens: " + list);
throw new ParseException("Mismatched Brackets: expected " + BRACKET_STRINGS.get(BRACKET_PAIRINGS.get(t.type)) + " but got: " + token.token, first, token);
}
}
if (token.type == type && bracketStack.isEmpty() ) {
finished = true;
}
list.add(token);
if (!finished) token = tokenizer.nextToken();
}
return list;
}
public ClassDeclarationElement createClassDeclaration(List tokens) throws ParseException {
Token first = tokens.get(0);
Token last = getLast(tokens);
boolean _abstract = false;
boolean _final = false;
String name = null;
Token tok = tokens.remove(0);
while (tok.type != Token.AGENT) {
switch (tok.type) {
case Token.ABSTRACT:
_abstract = true;
break;
case Token.FINAL:
_final = true;
break;
default:
throw new ParseException("Unknown modifier: " + tok.token, tok, tok);
}
tok = tokens.remove(0);
}
name = tokens.remove(0).token;
List parents = new ArrayList<>();
tok = tokens.remove(0);
if (tok.type == Token.EXTENDS) {
while (!tokens.isEmpty() && tok.type != Token.LEFT_BRACE) {
List list = splitAt(tokens, new int[] {Token.COMMA});
parents.add(getQualifiedName(list.subList(0, list.size()-1)));
tok = list.get(list.size()-1);
}
}
if (parents.isEmpty()) {
parents.add("astra.lang.Agent");
}
if (tok.type != Token.LEFT_BRACE) {
throw new ParseException("Invalid Class Declaration", first, last);
}
return new ClassDeclarationElement(name, parents.toArray(new String[parents.size()]),
_abstract, _final, first, last, tokenizer.getSource(first,last));
}
public ImportElement createImport(List tokens) throws ParseException {
Token first = tokens.get(0);
Token last = tokens.get(tokens.size() - 1);
return new ImportElement(getQualifiedName(tokens), first, last, tokenizer.getSource(first, last));
}
public PackageElement createPackage(List tokens) throws ParseException {
Token first = tokens.get(0);
Token last = tokens.get(tokens.size() - 1);
return new PackageElement(getQualifiedName(tokens), first, last, tokenizer.getSource(first, last));
}
/**
* Creates a plan rule node of the ASTRA AST.
*
* @param tokens the current stream of tokens to be parsed
* @return a RuleElement object
* @throws ParseException occurs if the token stream does not represent a valid ASTRA rule
*/
public RuleElement createRule(List tokens) throws ParseException {
Token first = tokens.get(0);
List list = splitAt(tokens, new int[] {Token.COLON, Token.LEFT_BRACE});
Token tok = list.remove(list.size()-1);
IEvent event = createEvent(list);
// If we split on a COLON, then we have a context...
IFormula context = new PredicateFormula("true", new LinkedList<>(), tok, tok, tokenizer.getSource(tok, tok));
if (tok.type == Token.COLON) {
list = splitAt(tokens, new int[] {Token.LEFT_BRACE});
// Now we have to have terminated with a LEFT_BRACE, so get it...
tok = list.remove(list.size()-1);
if (list.isEmpty()) throw new ParseException("Unexpected token: ':'", tok, tok);
context = createFormula(list);
}
// Re-insert left brace and process the statement...
tokens.add(0, tok);
return new RuleElement(event, context, createStatement(tokens),
first, tok, tokenizer.getSource(first, tok));
}
public GRuleElement createGRule(List tokens) throws ParseException {
Token first = tokens.get(0);
Token last = tokens.get(tokens.size() - 1);
List list = splitAt(tokens, new int[] {Token.COLON, Token.LESS_THAN, Token.LEFT_BRACE});
Token tok = list.remove(list.size()-1);
IEvent event = createEvent(list);
// System.out.println("Event: " + event);
// If we split on a COLON, then we have a context...
IFormula context = new PredicateFormula("true", new LinkedList<>(), tok, tok, tokenizer.getSource(tok, tok));
if (tok.type == Token.COLON) {
list = splitAt(tokens, new int[] {Token.LEFT_BRACE, Token.LESS_THAN});
// Now we have to have terminated with a LEFT_BRACE, so get it...
tok = list.remove(list.size()-1);
if (list.isEmpty()) throw new ParseException("Unexpected token: ':'", tok, tok);
context = createFormula(list);
}
// System.out.println("Context: " + context);
IFormula dropCondition = new IsDoneFormula(tok, tok, "");
if (tok.type == Token.LESS_THAN) {
// Remove the next token to check for a COLON (:)
tok = tokens.remove(0);
if (tok.type != Token.COLON) throw new ParseException("Unexpected token: "+tok.token, tok, tok);
list = splitAt(tokens, new int[] {Token.LEFT_BRACE});
// Now we have to have terminated with a LEFT_BRACE, so get it...
tok = list.remove(list.size()-1);
if (list.isEmpty()) throw new ParseException("Unexpected token: ':'", tok, tok);
dropCondition = createFormula(list);
}
// System.out.println("Drop Condition: " + dropCondition);
IStatement body = null;
List rules = new LinkedList<>();
// Re-insert left brace and process the statement...
// tokens.add(0, tok);
tok = tokens.remove(0);
while (tok.type != Token.RIGHT_BRACE) {
switch (tok.type) {
case Token.BODY:
body = createStatement(tokens);
// System.out.println("body: " + body);
break;
case Token.RULE:
RuleElement rule = this.createRule(tokens);
// System.out.println("rule: " + rule);
rules.add(rule);
break;
case Token.GRULE:
case Token.GOAL_TYPE:
rule = this.createGRule(tokens);
// System.out.println("grule: " + rule);
rules.add(rule);
break;
default:
throw new ParseException("Not a valid rule: " +tok.token, tok);
}
tok = tokens.remove(0);
}
if (body == null) {
body = new BlockStatement(new LinkedList<>(), first, last, "");
}
// System.out.println("FINAL: " + event + " / " + context + " / " + dropCondition + " / " + body);
return new GRuleElement(event, context, dropCondition, body, rules,
first, tok, tokenizer.getSource(first, tok));
}
public RuleElement createSynchronizedRule(List tokens) throws ParseException {
String synchronizationToken = "synchronized";
Token tok = tokens.remove(0);
if (tok.type == Token.LESS_THAN) {
tok = tokens.remove(0);
if (tok.type != Token.IDENTIFIER) {
throw new ParseException("Expected identifier for atomic rule atomic, but got: " + tok.token, tok, tok);
}
synchronizationToken = tok.token;
tok = tokens.remove(0);
if (tok.type != Token.GREATER_THAN) {
throw new ParseException("Expected close angled bracket > for atomic rule atomic, but got: " + tok.token, tok, tok);
}
tok = tokens.remove(0);
}
if (tok.type != Token.RULE) {
throw new ParseException("Expected rule keyword or <, but got: " + tok.token, tok, tok);
}
Token first = tokens.get(0);
Token last = tokens.get(tokens.size() - 1);
List list = splitAt(tokens, new int[] {Token.COLON, Token.LEFT_BRACE});
tok = list.remove(list.size()-1);
IEvent event = createEvent(list);
// If we split on a COLON, then we have a context...
IFormula context = new PredicateFormula("true", new LinkedList<>(), tok, tok, tokenizer.getSource(tok, tok));
if (tok.type == Token.COLON) {
list = splitAt(tokens, new int[] {Token.LEFT_BRACE});
// Now we have to have terminated with a LEFT_BRACE, so get it...
tok = list.remove(list.size()-1);
if (list.isEmpty()) throw new ParseException("Unexpected token: ':'", tok, tok);
context = createFormula(list);
}
// Re-insert left brace and process the statement...
tokens.add(0, tok);
// Convert the block into a synchronized block...
BlockStatement block = (BlockStatement) createStatement(tokens);
List statements = new LinkedList<>();
Collections.addAll(statements, block.statements());
SynchronizedBlockStatement sblock =
new SynchronizedBlockStatement(synchronizationToken, statements, block.start, block.end, block.getSource());
return new RuleElement(event, context, sblock,
first, last, tokenizer.getSource(first, last));
}
public FunctionElement createFunction(List tokens) throws ParseException {
Token first = tokens.get(0);
Token last = tokens.get(tokens.size() - 1);
List list = splitAt(tokens, new int[] {Token.LEFT_BRACE});
list.remove(list.size()-1);
if (last.type != Token.RIGHT_BRACE) throw new ParseException("Mismatched brackets", first, last);
tokens.remove(tokens.size()-1);
List rules = new ArrayList<>();
// Construct the TR Function, reading each action-selection rule
if (!tokens.isEmpty()) {
do {
List list2 = splitAt(tokens, new int[] {Token.MINUS});
while (!tokens.isEmpty() && tokens.get(0).type != Token.GREATER_THAN) {
list2.addAll(splitAt(tokens, new int[] {Token.MINUS}));
}
if (!tokens.isEmpty()) {
list2.remove(list2.size()-1);
tokens.remove(0);
Token l = tokens.get(tokens.size()-1);
Token f = list2.get(0);
List list3 = splitAt(tokens, new int[] {Token.RIGHT_BRACKET});
rules.add(new TRRuleElement(createFormula(list2), createAction(list3), f, l, tokenizer.getSource(f, l)));
}
} while (!tokens.isEmpty());
}
// System.out.println("list: "+ list);
PredicateFormula pred = createPredicate(list);
// System.out.println("Pred: " + pred);
return new FunctionElement(pred,
rules.toArray(new TRRuleElement[rules.size()]),
first, last, tokenizer.getSource(first, last));
}
public IAction createAction(List tokens) throws ParseException {
Token first = tokens.get(0);
Token last = tokens.get(tokens.size() - 1);
if (first.type == Token.IDENTIFIER) {
if (tokens.get(1).type == Token.PERIOD) {
// Primitive Action
tokens.remove(0);
tokens.remove(0);
List t_list = splitAt(tokens, new int[] {Token.RIGHT_BRACKET});
last = getLast(t_list);
return new TRModuleCallAction(first.token, createPredicate(t_list),
first, last, tokenizer.getSource(first, last));
} else {
return new FunctionCallAction(createPredicate(tokens), first, last,tokenizer.getSource(first,last));
}
} else if (first.type == Token.PLUS || first.type == Token.MINUS) {
tokens.remove(0);
return new UpdateAction(first.token, createPredicate(tokens),
first, last, tokenizer.getSource(first, last));
}
return null;
}
public InferenceElement createInference(List tokens) throws ParseException {
Token first = tokens.get(0);
Token last = tokens.get(tokens.size() - 1);
List list = splitAt(tokens, new int[] {Token.COLON});
if (list.remove(list.size()-1).type != Token.COLON || tokens.remove(0).type != Token.MINUS) {
throw new ParseException("Malformed Inference", first, last);
}
return new InferenceElement(createPredicate(list), createFormula(tokens),
first, last, tokenizer.getSource(first, last));
}
public List createConstant(List tokens) throws ParseException {
Token first = tokens.get(0);
Token last = tokens.get(tokens.size() - 1);
List constants = new ArrayList<>();
while (!tokens.isEmpty()) {
List list = splitAt(tokens, new int[] {Token.COMMA} );
if (getLast(list).type == Token.COMMA) list.remove(list.size()-1);
Token tok = list.remove(0);
if (!Token.isType(tok.type)) {
throw new ParseException("Expected type, but got: " + tok.token, tok);
}
IType type = new BasicType(Token.resolveType(tok.type));
Token tok2 = list.remove(0);
if (tok2.type != Token.IDENTIFIER) {
throw new ParseException("Expected a constant identifier, but got: " + tok2.token, tok2);
}
if (list.get(0).type != Token.ASSIGNMENT) {
throw new ParseException("Expected assigment, but got: " + tok2.token, tok2);
}
list.remove(0);
ITerm term = createTerm(list);
if (term == null) {
throw new ParseException("Expected term, but got: " + tokens, tokens.get(0));
}
constants.add(new ConstantElement(tok2.token, type, term,
first, last, tokenizer.getSource(first, last)));
}
return constants;
}
public List createInitial(List tokens) throws ParseException {
Token first = tokens.get(0);
Token last = tokens.get(tokens.size() - 1);
List initials = new ArrayList<>();
while (!tokens.isEmpty()) {
List list = splitAt(tokens, new int[] {Token.COMMA} );
if (getLast(list).type == Token.COMMA) list.remove(list.size()-1);
initials.add(new InitialElement(createPredicateOrBelief(list),
first, last, tokenizer.getSource(first, last)));
}
return initials;
}
public ModuleElement createModule(List tokens) throws ParseException {
Token first = tokens.get(0);
Token last = tokens.remove(tokens.size() - 1);
String qName = getQualifiedName(tokens);
List terms = null;
if (tokens.get(0).type == Token.LEFT_BRACKET) {
// have a constructor
tokens.remove(0);
if (tokens.remove(tokens.size()-1).type != Token.RIGHT_BRACKET) {
throw new ParseException("Syntax Error: Unmatched bracket for module constructor near: module " + qName, first, last);
}
terms = getTermList(tokens, false);
} else if (tokens.size() == 1) {
// if there is no brackets, 1 terms should be left in the list...
terms = new LinkedList<>();
} else {
throw new ParseException("Syntax Error: Not a valid module declaration near: module " + qName, first, last);
}
return new ModuleElement(qName, last.token, terms,
first, last, tokenizer.getSource(first, last));
}
public IStatement createStatement(List tokens) throws ParseException {
Token first = tokens.get(0);
Token last = tokens.get(tokens.size() - 1);
// HANDLE Variable Declaration (with Initialization)
Token tok = tokens.remove(0);
if (Token.isType(tok.type)) {
IType type = new BasicType(Token.resolveType(tok.type));
Token tok2 = tokens.remove(0);
if (tok2.type != Token.IDENTIFIER) {
throw new ParseException("Expected an identifier, but got: " + tok2.token, tok2);
}
if (tokens.get(0).type == Token.SEMI_COLON) {
tokens.remove(0);
return new DeclarationStatement(type, tok2.token,
first, last, tokenizer.getSource(first, last));
}
List list = splitAt(tokens, new int[] {Token.SEMI_COLON});
// Not sure this is needed... simpler view adopted - if there is a semi colon at the end,
// remove it...
if (list.get(list.size()-1).type == Token.SEMI_COLON) {
list.remove(list.size()-1);
}
// if (list.remove(list.size()-1).type != Token.SEMI_COLON) {
// throw new ParseException("Missing Semi Colon", list.get(0), list.get(list.size()-1));
// }
Token tok3 = list.remove(0);
if (tok3.type == Token.ASSIGNMENT) {
ITerm term = createTerm(list);
return new DeclarationStatement(type, tok2.token, term,
first, last, tokenizer.getSource(first, last));
}
throw new ParseException("Expected = or ;, but got: " + tok3.token, tok3);
}
String token = null;
switch ( tok.type ) {
case Token.MAINTAIN:
List list = this.splitAt(tokens, new int[]{Token.RECOVER,Token.RIGHT_BRACE});
if (list.get(list.size()-1).type == Token.RECOVER) {
list.remove(list.size()-1);
}
// System.out.println("list: " + list);
// System.out.println("tokens: " + tokens);
Token tok2 = list.remove(0);
if (tok2.type != Token.LEFT_BRACKET) {
throw new ParseException("Illegal token: expected ( but got: " + tok2.token, tok2);
}
IFormula formula = createFormula(splitAt(list, new int[] {Token.RIGHT_BRACKET}));
tok2 = list.remove(0);
if (tok2.type != Token.RIGHT_BRACKET) {
throw new ParseException("Illegal token: expected ) but got: " + tok2.token, tok2);
}
tok = list.remove(0);
if (tok.type != Token.LEFT_BRACE) {
throw new ParseException("Illegal token: expected { but got: " + tok.token, tok);
}
List statements = new LinkedList<>();
if (getLast(list).type != Token.RIGHT_BRACE) {
throw new ParseException("Illegal token: expected } but got "+getLast(list).token, first, getLast(list));
}
tok2 = list.get(0);
while ( tok2.type != Token.RIGHT_BRACE ) {
statements.add(createStatement(list));
if (list.isEmpty()) break;
tok2 = list.get(0);
}
List recover = new LinkedList<>();
if (!tokens.isEmpty() && tokens.get(0).type == Token.RECOVER) {
tok = tokens.remove(0);
if (tok.type != Token.LEFT_BRACE) {
throw new ParseException("Illegal token: expected { but got: " + tok.token, tok);
}
if (getLast(tokens).type != Token.RIGHT_BRACE) {
throw new ParseException("Illegal token: expected } but got "+getLast(tokens).token, tok, getLast(tokens));
}
tok2 = tokens.get(0);
while ( tok2.type != Token.RIGHT_BRACE ) {
recover.add(createStatement(tokens));
if (tokens.isEmpty()) break;
tok2 = tokens.get(0);
}
}
return new MaintainBlockStatement(formula, statements, recover, first, last, tokenizer.getSource(first, last));
case Token.SYNCHRONIZED:
tok2 = tokens.remove(0);
if (tok2.type != Token.LEFT_BRACKET) {
throw new ParseException("Illegal token: expected ( but got: " + tok2.token, tok2);
}
token = tokens.remove(0).token;
tok2 = tokens.remove(0);
if (tok2.type != Token.RIGHT_BRACKET) {
throw new ParseException("Illegal token: expected ) but got: " + tok2.token, tok2);
}
tok = tokens.remove(0);
case Token.LEFT_BRACE:
// THERE IS AN ERROR IN THIS PART OF THE CODEBASE...
// we have a block...
statements = new LinkedList<>();
tokens.add(0, tok);
List t_list = splitAt(tokens, new int[] {Token.RIGHT_BRACE});
if (getLast(t_list).type != Token.RIGHT_BRACE) {
throw new ParseException("Missing closing braces", first, last);
}
t_list.remove(0);
tok2 = t_list.get(0);
while ( tok2.type != Token.RIGHT_BRACE ) {
statements.add(createStatement(t_list));
if (t_list.isEmpty()) break;
tok2 = t_list.get(0);
}
if (token != null) {
return new SynchronizedBlockStatement(token, statements, first, last, tokenizer.getSource(first, last));
}
return new BlockStatement(statements, first, last, tokenizer.getSource(first, last));
case Token.SEND:
list = splitAt(tokens, new int[] {Token.SEMI_COLON});
semiColonCheck(list);
last = getLast(list);
tok2 = list.remove(0);
if (tok2.type != Token.LEFT_BRACKET) {
throw new ParseException("Malformed Statement: send(, , )", first, last);
}
if (last.type != Token.RIGHT_BRACKET) {
throw new ParseException("Malformed Statement: send(, , )", first, last);
}
List terms = getTermList(list.subList(0, list.size()-1), false);
if (terms.size() < 3 || terms.size() > 4) {
throw new ParseException("Malformed Statement: send(, , [,])", first, last);
}
IFormula content = this.convertToPredicate(terms.get(2));
ITerm params = null;
if (terms.size() == 4) params = terms.get(3);
list.remove(list.size()-1);
return new SendStatement(terms.get(0), terms.get(1), content, params,
first, last, tokenizer.getSource(first, last));
case Token.QUERY:
tok2 = tokens.get(0);
if (tok2.type != Token.LEFT_BRACKET) {
throw new ParseException("Malformed Statement: query()", first, last);
}
list = splitAt(tokens, new int[] {Token.SEMI_COLON});
semiColonCheck(list);
last = getLast(list);
if (last.type != Token.RIGHT_BRACKET) {
throw new ParseException("Malformed Statement: query()", first, last);
}
list.remove(0);
list.remove(list.size()-1);
return new QueryStatement(createFormula(list),
first, last, tokenizer.getSource(first, last));
case Token.IF:
tok2 = tokens.get(0);
if (tok2.type != Token.LEFT_BRACKET) {
throw new ParseException("Malformed Statement: if() [else ]", first, last);
}
list = splitAt(tokens, new int[] {Token.RIGHT_BRACKET});
if (list.size() < 2) {
throw new ParseException("Malformed Statement - NO GUARD: if() [else ]", first, last);
}
IFormula guard = createFormula(list.subList(1, list.size()-1));
if (tokens.get(0).type == Token.LEFT_BRACE) {
list = splitAt(tokens, new int[] {Token.RIGHT_BRACE});
} else {
list = tokens;
// list = splitAt(tokens, new int[] {Token.SEMI_COLON});
}
IStatement statement = createStatement(list);
if (!tokens.isEmpty() && tokens.get(0).type == Token.ELSE) {
tokens.remove(0);
return new IfStatement(guard, statement, createStatement(tokens),
first, last, tokenizer.getSource(first, last));
} else {
return new IfStatement(guard, statement,
first, last, tokenizer.getSource(first, last));
}
case Token.WHILE:
tok2 = tokens.get(0);
if (tok2.type != Token.LEFT_BRACKET) {
throw new ParseException("Malformed Statement: while() ", first, last);
}
list = splitAt(tokens, new int[] {Token.RIGHT_BRACKET});
guard = createFormula(list.subList(1, list.size()-1));
list = splitAt(tokens, new int[] {Token.RIGHT_BRACE, Token.SEMI_COLON});
return new WhileStatement(guard, createStatement(list),
first, last, tokenizer.getSource(first, last));
case Token.DONE:
list = splitAt(tokens, new int[] {Token.SEMI_COLON});
if (!list.isEmpty() && getLast(list).type == Token.SEMI_COLON) list.remove(list.size()-1);
if (!list.isEmpty()) {
throw new ParseException("Syntax Error: expected semi-colon after done statement, but got: " + list.get(0).token, first, last);
}
return new DoneStatement(first, last, tokenizer.getSource(first, last));
case Token.WAIT:
list = splitAt(tokens, new int[] {Token.SEMI_COLON});
if (getLast(list).type == Token.SEMI_COLON) list.remove(list.size()-1);
if (list.remove(0).type != Token.LEFT_BRACKET) {
throw new ParseException("Malformed Statement: Missing left bracket in wait statement)", first, last);
}
if (list.remove(list.size()-1).type != Token.RIGHT_BRACKET) {
throw new ParseException("Malformed Statement: Missing right bracket in wait statement", first, last);
}
ITerm timeout = null;
List formulaTokens = splitAt(list, new int[] {Token.COMMA});
// If there are move tokens, process
if (list.isEmpty()) {
try {
formula = this.createFormula(formulaTokens);
} catch (Exception th) {
throw new ParseException("Malformed formula in wait(...)", first, last);
}
} else {
// need this because there is a COMMA on the end...
try {
formula = this.createFormula(formulaTokens.subList(0, formulaTokens.size()-1));
} catch (Exception th) {
throw new ParseException("Malformed formula in wait(...)", first, last);
}
List timeoutList = splitAt(list, new int[] {Token.COMMA});
if (!list.isEmpty()) {
throw new ParseException("Incorrect number of arguments in wait(...) statement", first, last);
}
timeout = this.createTerm(timeoutList);
}
return new WaitStatement(formula, timeout,
first, last, tokenizer.getSource(first, last));
// if (terms.size() < 1 || terms.size() > 2) {
// throw new ParseException("Incorrect number of arguments in wait(...) statement", first, last);
// }
// formula = this.convertToPredicate(terms.get(0));
// ITerm timeout = null;
// if (terms.size() == 2) {
// timeout = terms.get(1);
// }
// // System.out.println("Creating wait statement: " + formula + " / " + timeout);
// return new WaitStatement(formula, timeout,
// first, last, tokenizer.getSource(first, last));
case Token.FOREACH:
tok2 = tokens.get(0);
if (tok2.type != Token.LEFT_BRACKET) {
throw new ParseException("Malformed Statement: when() ", first, last);
}
list = splitAt(tokens, new int[] {Token.RIGHT_BRACKET});
guard = createFormula(list.subList(1, list.size()-1));
list = splitAt(tokens, new int[] {Token.RIGHT_BRACE, Token.SEMI_COLON});
return new ForEachStatement(guard, createStatement(list),
first, last, tokenizer.getSource(first, last));
case Token.FORALL:
t_list = splitAt(tokens, new int[] {Token.RIGHT_BRACKET});
last = getLast(t_list);
if (t_list.remove(0).type != Token.LEFT_BRACKET)
throw new ParseException("Malformed Statement: missing left bracket\n\tExpected Syntax: forall( : ))", first, last);
if (getLast(t_list).type != Token.RIGHT_BRACKET)
throw new ParseException("Malformed Statement: missing right bracket\n\tExpected Syntax: forall( : ))", first, last);
list = splitAt(t_list, new int[] {Token.COLON});
if (getLast(list).type != Token.COLON)
throw new ParseException("Malformed Statement: missing colon\n\tExpected Syntax: forall( : ))", first, last);
list.remove(list.size()-1);
ITerm term = createTerm(list);
if (term instanceof InlineVariableDeclaration) {
ITerm listTerm = createTerm(t_list.subList(0, t_list.size()-1));
if (listTerm instanceof ListTerm || (listTerm instanceof VariableElement) || (listTerm instanceof ModuleTerm)) {
return new ForAllStatement(term, listTerm, createStatement(tokens),
first, last, tokenizer.getSource(first, last));
}
throw new ParseException("Malformed Statement: there should be a list after the colon\n\tExpected Syntax: forall( : ))", first, last);
}
throw new ParseException("Malformed Statement: there should be a variable before the colon\n\tExpected Syntax: forall( : ))", first, last);
case Token.TR_START:
t_list = splitAt(tokens, new int[] {Token.SEMI_COLON});
last = getLast(t_list);
if (last.type != Token.SEMI_COLON) throw new ParseException("Missing Semi-colon", first, last);
t_list.remove(t_list.size()-1);
if (t_list.remove(0).type != Token.LEFT_BRACKET) {
throw new ParseException("Malformed Statement: missing left bracket\n\t" + tok.token + "()", first, last);
}
if (t_list.remove(t_list.size()-1).type != Token.RIGHT_BRACKET) {
throw new ParseException("Malformed Statement: missing right bracket\n\t" + tok.token + "wait()", first, last);
}
return new TRStatement(tok.token, createPredicateOrVariableFormula(t_list), first, last, tokenizer.getSource(first, last));
case Token.TR_STOP:
t_list = splitAt(tokens, new int[] {Token.SEMI_COLON});
last = getLast(t_list);
if (last.type != Token.SEMI_COLON) throw new ParseException("Missing Semi-colon", first, last);
t_list.remove(t_list.size()-1);
if (t_list.size() != 2) {
throw new ParseException("Malformed Statement: stop() should contain no parameters", first, last);
}
if (t_list.remove(0).type != Token.LEFT_BRACKET) {
throw new ParseException("Malformed Statement: missing left bracket\n\t" + tok.token + "()", first, last);
}
if (t_list.remove(t_list.size()-1).type != Token.RIGHT_BRACKET) {
throw new ParseException("Malformed Statement: missing right bracket\n\t" + tok.token + "wait()", first, last);
}
return new TRStatement(tok.token, null, first, last, tokenizer.getSource(first, last));
case Token.TRY:
list = splitAt(tokens, new int[] {Token.RECOVER});
if (list.get(list.size()-1).type != Token.RECOVER) {
throw new ParseException("Malformed Statement: try recover ", first, last);
}
return new TryRecoverStatement(createStatement(list.subList(0, list.size()-1)),
createStatement(tokens), first, last, tokenizer.getSource(first, last));
case Token.BANG:
list = splitAt(tokens, new int[] {Token.SEMI_COLON});
semiColonCheck(list);
if (list.get(0).type == Token.BANG) {
return new SpawnGoalStatement(createGoal(list),
first, last, tokenizer.getSource(first, last));
} else {
list.add(0, tok);
return new SubGoalStatement(createGoal(list),
first, last, tokenizer.getSource(first, last));
}
case Token.QUESTION:
list = splitAt(tokens, new int[] {Token.SEMI_COLON});
semiColonCheck(list);
list.add(0,tok);
return new TestGoalStatement(createTestGoal(list),
first, last, tokenizer.getSource(first, last));
case Token.PLUS:
case Token.MINUS:
list = splitAt(tokens, new int[] {Token.SEMI_COLON});
semiColonCheck(list);
if (tok.type == Token.MINUS && list.get(0).type == Token.PLUS) {
list.remove(0);
PredicateFormula predicate = createPredicate(list);
// special case of -+update statement
return new UpdateStatement("-+", predicate,
first, last, tokenizer.getSource(first, last));
} else {
PredicateFormula predicate = createPredicate(list);
return new UpdateStatement(tok.token, predicate,
first, last, tokenizer.getSource(first, last));
}
case Token.IDENTIFIER:
// System.out.println("tokens: " + tokens);
// need to refine this further...
// now consider scoped operator + plan module call...
List m_list = splitAt(tokens, new int[] {Token.SEMI_COLON});
// This is pointless: semiColonCheck(m_list);
list = splitAt(m_list, new int[] {Token.COLON});
// System.out.println("tokens: " + tokens);
// System.out.println("m_list: " + m_list);
// System.out.println("list: " + list);
if (list.get(list.size()-1).type == Token.COLON) {
if (m_list.get(0).type == Token.COLON) {
m_list.remove(0);
list.remove(list.size() - 1);
list.add(0, tok);
// Re-insert the semi-colon for consistency
return new ScopedStatement(getQualifiedName(list),
createStatement(m_list), first, last, tokenizer.getSource(first, last));
} else {
throw new ParseException("Expected class scope operator (::) but only got a single colon (:)", list.get(list.size()-1), m_list.get(0));
}
}
StringBuilder qualifiedName = new StringBuilder();
qualifiedName.append(tok.token);
Token l = null;
Token t = tok2 = list.remove(0);
// System.out.println("t='" + t.token+"'");
while (list.size() > 1 && (t.type == Token.PERIOD)) {
String txt = t.token;
l = list.remove(0);
t = list.remove(0);
qualifiedName.append(txt).append(l.token);
}
if (t.type != Token.IDENTIFIER) {
if (l != null) {
list.add(0, t);
list.add(0, l);
}
} else {
IType type = new ObjectType(Token.OBJECT_TYPE, qualifiedName.toString());
if (list.remove(list.size()-1).type != Token.SEMI_COLON) {
throw new ParseException("Missing Semi Colon", list.get(0), list.get(list.size()-1));
}
if (list.isEmpty()) {
// we have a declaration (minus assignment)
return new DeclarationStatement(type, t.token,
first, last, tokenizer.getSource(first, last));
}
// Check if it is an assignment...
Token tok3 = list.remove(0);
if (tok3.type == Token.ASSIGNMENT) {
return new DeclarationStatement(type, t.token, createTerm(list),
first, last, tokenizer.getSource(first, last));
} else {
throw new ParseException("Incomplete Statement", first, last);
}
}
switch (tok2.type) {
case Token.PERIOD:
//its either . or = or
if (list.isEmpty())
throw new ParseException("Incomplete Statement", first, last);
// need to iterate through the tokens until the PERIOD pattern stops. If the
// pattern is followed by a ( we have a predicate; if we have and it is an
// assignment otherwise it is a syntax error...
// Code below assumes predicate...
// The code below assumes that the next part is a predicate, but this is not
// necessarily the case:
// e.g. mams.web.HttpRequest request; (VARIABLE DECLARATION);
// Need to scan forwards to see if there is a variable declaration...
if (!contains(list, new int[] {Token.RIGHT_BRACKET})) {
// System.out.println("qualifiedName: " + qualifiedName);
// assume we have a variable assignment...
list.remove(0);
IType type = new ObjectType(Token.OBJECT, qualifiedName.toString());
return new DeclarationStatement(type, list.get(0).token,
first, last, tokenizer.getSource(first, last));
}
// System.out.println(" >>>>>>>>>>>>>>>>> HANDLING NEW CASE <<<<<<<<<<<<<<<<<<<<<");
// System.out.println("list: " + list);
// if (contains(list, new int[] {Token.ASSIGNMENT})) {
// System.out.println("SPLIT ASSIGNMENT CASE OUT...");
// System.out.println("qualifiedName: " + qualifiedName);
// System.exit(0);
// }
t_list = splitAt(list, new int[] {Token.RIGHT_BRACKET});
// System.out.println("list: " + list);
// System.out.println("t_list: " + t_list);
if (list.isEmpty()) {
throw new ParseException("Syntax Error: Missing semi-colon", t_list.get(0), t_list.get(t_list.size()-1));
}
if (list.get(0).type != Token.SEMI_COLON) {
throw new ParseException("Syntax Error: Missing semi-colon", t_list.get(0), t_list.get(t_list.size()-1));
}
last = getLast(t_list);
// System.out.println("tokens: " + tokens);
// System.out.println("list: " + list);
// System.out.println("t_list: " + t_list);
if (!tokens.isEmpty() && tokens.get(0).type == Token.SEMI_COLON) tokens.remove(0);
PredicateFormula predicate = createPredicate(t_list);
// System.out.println("t_list: " + t_list);
if (!t_list.isEmpty()) throw new ParseException("Unexpected end of statement", t_list.get(0), t_list.get(t_list.size()-1));
// we have a module call
return new ModuleCallStatement(tok.token, predicate,
first, last, tokenizer.getSource(first, last));
case Token.PLUS:
// System.out.println("list: " + list);
if (list.get(0).type == Token.PLUS) {
return new PlusPlusStatement(tok.token, first, list.get(0), tokenizer.getSource(first, list.get(0)));
}
case Token.MINUS:
if (list.get(0).type == Token.MINUS) {
return new MinusMinusStatement(tok.token, first, list.get(0), tokenizer.getSource(first, list.get(0)));
}
case Token.ASSIGNMENT:
semiColonCheck(list);
return new AssignmentStatement(tok.token, createTerm(list),
first, last, tokenizer.getSource(first, last));
default:
// its just a predicate, so push the two tokens back onto the
// tokenizer and process the predicate
list.add(0, tok2);
list.add(0, tok);
last = getLast(list);
return new PlanCallStatement(createPredicate(list),
first, last, tokenizer.getSource(first, last));
}
default:
throw new ParseException("Malformed Statement: did not expect: " + tok.token, first, last);
}
}
private boolean contains(List list, int[] tokens) {
for (Token token : list) {
for (int type : tokens) {
if (token.type == type) return true;
}
}
return false;
}
private IFormula convertToPredicate(ITerm term) throws ParseException {
if (term instanceof Function) {
Function function = (Function) term;
return new PredicateFormula(function.functor(), function.terms(), function.start, function.end, function.getSource());
} else if (term instanceof Literal) {
Literal literal = (Literal) term;
if (literal.value().equalsIgnoreCase("true")) return new PredicateFormula("true", new LinkedList<>(), literal.start, literal.end, literal.getSource());
if (literal.value().equalsIgnoreCase("false")) return new PredicateFormula("false", new LinkedList<>(), literal.start, literal.end, literal.getSource());
} else if (term instanceof ModuleTerm) {
ModuleTerm mterm = (ModuleTerm) term;
return new ModuleFormula(mterm.module(), mterm.method(), mterm.start, mterm.end, mterm.getSource());
} else if (term instanceof InlineVariableDeclaration) {
InlineVariableDeclaration var = (InlineVariableDeclaration) term;
return new FormulaVariable(var.identifier(),var.start, var.end, var.getSource());
} else if (term instanceof VariableElement) {
VariableElement var = (VariableElement) term;
return new FormulaVariable(var.identifier(),var.start, var.end, var.getSource());
}
throw new ParseException("Unable to convert term to predicate: " + term.getClass().getCanonicalName(), term);
}
private void semiColonCheck(List list) throws ParseException {
Token token= list.remove(list.size()-1);
if (token.type != Token.SEMI_COLON) {
throw new ParseException("Missing semi-colon", list.get(0), token);
}
}
public IFormula createPredicateOrVariableFormula(List tokens) throws ParseException {
Token first = tokens.get(0);
Token last = getLast(tokens);
if (first.type == Token.FORMULA) {
tokens.remove(0);
return new FormulaVariable(tokens.remove(0).token,
first, last, tokenizer.getSource(first, last));
} else {
return createPredicate(tokens);
}
}
public IEvent createEvent(List tokens) throws ParseException {
Token first = tokens.get(0);
Token last = tokens.get(tokens.size() - 1);
Token tok = tokens.remove(0);
if (tokens.get(0).type == Token.DOLLAR) {
// We have a symbol prefixing an event token....
// first refers to this prefix, so update tok to refer to
// the dollar token so the switch goes to the correct section...
tok = tokens.remove(0);
}
switch ( tok.type ) {
case Token.PLUS:
case Token.MINUS:
case Token.QUESTION:
case Token.HAT:
return new UpdateEvent(tok.token, createPredicateOrBelief(tokens),
first, last, tokenizer.getSource(first, last));
case Token.MESSAGE:
Token tok2 = tokens.get(0);
if (tok2.type != Token.LEFT_BRACKET) {
throw new ParseException("Malformed Message Event: @message(, , )", first, last);
}
if (last.type != Token.RIGHT_BRACKET) {
throw new ParseException("Malformed Message Event: @message(, , )", first, last);
}
tokens.remove(0);
List terms = getTermList(tokens.subList(0, tokens.size()-1), false);
if (terms.size() < 3 || terms.size() > 4) {
throw new ParseException("Malformed Message Event: @message(, , )", first, last);
}
IFormula content = this.convertToPredicate(terms.get(2));
ITerm params = null;
if (terms.size() == 4) params = terms.get(3);
return new MessageEvent(terms.get(0), terms.get(1), content, params,
first, last, tokenizer.getSource(first, last));
case Token.DOLLAR:
tok2 = tokens.remove(0);
if (tokens.remove(0).type != Token.PERIOD) {
throw new ParseException("Invalid Module Event format expected: []$.", first, last);
}
PredicateFormula evt = this.createPredicate(tokens);
return new ModuleEvent(first.equals(tok) ? null:first.token,tok2.token, evt, tok, last, tokenizer.getSource(first, last));
default:
}
throw new ParseException("Unexpected Event: " + first.token, first, last);
}
private IFormula createPredicateOrBelief(List tokens) throws ParseException {
// System.out.println("HERE: " + tokens.get(0).type);
if (tokens.get(0).type == Token.BANG) {
return createGoal(tokens);
} else if (tokens.get(0).type == Token.QUESTION) {
return createTestGoal(tokens);
}
return createPredicate(tokens);
}
public IFormula createFormula(List tokens) throws ParseException {
Token first = tokens.get(0);
Token last = tokens.get(tokens.size() - 1);
for (int type : BOOLEAN_OPERATOR_PRECEDENCE) {
int i = 0;
Stack bracketStack = new Stack<>();
while (i < tokens.size()) {
Token token = tokens.get(i);
if (BRACKET_PAIRINGS.containsKey(token.type)) {
bracketStack.push(token);
} else if (BRACKET_PAIRINGS.containsValue(token.type)) {
if (bracketStack.isEmpty()) {
throw new ParseException("Too many brackets", token, token);
}
Token t = bracketStack.pop();
if (BRACKET_PAIRINGS.get(t.type) != token.type)
throw new ParseException("Mismatched Brackets", first, last);
} else if (token.type == type && bracketStack.isEmpty()) {
if (i == 0 || i == tokens.size()-1) throw new ParseException("Unexpected Operator: " + tokens.get(i).token, token, token);
IFormula left = createFormula(new ArrayList<>(tokens.subList(0, i)));
IFormula right = createFormula(new ArrayList<>(tokens.subList(i+1, tokens.size())));
if (type == Token.AND) {
return new AndFormula(left, right, first, last, tokenizer.getSource(first, last));
} else if (type == Token.OR) {
return new OrFormula(left, right, tokens.get(0), token, tokenizer.getSource(tokens.get(0), token));
}
}
i++;
}
}
// AND / OR discounted...
for (int[] types : COMPARISON_OPERATOR_PRECEDENCE) {
int i = 0;
Stack bracketStack = new Stack<>();
while (i < tokens.size()) {
StringBuilder op = new StringBuilder();
Token token = tokens.get(i);
if (BRACKET_PAIRINGS.containsKey(token.type)) {
bracketStack.push(token);
} else if (BRACKET_PAIRINGS.containsValue(token.type)) {
if (bracketStack.isEmpty()) {
throw new ParseException("Too many brackets", token, token);
}
Token t = bracketStack.pop();
if (BRACKET_PAIRINGS.get(t.type) != token.type)
throw new ParseException("Mismatched Brackets", first, last);
} else if (token.type == types[0] && tokens.size() > i + types.length && bracketStack.isEmpty()) {
boolean match = true;
int j = 1;
op.append(token.token);
while (match && j < types.length) {
match = types[j] == tokens.get(i+j).type;
op.append(tokens.get(i+j).token);
j++;
}
if (match) {
ITerm left = createTerm(new ArrayList<>(tokens.subList(0, i)));
ITerm right = createTerm(new ArrayList<>(tokens.subList(i+j, tokens.size())));
return new ComparisonFormula(op.toString(), left, right, tokens.get(0), getLast(tokens), tokenizer.getSource(tokens.get(0), getLast(tokens)));
}
}
i++;
}
}
Token tok = tokens.remove(0);
if (tok.type == Token.BANG) {
tokens.add(0, tok);
return createGoal(tokens);
} else if (tok.type == Token.QUESTION) {
tokens.add(0, tok);
return createTestGoal(tokens);
} else if (tok.type == Token.BIND) {
Token tok2 = tokens.remove(0);
if (tok2.type == Token.LEFT_BRACKET) {
if (getLast(tokens).type != Token.RIGHT_BRACKET)
throw new ParseException("Unexpected Tokens", tok2, getLast(tokens));
tokens.remove(tokens.size()-1);
List list = getTermList(tokens, false);
if (list.size() > 2) throw new ParseException("Malformed bind formula: bind(,)", first, last);
if (VariableElement.class.isInstance(list.get(0))||InlineVariableDeclaration.class.isInstance(list.get(0))) {
return new BindFormula(list.get(0), list.get(1), first, last, tokenizer.getSource(first, last));
}
throw new ParseException("First argument of bind should be a variable", first, last);
}
} else if (tok.type == Token.LEFT_BRACKET) {
if (last.type != Token.RIGHT_BRACKET) {
throw new ParseException("Malformed brackets", first, last);
}
tokens.remove(tokens.size()-1);
return new BracketFormula(createFormula(tokens), first, last, tokenizer.getSource(first, last));
} else if (tok.type == Token.NOT) {
return new NOTFormula(createFormula(tokens),
first, last, tokenizer.getSource(first, last));
} else if (tok.type == Token.BOOLEAN) {
return new PredicateFormula(tok.token, new ArrayList<>(),
first, last, tokenizer.getSource(first, last));
} else if (tok.type == Token.FORMULA) {
return new FormulaVariable(tokens.remove(0).token,
first, last, tokenizer.getSource(first, last));
} else if (tok.type == Token.IDENTIFIER) {
if (tokens.isEmpty()) {
return new BooleanTermElement(
new VariableElement(tok.token, tok, tok, tokenizer.getSource(tok,tok)),
first, last, tokenizer.getSource(first, last));
}
Token tok2 = tokens.get(0);
if (tok2.type == Token.PERIOD) {
return new ModuleFormula(tok.token, createPredicate(tokens.subList(1, tokens.size())),
first, last, tokenizer.getSource(first, last));
}
// Akshot: This is where the code for handling the event scope operator was put...
tokens.add(0, tok);
String name = getQualifiedName(tokens);
tok2 = tokens.get(0);
if (tok2.type == Token.COLON) {
tok2 = tokens.get(1);
if (tok2.type != Token.COLON) {
throw new ParseException("Malformed Scope Operator.", first, last);
}
IFormula formula = createFormula(tokens.subList(2, tokens.size()));
if (formula instanceof GoalFormula) {
return new ScopedGoalFormula(name, (GoalFormula) formula,
first, last, tokenizer.getSource(first, last));
} else {
throw new ParseException("Malformed Scope Operator.", first, last);
}
// } else {
// // Not sure what this is, hoping it is a boolean expression (using terms)
// tokens.add(0, tok);
// System.out.println("Creating term: " + tokens);
// try {
// return new BooleanTermElement(createTerm(tokens),
// first, last, tokenizer.getSource(first, last));
// } catch (Throwable th) {
// throw new ParseException("Attempted to construct boolean term, but got: " + th.getMessage(), tok);
// }
}
}
tokens.add(0, tok);
return createPredicate(tokens);
}
private GoalFormula createGoal(List tokens) throws ParseException {
Token first = tokens.get(0);
Token last = tokens.get(tokens.size() - 1);
tokens.remove(0);
return new GoalFormula(createPredicate(tokens),
first, last, tokenizer.getSource(first, last));
}
private TestGoalFormula createTestGoal(List tokens) throws ParseException {
Token first = tokens.get(0);
Token last = tokens.get(tokens.size() - 1);
tokens.remove(0);
return new TestGoalFormula(createPredicate(tokens),
first, last, tokenizer.getSource(first, last));
}
private List splitAt(List tokens, int[] types) throws ParseException {
if (tokens.isEmpty()) return tokens;
Token first = tokens.get(0);
Token last = tokens.get(tokens.size() - 1);
List list = new ArrayList<>();
Stack bracketStack = new Stack<>();
while (!tokens.isEmpty()) {
// Problem here - if a type is a bracket type...
Token token = tokens.remove(0);
if (BRACKET_PAIRINGS.containsKey(token.type)) {
bracketStack.push(token);
} else if (BRACKET_PAIRINGS.containsValue(token.type)) {
// If we have a close bracket and the bracketStack is
// empty, then we have a problem...
if (bracketStack.isEmpty()) {
// throw new ParseException("Unexpected Bracket: " + token.token, first, last);
return list;
}
// Check if the closing bracket type matches the opening bracket type on top
// of the bracket stack - if not, we have a problem
Token t = bracketStack.pop();
if (BRACKET_PAIRINGS.get(t.type) != token.type)
throw new ParseException("Mismatched Brackets", first, last);
}
for (int t : types) {
// Special case for matching an opening bracket...
if (BRACKET_PAIRINGS.containsKey(t)) {
if (token.type == t && bracketStack.size() == 1) {
list.add(token);
return list;
}
} else {
// General matching case
if (token.type == t && bracketStack.isEmpty()) {
list.add(token);
return list;
}
}
}
list.add(token);
}
return list;
}
public PredicateFormula createPredicate(List tokens) throws ParseException {
// System.out.println("tokens: " + tokens);
Token first = tokens.get(0);
Token last = tokens.get(tokens.size()-1);
Token tok = tokens.remove(0);
String predicate = tok.token;
if (tokens.isEmpty()) {
throw new ParseException("Invalid Predicate Formula", first, last);
}
if (tokens.remove(0).type != Token.LEFT_BRACKET) {
throw new ParseException("Missing Left Bracket", first, last);
}
if (tokens.remove(tokens.size()-1).type != Token.RIGHT_BRACKET) {
throw new ParseException("Missing Right Bracket", first, last);
}
return new PredicateFormula(predicate, getTermList(tokens, false),
first, last, tokenizer.getSource(first, last));
}
public ITerm createTerm(List tokens) throws ParseException {
// System.out.println("createTerm: " + tokens);
Token first = tokens.get(0);
Token last = tokens.get(tokens.size()-1);
if (first.type == Token.MINUS && tokens.size() == 2) {
//Special Case: negative literal
return new Literal("-"+last.token, new BasicType(last.type), first, last, tokenizer.getSource(first, last));
}
List list = tokens;
for (int type : OPERATOR_PRECEDENCE) {
List list2 = splitAt(list, new int[] {type});
while (!list.isEmpty()) {
Token token = list2.remove(list2.size()-1);
if (token.type == type) {
ITerm left = createTerm(new ArrayList<>(list2));
ITerm right = createTerm(new ArrayList<>(list));
return new Operator(token.token, left, right, token, last, tokenizer.getSource(token, last));
} else {
list2.add(token);
list2.addAll(splitAt(list, new int[] {type}));
}
}
list = list2;
}
tokens = list;
Token tok = tokens.remove(0);
if (tokens.isEmpty()) {
if (Token.isLiteral(tok.type)) {
return new Literal(tok.token, new BasicType(tok.type), tok, tok, tokenizer.getSource(tok, tok));
} else if (tok.type == Token.IDENTIFIER) {
return new VariableElement(tok.token, tok, tok, tokenizer.getSource(tok, tok));
} else {
throw new ParseException("Unexpected token in term list: " + tok.token, tok, tok);
}
} else {
if (Token.isType(tok.type)) {
// System.out.println("Tokens: " + tokens);
IType type = new BasicType(Token.resolveType(tok.type));
if (tokens.isEmpty()) throw new ParseException("Expected variable identifier none given", tok, tok);
Token tok2 = tokens.remove(0);
if (tok2.type != Token.IDENTIFIER) {
throw new ParseException("Expected variable identifier, but got: "+ tok2.token, tok, tok2);
}
if (!tokens.isEmpty()) throw new ParseException("Unexpected Tokens after inline variable declaration" , getLast(tokens));
return new InlineVariableDeclaration(type, tok2.token, tok, tok2, tokenizer.getSource(tok, tok2));
} else if (tok.type == Token.COUNT) {
Token tok2 = tokens.remove(0);
if (tok2.type == Token.LEFT_BRACKET) {
if (getLast(tokens).type != Token.RIGHT_BRACKET)
throw new ParseException("Unexpected Tokens", tok2, getLast(tokens));
tokens.remove(tokens.size()-1);
List terms = this.getTermList(tokens, false);
if (terms.size() != 1) throw new ParseException("Expected: count(|)", first, last);
return new CountTerm(terms.get(0), first, last, tokenizer.getSource(first, last));
}
} else if (tok.type == Token.COUNT_FORMULAE) {
Token tok2 = tokens.remove(0);
if (tok2.type == Token.LEFT_BRACKET) {
if (getLast(tokens).type != Token.RIGHT_BRACKET)
throw new ParseException("Unexpected Tokens", tok2, getLast(tokens));
tokens.remove(tokens.size()-1);
IFormula formula = null;
try {
formula = this.createFormula(tokens);
} catch (ParseException e) {
throw new ParseException("Expected: count_formulae() but got problem parsing the formula", e, first, last);
}
return new CountFormulaeTerm(formula, first, last, tokenizer.getSource(first, last));
}
} else if (tok.type == Token.HEAD) {
Token tok2 = tokens.remove(0);
if (tok2.type == Token.LEFT_BRACKET) {
if (getLast(tokens).type != Token.RIGHT_BRACKET)
throw new ParseException("Unexpected Tokens", tok2, getLast(tokens));
tokens.remove(tokens.size()-1);
List> terms = this.getTermParts(tokens, false);
// System.out.println("terms: " + terms);
if (terms.size() != 2) throw new ParseException("Expected: head(, )", first, last);
if (terms.get(1).size() != 1) throw new ParseException("Expected: head(, )", first, last);
return new HeadTerm(createTerm(terms.get(0)), new BasicType(Token.resolveType(terms.get(1).get(0).type)), first, last, tokenizer.getSource(first, last));
}
} else if (tok.type == Token.TAIL) {
Token tok2 = tokens.remove(0);
if (tok2.type == Token.LEFT_BRACKET) {
if (getLast(tokens).type != Token.RIGHT_BRACKET)
throw new ParseException("Unexpected Tokens", tok2, getLast(tokens));
tokens.remove(tokens.size()-1);
List> terms = this.getTermParts(tokens, false);
// System.out.println("terms: " + terms);
if (terms.size() != 1) throw new ParseException("Expected: tail()", first, last);
return new TailTerm(createTerm(terms.get(0)), first, last, tokenizer.getSource(first, last));
}
} else if (tok.type == Token.AT_INDEX) {
Token tok2 = tokens.remove(0);
if (tok2.type == Token.LEFT_BRACKET) {
if (getLast(tokens).type != Token.RIGHT_BRACKET)
throw new ParseException("Unexpected Tokens", tok2, getLast(tokens));
tokens.remove(tokens.size()-1);
List> terms = this.getTermParts(tokens, false);
if (terms.size() != 3) throw new ParseException("Expected: at_index(, , )", first, last);
return new AtIndexTerm(
createTerm(terms.get(0)),
createTerm(terms.get(1)),
new BasicType(Token.resolveType(terms.get(2).get(0).type)),
first, last, tokenizer.getSource(first, last));
}
} else if (tok.type == Token.LEFT_BRACKET) {
if (tokens.get(tokens.size()-1).type != Token.RIGHT_BRACKET) {
throw new ParseException("Bracket mismatch for term", tok, tokens.get(tokens.size()-1));
}
tokens.remove(tokens.size()-1);
return new Brackets(createTerm(tokens), first, last, tokenizer.getSource(first, last));
} else if (tok.type == Token.QUERY) {
Token tok2 = tokens.remove(0);
if (tok2.type != Token.LEFT_BRACKET) {
throw new ParseException("Invalid syntax: expected query( )", tok, getLast(tokens));
}
if (getLast(tokens).type != Token.RIGHT_BRACKET) {
throw new ParseException("Invalid syntax: expected query( )", tok, getLast(tokens));
}
tokens.remove(tokens.size()-1);
IFormula query = createFormula(tokens);
return new QueryTerm(query, tok, tok2, tokenizer.getSource(tok, tok2));
} else if (tok.type == Token.IDENTIFIER) {
// System.out.println("Here: " + tokens);
Token tok2 = tokens.get(0);
if (tok2.type == Token.PERIOD) {
if ((tokens.size() > 2) && (tokens.get(2).type == Token.LEFT_BRACKET)) {
tokens.remove(0);
PredicateFormula formula = createPredicate(tokens);
return new ModuleTerm(tok.token, formula, tok, tokenizer.getLastToken(), tokenizer.getSource(tok, tok));
} else {
tokens.add(0, tok);
IType type = new ObjectType(Token.OBJECT_TYPE, getQualifiedName(tokens));
if (tokens.isEmpty()) throw new ParseException("Expected variable identifier none given", tok, tok);
tok2 = tokens.remove(0);
if (tok2.type != Token.IDENTIFIER) {
throw new ParseException("Expected variable identifier but got: "+ tok2.token, tok, tok2);
}
if (!tokens.isEmpty()) throw new ParseException("Unexpected Tokens after inline variable declaration" , getLast(tokens));
return new InlineVariableDeclaration(type, tok2.token, tok, tok2, tokenizer.getSource(tok, tok2));
}
} else if (tok2.type == Token.LEFT_BRACKET) {
if (getLast(tokens).type != Token.RIGHT_BRACKET) {
throw new ParseException("Invalid syntax: missing right bracket for functional term", tok, getLast(tokens));
}
// strip outer brackets...
tokens.remove(0);
tokens.remove(tokens.size()-1);
return new Function(tok.token, getTermList(tokens, false), tok, last, tokenizer.getSource(tok, last));
} else {
IType type = new ObjectType(Token.OBJECT_TYPE, tok.token);
if (tokens.isEmpty()) throw new ParseException("Expected variable identifier but none given", tok, tok);
tok2 = tokens.remove(0);
if (tok2.type != Token.IDENTIFIER) {
throw new ParseException("Expected variable identifier but got: "+ tok2.token, tok, tok2);
}
if (!tokens.isEmpty()) throw new ParseException("Unexpected Tokens after inline variable declaration" , getLast(tokens));
return new InlineVariableDeclaration(type, tok2.token, tok, tok2, tokenizer.getSource(tok, tok2));
}
} else if (tok.type == Token.LEFT_SQ_BRACKET) {
if (getLast(tokens).type != Token.RIGHT_SQ_BRACKET) {
throw new ParseException("Malformed ASTRA list", tok, getLast(tokens));
}
tokens.remove(tokens.size()-1);
// System.out.println("{A} tokens: " + tokens);
int sIndex = getSplitterIndex(tokens);
if (sIndex > -1) {
// if (tokens.size() > 2 && tokens.get(2).type == Token.OR) {
// System.out.println("left: " + tokens.subList(0, sIndex));
// System.out.println("right: " + tokens.subList(sIndex+1, tokens.size()));
return createListSplitter(new LinkedList<>(tokens.subList(0, sIndex)), new LinkedList<>(tokens.subList(sIndex+1, tokens.size())), first, last, tokenizer.getSource(first, last));
}
return new ListTerm(getTermList(tokens, false), tok, last, tokenizer.getSource(tok, last));
} else if (tok.type == Token.MINUS) {
Token tok2 = tokens.remove(0);
if (Token.isLiteral(tok2.type)) {
return new Literal(tok.token+tok2.token, new BasicType(tok2.type), first, last, tokenizer.getSource(first, last));
}
throw new ParseException("Malformed literal: " + tok.token+tok2.token, tok, tok2);
} else if (tok.type == Token.RETURNS) {
ITerm term = createTerm(tokens);
if (term instanceof InlineVariableDeclaration) {
((InlineVariableDeclaration) term).returns(true);
} else {
throw new ParseException("Attempt to return a non variable value.", tok, tok);
}
return term;
} else if (tok.type == Token.NOT) {
ITerm term = createTerm(tokens);
return new NotTerm(term, first, last, tokenizer.getSource(first, last));
}
}
System.out.println("tok: " + tok.token);
System.out.println("tokens: " + tokens);
throw new ParseException("Unknown Term", first, last);
}
private int getSplitterIndex(List tokens) {
int i = 0;
int brackets = 0;
while (i < tokens.size()) {
switch (tokens.get(i).type) {
case Token.LEFT_SQ_BRACKET:
brackets++;
break;
case Token.RIGHT_SQ_BRACKET:
brackets--;
break;
case Token.OR:
if (brackets == 0) return i;
default:
}
i++;
}
return -1;
}
private ITerm createListSplitter(List subList, List subList2, Token first, Token last, String source) throws ParseException {
ITerm head = createTerm(subList);
if (head instanceof InlineVariableDeclaration || head instanceof Function) {
ITerm tail = createTerm(subList2);
if (tail instanceof InlineVariableDeclaration && tail.type().type()==Token.LIST) {
return new ListSplitterTerm(head, tail, first, last, source);
}
}
throw new ParseException("List Splitter should contain new variables.", first, last);
}
private Token getLast(List tokens) {
return tokens.get(tokens.size()-1);
}
private List getTermList(List tokens, boolean ignoreLast) throws ParseException {
// System.out.println("term tokens: " + tokens);
List list = new LinkedList<>();
if (tokens.isEmpty()) return list;
List> termParts = getTermParts(tokens, ignoreLast);
for (List termPart : termParts) {
list.add(createTerm(termPart));
}
return list;
}
private List> getTermParts(List tokens, boolean ignoreLast) throws ParseException {
List> termParts = new ArrayList<>();
List term = new ArrayList<>();
// System.out.println("tokens: " + tokens);
int i = 0;
Stack bracketStack = new Stack<>();
while (i < tokens.size()) {
// System.out.println("bracket stack: " + bracketStack);
Token token = tokens.remove(i);
if (BRACKET_PAIRINGS.containsKey(token.type)) {
bracketStack.push(token);
term.add(token);
} else if (BRACKET_PAIRINGS.containsValue(token.type)) {
if (bracketStack.isEmpty()) {
throw new ParseException("Too many brackets", token, token);
}
Token t = bracketStack.pop();
if (BRACKET_PAIRINGS.get(t.type) != token.type)
throw new ParseException("Mismatched Bracket", t, t);
term.add(token);
} else if (token.type == Token.COMMA && bracketStack.isEmpty()) {
if (term.isEmpty()) {
throw new ParseException("Duplicate Comma: " + tokens, token, token);
}
termParts.add(term);
term = new ArrayList<>();
} else {
term.add(token);
}
}
if (!term.isEmpty()) {
if (ignoreLast) {
while (!term.isEmpty()) {
tokens.add(0, term.remove(term.size()-1));
}
} else {
termParts.add(term);
}
}
return termParts;
}
private String getQualifiedName(List tokens) throws ParseException {
Token tok = tokens.get(0);
StringBuffer buf = new StringBuffer();
Token tok2 = null;
do {
if (tok2 != null) buf.append(tok2.token);
tok2 = tokens.remove(0);
if (tok2.type != Token.IDENTIFIER) {
if (tok2.type == Token.MULTIPLY) {
buf.append(tok2.token);
if (!tokens.isEmpty()) {
throw new ParseException("Illegal character: '" + tok2.token + "' can only be used at the end of an import statement", tok, tokens.get(tokens.size()-1));
}
} else {
throw new ParseException("Illegal character: '" + tok2.token + "' ", tok, tok2);
}
} else {
buf.append(tok2.token);
}
if (!tokens.isEmpty()) tok2 = tokens.remove(0);
} while (tok2.type == Token.PERIOD && !tokens.isEmpty());
tokens.add(0, tok2);
return buf.toString();
}
public TypesElement createTypes(List subList) throws ParseException {
Token start = subList.remove(0);
Token end = subList.get(subList.size()-1);
if (start.type != Token.IDENTIFIER) throw new ParseException("Identifier expected, but got: " + start.token, start);
String name = start.token;
// Check left brace
Token tok = subList.remove(0);
if (tok.type != Token.LEFT_BRACE) {
throw new ParseException("Missing Left Brace", tok);
}
// // Check right brace
// tok = subList.remove(subList.size()-1);
// if (tok.type != Token.RIGHT_BRACE) {
// throw new ParseException("Missing Right Brace", tok);
// }
// Create formulae
List definitions = new ArrayList<>();
while (!subList.isEmpty()) {
List list = this.splitAt(subList, new int[] {Token.SEMI_COLON});
start = list.remove(0);
end = list.get(list.size()-1);
if (start.type == Token.FORMULA) {
tok = list.remove(0);
if (tok.type != Token.IDENTIFIER) throw new ParseException("Identifier expected, but got: " +tok.token, start, end);
String identifier = tok.token;
List types = new ArrayList<>();
tok = list.remove(0);
if (tok.type != Token.LEFT_BRACKET) throw new ParseException("Missing left bracket, got: " + tok.token, start, end);
tok = list.remove(0);
while (!list.isEmpty() && tok.type != Token.RIGHT_BRACKET) {
if (tok.type==20) {
// This is an identifier - so the type should be a Java classname
StringBuilder cls = new StringBuilder();
cls.append(tok.token);
while ((list.get(0).type != Token.COMMA) && (list.get(0).type != Token.RIGHT_BRACKET)) {
cls.append(list.remove(0).token);
}
types.add(new TypeDefinition(cls.toString(), Token.OBJECT_TYPE));
} else {
if (Token.isType(tok.type)) {
types.add(new TypeDefinition(tok.token, tok.type));
} else {
throw new ParseException("The arguments of a formula definition must be types, but got: " + tok.token, start, end);
}
}
tok = list.remove(0);
if (tok.type != Token.RIGHT_BRACKET) {
if (tok.type != Token.COMMA)
throw new ParseException("Error in formula definition: expected a close bracket or a comma, but got: " + tok.token, start, end);
tok = list.remove(0);
}
}
if (tok.type != Token.RIGHT_BRACKET)
throw new ParseException("Malformed formula description", start, end);
if (list.size() == 1 && list.get(0).type == Token.SEMI_COLON)
definitions.add(new FormulaDefinition(identifier, types.toArray(new TypeDefinition[types.size()]) , start, end, tokenizer.getSource(start, end)));
else
throw new ParseException("Unexpected termination of formula definition", start, end);
} else {
throw new ParseException("Unknown type: " + tok.token, start, end);
}
}
return new TypesElement(name, definitions.toArray(new ILanguageDefinition[definitions.size()]), start, end, tokenizer.getSource(start, end));
}
}