/*******************************************************************************
*
* 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.ASystemClassDefinition;
import org.overture.ast.definitions.PDefinition;
import org.overture.ast.definitions.SClassDefinition;
import org.overture.ast.factory.AstFactory;
import org.overture.ast.intf.lex.ILexNameToken;
import org.overture.ast.lex.Dialect;
import org.overture.ast.lex.LexIdentifierToken;
import org.overture.ast.lex.LexNameList;
import org.overture.ast.lex.VDMToken;
import org.overture.ast.util.definitions.ClassList;
import org.overture.config.Settings;
import org.overture.parser.lex.LexException;
import org.overture.parser.lex.LexTokenReader;
import org.overture.parser.messages.LocatedException;
/**
* A syntax analyser to parse class definitions.
*/
public class ClassReader extends SyntaxReader
{
public ClassReader(LexTokenReader reader)
{
super(reader);
}
public ClassList readClasses()
{
ClassList list = new ClassList();
try
{
if (lastToken().is(VDMToken.EOF))
{
return list; // The file is empty
}
if (lastToken().isNot(VDMToken.CLASS)
&& lastToken().isNot(VDMToken.SYSTEM))
{
warning(5015, "LaTeX source should start with %comment, \\document, \\section or \\subsection", lastToken().location);
throwMessage(2005, Settings.dialect == Dialect.VDM_RT ? "Expecting list of 'class' or 'system' definitions"
: "Expecting list of 'class' definitions");
}
while (lastToken().is(VDMToken.CLASS)
|| lastToken().is(VDMToken.SYSTEM))
{
if (lastToken().is(VDMToken.CLASS))
{
list.add(readClass());
} else
{
list.add(readSystem());
}
}
if (lastToken().isNot(VDMToken.EOF))
{
throwMessage(2006, "Found tokens after class definitions");
}
} catch (LocatedException e)
{
VDMToken[] end = new VDMToken[0];
report(e, end, end);
}
return list;
}
private SClassDefinition readClass() throws ParserException, LexException
{
LexNameList superclasses = new LexNameList();
if (lastToken().is(VDMToken.CLASS))
{
setCurrentModule("");
nextToken();
LexIdentifierToken classId = readIdToken("Expecting class ID");
ILexNameToken className = classId.getClassName();
setCurrentModule(classId.getName());
if (lastToken().is(VDMToken.IS))
{
nextToken();
checkFor(VDMToken.SUBCLASS, 2075, "Expecting 'is subclass of'");
checkFor(VDMToken.OF, 2076, "Expecting 'is subclass of'");
LexIdentifierToken id = readIdToken("Expecting class identifier");
superclasses.add(id.getClassName());
while (ignore(VDMToken.COMMA))
{
id = readIdToken("Expecting class identifier");
superclasses.add(id.getClassName());
}
}
List<PDefinition> members = getDefinitionReader().readDefinitions();
checkFor(VDMToken.END, 2077, "Expecting 'end' after class members");
LexIdentifierToken endname = readIdToken("Expecting 'end <name>' after class members");
if (classId != null && !classId.equals(endname))
{
throwMessage(2007, "Expecting 'end " + classId.getName() + "'");
}
return AstFactory.newAClassClassDefinition(className, superclasses, members);
// SClassDefinition def = new
// AClassClassDefinition(className.location,className,NameScope.CLASSNAME,true,null,new
// AAccessSpecifierAccessSpecifier(new APublicAccess(), null, null),null,null, null, superclasses,
// members,null,null,false,ClassDefinitionSettings.UNSET , null, false, null, false,false,false,
// null,false,null);
// PDefinitionAssistant.setClassDefinition(def,def);
// return def;
} else
{
throwMessage(2008, "Class does not start with 'class'");
}
return null;
}
private ASystemClassDefinition readSystem() throws ParserException,
LexException
{
if (lastToken().is(VDMToken.SYSTEM))
{
setCurrentModule("");
nextToken();
LexIdentifierToken classId = readIdToken("Expecting class ID");
ILexNameToken className = classId.getClassName();
setCurrentModule(classId.getName());
if (lastToken().is(VDMToken.IS))
{
nextToken();
checkFor(VDMToken.SUBCLASS, 2075, "Expecting 'is subclass of'");
checkFor(VDMToken.OF, 2076, "Expecting 'is subclass of'");
throwMessage(2280, "System class cannot be a subclass");
}
List<PDefinition> members = new Vector<PDefinition>();
DefinitionReader dr = getDefinitionReader();
while (lastToken().is(VDMToken.INSTANCE)
|| lastToken().is(VDMToken.OPERATIONS))
{
if (lastToken().is(VDMToken.INSTANCE))
{
members.addAll(dr.readInstanceVariables());
} else
{
members.addAll(dr.readOperations());
}
}
switch (lastToken().type)
{
case TYPES:
case VALUES:
case FUNCTIONS:
case THREAD:
case SYNC:
throwMessage(2290, "System class can only define instance variables and a constructor");
break;
case END:
nextToken();
break;
default:
throwMessage(2077, "Expecting 'end' after system members");
}
LexIdentifierToken endname = readIdToken("Expecting 'end <name>' after system members");
if (classId != null && !classId.equals(endname))
{
throwMessage(2007, "Expecting 'end " + classId.getName() + "'");
}
return AstFactory.newASystemClassDefinition(className, members);// new
// ASystemClassDefinition(className.location,className,NameScope.CLASSNAME,true,null,new
// AAccessSpecifierAccessSpecifier(new
// APublicAccess(), null, null),null,
// null,null, new LexNameList(),
// members,null,null,false,null, null,
// false, null,
// false,false,false,null,false,null);
// for (PDefinition pDefinition : def.getDefinitions())
// {
// pDefinition.setClassDefinition(def);
// }
// return def;
} else
{
throwMessage(2008, "System class does not start with 'system'");
}
return null;
}
}