blob: 12e2ed773d3988e226ec44f399a48f1be7861e64 [file] [log] [blame]
/* --COPYRIGHT--,EPL
* Copyright (c) 2008 Texas Instruments and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Texas Instruments - initial implementation
*
* --/COPYRIGHT--*/
package xdc.services.spec;
import java.util.*;
public class Decl
extends Node
{
// Static Serialization UID
static final long serialVersionUID = 3468768778188819860L;
Decl over = null;
// Annexable
public interface Annexable
{
}
// AuxDef
public interface AuxDef
{
}
// IsType
public interface IsType
{
}
// LocalUnit
public interface LocalUnit
{
Unit getUnit();
}
// OverridableDef
public interface OverridableDef
{
}
// Signature
public interface Signature
{
enum ObjKind { NONE, SINGLE, ARRAY };
Type getType();
String getTypeCode();
String getTypeSig();
}
// Sizeable
public interface Sizeable
{
void sizeof( List<String> sL );
}
private static void checkSig( Signature sig )
{
Signature.ObjKind kind = Decl.objKind(sig);
if (kind == Signature.ObjKind.NONE) {
return;
}
if (sig instanceof Decl.Field) {
Decl.Struct str = (Decl.Struct)((Decl.Field)sig).getParent();
if (str.getName().equals("Module_State") || str.getName().equals("Instance_State")) {
return;
}
}
Decl decl = (Decl)sig;
Session ses = decl.getSession();
ses.msg.error(decl.getAtom(), "bad use of Object type");
}
// overrides
public Decl overrides()
{
return this.over;
}
// finalCheck
void finalCheck()
{
super.finalCheck();
List<? extends Decl> dL = this.getChildren();
if (dL == null) {
return;
}
for (Decl d : dL) {
d.finalCheck();
}
}
// getChildren
public List<? extends Decl> getChildren()
{
return null;
}
// getQualName
public String getQualName()
{
return this.parent.getQualName() + '.' + this.name.text;
}
// getXmlTag
public String getXmlTag()
{
return this.getClass().getSimpleName().toLowerCase();
}
/**
* Generate the XDoc for a Decl. Unlike other Nodes, documentation
* for a Decl accumulates any docs coming from parent interfaces. This
* method collects the docs from the override chain, then appends the
* docs specific for this Decl.
*/
void parseXDoc() {
XDoc od = overrides() == null ? null : overrides().makeXDoc();
this.xdoc = new XDoc(getDocs(), od, summary, isNodoc);
}
// objKind
public static final Decl.Signature.ObjKind objKind( Decl.Signature sig )
{
return objKind(sig.getType(), sig.getTypeCode());
}
public static final Decl.Signature.ObjKind objKind( Type type, String tcode )
{
if (tcode.equals("O")) {
return Decl.Signature.ObjKind.SINGLE;
}
else if (tcode.equals("AO")) {
Type.Array tarr = (Type.Array)type;
return tarr.getDim() != null ? Decl.Signature.ObjKind.ARRAY : Decl.Signature.ObjKind.NONE;
}
else {
return Decl.Signature.ObjKind.NONE;
}
}
// parseDocs
void parseDocs()
{
super.parseDocs();
List<? extends Decl> dL = this.getChildren();
if (dL == null) {
return;
}
for (Decl d : dL) {
d.parseDocs();
}
}
// pass1Check
void pass1Check()
{
List<? extends Decl> dL = this.getChildren();
if (dL == null) {
return;
}
for (Decl d : dL) {
d.bindParent(d instanceof Decl.EnumVal ? this.parent : this);
Session ses = d.getSession();
if (!ses.enterNode(d.getQualName(), d)) {
ses.msg.error(d.name, "multiple declaration in enclosing scope");
continue;
}
}
}
// resolve
void resolve( Unit uspec )
{
// TODO: common stuff ???
}
// Decl.Arg
static public class Arg
extends Decl
implements Decl.Signature
{
static final long serialVersionUID = -7298373774659045568L;
Type type;
Expr init;
Arg( Atom name, EnumSet<Qual> quals, Type type )
{
this(name, quals, type, null);
}
Arg( Atom name, EnumSet<Qual> quals, Type type, Expr init )
{
this.name = name;
this.quals = quals;
this.type = type;
this.init = init;
}
// getInit
public final Expr getInit()
{
return this.init;
}
// getType
public final Type getType()
{
return this.type;
}
// getTypeCode
public final String getTypeCode()
{
return ((this.type == null) ? "" : this.type.tcode());
}
// getTypeSig
public final String getTypeSig()
{
return ((this.type == null) ? "" : this.type.tsig());
}
// resolve
void resolve( Unit uspec )
{
if (this.type != null) {
this.type.resolve(uspec);
if (this.init != null) {
this.init.resolve(uspec);
}
}
Decl.checkSig(this);
}
}
// Decl.Config
static public class Config
extends Decl
implements Decl.Annexable, Decl.Signature
{
static final long serialVersionUID = -3472392753188999914L;
Type type;
Expr init;
static HashSet<String> reservedAttrs = new HashSet(Arrays.asList(new String[] {
Attr.A_Annex,
Attr.A_CommandOption,
Attr.A_Facet,
Attr.A_System,
}));
Config( Atom name, EnumSet<Qual> quals, Type type, Expr init )
{
this.name = name;
this.quals = quals;
this.type = type;
this.init = init;
}
// checkFacet
private void checkFacet()
{
if (!this.isMeta()) {
ses.msg.error(this.name, "@Facet configs must be metaonly");
}
Ref r = this.type.tspec().getRef();
Node n = r.getNode();
HashSet<String> facSet = ((Unit)this.getParent()).facSet;
if (!(n instanceof Unit) || !n.hasAttr(Attr.A_Facet) || !r.getId().equals("Instance")) {
ses.msg.error(this.name, "@Facet config types must be a @Facet Instance");
}
else if (facSet.contains(n.getQualName())) {
ses.msg.error(this.name, "multiple @Facet configs of the same type");
}
else {
facSet.add(n.getQualName());
}
}
// finalCheck
void finalCheck()
{
super.finalCheck();
String tc = this.getTypeCode();
if (this.hasAttr(Attr.A_Facet)) {
this.checkFacet();
}
}
// getInit
public final Expr getInit()
{
return this.init;
}
// getType
public final Type getType()
{
return this.type;
}
// getTypeCode
public final String getTypeCode()
{
return ((this.type == null) ? "" : this.type.tcode());
}
// getTypeSig
public final String getTypeSig()
{
return ((this.type == null) ? "" : this.type.tsig());
}
// overrides
public final Decl.Config overrides()
{
return (Decl.Config) this.over;
}
// resolve
void resolve( Unit uspec )
{
this.enterAttrs(Decl.Config.reservedAttrs);
if (this.type != null) {
this.type.resolve(uspec, true);
if (this.init != null) {
this.init.resolve(uspec);
}
}
Decl.checkSig(this);
}
}
// Decl.Const
static public class Const
extends Decl
implements Decl.AuxDef, Decl.OverridableDef, Decl.Signature
{
static final long serialVersionUID = -5129490619630763331L;
Type type;
Expr init;
Const( Atom name, EnumSet<Qual> quals, Type type, Expr init )
{
this.name = name;
this.quals = quals;
this.type = type;
this.init = init;
if (this.init != null) {
this.quals.add(Qual.FINAL);
}
}
// getInit
public final Expr getInit()
{
return this.init;
}
// getType
public final Type getType()
{
return this.type;
}
// getTypeCode
public final String getTypeCode()
{
return ((this.type == null) ? "" : this.type.tcode());
}
// getTypeSig
public final String getTypeSig()
{
return ((this.type == null) ? "" : this.type.tsig());
}
// resolve
void resolve( Unit uspec )
{
if (this.type != null) {
this.type.resolve(uspec);
if (this.init != null) {
this.init.resolve(uspec);
}
else {
((Unit) this.parent).custHdr = true;
}
}
Decl.checkSig(this);
}
}
// Decl.Enum
static public class Enum
extends Decl
implements Decl.AuxDef, Decl.IsType, Decl.Sizeable
{
static final long serialVersionUID = -7076604082337550848L;
List<EnumVal> vals;
Type.Spec rep;
Enum( Atom name, EnumSet<Qual> quals, List<EnumVal> vals, Type.Spec rep )
{
this.name = name;
this.quals = quals;
this.vals = vals;
this.rep = rep;
}
// getChildren
public List<EnumVal> getChildren()
{
return this.vals;
}
// getRep
public final Type.Spec getRep()
{
return this.rep;
}
// getVals
public final List<EnumVal> getVals()
{
return this.vals;
}
// resolve
void resolve( Unit uspec )
{
for (EnumVal e : this.vals) {
if (e.init != null) {
e.init.resolve(uspec);
}
}
if (this.rep != null) {
this.rep.resolve(uspec);
}
}
// sizeof
public void sizeof( List<String> sL )
{
if (this.rep != null) {
this.rep.sizeof(sL);
}
else {
sL.add("N" + this.getQualName());
}
}
}
// Decl.EnumVal
static public class EnumVal
extends Decl
implements Decl.AuxDef
{
static final long serialVersionUID = -3594208666128592956L;
Expr init;
EnumVal( Atom name, EnumSet<Qual> quals, Expr init )
{
this.name = name;
this.quals = quals;
this.init = init;
}
// getInit
public final Expr getInit()
{
return this.init;
}
}
// Decl.Error
static class Error
extends Decl
{
static final long serialVersionUID = 3065995409031385368L;
Error()
{
}
}
// Decl.Extern
static public class Extern
extends Decl
implements Decl.AuxDef, Decl.Signature
{
static final long serialVersionUID = -5537398406232068500L;
Type type;
Atom init;
Extern( Atom name, EnumSet<Qual> quals, Type type, Atom init )
{
this.name = name;
this.quals = quals;
this.type = type;
this.init = init;
}
// finalCheck
void finalCheck()
{
super.finalCheck();
if (!this.parent.isMod()) {
ses.msg.error(this.name, "extern declaration permitted only in modules");
}
}
// getType
public final Type getType()
{
return this.type;
}
// getTypeCode
public final String getTypeCode()
{
return ((this.type == null) ? "" : this.type.tcode());
}
// getTypeSig
public final String getTypeSig()
{
return ((this.type == null) ? "" : this.type.tsig());
}
// getValue
public final String getValue()
{
return ((this.init == null) ? this.getQualName().replace('.', '_') : this.init.text);
}
// resolve
void resolve( Unit uspec )
{
if (this.type != null) {
this.type.resolve(uspec);
}
Decl.checkSig(this);
}
}
// Decl.Field
static public class Field
extends Decl
implements Decl.Signature
{
static final long serialVersionUID = 1865932903245823181L;
Type type;
Field( Atom name, EnumSet<Qual> quals, Type type )
{
this.name = name;
this.quals = quals;
this.type = type;
}
// getType
public final Type getType()
{
return this.type;
}
// getTypeCode
public final String getTypeCode()
{
return ((this.type == null) ? "" : this.type.tcode());
}
// getTypeSig
public final String getTypeSig()
{
return ((this.type == null) ? "" : this.type.tsig());
}
// resolve
void resolve( Unit uspec )
{
if (this.type != null) {
this.type.resolve(uspec);
}
Decl.checkSig(this);
}
}
// Decl.Fxn
static public class Fxn
extends Decl
implements Decl.Annexable, Decl.Signature
{
static final long serialVersionUID = 4734759580216702060L;
Type type;
List<Arg> args;
boolean isVarg;
int minargc = 0;
String structName = null;
static HashSet<String> reservedAttrs = new HashSet(Arrays.asList(new String[] {
Attr.A_Annex,
Attr.A_DirectCall,
Attr.A_Macro,
Attr.A_System,
}));
Fxn( Atom name, EnumSet<Qual> quals, Type type, List<Arg> args, boolean isVarg )
{
this.name = name;
this.quals = quals;
this.type = type;
this.args = args;
this.isVarg = isVarg;
}
// finalCheck
void finalCheck()
{
super.finalCheck();
if (this.type == null) {
return;
}
if (this.type instanceof Type.Creator && this.isStatic()) {
ses.msg.error(this.name, "declaration must be per-instance");
}
Type t = this.type.root();
if (t != null && (t instanceof Type.Fxn || t instanceof Type.Array)) {
ses.msg.error(this.name, "function can't return functions or arrays");
}
if (!this.isStruct()) {
return;
}
if (!this.isStatic()) {
ses.msg.error(this.name, "struct-qualified functions must be module-wide");
}
String fn = this.name.getText();
this.name.replaceText(fn.replace('.', '_'));
int k = fn.lastIndexOf('.');
if (k != -1) {
String sn = fn.substring(0, k);
String qn = this.parent.getQualName() + '.' + sn;
if (!(ses.lookup(qn) instanceof Decl.Struct)) {
ses.msg.error(this.name, "qualified name must reference a struct in scope");
}
}
}
// getArgs
public final List<Arg> getArgs()
{
return this.args;
}
// getChildren
public List<Arg> getChildren()
{
return this.args;
}
// getMinArgc
public final int getMinArgc()
{
return this.minargc;
}
// getStructName
public final String getStructName()
{
return this.structName;
}
// getType
public final Type getType()
{
return this.type;
}
// getTypeCode
public final String getTypeCode()
{
if (this.type == null) {
return ("");
}
return this.type instanceof Type.Creator ? "C" : this.type.tcode();
}
// getTypeSig
public final String getTypeSig()
{
if (this.type == null) {
return "void";
}
String res = this.type instanceof Type.Creator ? "$Instance" : this.type.tsig();
res += "(*)(";
String sp = "";
if (this.args.size() == 0 && !this.isVarg) {
return res + "xdc_Void)";
}
for (Arg arg : this.args) {
res += sp + arg.type.tsig();
sp = ",";
}
res += this.isVarg ? ",...)" : ")";
return res;
}
// isLoggable
public final boolean isLoggable()
{
return
!this.isMeta() &&
!this.isSys() &&
!this.isInternal() &&
!this.hasAttr(Attr.A_Macro) &&
!this.hasAttr(Attr.A_DirectCall);
}
// isStruct
public final boolean isStruct()
{
return this.structName != null;
}
// isVarg
public final boolean isVarg()
{
return this.isVarg;
}
// overrides
public final Decl.Fxn overrides()
{
return (Decl.Fxn) this.over;
}
// resolve
void resolve( Unit uspec )
{
this.enterAttrs(Decl.Fxn.reservedAttrs);
if (this.hasAttr(Attr.A_Macro)) {
((Unit) this.parent).custHdr = true;
}
if (this.type == null) {
return;
}
String fn = this.name.getText();
int k = fn.lastIndexOf('.');
if (k != -1) {
this.structName = fn.substring(0, k);
Decl.Arg arg = new Decl.Arg(
new Atom("__this"),
EnumSet.noneOf(Qual.class),
new Type.Ptr(
new Type.Declarator(
new Type.Spec(new Ref(null, this.name.copy(this.structName)), null, false, null),
new Atom("__this")),
EnumSet.noneOf(Type.Modifier.class)),
null);
this.args.add(0, arg);
}
this.type.resolve(uspec);
boolean defflg = false;
for (Arg arg : this.args) {
if (arg.init == null) {
if (!defflg) {
this.minargc++;
}
else {
ses.msg.error(arg.name, "default value required");
}
}
else {
defflg = true;
}
arg.resolve(uspec);
}
if (this.isStruct()) {
if (!(this.args.get(0).getType().tspec().getRef().getNode() instanceof Decl.Struct)) {
ses.msg.error(this.name, "qualified name does not reference a struct type");
}
this.minargc--;
}
Decl.checkSig(this);
}
}
// Decl.Imp
static public class Imp
extends Decl
implements Decl.AuxDef, Decl.LocalUnit
{
static final long serialVersionUID = -2L;
Import imp;
Sup sup;
Imp( Atom name, Import imp )
{
this(name, imp, null);
}
Imp( Atom name, Sup sup )
{
this(name, null, sup);
}
private Imp( Atom name, Import imp, Sup sup )
{
this.name = name;
this.imp = imp;
this.sup = sup;
this.quals = EnumSet.noneOf(Qual.class);
}
public final void bindImport( Import imp )
{
this.imp = imp;
}
public final Import getImport()
{
return this.imp;
}
public final Unit getUnit()
{
return this.imp.unit;
}
// finalCheck
void finalCheck()
{
super.finalCheck();
if (this.imp == null) {
ses.msg.error(this.name, "no corresponding import");
}
boolean found = true;
if (this.sup != null) {
found = false;
for (Unit iu : this.getUnit().getInherits()) {
if (iu == sup.getUnit()) {
found = true;
break;
}
}
}
if (!found) {
ses.msg.error(this.name, "does not inherit from " + sup.getUnit().getQualName());
throw new SessionRuntimeException("parser failed");
}
}
// resolve
void resolve( Unit u )
{
if (this.sup != null) {
this.sup.resolve(u);
}
}
}
// Decl.Proxy
static public class Proxy
extends Decl
implements Decl.LocalUnit
{
static final long serialVersionUID = -5207411272617839552L;
Sup sup;
Unit unit;
Proxy( Atom name, EnumSet<Qual> quals, Sup sup )
{
this.name = name;
this.quals = quals;
this.sup = sup;
}
// getInherits
public final Unit getInherits()
{
return this.sup.unit;
}
// getUnit
public final Unit getUnit()
{
Unit u = this.getParent().getSession().findUnit(
this.getParent().getQualName() + '_' + this.getName());
return u == null ? this.sup.unit : u;
}
}
// Decl.Struct
static public class Struct
extends Decl
implements Decl.AuxDef, Decl.IsType, Decl.Sizeable
{
static final long serialVersionUID = 8653474625146200716L;
List<Field> flds;
List<String> fldSizes;
boolean uflag;
static HashSet<String> reservedAttrs = new HashSet(Arrays.asList(new String[] {
Attr.A_Opaque,
Attr.A_XmlDtd,
}));
Struct( Atom name, EnumSet<Qual> quals, List<Field> flds, boolean uflag )
{
this.name = name;
this.quals = quals;
this.flds = flds;
this.uflag = uflag;
this.fldSizes = new ArrayList();
}
// finalCheck
void finalCheck()
{
super.finalCheck();
if (this.name.text.equals("Object")) {
ses.msg.error(this.name, "reserved name");
}
}
// getChildren
public List<Field> getChildren()
{
return this.flds;
}
// getFields
public final List<Field> getFields()
{
return this.flds;
}
// getSizes
public final List<String> getSizes()
{
return this.fldSizes;
}
// getXmlTag
public String getXmlTag()
{
return this.uflag ? "union" : "struct";
}
// isAnon
public final boolean isAnon()
{
return this.name.text.startsWith("__struct__");
}
// isUnion
public final boolean isUnion()
{
return this.uflag;
}
// resolve
void resolve( Unit uspec )
{
this.enterAttrs(Decl.Struct.reservedAttrs);
if (this.flds == null) {
return;
}
boolean isState =
this.getName().equals("Module_State") || this.getName().equals("Instance_State");
for (Field fld : this.flds) {
fld.resolve(uspec);
}
if (isState) {
List<Field> fL = new ArrayList<Field>();
for (ListIterator<Field> it = this.flds.listIterator(); it.hasNext(); ) {
Field fld = it.next();
if (Decl.objKind(fld) != Decl.Signature.ObjKind.NONE) {
fL.add(fld);
it.remove();
}
}
this.flds.addAll(fL);
}
for (Field fld : this.flds) {
fld.type.sizeof(this.fldSizes);
}
}
// sizeof
public void sizeof( List<String> sL )
{
Unit unit = (Unit) this.parent;
sL.add("S" + unit.getQualName() + ';' + this.name.text);
}
}
// Decl.Typedef
static public class Typedef
extends Decl
implements Decl.AuxDef, Decl.IsType, Decl.Signature, Decl.Sizeable
{
static final long serialVersionUID = -3286912318315178858L;
Type type;
static HashSet<String> reservedAttrs = new HashSet(Arrays
.asList(new String[] { Attr.A_Encoded,
}));
Typedef( Atom name, EnumSet<Qual> quals, Type type )
{
this.name = name;
this.quals = quals;
this.type = type;
}
// getType
public final Type getType()
{
return this.type;
}
// getTypeCode
public final String getTypeCode()
{
return ((this.type == null) ? "" : this.type.tcode());
}
// getTypeSig
public final String getTypeSig()
{
return ((this.type == null) ? "" : this.type.tsig());
}
// resolve
void resolve( Unit uspec )
{
this.enterAttrs(Decl.Typedef.reservedAttrs);
if (this.hasAttr(Attr.A_Encoded)) {
((Unit) this.parent).custHdr = true;
}
if (this.type == null) {
return;
}
this.type.resolve(uspec, this.attrBool(Attr.A_Encoded));
Type t = this.type;
while (t instanceof Type.Declarator) {
Node n = t.tspec().getRef().getNode();
if (n == this) {
ses.msg.error(this.name, "circular typedef");
return;
}
if (!(n instanceof Typedef)) {
break;
}
t = ((Typedef) n).getType();
}
Decl.checkSig(this);
}
// sizeof
public void sizeof( List<String> sL )
{
if (this.attrBool(Attr.A_Encoded)) {
Unit unit = (Unit) this.parent;
sL.add("E" + unit.getQualName() + ';' + this.name.text);
}
else {
this.type.sizeof(sL);
}
}
}
}