/******************************************************************************* * * Copyright (c) 2008 Fujitsu Services Ltd. * * Author: Nick Battle * * This file is part of VDMJ. * * VDMJ is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * VDMJ is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with VDMJ. If not, see <http://www.gnu.org/licenses/>. * ******************************************************************************/ package org.overture.parser.syntax; import java.util.List; import java.util.Vector; import org.overture.ast.definitions.PDefinition; import org.overture.ast.expressions.ACaseAlternative; import org.overture.ast.expressions.ACasesExp; import org.overture.ast.expressions.ADefExp; import org.overture.ast.expressions.AElseIfExp; import org.overture.ast.expressions.AEqualsBinaryExp; import org.overture.ast.expressions.AExists1Exp; import org.overture.ast.expressions.AExistsExp; import org.overture.ast.expressions.AForAllExp; import org.overture.ast.expressions.AIfExp; import org.overture.ast.expressions.AIotaExp; import org.overture.ast.expressions.AIsExp; import org.overture.ast.expressions.AIsOfBaseClassExp; import org.overture.ast.expressions.AIsOfClassExp; import org.overture.ast.expressions.ALambdaExp; import org.overture.ast.expressions.ALetBeStExp; import org.overture.ast.expressions.ALetDefExp; import org.overture.ast.expressions.AMapletExp; import org.overture.ast.expressions.AMuExp; import org.overture.ast.expressions.ANarrowExp; import org.overture.ast.expressions.ANewExp; import org.overture.ast.expressions.APreExp; import org.overture.ast.expressions.ARecordModifier; import org.overture.ast.expressions.ASameBaseClassExp; import org.overture.ast.expressions.ASameClassExp; import org.overture.ast.expressions.AVariableExp; import org.overture.ast.expressions.PExp; import org.overture.ast.expressions.SMapExp; import org.overture.ast.expressions.SSeqExp; import org.overture.ast.expressions.SSetExp; import org.overture.ast.factory.AstFactory; import org.overture.ast.intf.lex.ILexLocation; import org.overture.ast.intf.lex.ILexNameToken; import org.overture.ast.lex.Dialect; import org.overture.ast.lex.LexBooleanToken; import org.overture.ast.lex.LexCharacterToken; import org.overture.ast.lex.LexIdentifierToken; import org.overture.ast.lex.LexIntegerToken; import org.overture.ast.lex.LexKeywordToken; import org.overture.ast.lex.LexNameList; import org.overture.ast.lex.LexNameToken; import org.overture.ast.lex.LexQuoteToken; import org.overture.ast.lex.LexRealToken; import org.overture.ast.lex.LexStringToken; import org.overture.ast.lex.LexToken; import org.overture.ast.lex.VDMToken; import org.overture.ast.node.NodeList; import org.overture.ast.patterns.ATypeBind; import org.overture.ast.patterns.PBind; import org.overture.ast.patterns.PMultipleBind; import org.overture.ast.patterns.PPattern; import org.overture.ast.typechecker.NameScope; import org.overture.ast.types.AUnresolvedType; import org.overture.ast.types.PType; import org.overture.config.Release; import org.overture.config.Settings; import org.overture.parser.lex.LexException; import org.overture.parser.lex.LexTokenReader; /** * A syntax analyser to parse expressions. */ public class ExpressionReader extends SyntaxReader { public ExpressionReader(LexTokenReader reader) { super(reader); } public List<PExp> readExpressionList() throws ParserException, LexException { List<PExp> list = new NodeList<PExp>(null); list.add(readExpression()); while (ignore(VDMToken.COMMA)) { list.add(readExpression()); } return list; } // Constructor Family... public PExp readExpression() throws ParserException, LexException { return readConnectiveExpression(); } // Connectives Family. All (recursive) right grouping... private PExp readConnectiveExpression() throws ParserException, LexException { PExp exp = readImpliesExpression(); LexToken token = lastToken(); if (token.is(VDMToken.EQUIVALENT)) { nextToken(); exp = AstFactory.newAEquivalentBooleanBinaryExp(exp, token, readConnectiveExpression()); } return exp; } private PExp readImpliesExpression() throws ParserException, LexException { PExp exp = readOrExpression(); LexToken token = lastToken(); if (token.is(VDMToken.IMPLIES)) { nextToken(); exp = AstFactory.newAImpliesBooleanBinaryExp(exp, token, readImpliesExpression()); } return exp; } private PExp readOrExpression() throws ParserException, LexException { PExp exp = readAndExpression(); LexToken token = lastToken(); if (token.is(VDMToken.OR)) { nextToken(); exp = AstFactory.newAOrBooleanBinaryExp(exp, token, readOrExpression()); } return exp; } private PExp readAndExpression() throws ParserException, LexException { PExp exp = readNotExpression(); LexToken token = lastToken(); if (token.is(VDMToken.AND)) { nextToken(); exp = AstFactory.newAAndBooleanBinaryExp(exp, token, readAndExpression()); } return exp; } private PExp readNotExpression() throws ParserException, LexException { PExp exp = null; LexToken token = lastToken(); if (token.is(VDMToken.NOT)) { nextToken(); exp = AstFactory.newANotUnaryExp(token.location, readNotExpression()); } else { exp = readRelationalExpression(); } return exp; } // Relations Family... public AEqualsBinaryExp readDefEqualsExpression() throws ParserException, LexException { // This is an oddball parse for the "def" expression :-) PExp exp = readEvaluatorP1Expression(); LexToken token = lastToken(); if (readToken().is(VDMToken.EQUALS)) { return AstFactory.newAEqualsBinaryExp(exp, token, readEvaluatorP1Expression()); } throwMessage(2029, "Expecting <set bind> = <expression>"); return null; } private PExp readRelationalExpression() throws ParserException, LexException { PExp exp = readEvaluatorP1Expression(); LexToken token = lastToken(); if (token.is(VDMToken.NOT)) { // Check for "not in set" reader.push(); if (nextToken().is(VDMToken.IN)) { if (nextToken().is(VDMToken.SET)) { token = new LexKeywordToken(VDMToken.NOTINSET, token.location); reader.unpush(); } else { reader.pop(); } } else { reader.pop(); } } else if (token.is(VDMToken.IN)) { // Check for "in set" reader.push(); if (nextToken().is(VDMToken.SET)) { token = new LexKeywordToken(VDMToken.INSET, token.location); reader.unpush(); } else { reader.pop(); } } // No grouping for relationals... switch (token.type) { case LT: nextToken(); exp = AstFactory.newALessNumericBinaryExp(exp, token, readNotExpression()); break; case LE: nextToken(); exp = AstFactory.newALessEqualNumericBinaryExp(exp, token, readNotExpression()); break; case GT: nextToken(); exp = AstFactory.newAGreaterNumericBinaryExp(exp, token, readNotExpression()); break; case GE: nextToken(); exp = AstFactory.newAGreaterEqualNumericBinaryExp(exp, token, readNotExpression()); break; case NE: nextToken(); exp = AstFactory.newANotEqualBinaryExp(exp, token, readNotExpression()); break; case EQUALS: nextToken(); exp = AstFactory.newAEqualsBinaryExp(exp, token, readNotExpression()); break; case SUBSET: nextToken(); exp = AstFactory.newASubsetBinaryExp(exp, token, readNotExpression()); break; case PSUBSET: nextToken(); exp = AstFactory.newAProperSubsetBinaryExp(exp, token, readNotExpression()); break; case INSET: nextToken(); exp = AstFactory.newAInSetBinaryExp(exp, token, readNotExpression()); break; case NOTINSET: nextToken(); exp = AstFactory.newANotInSetBinaryExp(exp, token, readNotExpression()); break; default: break; } return exp; } // Evaluator Family... private PExp readEvaluatorP1Expression() throws ParserException, LexException { PExp exp = readEvaluatorP2Expression(); boolean more = true; while (more) // Left grouping { LexToken token = lastToken(); switch (token.type) { case PLUS: nextToken(); exp = AstFactory.newAPlusNumericBinaryExp(exp, token, readEvaluatorP2Expression()); break; case MINUS: nextToken(); exp = AstFactory.newASubstractNumericBinaryExp(exp, token, readEvaluatorP2Expression()); break; case UNION: nextToken(); exp = AstFactory.newASetUnionBinaryExp(exp, token, readEvaluatorP2Expression()); break; case SETDIFF: nextToken(); exp = AstFactory.newASetDifferenceBinaryExp(exp, token, readEvaluatorP2Expression()); break; case MUNION: nextToken(); exp = AstFactory.newAMapUnionBinaryExp(exp, token, readEvaluatorP2Expression()); break; case PLUSPLUS: nextToken(); exp = AstFactory.newAPlusPlusBinaryExp(exp, token, readEvaluatorP2Expression()); break; case CONCATENATE: nextToken(); exp = AstFactory.newASeqConcatBinaryExp(exp, token, readEvaluatorP2Expression()); break; default: more = false; break; } } return exp; } private PExp readEvaluatorP2Expression() throws ParserException, LexException { PExp exp = readEvaluatorP3Expression(); boolean more = true; while (more) // Left grouping { LexToken token = lastToken(); switch (token.type) { case TIMES: nextToken(); exp = AstFactory.newATimesNumericBinaryExp(exp, token, readEvaluatorP3Expression()); break; case DIVIDE: nextToken(); exp = AstFactory.newADivideNumericBinaryExp(exp, token, readEvaluatorP3Expression()); break; case REM: nextToken(); exp = AstFactory.newARemNumericBinaryExp(exp, token, readEvaluatorP3Expression()); break; case MOD: nextToken(); exp = AstFactory.newAModNumericBinaryExp(exp, token, readEvaluatorP3Expression()); break; case DIV: nextToken(); exp = AstFactory.newADivNumericBinaryExp(exp, token, readEvaluatorP3Expression()); break; case INTER: nextToken(); exp = AstFactory.newASetIntersectBinaryExp(exp, token, readEvaluatorP3Expression()); break; default: more = false; break; } } return exp; } private PExp readEvaluatorP3Expression() throws ParserException, LexException { PExp exp = null; LexToken token = lastToken(); if (token.is(VDMToken.INVERSE)) { nextToken(); // Unary, so recursion OK for left grouping exp = AstFactory.newAMapInverseUnaryExp(token.location, readEvaluatorP3Expression()); } else { exp = readEvaluatorP4Expression(); } return exp; } private PExp readEvaluatorP4Expression() throws ParserException, LexException { PExp exp = readEvaluatorP5Expression(); boolean more = true; while (more) { LexToken token = lastToken(); switch (token.type) { case DOMRESTO: nextToken(); exp = AstFactory.newADomainResToBinaryExp(exp, token, readEvaluatorP5Expression()); break; case DOMRESBY: nextToken(); exp = AstFactory.newADomainResByBinaryExp(exp, token, readEvaluatorP5Expression()); break; default: more = false; break; } } return exp; } private PExp readEvaluatorP5Expression() throws ParserException, LexException { PExp exp = readEvaluatorP6Expression(); boolean more = true; while (more) { LexToken token = lastToken(); switch (token.type) { case RANGERESTO: nextToken(); exp = AstFactory.newARangeResToBinaryExp(exp, token, readEvaluatorP6Expression()); break; case RANGERESBY: nextToken(); exp = AstFactory.newARangeResByBinaryExp(exp, token, readEvaluatorP6Expression()); break; default: more = false; break; } } return exp; } private PExp readEvaluatorP6Expression() throws ParserException, LexException { PExp exp = null; LexToken token = lastToken(); ILexLocation location = token.location; // Unary operators, so recursion OK for left grouping switch (token.type) { case PLUS: nextToken(); exp = AstFactory.newAUnaryPlusUnaryExp(location, readEvaluatorP6Expression()); break; case MINUS: nextToken(); exp = AstFactory.newAUnaryMinusUnaryExp(location, readEvaluatorP6Expression()); break; case CARD: nextToken(); exp = AstFactory.newACardinalityUnaryExp(location, readEvaluatorP6Expression()); break; case DOM: nextToken(); exp = AstFactory.newAMapDomainUnaryExp(location, readEvaluatorP6Expression()); break; case LEN: nextToken(); exp = AstFactory.newALenUnaryExp(location, readEvaluatorP6Expression()); break; case POWER: nextToken(); exp = AstFactory.newAPowerSetUnaryExp(location, readEvaluatorP6Expression()); break; case RNG: nextToken(); exp = AstFactory.newAMapRangeUnaryExp(location, readEvaluatorP6Expression()); break; case ELEMS: nextToken(); exp = AstFactory.newAElementsUnaryExp(location, readEvaluatorP6Expression()); break; case ABS: nextToken(); exp = AstFactory.newAAbsoluteUnaryExp(location, readEvaluatorP6Expression()); break; case DINTER: nextToken(); exp = AstFactory.newADistIntersectUnaryExp(location, readEvaluatorP6Expression()); break; case MERGE: nextToken(); exp = AstFactory.newADistMergeUnaryExp(location, readEvaluatorP6Expression()); break; case HEAD: nextToken(); exp = AstFactory.newAHeadUnaryExp(location, readEvaluatorP6Expression()); break; case TAIL: nextToken(); exp = AstFactory.newATailUnaryExp(location, readEvaluatorP6Expression()); break; case REVERSE: if (Settings.release == Release.CLASSIC) { throwMessage(2291, "'reverse' not available in VDM classic"); } nextToken(); exp = AstFactory.newAReverseUnaryExp(location, readEvaluatorP6Expression()); break; case FLOOR: nextToken(); exp = AstFactory.newAFloorUnaryExp(location, readEvaluatorP6Expression()); break; case DUNION: nextToken(); exp = AstFactory.newADistUnionUnaryExp(location, readEvaluatorP6Expression()); break; case DISTCONC: nextToken(); exp = AstFactory.newADistConcatUnaryExp(location, readEvaluatorP6Expression()); break; case INDS: nextToken(); exp = AstFactory.newAIndicesUnaryExp(location, readEvaluatorP6Expression()); break; default: exp = readApplicatorExpression(); break; } return exp; } // Applicator Family. Left grouping(?) private PExp readApplicatorExpression() throws ParserException, LexException { PExp exp = readBasicExpression(); boolean more = true; while (more) { LexToken token = lastToken(); switch (token.type) { case BRA: // Either sequence(from, ..., to) or func(args) or map(key) // or mk_*(), is_*(), mu(), pre_*(), post_*(), // init_*() or inv_*() if (nextToken().is(VDMToken.KET)) { if (exp instanceof AVariableExp) { AVariableExp ve = (AVariableExp) exp; String name = ve.getName().getName(); if (name.startsWith("mk_")) { // a mk_TYPE() with no field values exp = readMkExpression(ve); break; } } exp = AstFactory.newAApplyExp(exp); nextToken(); } else { if (exp instanceof AVariableExp) { AVariableExp ve = (AVariableExp) exp; String name = ve.getName().getName(); if (name.equals("mu")) { exp = readMuExpression(ve); break; } else if (name.startsWith("mk_")) { exp = readMkExpression(ve); break; } else if (name.startsWith("is_")) { exp = readIsExpression(ve); break; } else if (name.equals("pre_")) { exp = readPreExpression(ve); break; } else if (name.startsWith("narrow_")) { if (Settings.release == Release.CLASSIC) { throwMessage(2303, "Narrow not available in VDM classic", ve.getName()); } else { exp = readNarrowExpression(ve); } break; } } // So we're a function/operation call, a list subsequence or // a map index... PExp first = readExpression(); if (lastToken().is(VDMToken.COMMA)) { reader.push(); if (nextToken().is(VDMToken.RANGE)) { nextToken(); checkFor(VDMToken.COMMA, 2120, "Expecting 'e1,...,e2' in subsequence"); PExp last = readExpression(); checkFor(VDMToken.KET, 2121, "Expecting ')' after subsequence"); reader.unpush(); exp = AstFactory.newASubseqExp(exp, first, last); break; } reader.pop(); // Not a subsequence then... } // OK, so read a (list, of, arguments)... List<PExp> args = new NodeList<PExp>(null); args.add(first); while (ignore(VDMToken.COMMA)) { args.add(readExpression()); } checkFor(VDMToken.KET, 2122, "Expecting ')' after function args"); exp = AstFactory.newAApplyExp(exp, args); } break; case SEQ_OPEN: // Polymorphic function instantiation List<PType> types = new Vector<PType>(); TypeReader tr = getTypeReader(); nextToken(); types.add(tr.readType()); while (ignore(VDMToken.COMMA)) { types.add(tr.readType()); } checkFor(VDMToken.SEQ_CLOSE, 2123, "Expecting ']' after function instantiation"); exp = AstFactory.newAFuncInstatiationExp(exp, types); break; case POINT: // Field selection by name or number switch (nextToken().type) { case NAME: if (dialect != Dialect.VDM_SL) { exp = AstFactory.newAFieldExp(exp, lastNameToken()); } else { throwMessage(2030, "Expecting simple field identifier"); } break; case IDENTIFIER: exp = AstFactory.newAFieldExp(exp, lastIdToken()); break; case HASH: if (nextToken().isNot(VDMToken.NUMBER)) { throwMessage(2031, "Expecting field number after .#"); } LexIntegerToken num = (LexIntegerToken) lastToken(); exp = AstFactory.newAFieldNumberExp(exp, num); break; default: throwMessage(2032, "Expecting field name"); } nextToken(); break; default: more = false; break; } } // If we've collected as many applicators as we can, but we're still // just a variable, this is a bare variable expression. In VDM++, these // are always qualified (ie. x refers to C`x where it was declared, not // an overriding version lower down). if (exp instanceof AVariableExp) { AVariableExp ve = (AVariableExp) exp; ve.setName(ve.getName().getExplicit(true)); } // Combinator Family. Right grouping. LexToken token = lastToken(); if (token.is(VDMToken.COMP)) { nextToken(); return AstFactory.newACompBinaryExp(exp, token, readApplicatorExpression()); } if (token.is(VDMToken.STARSTAR)) { nextToken(); return AstFactory.newAStarStarBinaryExp(exp, token, readEvaluatorP6Expression()); } return exp; } private PExp readBasicExpression() throws ParserException, LexException { LexToken token = lastToken(); switch (token.type) { case NUMBER: nextToken(); return AstFactory.newAIntLiteralExp((LexIntegerToken) token); case REALNUMBER: nextToken(); return AstFactory.newARealLiteralExp((LexRealToken) token); case NAME: // Includes mk_ constructors LexNameToken name = lastNameToken(); nextToken(); return AstFactory.newAVariableExp(name); case IDENTIFIER: // Includes mk_ constructors // Note we can't use lastNameToken as this checks that we don't // use old~ names. LexNameToken id = new LexNameToken(reader.currentModule, (LexIdentifierToken) token); nextToken(); return AstFactory.newAVariableExp(id); case STRING: nextToken(); return AstFactory.newAStringLiteralExp((LexStringToken) token); case CHARACTER: nextToken(); return AstFactory.newACharLiteralExp((LexCharacterToken) token); case QUOTE: nextToken(); return AstFactory.newAQuoteLiteralExp((LexQuoteToken) token); case TRUE: case FALSE: nextToken(); return AstFactory.newABooleanConstExp((LexBooleanToken) token); case UNDEFINED: nextToken(); return AstFactory.newAUndefinedExp(token.location); // return new UndefinedExpression(token.location); case NIL: nextToken(); return AstFactory.newANilExp(token.location); case THREADID: nextToken(); return AstFactory.newAThreadIdExp(token.location); case BRA: nextToken(); PExp exp = readExpression(); checkFor(VDMToken.KET, 2124, "Expecting ')'"); return exp; case SET_OPEN: nextToken(); return readSetOrMapExpression(token.location); case SEQ_OPEN: nextToken(); return readSeqExpression(token.location); case FORALL: nextToken(); return readForAllExpression(token.location); case EXISTS: nextToken(); return readExistsExpression(token.location); case EXISTS1: nextToken(); return readExists1Expression(token.location); case IOTA: nextToken(); return readIotaExpression(token.location); case LAMBDA: nextToken(); return readLambdaExpression(token.location); case IF: nextToken(); return readIfExpression(token.location); case CASES: nextToken(); return readCasesExpression(token.location); case LET: nextToken(); return readLetExpression(token.location); case DEF: nextToken(); return readDefExpression(token.location); case NEW: nextToken(); return readNewExpression(token.location); case SELF: nextToken(); return AstFactory.newASelfExp(token.location); case ISOFBASECLASS: nextToken(); return readIsOfBaseExpression(token.location); case ISOFCLASS: nextToken(); return readIsOfClassExpression(token.location); case SAMEBASECLASS: nextToken(); return readSameBaseExpression(token.location); case SAMECLASS: nextToken(); return readSameClassExpression(token.location); case REQ: case ACT: case FIN: case ACTIVE: case WAITING: return readHistoryExpression(token.location); case TIME: return readTimeExpression(token.location); default: throwMessage(2034, "Unexpected token in expression: " + token.type); return null; } } private PExp readTimeExpression(ILexLocation location) throws LexException { nextToken(); return AstFactory.newATimeExp(location); } private AMuExp readMuExpression(AVariableExp ve) throws ParserException, LexException { List<ARecordModifier> args = new Vector<ARecordModifier>(); PExp record = readExpression(); do { checkFor(VDMToken.COMMA, 2128, "Expecting comma separated record modifiers"); LexIdentifierToken id = readIdToken("Expecting <identifier> |-> <expression>"); checkFor(VDMToken.MAPLET, 2129, "Expecting <identifier> |-> <expression>"); args.add(AstFactory.newARecordModifier(id, readExpression())); } while (lastToken().is(VDMToken.COMMA)); checkFor(VDMToken.KET, 2130, "Expecting ')' after mu maplets"); return AstFactory.newAMuExp(ve.getLocation(), record, args); } private PExp readMkExpression(AVariableExp ve) throws ParserException, LexException { List<PExp> args = new NodeList<PExp>(null); if (lastToken().isNot(VDMToken.KET)) // NB. mk_T() is legal { args.add(readExpression()); while (ignore(VDMToken.COMMA)) { args.add(readExpression()); } } checkFor(VDMToken.KET, 2131, "Expecting ')' after mk_ tuple"); PExp exp = null; if (ve.getName().getName().equals("mk_")) { if (args.size() < 2) { throwMessage(2035, "Tuple must have >1 argument"); } exp = AstFactory.newATupleExp(ve.getLocation(), args); } else { LexNameToken typename = getMkTypeName(ve.getName()); VDMToken type = VDMToken.lookup(typename.name, Dialect.VDM_SL); if (type != null) { if (args.size() != 1) { throwMessage(2300, "mk_<type> must have a single argument"); } PExp value = args.get(0); switch (type) { case BOOL: exp = AstFactory.newAMkBasicExp(AstFactory.newABooleanBasicType(ve.getLocation()), value); break; case NAT: exp = AstFactory.newAMkBasicExp(AstFactory.newANatNumericBasicType(ve.getLocation()), value); break; case NAT1: exp = AstFactory.newAMkBasicExp(AstFactory.newANatOneNumericBasicType(ve.getLocation()), value); break; case INT: exp = AstFactory.newAMkBasicExp(AstFactory.newAIntNumericBasicType(ve.getLocation()), value); break; case RAT: exp = AstFactory.newAMkBasicExp(AstFactory.newARationalNumericBasicType(ve.getLocation()), value); break; case REAL: exp = AstFactory.newAMkBasicExp(AstFactory.newARealNumericBasicType(ve.getLocation()), value); break; case CHAR: exp = AstFactory.newAMkBasicExp(AstFactory.newACharBasicType(ve.getLocation()), value); break; case TOKEN: exp = AstFactory.newAMkBasicExp(AstFactory.newATokenBasicType(ve.getLocation()), value); break; default: throwMessage(2036, "Expecting mk_<type>"); } } else { exp = AstFactory.newAMkTypeExp(typename, args); } } return exp; } private LexNameToken getMkTypeName(ILexNameToken mktoken) throws ParserException, LexException { String typename = mktoken.getName().substring(3); // mk_... or is_... String[] parts = typename.split("`"); switch (parts.length) { case 1: return new LexNameToken(getCurrentModule(), parts[0], mktoken.getLocation()); case 2: return new LexNameToken(parts[0], parts[1], mktoken.getLocation(), false, true); default: throwMessage(2037, "Malformed mk_<type> name " + typename); } return null; } private AIsExp readIsExpression(AVariableExp ve) throws ParserException, LexException { String name = ve.getName().getName(); AIsExp exp = null; if (name.equals("is_")) { PExp test = readExpression(); checkFor(VDMToken.COMMA, 2132, "Expecting is_(expression, type)"); TypeReader tr = getTypeReader(); PType type = tr.readType(); if (type instanceof AUnresolvedType) { AUnresolvedType nt = (AUnresolvedType) type; exp = AstFactory.newAIsExp(ve.getLocation(), nt.getName(), test); } else { exp = AstFactory.newAIsExp(ve.getLocation(), type, test); } } else { LexNameToken typename = getMkTypeName(ve.getName()); VDMToken type = VDMToken.lookup(typename.name, Dialect.VDM_SL); if (type != null) { switch (type) { case BOOL: exp = AstFactory.newAIsExp(ve.getLocation(), AstFactory.newABooleanBasicType(ve.getLocation()), readExpression()); break; case NAT: exp = AstFactory.newAIsExp(ve.getLocation(), AstFactory.newANatNumericBasicType(ve.getLocation()), readExpression()); break; case NAT1: exp = AstFactory.newAIsExp(ve.getLocation(), AstFactory.newANatOneNumericBasicType(ve.getLocation()), readExpression()); break; case INT: exp = AstFactory.newAIsExp(ve.getLocation(), AstFactory.newAIntNumericBasicType(ve.getLocation()), readExpression()); break; case RAT: exp = AstFactory.newAIsExp(ve.getLocation(), AstFactory.newARationalNumericBasicType(ve.getLocation()), readExpression()); break; case REAL: exp = AstFactory.newAIsExp(ve.getLocation(), AstFactory.newARealNumericBasicType(ve.getLocation()), readExpression()); break; case CHAR: exp = AstFactory.newAIsExp(ve.getLocation(), AstFactory.newACharBasicType(ve.getLocation()), readExpression()); break; case TOKEN: exp = AstFactory.newAIsExp(ve.getLocation(), AstFactory.newATokenBasicType(ve.getLocation()), readExpression()); break; default: throwMessage(2038, "Expecting is_<type>"); } } else { exp = AstFactory.newAIsExp(ve.getLocation(), typename, readExpression()); } } checkFor(VDMToken.KET, 2133, "Expecting ')' after is_ expression"); return exp; } private PExp readNarrowExpression(AVariableExp ve) throws ParserException, LexException { ANarrowExp exp = null; PExp test = readExpression(); checkFor(VDMToken.COMMA, 2301, "Expecting narrow_(expression, type)"); TypeReader tr = getTypeReader(); PType type = tr.readType(); if (type instanceof AUnresolvedType) { AUnresolvedType nt = (AUnresolvedType) type; exp = AstFactory.newANarrowExpression(ve.getLocation(), nt.getName(), test); } else { exp = AstFactory.newANarrowExpression(ve.getLocation(), type, test); } checkFor(VDMToken.KET, 2302, "Expecting ')' after narrow_ expression"); return exp; } private APreExp readPreExpression(AVariableExp ve) throws ParserException, LexException { List<PExp> args = new Vector<PExp>(); PExp function = readExpression(); while (ignore(VDMToken.COMMA)) { args.add(readExpression()); } checkFor(VDMToken.KET, 2134, "Expecting pre_(function [,args])"); return AstFactory.newAPreExp(ve.getLocation(), function, args); } private PExp readSetOrMapExpression(ILexLocation start) throws ParserException, LexException { LexToken token = lastToken(); if (token.is(VDMToken.SET_CLOSE)) { nextToken(); return AstFactory.newASetEnumSetExp(start); // empty set } else if (token.is(VDMToken.MAPLET)) { nextToken(); checkFor(VDMToken.SET_CLOSE, 2135, "Expecting '}' in empty map"); return AstFactory.newAMapEnumMapExp(start); // empty map } PExp first = readExpression(); token = lastToken(); if (token.is(VDMToken.MAPLET)) { nextToken(); AMapletExp maplet = AstFactory.newAMapletExp(first, token, readExpression()); return readMapExpression(start, maplet); } else { return readSetExpression(start, first); } } private SSetExp readSetExpression(ILexLocation start, PExp first) throws ParserException, LexException { SSetExp result = null; if (lastToken().is(VDMToken.PIPE)) { nextToken(); BindReader br = getBindReader(); List<PMultipleBind> bindings = br.readBindList(); PExp exp = null; if (lastToken().is(VDMToken.AMPERSAND)) { nextToken(); exp = readExpression(); } checkFor(VDMToken.SET_CLOSE, 2136, "Expecting '}' after set comprehension"); result = AstFactory.newASetCompSetExp(start, first, bindings, exp); } else { if (lastToken().is(VDMToken.COMMA)) { reader.push(); if (nextToken().is(VDMToken.RANGE)) { nextToken(); checkFor(VDMToken.COMMA, 2137, "Expecting 'e1,...,e2' in set range"); PExp end = readExpression(); checkFor(VDMToken.SET_CLOSE, 2138, "Expecting '}' after set range"); reader.unpush(); return AstFactory.newASetRangeSetExp(start, first, end); } reader.pop(); // Not a set range then... } List<PExp> members = new NodeList<PExp>(null); members.add(first); while (ignore(VDMToken.COMMA)) { members.add(readExpression()); } checkFor(VDMToken.SET_CLOSE, 2139, "Expecting '}' after set enumeration"); result = AstFactory.newASetEnumSetExp(start, members); } return result; } private SMapExp readMapExpression(ILexLocation start, AMapletExp first) throws ParserException, LexException { SMapExp result = null; if (lastToken().is(VDMToken.PIPE)) { nextToken(); BindReader br = getBindReader(); List<PMultipleBind> bindings = br.readBindList(); PExp exp = null; if (lastToken().is(VDMToken.AMPERSAND)) { nextToken(); exp = readExpression(); } checkFor(VDMToken.SET_CLOSE, 2140, "Expecting '}' after map comprehension"); result = AstFactory.newAMapCompMapExp(start, first, bindings, exp); } else { List<AMapletExp> members = new Vector<AMapletExp>(); members.add(first); while (ignore(VDMToken.COMMA)) { PExp member = readExpression(); LexToken token = lastToken(); if (token.is(VDMToken.MAPLET)) { nextToken(); AMapletExp maplet = AstFactory.newAMapletExp(member, token, readExpression()); members.add(maplet); } else { throwMessage(2039, "Expecting maplet in map enumeration"); } } checkFor(VDMToken.SET_CLOSE, 2141, "Expecting '}' after map enumeration"); result = AstFactory.newAMapEnumMapExp(start, members); } return result; } private SSeqExp readSeqExpression(ILexLocation start) throws ParserException, LexException { if (lastToken().is(VDMToken.SEQ_CLOSE)) { nextToken(); return AstFactory.newASeqEnumSeqExp(start); } SSeqExp result = null; PExp first = readExpression(); if (lastToken().is(VDMToken.PIPE)) { nextToken(); BindReader br = getBindReader(); PBind setbind = br.readSetSeqBind(); PExp exp = null; if (lastToken().is(VDMToken.AMPERSAND)) { nextToken(); exp = readExpression(); } checkFor(VDMToken.SEQ_CLOSE, 2142, "Expecting ']' after list comprehension"); result = AstFactory.newASeqCompSeqExp(start, first, setbind, exp); } else { List<PExp> members = new NodeList<PExp>(null); members.add(first); while (ignore(VDMToken.COMMA)) { members.add(readExpression()); } checkFor(VDMToken.SEQ_CLOSE, 2143, "Expecting ']' after list enumeration"); result = AstFactory.newASeqEnumSeqExp(start, members); } return result; } private AIfExp readIfExpression(ILexLocation start) throws ParserException, LexException { PExp exp = readExpression(); checkFor(VDMToken.THEN, 2144, "Missing 'then'"); PExp thenExp = readExpression(); List<AElseIfExp> elseList = new Vector<AElseIfExp>(); while (lastToken().is(VDMToken.ELSEIF)) { nextToken(); elseList.add(readElseIfExpression(lastToken().location)); } PExp elseExp = null; if (lastToken().is(VDMToken.ELSE)) { nextToken(); elseExp = readConnectiveExpression(); // Precedence < maplet? } else { throwMessage(2040, "Expecting 'else' in 'if' expression"); } return AstFactory.newAIfExp(start, exp, thenExp, elseList, elseExp); } private AElseIfExp readElseIfExpression(ILexLocation start) throws ParserException, LexException { PExp exp = readExpression(); checkFor(VDMToken.THEN, 2145, "Missing 'then' after 'elseif'"); PExp thenExp = readExpression(); return AstFactory.newAElseIfExp(start, exp, thenExp); } private ACasesExp readCasesExpression(ILexLocation start) throws ParserException, LexException { PExp exp = readExpression(); checkFor(VDMToken.COLON, 2146, "Expecting ':' after cases expression"); List<ACaseAlternative> cases = new Vector<ACaseAlternative>(); PExp others = null; cases.addAll(readCaseAlternatives(exp)); while (lastToken().is(VDMToken.COMMA)) { if (nextToken().is(VDMToken.OTHERS)) { nextToken(); checkFor(VDMToken.ARROW, 2147, "Expecting '->' after others"); others = readExpression(); break; } else { cases.addAll(readCaseAlternatives(exp)); } } checkFor(VDMToken.END, 2148, "Expecting ', case alternative' or 'end' after cases"); return AstFactory.newACasesExp(start, exp, cases, others); } private List<ACaseAlternative> readCaseAlternatives(PExp exp) throws ParserException, LexException { List<ACaseAlternative> alts = new Vector<ACaseAlternative>(); List<PPattern> plist = getPatternReader().readPatternList(); checkFor(VDMToken.ARROW, 2149, "Expecting '->' after case pattern list"); PExp then = readExpression(); for (PPattern p : plist) { alts.add(AstFactory.newACaseAlternative(exp.clone(), p.clone(), then.clone())); } return alts; } private PExp readLetExpression(ILexLocation start) throws ParserException, LexException { ParserException letDefError = null; try { reader.push(); ALetDefExp exp = readLetDefExpression(start); reader.unpush(); return exp; } catch (ParserException e) { e.adjustDepth(reader.getTokensRead()); reader.pop(); letDefError = e; } try { reader.push(); ALetBeStExp exp = readLetBeStExpression(start); reader.unpush(); return exp; } catch (ParserException e) { e.adjustDepth(reader.getTokensRead()); reader.pop(); throw e.deeperThan(letDefError) ? e : letDefError; } } private ALetDefExp readLetDefExpression(ILexLocation start) throws ParserException, LexException { DefinitionReader dr = getDefinitionReader(); List<PDefinition> localDefs = new Vector<PDefinition>(); localDefs.add(dr.readLocalDefinition(NameScope.LOCAL)); while (ignore(VDMToken.COMMA)) { localDefs.add(dr.readLocalDefinition(NameScope.LOCAL)); } checkFor(VDMToken.IN, 2150, "Expecting 'in' after local definitions"); // Note we read a Connective expression for the body, so that |-> // terminates the parse. return AstFactory.newALetDefExp(start, localDefs, readConnectiveExpression()); } private ALetBeStExp readLetBeStExpression(ILexLocation start) throws ParserException, LexException { PMultipleBind bind = getBindReader().readMultipleBind(); PExp stexp = null; if (lastToken().is(VDMToken.BE)) { nextToken(); checkFor(VDMToken.ST, 2151, "Expecting 'st' after 'be' in let expression"); stexp = readExpression(); } checkFor(VDMToken.IN, 2152, "Expecting 'in' after bind in let expression"); // Note we read a Connective expression for the body, so that |-> // terminates the parse. return AstFactory.newALetBeStExp(start, bind, stexp, readConnectiveExpression()); } private AForAllExp readForAllExpression(ILexLocation start) throws ParserException, LexException { List<PMultipleBind> bindList = getBindReader().readBindList(); checkFor(VDMToken.AMPERSAND, 2153, "Expecting '&' after bind list in forall"); return AstFactory.newAForAllExp(start, bindList, readExpression()); } private AExistsExp readExistsExpression(ILexLocation start) throws ParserException, LexException { List<PMultipleBind> bindList = getBindReader().readBindList(); checkFor(VDMToken.AMPERSAND, 2154, "Expecting '&' after bind list in exists"); return AstFactory.newAExistsExp(start, bindList, readExpression()); } private AExists1Exp readExists1Expression(ILexLocation start) throws ParserException, LexException { PBind bind = getBindReader().readBind(); checkFor(VDMToken.AMPERSAND, 2155, "Expecting '&' after single bind in exists1"); return AstFactory.newAExists1Exp(start, bind, readExpression()); } private AIotaExp readIotaExpression(ILexLocation start) throws ParserException, LexException { PBind bind = getBindReader().readBind(); checkFor(VDMToken.AMPERSAND, 2156, "Expecting '&' after single bind in iota"); return AstFactory.newAIotaExp(start, bind, readExpression()); } private ALambdaExp readLambdaExpression(ILexLocation start) throws ParserException, LexException { List<ATypeBind> bindList = getBindReader().readTypeBindList(); checkFor(VDMToken.AMPERSAND, 2157, "Expecting '&' after bind list in lambda"); return AstFactory.newALambdaExp(start, bindList, readExpression()); } private ADefExp readDefExpression(ILexLocation start) throws ParserException, LexException { DefinitionReader dr = getDefinitionReader(); List<PDefinition> equalsDefs = new Vector<PDefinition>(); while (lastToken().isNot(VDMToken.IN)) { equalsDefs.add(dr.readEqualsDefinition()); ignore(VDMToken.SEMICOLON); } checkFor(VDMToken.IN, 2158, "Expecting 'in' after equals definitions"); return AstFactory.newADefExp(start, equalsDefs, readExpression()); } private ANewExp readNewExpression(ILexLocation start) throws ParserException, LexException { LexIdentifierToken name = readIdToken("Expecting class name after 'new'"); checkFor(VDMToken.BRA, 2159, "Expecting '(' after new class name"); List<PExp> args = new NodeList<PExp>(null); ExpressionReader er = getExpressionReader(); if (lastToken().isNot(VDMToken.KET)) { args.add(er.readExpression()); while (ignore(VDMToken.COMMA)) { args.add(er.readExpression()); } } checkFor(VDMToken.KET, 2124, "Expecting ')' after constructor args"); return AstFactory.newANewExp(start, name, args); } private AIsOfBaseClassExp readIsOfBaseExpression(ILexLocation start) throws ParserException, LexException { checkFor(VDMToken.BRA, 2160, "Expecting '(' after 'isofbase'"); List<PExp> args = readExpressionList(); checkFor(VDMToken.KET, 2161, "Expecting ')' after 'isofbase' args"); if (args.size() != 2) { throwMessage(2041, "Expecting two arguments for 'isofbase'"); } if (!(args.get(0) instanceof AVariableExp)) { throwMessage(2042, "Expecting (<class>,<exp>) arguments for 'isofbase'"); } ILexNameToken classname = ((AVariableExp) args.get(0)).getName(); if (classname.getOld()) { throwMessage(2295, "Can't use old name here", classname); } return AstFactory.newAIsOfBaseClassExp(start, classname, args.get(1)); } private AIsOfClassExp readIsOfClassExpression(ILexLocation start) throws ParserException, LexException { checkFor(VDMToken.BRA, 2162, "Expecting '(' after 'isofclass'"); List<PExp> args = readExpressionList(); checkFor(VDMToken.KET, 2163, "Expecting ')' after 'isofclass' args"); if (args.size() != 2) { throwMessage(2043, "Expecting two arguments for 'isofclass'"); } if (!(args.get(0) instanceof AVariableExp)) { throwMessage(2044, "Expecting (<class>,<exp>) arguments for 'isofclass'"); } ILexNameToken classname = ((AVariableExp) args.get(0)).getName(); if (classname.getOld()) { throwMessage(2295, "Can't use old name here", classname); } return AstFactory.newAIsOfClassExp(start, classname, args.get(1)); } private ASameBaseClassExp readSameBaseExpression(ILexLocation start) throws ParserException, LexException { checkFor(VDMToken.BRA, 2164, "Expecting '(' after 'samebaseclass'"); List<PExp> args = readExpressionList(); checkFor(VDMToken.KET, 2165, "Expecting ')' after 'samebaseclass' args"); if (args.size() != 2) { throwMessage(2045, "Expecting two expressions in 'samebaseclass'"); } return AstFactory.newASameBaseClassExp(start, args); } private ASameClassExp readSameClassExpression(ILexLocation start) throws ParserException, LexException { checkFor(VDMToken.BRA, 2166, "Expecting '(' after 'sameclass'"); List<PExp> args = readExpressionList(); checkFor(VDMToken.KET, 2167, "Expecting ')' after 'sameclass' args"); if (args.size() != 2) { throwMessage(2046, "Expecting two expressions in 'sameclass'"); } return AstFactory.newASameClassExp(start, args); } private boolean inPerExpression = false; public PExp readPerExpression() throws ParserException, LexException { inPerExpression = true; PExp e = readExpression(); inPerExpression = false; return e; } private PExp readHistoryExpression(ILexLocation location) throws ParserException, LexException { if (!inPerExpression) { throwMessage(2047, "Can't use history expression here"); } LexToken op = lastToken(); String s = op.type.toString().toLowerCase(); switch (op.type) { case ACT: case FIN: case ACTIVE: case REQ: case WAITING: nextToken(); checkFor(VDMToken.BRA, 2168, "Expecting " + s + "(name(s))"); LexNameList opnames = new LexNameList(); LexNameToken opname = readNameToken("Expecting a name"); opnames.add(opname); while (ignore(VDMToken.COMMA)) { opname = readNameToken("Expecting " + s + "(name(s))"); opnames.add(opname); } checkFor(VDMToken.KET, 2169, "Expecting " + s + "(name(s))"); return AstFactory.newAHistoryExp(location, op, opnames); default: throwMessage(2048, "Expecting #act, #active, #fin, #req or #waiting"); return null; } } }