/* * #%~ * The Overture Abstract Syntax Tree * %% * Copyright (C) 2008 - 2014 Overture * %% * This program 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. * * This program 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 this program. If not, see * <http://www.gnu.org/licenses/gpl-3.0.html>. * #~% */ package org.overture.ast.lex; import java.io.Serializable; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Vector; import org.overture.ast.analysis.AnalysisException; import org.overture.ast.analysis.intf.IAnalysis; import org.overture.ast.analysis.intf.IAnswer; import org.overture.ast.analysis.intf.IQuestion; import org.overture.ast.analysis.intf.IQuestionAnswer; import org.overture.ast.intf.lex.ILexIdentifierToken; import org.overture.ast.intf.lex.ILexLocation; import org.overture.ast.intf.lex.ILexNameToken; import org.overture.ast.messages.InternalException; import org.overture.ast.types.PType; import org.overture.ast.util.Utils; public class LexNameToken extends LexToken implements ILexNameToken, Serializable { private static final long serialVersionUID = 1L; public final String module; public final String name; public final boolean old; public final boolean explicit; // Name has an explicit module/class public List<PType> typeQualifier = null; private int hashcode = 0; @Override public boolean getExplicit() { return explicit; } public String getName() { return name; } @Override public boolean getOld() { return old; } @Override public List<PType> typeQualifier() { return typeQualifier; } public LexNameToken(String module, String name, ILexLocation location, boolean old, boolean explicit) { super(location, VDMToken.NAME); this.module = module; this.name = name; this.old = old; this.explicit = explicit; } public LexNameToken(String module, String name, ILexLocation location) { this(module, name, location, false, false); } public LexNameToken(String module, ILexIdentifierToken id) { super(id.getLocation(), VDMToken.NAME); this.module = module; this.name = id.getName(); this.old = id.isOld(); this.explicit = false; } public LexIdentifierToken getIdentifier() { return new LexIdentifierToken(name, old, location); } public LexNameToken getExplicit(boolean ex) { return new LexNameToken(module, name, location, old, ex); } public LexNameToken getOldName() { return new LexNameToken(module, new LexIdentifierToken(name, true, location)); } public String getFullName() { // Flat specifications have blank module names return (explicit ? module.length() > 0 ? module + "`" : "" : "") + name + (old ? "~" : ""); // NB. No qualifier } public LexNameToken getNewName() { return new LexNameToken(module, new LexIdentifierToken(name, false, location)); } public String getSimpleName() { return name; } public LexNameToken getPreName(ILexLocation l) { return new LexNameToken(module, "pre_" + name, l); } public LexNameToken getPostName(ILexLocation l) { return new LexNameToken(module, "post_" + name, l); } public LexNameToken getInvName(ILexLocation l) { return new LexNameToken(module, "inv_" + name, l); } public LexNameToken getInitName(ILexLocation l) { return new LexNameToken(module, "init_" + name, l); } public boolean isReserved() { return name.startsWith("pre_") || name.startsWith("post_") || name.startsWith("inv_") || name.startsWith("init_"); } public LexNameToken getModifiedName(String classname) { LexNameToken mod = new LexNameToken(classname, name, location, old, explicit); mod.setTypeQualifier(typeQualifier); return mod; } public LexNameToken getModifiedName(List<PType> qualifier) { LexNameToken mod = new LexNameToken(module, name, location, old, explicit); mod.setTypeQualifier(qualifier); return mod; } public LexNameToken getSelfName() { if (module.equals("CLASS")) { return new LexNameToken(name, "self", location); } else { return new LexNameToken(module, "self", location); } } public LexNameToken getThreadName() { if (module.equals("CLASS")) { LexNameToken thread = new LexNameToken(name, "thread", location); thread.setTypeQualifier(new Vector<PType>()); return thread; } else { LexNameToken thread = new LexNameToken(module, "thread", location); thread.setTypeQualifier(new Vector<PType>()); return thread; } } public LexNameToken getThreadName(ILexLocation loc) { LexNameToken thread = new LexNameToken(loc.getModule(), "thread", loc); thread.setTypeQualifier(new Vector<PType>()); return thread; } public LexNameToken getPerName(ILexLocation loc) { return new LexNameToken(module, "per_" + name, loc); } public LexNameToken getClassName() { return new LexNameToken("CLASS", name, location); } public void setTypeQualifier(List<PType> types) { if (hashcode != 0) { if (typeQualifier == null && types != null || typeQualifier != null && !typeQualifier.equals(types)) { throw new InternalException(2, "Cannot change type qualifier: " + this + " to " + types); } } typeQualifier = types; } /** * Basic equals method for LexNameTokens. This method does not handle type qualifiers in that case use * {@link HackLexNameToken} */ @SuppressWarnings("javadoc") @Override public boolean equals(Object other) { if (!(other instanceof ILexNameToken)) { return false; } ILexNameToken lother = (ILexNameToken) other; if (typeQualifier != null && lother.getTypeQualifier() != null) { // For testing purpose the following line can be uncommented. The Type Checker is not supose to rely on this // equal method but use the HelpLexNameToken class for that // throw new InternalException(-1, "Use HelpLexNameToken.isEqual to compare"); } else if (typeQualifier != null && lother.getTypeQualifier() == null || typeQualifier == null && lother.getTypeQualifier() != null) { return false; } return matches(lother); } public boolean matches(ILexNameToken other) { return module.equals(other.getModule()) && name.equals(other.getName()) && old == other.getOld(); } @Override // what does this overrides? public int hashCode() { if (hashcode == 0) { hashcode = module.hashCode() + name.hashCode() + (old ? 1 : 0) + (typeQualifier == null ? 0 : typeQualifier.toString().hashCode()); } return hashcode; } @Override public String toString() { return getFullName() + (typeQualifier == null ? "" : "(" + Utils.listToString(typeQualifier) + ")"); } public LexNameToken copy() { LexNameToken c = new LexNameToken(module, name, location, old, explicit); c.setTypeQualifier(typeQualifier); return c; } public int compareTo(ILexNameToken o) { return toString().compareTo(o.toString()); } public ILexLocation getLocation() { return location; } public String getModule() { return module; } @Override public ILexNameToken clone() { return copy(); } public List<PType> getTypeQualifier() { return typeQualifier; } public boolean isOld() { return old; } @Override public void apply(IAnalysis analysis) throws AnalysisException { analysis.caseILexNameToken(this); } @Override public <A> A apply(IAnswer<A> caller) throws AnalysisException { return caller.caseILexNameToken(this); } @Override public <Q> void apply(IQuestion<Q> caller, Q question) throws AnalysisException { caller.caseILexNameToken(this, question); } @Override public <Q, A> A apply(IQuestionAnswer<Q, A> caller, Q question) throws AnalysisException { return caller.caseILexNameToken(this, question); } /** * Creates a map of all field names and their value * * @param includeInheritedFields * if true all inherited fields are included * @return a a map of names to values of all fields */ @Override public Map<String, Object> getChildren(Boolean includeInheritedFields) { Map<String, Object> fields = new HashMap<String, Object>(); if (includeInheritedFields) { fields.putAll(super.getChildren(includeInheritedFields)); } fields.put("module", this.module); fields.put("name", this.name); fields.put("old", this.old); fields.put("explicit", this.explicit); return fields; } }