/*******************************************************************************
*
* 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.io.File;
import java.util.List;
import java.util.Vector;
import org.overture.ast.definitions.ATypeDefinition;
import org.overture.ast.definitions.PDefinition;
import org.overture.ast.factory.AstFactory;
import org.overture.ast.intf.lex.ILexNameToken;
import org.overture.ast.lex.LexIdentifierToken;
import org.overture.ast.lex.LexLocation;
import org.overture.ast.lex.LexNameList;
import org.overture.ast.lex.LexNameToken;
import org.overture.ast.lex.LexToken;
import org.overture.ast.lex.VDMToken;
import org.overture.ast.modules.AFromModuleImports;
import org.overture.ast.modules.AFunctionExport;
import org.overture.ast.modules.AFunctionValueImport;
import org.overture.ast.modules.AModuleExports;
import org.overture.ast.modules.AModuleImports;
import org.overture.ast.modules.AModuleModules;
import org.overture.ast.modules.AOperationExport;
import org.overture.ast.modules.AOperationValueImport;
import org.overture.ast.modules.ATypeExport;
import org.overture.ast.modules.ATypeImport;
import org.overture.ast.modules.AValueExport;
import org.overture.ast.modules.PExport;
import org.overture.ast.modules.PImport;
import org.overture.ast.modules.SValueImport;
import org.overture.ast.types.AFunctionType;
import org.overture.ast.types.PType;
import org.overture.ast.util.ClonableFile;
import org.overture.ast.util.modules.ModuleList;
import org.overture.parser.lex.LexException;
import org.overture.parser.lex.LexTokenReader;
import org.overture.parser.messages.LocatedException;
/**
* A syntax analyser to parse modules.
*/
public class ModuleReader extends SyntaxReader
{
public ModuleReader(LexTokenReader reader)
{
super(reader);
}
public ModuleList readModules()
{
ModuleList modules = new ModuleList();
try
{
if (lastToken().is(VDMToken.EOF))
{
return modules; // The file is empty
}
if (lastToken().isNot(VDMToken.MODULE)
&& !DefinitionReader.newSection(lastToken()))
{
warning(5015, "LaTeX source should start with %comment, \\document, \\section or \\subsection", lastToken().location);
}
while (lastToken().isNot(VDMToken.EOF)
&& lastToken().isNot(VDMToken.END))
{
switch (lastToken().type)
{
case MODULE:
modules.add(readModule());
break;
case DLMODULE:
modules.add(readDLModule());
break;
case IDENTIFIER:
LexIdentifierToken id = lastIdToken();
if (id.getName().equals("class"))
{
throwMessage(2260, "Module starts with 'class' instead of 'module'");
}
// else fall through to a flat definition...
default:
modules.add(readFlatModule());
break;
}
}
} catch (LocatedException e)
{
VDMToken[] end = new VDMToken[0];
report(e, end, end);
}
return modules;
}
public static AFromModuleImports importAll(LexIdentifierToken from)
{
List<List<PImport>> types = new Vector<List<PImport>>();
LexNameToken all = new LexNameToken(from.getName(), "all", from.location);
List<PImport> impAll = new Vector<PImport>();
impAll.add(AstFactory.newAAllImport(all));
types.add(impAll);
return AstFactory.newAFromModuleImports(from, types);
}
private AModuleModules readFlatModule() throws ParserException,
LexException
{
File file = lastToken().location.getFile();
setCurrentModule("DEFAULT");
List<PDefinition> definitions = getDefinitionReader().readDefinitions();
checkFor(VDMToken.EOF, 2318, "Unexpected token after flat definitions");
return AstFactory.newAModuleModules(file, definitions);
}
private AModuleModules readModule() throws ParserException, LexException
{
LexIdentifierToken name = new LexIdentifierToken("?", false, lastToken().location);
AModuleImports imports = null;
AModuleExports exports = null;
try
{
setCurrentModule("");
checkFor(VDMToken.MODULE, 2170, "Expecting 'module' at module start");
name = readIdToken("Expecting identifier after 'module'");
setCurrentModule(name.getName());
if (lastToken().is(VDMToken.IMPORTS))
{
imports = readImports(name);
}
if (lastToken().is(VDMToken.EXPORTS))
{
exports = readExports();
}
// Be forgiving about the ordering...
if (imports == null && lastToken().is(VDMToken.IMPORTS))
{
imports = readImports(name);
}
} catch (LocatedException e)
{
VDMToken[] after = { VDMToken.DEFINITIONS };
VDMToken[] upto = { VDMToken.END };
report(e, after, upto);
}
List<PDefinition> defs = null;
if (lastToken().is(VDMToken.DEFINITIONS))
{
nextToken();
defs = getDefinitionReader().readDefinitions();
} else
{
defs = new Vector<PDefinition>();
}
checkFor(VDMToken.END, 2171, "Expecting 'end' after module definitions");
LexIdentifierToken endname = readIdToken("Expecting 'end <name>' after module definitions");
if (name != null && !name.equals(endname))
{
throwMessage(2049, "Expecting 'end " + name.getName() + "'");
}
LexLocation.addSpan(idToName(name), lastToken());
return AstFactory.newAModuleModules(name, imports, exports, defs);
}
private AModuleModules readDLModule() throws ParserException, LexException
{
LexIdentifierToken name = new LexIdentifierToken("?", false, lastToken().location);
// FIXME dlmodules not implemented
AModuleImports imports = null;
AModuleExports exports = null;
// LexStringToken library = null;
try
{
checkFor(VDMToken.DLMODULE, 2172, "Expecting 'dlmodule' at module start");
name = readIdToken("Expecting identifier after 'dlmodule'");
setCurrentModule(name.getName());
if (lastToken().is(VDMToken.IMPORTS))
{
imports = readImports(name);
}
if (lastToken().is(VDMToken.EXPORTS))
{
exports = readExports();
}
if (lastToken().is(VDMToken.USELIB))
{
if (nextToken().is(VDMToken.STRING))
{
/* library = (LexStringToken) */lastToken();
nextToken();
} else
{
throwMessage(2050, "Expecting library name after 'uselib'");
}
}
} catch (LocatedException e)
{
VDMToken[] after = {};
VDMToken[] upto = { VDMToken.END };
report(e, after, upto);
}
checkFor(VDMToken.END, 2173, "Expecting 'end' after dlmodule definitions");
LexIdentifierToken endname = readIdToken("Expecting 'end <name>' after dlmodule definitions");
if (name != null && !name.equals(endname))
{
throwMessage(2051, "Expecting 'end " + name.getName() + "'");
}
// return new DLModule(name, imports, exports, library);
List<ClonableFile> files = new Vector<ClonableFile>();
files.add(new ClonableFile(name.location.getFile()));
AModuleModules module = AstFactory.newAModuleModules(name, imports, exports, null);
module.setFiles(files);
module.setIsDLModule(true);
return module;
}
private AModuleExports readExports() throws ParserException, LexException
{
checkFor(VDMToken.EXPORTS, 2174, "Malformed imports? Expecting 'exports' section");
return AstFactory.newAModuleExports(readExportsFromModule());
}
private List<List<PExport>> readExportsFromModule() throws ParserException,
LexException
{
List<List<PExport>> types = new Vector<List<PExport>>();
if (lastToken().is(VDMToken.ALL))
{
LexNameToken all = new LexNameToken(getCurrentModule(), "all", lastToken().location);
List<PExport> expAll = new Vector<PExport>();
expAll.add(AstFactory.newAAllExport(all.location));
types.add(expAll);
nextToken();
return types;
}
types.add(readExportsOfOneType());
while (newType())
{
types.add(readExportsOfOneType());
}
return types;
}
private List<PExport> readExportsOfOneType() throws ParserException,
LexException
{
switch (lastToken().type)
{
case TYPES:
nextToken();
return readExportedTypes();
case VALUES:
nextToken();
return readExportedValues();
case FUNCTIONS:
nextToken();
return readExportedFunctions();
case OPERATIONS:
nextToken();
return readExportedOperations();
default:
throwMessage(2052, "Expecting 'all', 'types', 'values', 'functions' or 'operations'");
return null;
}
}
private List<PExport> readExportedTypes() throws ParserException,
LexException
{
List<PExport> list = new Vector<PExport>();
list.add(readExportedType());
while (lastToken().isNot(VDMToken.DEFINITIONS)
&& lastToken().isNot(VDMToken.USELIB) && !newType())
{
list.add(readExportedType());
}
return list;
}
private ATypeExport readExportedType() throws ParserException, LexException
{
boolean struct = lastToken().is(VDMToken.STRUCT);
if (struct)
{
nextToken();
}
LexNameToken name = readNameToken("Expecting exported type name");
ignore(VDMToken.SEMICOLON);
return AstFactory.newATypeExport(name, struct);
}
private List<PExport> readExportedValues() throws ParserException,
LexException
{
List<PExport> list = new Vector<PExport>();
list.add(readExportedValue());
while (lastToken().isNot(VDMToken.DEFINITIONS)
&& lastToken().isNot(VDMToken.USELIB) && !newType())
{
list.add(readExportedValue());
}
return list;
}
private AValueExport readExportedValue() throws ParserException,
LexException
{
LexToken token = lastToken();
List<ILexNameToken> nameList = readIdList();
checkFor(VDMToken.COLON, 2175, "Expecting ':' after export name");
PType type = getTypeReader().readType();
ignore(VDMToken.SEMICOLON);
return AstFactory.newAValueExport(token.location, nameList, type);
}
private List<PExport> readExportedFunctions() throws ParserException,
LexException
{
List<PExport> list = new Vector<PExport>();
list.add(readExportedFunction());
while (lastToken().is(VDMToken.IDENTIFIER)
|| lastToken().is(VDMToken.NAME))
{
list.add(readExportedFunction());
}
return list;
}
private AFunctionExport readExportedFunction() throws ParserException,
LexException
{
LexToken token = lastToken();
List<ILexNameToken> nameList = readIdList();
List<ILexNameToken> typeParams = ignoreTypeParams();
checkFor(VDMToken.COLON, 2176, "Expecting ':' after export name");
LexToken tloc = lastToken();
PType type = getTypeReader().readType();
if (!(type instanceof AFunctionType))
{
throwMessage(2053, "Exported function is not a function type", tloc);
}
ignore(VDMToken.SEMICOLON);
return AstFactory.newAFunctionExport(token.location, nameList, type, typeParams);
}
private List<PExport> readExportedOperations() throws ParserException,
LexException
{
List<PExport> list = new Vector<PExport>();
list.add(readExportedOperation());
while (lastToken().is(VDMToken.IDENTIFIER)
|| lastToken().is(VDMToken.NAME))
{
list.add(readExportedOperation());
}
return list;
}
private AOperationExport readExportedOperation() throws ParserException,
LexException
{
LexToken token = lastToken();
List<ILexNameToken> nameList = readIdList();
checkFor(VDMToken.COLON, 2177, "Expecting ':' after export name");
PType type = getTypeReader().readOperationType();
ignore(VDMToken.SEMICOLON);
return AstFactory.newAOperationExport(token.location, nameList, type);
}
private List<ILexNameToken> readIdList() throws ParserException,
LexException
{
List<ILexNameToken> list = new Vector<ILexNameToken>();
list.add(readNameToken("Expecting name list"));
while (ignore(VDMToken.COMMA))
{
list.add(readNameToken("Expecting name list"));
}
return list;
}
private AModuleImports readImports(LexIdentifierToken name)
throws ParserException, LexException
{
checkFor(VDMToken.IMPORTS, 2178, "Expecting 'imports'");
List<AFromModuleImports> imports = new Vector<AFromModuleImports>();
imports.add(readImportDefinition());
while (ignore(VDMToken.COMMA))
{
imports.add(readImportDefinition());
}
return AstFactory.newAModuleImports(name, imports);
}
private AFromModuleImports readImportDefinition() throws ParserException,
LexException
{
checkFor(VDMToken.FROM, 2179, "Expecting 'from' in import definition");
LexIdentifierToken from = readIdToken("Expecting module identifier after 'from'");
return AstFactory.newAFromModuleImports(from, readImportsFromModule(from));
}
private List<List<PImport>> readImportsFromModule(LexIdentifierToken from)
throws ParserException, LexException
{
List<List<PImport>> types = new Vector<List<PImport>>();
if (lastToken().is(VDMToken.ALL))
{
LexNameToken all = new LexNameToken(getCurrentModule(), "all", lastToken().location);
List<PImport> impAll = new Vector<PImport>();
impAll.add(AstFactory.newAAllImport(all));
types.add(impAll);
nextToken();
return types;
}
types.add(readImportsOfOneType(from));
while (newType())
{
types.add(readImportsOfOneType(from));
}
return types;
}
private List<PImport> readImportsOfOneType(LexIdentifierToken from)
throws ParserException, LexException
{
switch (lastToken().type)
{
case TYPES:
nextToken();
return readImportedTypes(from);
case VALUES:
nextToken();
return readImportedValues(from);
case FUNCTIONS:
nextToken();
return readImportedFunctions(from);
case OPERATIONS:
nextToken();
return readImportedOperations(from);
default:
throwMessage(2054, "Expecting types, values, functions or operations");
return null;
}
}
private List<PImport> readImportedTypes(LexIdentifierToken from)
throws ParserException, LexException
{
List<PImport> list = new Vector<PImport>();
list.add(readImportedType(from));
while (lastToken().is(VDMToken.IDENTIFIER)
|| lastToken().is(VDMToken.NAME))
{
list.add(readImportedType(from));
}
return list;
}
private ATypeImport readImportedType(LexIdentifierToken from)
throws ParserException, LexException
{
String savedModule = getCurrentModule();
try
{
reader.push();
setCurrentModule(from.getName()); // So names are from "from" in...
ATypeDefinition def = getDefinitionReader().readTypeDefinition();
setCurrentModule(savedModule); // and restore
reader.unpush();
LexNameToken renamed = null;
if (ignore(VDMToken.RENAMED))
{
renamed = readNameToken("Expected renamed type name");
}
ignore(VDMToken.SEMICOLON);
return AstFactory.newATypeImport(def, renamed);
} catch (ParserException e)
{
reader.pop();
setCurrentModule(savedModule);
}
LexNameToken name = readNameToken("Expecting imported type name");
LexNameToken defname = getDefName(from, name);
LexNameToken renamed = null;
if (ignore(VDMToken.RENAMED))
{
renamed = readNameToken("Expected renamed type name");
}
ignore(VDMToken.SEMICOLON);
return AstFactory.newATypeImport(defname, renamed);
}
private List<PImport> readImportedValues(LexIdentifierToken from)
throws ParserException, LexException
{
List<PImport> list = new Vector<PImport>();
list.add(readImportedValue(from));
while (lastToken().is(VDMToken.IDENTIFIER)
|| lastToken().is(VDMToken.NAME))
{
list.add(readImportedValue(from));
}
return list;
}
private SValueImport readImportedValue(LexIdentifierToken from)
throws ParserException, LexException
{
LexNameToken name = readNameToken("Expecting imported value name");
LexNameToken defname = getDefName(from, name);
PType type = null;
if (lastToken().is(VDMToken.COLON))
{
nextToken();
type = getTypeReader().readType();
}
LexNameToken renamed = null;
if (ignore(VDMToken.RENAMED))
{
renamed = readNameToken("Expected renamed value name");
}
ignore(VDMToken.SEMICOLON);
return AstFactory.newAValueValueImport(defname, type, renamed);
}
private List<PImport> readImportedFunctions(LexIdentifierToken from)
throws ParserException, LexException
{
List<PImport> list = new Vector<PImport>();
list.add(readImportedFunction(from));
while (lastToken().is(VDMToken.IDENTIFIER)
|| lastToken().is(VDMToken.NAME))
{
list.add(readImportedFunction(from));
}
return list;
}
private AFunctionValueImport readImportedFunction(LexIdentifierToken from)
throws ParserException, LexException
{
LexNameToken name = readNameToken("Expecting imported function name");
LexNameToken defname = getDefName(from, name);
LexNameList typeParams = getDefinitionReader().readTypeParams();
PType type = null;
if (lastToken().is(VDMToken.COLON))
{
nextToken();
LexToken tloc = lastToken();
type = getTypeReader().readType();
if (!(type instanceof AFunctionType))
{
throwMessage(2055, "Imported function is not a function type", tloc);
}
}
LexNameToken renamed = null;
if (ignore(VDMToken.RENAMED))
{
renamed = readNameToken("Expected renamed function name");
}
ignore(VDMToken.SEMICOLON);
return AstFactory.newAFunctionValueImport(defname, type, typeParams, renamed);
}
private List<PImport> readImportedOperations(LexIdentifierToken from)
throws ParserException, LexException
{
List<PImport> list = new Vector<PImport>();
list.add(readImportedOperation(from));
while (lastToken().is(VDMToken.IDENTIFIER)
|| lastToken().is(VDMToken.NAME))
{
list.add(readImportedOperation(from));
}
return list;
}
private AOperationValueImport readImportedOperation(LexIdentifierToken from)
throws ParserException, LexException
{
LexNameToken name = readNameToken("Expecting imported operation name");
LexNameToken defname = getDefName(from, name);
PType type = null;
if (lastToken().is(VDMToken.COLON))
{
nextToken();
type = getTypeReader().readOperationType();
}
LexNameToken renamed = null;
if (ignore(VDMToken.RENAMED))
{
renamed = readNameToken("Expected renamed operation name");
}
ignore(VDMToken.SEMICOLON);
return AstFactory.newAOperationValueImport(defname, type, renamed);
}
private boolean newType() throws LexException
{
switch (lastToken().type)
{
case TYPES:
case VALUES:
case FUNCTIONS:
case OPERATIONS:
case EOF:
return true;
default:
return false;
}
}
private LexNameToken getDefName(LexIdentifierToken impmod, LexNameToken name)
{
if (name.module.equals(getCurrentModule())) // ie. it was an id
{
return new LexNameToken(impmod.getName(), name.name, name.location);
}
return name;
}
private LexNameList ignoreTypeParams() throws LexException, ParserException
{
if (lastToken().is(VDMToken.SEQ_OPEN))
{
return getDefinitionReader().readTypeParams();
}
else
{
return null;
}
}
}