/******************************************************************************* * * 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.factory.AstFactory; 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.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.patterns.AMapletPatternMaplet; import org.overture.ast.patterns.ANamePatternPair; import org.overture.ast.patterns.PPattern; 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 pattern definitions. */ public class PatternReader extends SyntaxReader { public PatternReader(LexTokenReader reader) { super(reader); } public PPattern readPattern() throws ParserException, LexException { PPattern pattern = readSimplePattern(); while (lastToken().is(VDMToken.UNION) || lastToken().is(VDMToken.CONCATENATE) || lastToken().is(VDMToken.MUNION)) { LexToken token = lastToken(); switch (token.type) { case UNION: nextToken(); pattern = AstFactory.newAUnionPattern(pattern, token.location, readPattern()); break; case CONCATENATE: nextToken(); pattern = AstFactory.newAConcatenationPattern(pattern, token.location, readPattern()); break; case MUNION: if (Settings.release == Release.VDM_10) { nextToken(); pattern = AstFactory.newAMapUnionPattern(pattern, token.location, readPattern()); } else { throwMessage(2298, "Map patterns not available in VDM classic"); } break; default: break; } } return pattern; } private PPattern readSimplePattern() throws ParserException, LexException { PPattern pattern = null; LexToken token = lastToken(); boolean rdtok = true; switch (token.type) { case NUMBER: pattern = AstFactory.newAIntegerPattern((LexIntegerToken) token); break; case REALNUMBER: pattern = AstFactory.newARealPattern((LexRealToken) token); break; case CHARACTER: pattern = AstFactory.newACharacterPattern((LexCharacterToken) token); break; case STRING: pattern = AstFactory.newAStringPattern((LexStringToken) token); break; case QUOTE: pattern = AstFactory.newAQuotePattern((LexQuoteToken) token); break; case TRUE: case FALSE: pattern = AstFactory.newABooleanPattern((LexBooleanToken) token); break; case NIL: pattern = AstFactory.newANilPattern((LexKeywordToken) token); break; case BRA: nextToken(); ExpressionReader expr = getExpressionReader(); pattern = AstFactory.newAExpressionPattern(expr.readExpression()); checkFor(VDMToken.KET, 2180, "Mismatched brackets in pattern"); rdtok = false; break; case SET_OPEN: if (nextToken().is(VDMToken.SET_CLOSE)) { pattern = AstFactory.newASetPattern(token.location, new Vector<PPattern>()); } else if (lastToken().is(VDMToken.MAPLET)) { if (Settings.release == Release.VDM_10) { pattern = AstFactory.newAMapPattern(token.location, new Vector<AMapletPatternMaplet>()); nextToken(); checkFor(VDMToken.SET_CLOSE, 2299, "Expecting {|->} empty map pattern"); rdtok = false; } else { throwMessage(2298, "Map patterns not available in VDM classic"); } } else { reader.push(); readPattern(); // ignored if (lastToken().is(VDMToken.MAPLET)) { reader.pop(); if (Settings.release == Release.VDM_10) { pattern = AstFactory.newAMapPattern(token.location, readMapletPatternList()); } else { throwMessage(2298, "Map patterns not available in VDM classic"); } } else { reader.pop(); pattern = AstFactory.newASetPattern(token.location, readPatternList()); } checkFor(VDMToken.SET_CLOSE, 2181, "Mismatched braces in pattern"); rdtok = false; } break; case SEQ_OPEN: if (nextToken().is(VDMToken.SEQ_CLOSE)) { pattern = AstFactory.newASeqPattern(token.location, new Vector<PPattern>()); } else { pattern = AstFactory.newASeqPattern(token.location, readPatternList()); checkFor(VDMToken.SEQ_CLOSE, 2182, "Mismatched square brackets in pattern"); rdtok = false; } break; case NAME: throwMessage(2056, "Cannot use module'id name in patterns"); break; case IDENTIFIER: LexIdentifierToken id = lastIdToken(); if (id.name.startsWith("mk_")) { nextToken(); if (id.name.equals("mk_")) { checkFor(VDMToken.BRA, 2183, "Expecting '(' after mk_ tuple"); pattern = AstFactory.newATuplePattern(token.location, readPatternList()); checkFor(VDMToken.KET, 2184, "Expecting ')' after mk_ tuple"); } else { checkFor(VDMToken.BRA, 2185, "Expecting '(' after " + id + " record"); LexNameToken typename = null; int backtick = id.name.indexOf('`'); if (backtick >= 0) { // Strange case of "mk_MOD`name" String mod = id.name.substring(3, backtick); String name = id.name.substring(backtick + 1); typename = new LexNameToken(mod, name, id.location); } else { // Regular case of "mk_Name" LexIdentifierToken type = new LexIdentifierToken(id.name.substring(3), false, id.location); typename = idToName(type); } if (lastToken().is(VDMToken.KET)) { // An empty pattern list pattern = AstFactory.newARecordPattern(typename, new Vector<PPattern>()); nextToken(); } else { pattern = AstFactory.newARecordPattern(typename, readPatternList()); checkFor(VDMToken.KET, 2186, "Expecting ')' after " + id + " record"); } } rdtok = false; } else if (id.name.startsWith("obj_")) // Object pattern { if (Settings.release == Release.CLASSIC) { throwMessage(2323, "Object patterns not available in VDM classic", Integer.MAX_VALUE); } else if (id.name.equals("obj_")) { throwMessage(2319, "Expecting class name after obj_ in object pattern"); } else { nextToken(); String classname = id.name.substring(4); LexNameToken name = new LexNameToken("CLASS", classname, id.location); checkFor(VDMToken.BRA, 2320, "Expecting '(' after obj_ pattern"); pattern = AstFactory.newAObjectPattern(name, readNamePatternList(classname)); checkFor(VDMToken.KET, 2322, "Expecting ')' after obj_ pattern"); rdtok = false; } } else { pattern = AstFactory.newAIdentifierPattern(idToName(id)); } break; case MINUS: pattern = AstFactory.newAIgnorePattern(token.location); break; default: throwMessage(2057, "Unexpected token in pattern"); } if (rdtok) { nextToken(); } return pattern; } private List<AMapletPatternMaplet> readMapletPatternList() throws LexException, ParserException { List<AMapletPatternMaplet> list = new Vector<AMapletPatternMaplet>(); list.add(readMaplet()); while (ignore(VDMToken.COMMA)) { list.add(readMaplet()); } return list; } private AMapletPatternMaplet readMaplet() throws ParserException, LexException { PPattern key = readPattern(); checkFor(VDMToken.MAPLET, 2297, "Expecting '|->' in map pattern"); PPattern value = readPattern(); return AstFactory.newAMapletPatternMaplet(key, value); } public List<PPattern> readPatternList() throws ParserException, LexException { List<PPattern> list = new Vector<PPattern>(); list.add(readPattern()); while (ignore(VDMToken.COMMA)) { list.add(readPattern()); } return list; } private ANamePatternPair readNamePatternPair(String classname) throws LexException, ParserException { LexNameToken fieldname = lastNameToken().getModifiedName(classname); nextToken(); checkFor(VDMToken.MAPLET, 2321, "Expecting '|->' in object pattern"); PPattern pattern = readPattern(); return AstFactory.newANamePatternPair(fieldname, pattern); } private List<ANamePatternPair> readNamePatternList(String classname) throws LexException, ParserException { List<ANamePatternPair> list = new Vector<ANamePatternPair>(); if (lastToken().is(VDMToken.IDENTIFIER)) // Can be empty { list.add(readNamePatternPair(classname)); while (ignore(VDMToken.COMMA)) { list.add(readNamePatternPair(classname)); } } return list; } }