/*******************************************************************************
*
* 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.intf.lex.ILexLocation;
import org.overture.ast.lex.LexIdentifierToken;
import org.overture.ast.lex.LexNameToken;
import org.overture.ast.lex.LexQuoteToken;
import org.overture.ast.lex.LexToken;
import org.overture.ast.lex.VDMToken;
import org.overture.ast.types.AFieldField;
import org.overture.ast.types.AOperationType;
import org.overture.ast.types.AProductType;
import org.overture.ast.types.ARecordInvariantType;
import org.overture.ast.types.AVoidType;
import org.overture.ast.types.PField;
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 type expressions.
*/
public class TypeReader extends SyntaxReader
{
public TypeReader(LexTokenReader reader)
{
super(reader);
}
public PType readType() throws ParserException, LexException
{
PType type = readUnionType();
if (lastToken().is(VDMToken.ARROW)
|| lastToken().is(VDMToken.TOTAL_FUNCTION))
{
LexToken token = lastToken();
nextToken();
PType result = readType();
if (result instanceof AVoidType)
{
throwMessage(2070, "Function type cannot return void type");
}
type = AstFactory.newAFunctionType(token.location, token.is(VDMToken.ARROW), productExpand(type), result);
}
return type;
}
private PType readUnionType() throws ParserException, LexException
{
PType type = readProductType();
while (lastToken().type == VDMToken.PIPE)
{
LexToken token = lastToken();
nextToken();
type = AstFactory.newAUnionType(token.location, type, readProductType());
}
return type;
}
private PType readProductType() throws ParserException, LexException
{
LexToken token = lastToken();
PType type = readComposeType();
List<PType> productList = new Vector<PType>();
productList.add(type);
while (lastToken().type == VDMToken.TIMES)
{
nextToken();
productList.add(readComposeType());
}
if (productList.size() == 1)
{
return type;
}
return AstFactory.newAProductType(token.location, productList);
}
private PType readComposeType() throws ParserException, LexException
{
PType type = null;
if (lastToken().is(VDMToken.COMPOSE))
{
nextToken();
LexIdentifierToken id = readIdToken("Compose not followed by record identifier");
checkFor(VDMToken.OF, 2249, "Missing 'of' in compose type");
ARecordInvariantType rtype = AstFactory.newARecordInvariantType(idToName(id), readFieldList());
rtype.setComposed(true);
checkFor(VDMToken.END, 2250, "Missing 'end' in compose type");
type = rtype;
} else
{
type = readMapType();
}
return type;
}
public List<AFieldField> readFieldList() throws ParserException,
LexException
{
List<AFieldField> list = new Vector<AFieldField>();
while (lastToken().isNot(VDMToken.END)
&& lastToken().isNot(VDMToken.SEMICOLON)
&& lastToken().isNot(VDMToken.INV))
{
reader.push();
LexToken tag = lastToken();
LexToken separator = nextToken();
if (separator.is(VDMToken.COLON))
{
if (tag.isNot(VDMToken.IDENTIFIER))
{
throwMessage(2071, "Expecting field identifier before ':'");
}
nextToken();
LexIdentifierToken tagid = (LexIdentifierToken) tag;
if (tagid.isOld())
{
throwMessage(2295, "Can't use old name here", tag);
}
LexNameToken tagname = idToName(tagid);
list.add(AstFactory.newAFieldField(tagname, tagid.getName(), readType(), false));
reader.unpush();
} else if (separator.is(VDMToken.EQABST))
{
if (tag.isNot(VDMToken.IDENTIFIER))
{
throwMessage(2072, "Expecting field name before ':-'");
}
nextToken();
LexIdentifierToken tagid = (LexIdentifierToken) tag;
if (tagid.isOld())
{
throwMessage(2295, "Can't use old name here", tag);
}
LexNameToken tagname = idToName(tagid);
list.add(AstFactory.newAFieldField(tagname, tagid.getName(), readType(), true));
reader.unpush();
} else
// Anonymous field or end of fields
{
try
{
reader.retry();
String anon = Integer.toString(list.size() + 1);
PType ftype = readType();
LexNameToken tagname = new LexNameToken(getCurrentModule(), anon, ftype.getLocation());
list.add(AstFactory.newAFieldField(tagname, anon, ftype, false));
reader.unpush();
} catch (Exception e)
{
// End? EOF? Or badly formed type, fails elsewhere...
reader.pop();
break;
}
}
}
for (PField f1 : list)
{
for (PField f2 : list)
{
if (f1 != f2
&& ((AFieldField) f1).getTag().equals(((AFieldField) f2).getTag()))
{
throwMessage(2073, "Duplicate field names in record type");
}
}
}
return list;
}
private PType readMapType() throws ParserException, LexException
{
PType type = null;
LexToken token = lastToken();
switch (token.type)
{
case MAP:
nextToken();
type = readType(); // Effectively bracketed by 'to'
checkFor(VDMToken.TO, 2251, "Expecting 'to' in map type");
type = AstFactory.newAMapMapType(token.location, type, readComposeType());
break;
case INMAP:
nextToken();
type = readType(); // Effectively bracketed by 'to'
checkFor(VDMToken.TO, 2252, "Expecting 'to' in inmap type");
type = AstFactory.newAInMapMapType(token.location, type, readComposeType());
break;
default:
type = readSetSeqType();
break;
}
return type;
}
private PType readSetSeqType() throws ParserException, LexException
{
PType type = null;
LexToken token = lastToken();
switch (token.type)
{
case SET:
nextToken();
checkFor(VDMToken.OF, 2253, "Expecting 'of' after set");
type = AstFactory.newASetSetType(token.location, readComposeType());
break;
case SET1:
if (Settings.release == Release.CLASSIC)
{
throwMessage(2327, "Type set1 is not available in classic");
}
nextToken();
checkFor(VDMToken.OF, 2326, "Expecting 'of' after set1");
type = AstFactory.newASet1SetType(token.location, readComposeType());
break;
case SEQ:
nextToken();
checkFor(VDMToken.OF, 2254, "Expecting 'of' after seq");
type = AstFactory.newASeqSeqType(token.location, readComposeType());
break;
case SEQ1:
nextToken();
checkFor(VDMToken.OF, 2255, "Expecting 'of' after seq1");
type = AstFactory.newASeq1SeqType(token.location, readComposeType());
break;
default:
type = readBasicType();
break;
}
return type;
}
private PType readBasicType() throws ParserException, LexException
{
PType type = null;
LexToken token = lastToken();
ILexLocation location = token.location;
switch (token.type)
{
case NAT:
type = AstFactory.newANatNumericBasicType(location);
nextToken();
break;
case NAT1:
type = AstFactory.newANatOneNumericBasicType(location);
nextToken();
break;
case BOOL:
type = AstFactory.newABooleanBasicType(location);
nextToken();
break;
case REAL:
type = AstFactory.newARealNumericBasicType(location);
nextToken();
break;
case INT:
type = AstFactory.newAIntNumericBasicType(location);
nextToken();
break;
case RAT:
type = AstFactory.newARationalNumericBasicType(location);
nextToken();
break;
case CHAR:
type = AstFactory.newACharBasicType(location);
nextToken();
break;
case TOKEN:
type = AstFactory.newATokenBasicType(location);
nextToken();
break;
case QUOTE:
type = AstFactory.newAQuoteType((LexQuoteToken) token);
nextToken();
break;
case BRA:
if (nextToken().is(VDMToken.KET))
{
type = AstFactory.newAVoidType(location);
nextToken();
} else
{
type = AstFactory.newABracketType(location, readType());
checkFor(VDMToken.KET, 2256, "Bracket mismatch");
}
break;
case SEQ_OPEN:
nextToken();
type = AstFactory.newAOptionalType(location, readType());
checkFor(VDMToken.SEQ_CLOSE, 2257, "Missing close bracket after optional type");
break;
case IDENTIFIER:
LexIdentifierToken id = (LexIdentifierToken) token;
type = AstFactory.newAUnresolvedType(idToName(id));
nextToken();
break;
case NAME:
type = AstFactory.newAUnresolvedType((LexNameToken) token);
nextToken();
break;
case AT:
nextToken();
type = AstFactory.newAParameterType(idToName(readIdToken("Invalid type parameter")));
break;
case QMARK:
nextToken();
type = AstFactory.newAUnknownType(location); // Not strictly VDM :-)
break;
default:
throwMessage(2074, "Unexpected token in type expression");
}
return type;
}
public AOperationType readOperationType() throws ParserException,
LexException
{
PType paramtype = readType();
LexToken arrow = lastToken();
checkFor(VDMToken.OPDEF, 2258, "Expecting '==>' in explicit operation type");
PType resulttype = readType();
return AstFactory.newAOperationType(arrow.location, productExpand(paramtype), resulttype);
}
private List<PType> productExpand(PType parameters)
{
List<PType> types = new Vector<PType>();
if (parameters instanceof AProductType)
{
// Expand unbracketed product types
AProductType pt = (AProductType) parameters;
types.addAll(pt.getTypes());
} else if (parameters instanceof AVoidType)
{
// No type
} else
{
// One parameter, including bracketed product types
types.add(parameters);
}
return types;
}
}