blob: 0070db099dedecf6a3509c08730f770111086509 [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 Unit
extends Node
{
// Static Serialization UID
static final long serialVersionUID = -1475297028398889384L;
List<Decl.Config> cfgs; // most specific override
Decl.Fxn creator;
int curPass;
boolean custHdr;
List<Decl> decls;
Sup dlg;
List<Decl.Fxn> fxns; // all external fxns, most specific override
int icfgCnt;
private List<Decl.Fxn> ifxns;
List<Import> imps;
boolean inherits;
boolean iobjFlag;
Sup isa;
List<Decl.Fxn> mbrs; // target-fxns, order of decl; may contain dups if override
String pkgName;
boolean proxy;
List<Unit> prxs;
boolean rtsFlag;
int scfgCnt;
boolean sizeFlag;
Set<Unit> uses;
transient HashSet<String> facSet = new HashSet();
transient List<Impl.Assign> cfgAssigns;
transient List<Impl.Body> fxnBodies;
transient String codeFrag;
static HashSet<String> reservedAttrs = new HashSet(Arrays.asList(new String[] {
Attr.A_CustomHeader,
Attr.A_Facet,
Attr.A_Gated,
Attr.A_GlobalNames,
Attr.A_InstanceInitError,
Attr.A_InstanceFinalize,
Attr.A_ModuleStartup,
Attr.A_NoRuntime,
Attr.A_Prefix,
Attr.A_Proxy,
Attr.A_TargetHeader,
Attr.A_Template,
}));
Unit(
Atom name,
String pkgName,
EnumSet<Qual> quals,
List<Decl> decls,
List<Import> imps,
Sup isa, Sup dlg )
{
this.name = name;
this.pkgName = pkgName;
this.quals = quals;
this.decls = decls;
this.imps = imps;
this.isa = isa;
this.dlg = dlg;
this.cfgs = new ArrayList();
this.creator = null;
this.curPass = 0;
this.fxns = new ArrayList();
this.icfgCnt = 0;
this.ifxns = new ArrayList();
this.inherits = false;
this.iobjFlag = false;
this.mbrs = new ArrayList();
this.proxy = false;
this.prxs = new ArrayList();
this.rtsFlag = true;
this.scfgCnt = 0;
this.sizeFlag = true;
this.uses = new HashSet();
if (this.getQualName().equals("xdc.runtime.IInstance")) {
return;
}
if (this.isa == null && !this.isMeta() && !this.getQualName().equals("xdc.runtime.IModule")) {
Atom a = this.name.copy("xdc.runtime.IModule");
this.isa = new Sup(a);
// TODO: add to incvec???
}
}
// addProxy
private void addProxy( Decl.Proxy prx, boolean strict )
{
prx.sup.resolve(this);
if (this.isInter()) {
return;
}
if (this.isProxy()) {
return;
}
EnumSet<Qual> qS = EnumSet.copyOf(prx.sup.unit.quals);
qS.remove(Qual.INTERFACE);
qS.add(Qual.MODULE);
Unit pu;
pu = new Unit(prx.name.copy(this.name.text + '_' + prx.name.text), this.pkgName, qS,
new ArrayList(), new ArrayList(), prx.sup, null);
pu.bindParent(this.getParent());
pu.proxy = true;
pu.pass1Check();
pu.pass2Check(strict);
pu.finalCheck();
this.prxs.add(pu);
this.uses.add(pu);
}
/*
private void addProxy( Decl.Proxy prx, String pre )
{
EnumSet<Qual> qS = EnumSet.copyOf(prx.sup.unit.quals);
qS.remove(Qual.INTERFACE);
qS.add(Qual.MODULE);
Unit pu;
pu = new Unit(prx.name.copy(this.name.text + pre + "_" + prx.name.text), this.pkgName, qS,
new ArrayList(), new ArrayList(), prx.sup, null);
pu.bindParent(this.getParent());
pu.proxy = true;
pu.pass1Check();
pu.pass2Check();
this.prxs.add(pu);
this.uses.add(pu);
for (Decl d : prx.sup.unit.decls) {
if (d instanceof Decl.Proxy) {
this.addProxy((Decl.Proxy)d, "_" + prx.name.text);
}
}
}
*/
// addUse
void addUse( Ref ref )
{
// TODO: not needed ???
}
// bindCodeFrag
void bindCodeFrag( String cf )
{
this.codeFrag = cf;
}
// bindCfgAssigns
void bindCfgAssigns( List<Impl.Assign> aL)
{
this.cfgAssigns = aL;
}
// bindFxnBodies
void bindFxnBodies( List<Impl.Body> fL )
{
this.fxnBodies = fL;
}
// checkOver
private void checkOver( Decl d, boolean strict )
{
if (d.isInternal() || this.getSuper() == null) {
return;
}
if (d.name.text.equals("create")) {
return;
}
Decl over = this.lookupSup(d.name.text, this.getSuper());
d.over = over;
if (over != null) {
if (!d.isOver()) {
ses.msg.error(d.name, "multiple declaration in current scope");
return;
}
if (over.isFinal()) {
ses.msg.error(d.name, "can't override final declaration");
return;
}
if (over instanceof Decl.Struct) {
if (((Decl.Struct)over).flds != null) {
ses.msg.error(d.name, "can only override an incomplete struct");
}
if (((Decl.Struct)d).flds == null) {
ses.msg.error(d.name, "struct override cannot be incomplete");
}
return;
}
String osig = ((Decl.Signature) over).getTypeSig();
String sig = ((Decl.Signature) d).getTypeSig();
boolean compat = osig.equals(sig)
&& over.getClass() == d.getClass()
&& over.isStatic() == d.isStatic()
&& over.isMeta() == d.isMeta();
if (over.isReadonly() != d.isReadonly()) {
if (strict || d.isReadonly()) {
compat = false;
}
else {
ses.msg.warn(d.name, "can't remove readonly qualification");
}
}
if (!compat) {
ses.msg.error(d.name, "incompatible override");
return;
}
}
else if (d.isOver()) {
ses.msg.error(d.name, "no definition to override");
return;
}
}
// decl
public final Decl decl( String name )
{
return this.parent.ses.findDecl(this.getQualName() + '.' + name);
}
// delegatesTo
public final Unit delegatesTo()
{
return this.dlg == null ? null : this.dlg.unit;
}
// finalCheck
void finalCheck()
{
//TODO: handle @Facet uniqueness when inheriting an interface
List<Decl> cL = new ArrayList();
List<Decl> eL = new ArrayList();
super.finalCheck();
for (Decl d : this.decls) {
if (d.parent == this) {
d.finalCheck();
}
if (d instanceof Decl.Fxn) {
Decl.Fxn fxn = (Decl.Fxn) d;
if (fxn.over != null) {
this.fxns.remove(fxn.over);
}
if (fxn.parent != this && fxn.isStruct()) {
fxn.finalCheck();
}
}
else if (d instanceof Decl.Config) {
Decl.Config cfg = (Decl.Config) d;
if (cfg.over != null) {
this.cfgs.remove(cfg.over);
}
}
else if (d instanceof Decl.Enum) {
eL.addAll(d.getChildren());
}
else if (d instanceof Decl.Const && d.over != null) {
cL.add(d.over);
}
}
this.decls.addAll(eL);
this.decls.removeAll(cL);
if (this.isInter() || this.isMeta()) {
return;
}
int maxAnnex = 0;
for (Decl d: this.decls) {
if (d instanceof Decl.Annexable) {
int a = d.attrInt(Attr.A_Annex);
if (a > maxAnnex) {
maxAnnex = a;
}
}
}
if (maxAnnex == 0) {
return;
}
List<Decl> dL = new ArrayList();
for (int i = 1; i <= maxAnnex; i++) {
for (Decl d: this.decls) {
if (!(d instanceof Decl.Annexable) || d.attrInt(Attr.A_Annex) != i) {
continue;
}
dL.add(d);
if (d instanceof Decl.Config) {
this.cfgs.remove(d);
this.cfgs.add((Decl.Config)d);
}
else if (d instanceof Decl.Fxn) {
this.fxns.remove(d);
this.mbrs.remove(d);
this.fxns.add((Decl.Fxn)d);
this.mbrs.add((Decl.Fxn)d);
}
}
}
this.decls.removeAll(dL);
this.decls.addAll(dL);
}
// getAllFxns
public final List<Decl.Fxn> getAllFxns()
{
return this.mbrs;
}
// getCodeFrag
public final String getCodeFrag()
{
return this.codeFrag;
}
// getCreator
public final Decl.Fxn getCreator()
{
return this.creator;
}
// getChildren
public List<Decl> getChildren()
{
return this.decls;
}
// getCfgAssigns
public final List<Impl.Assign> getCfgAssigns()
{
return this.cfgAssigns;
}
// getConfigs
public final List<Decl.Config> getConfigs()
{
return this.cfgs;
}
// getDecls
public final List<Decl> getDecls()
{
return this.decls;
}
// getEmbeds
public final Set<Unit> getEmbeds()
{
Set<Unit> res = new HashSet();
for (String name : new String[] {"Module_State", "Instance_State"}) {
Decl d = this.ses.findDecl(this, name);
if (d == null) {
continue;
}
for (Decl.Field fld : ((Decl.Struct)d).flds) {
if (Decl.objKind(fld) != Decl.Signature.ObjKind.NONE) {
res.add((Unit)fld.getType().tspec().getRef().getNode());
}
}
}
return res;
}
// getFxns
public final List<Decl.Fxn> getFxns()
{
return this.fxns;
}
// getFxnImpls
public final List<Impl.Body> getFxnImpls()
{
return this.fxnBodies;
}
// getImports
public final List<Import> getImports()
{
return this.imps;
}
// getInherits
public final List<Unit> getInherits()
{
List<Unit> uL = new ArrayList();
for (Unit iu = this.getSuper(); iu != null; iu = iu.getSuper()) {
uL.add(iu);
}
return uL;
}
// getInternFxns
public final List<Decl.Fxn> getInternFxns()
{
return this.ifxns;
}
// getProxies
public final List<Unit> getProxies()
{
return this.prxs;
}
// getPkgName
public final String getPkgName()
{
return this.pkgName;
}
// getQualName
public final String getQualName()
{
return this.pkgName + '.' + this.name.text;
}
// getSuper
public final Unit getSuper()
{
return
// this.inherits ? this.isa.unit :
this.dlg != null ? this.dlg.unit : this.isa != null ? this.isa.unit : null;
}
// getUses
public final Set<Unit> getUses()
{
return this.uses;
}
// getXmlTag
public final String getXmlTag()
{
return this.isMod() ? "module" : "interface";
}
// hasCustHdr
public final boolean hasCustHdr()
{
return this.custHdr;
}
// hasCreateArgs
public boolean hasCreateArgs()
{
return this.creator != null && this.creator.args.size() > 0;
}
// isForwarding
public final boolean isForwarding()
{
return this.proxy || this.dlg != null;
}
// isHeir
public final boolean isHeir()
{
return this.inherits;
}
// isProxy
public final boolean isProxy()
{
return this.proxy;
}
// isSized
public final boolean isSized()
{
return this.sizeFlag;
}
// hasInstObj
public final boolean hasInstObj()
{
return this.iobjFlag;
}
// lookupSup
private Decl lookupSup( String name, Unit su )
{
Decl cur = null;
for (; su != null; su = su.getSuper()) {
if ((cur = this.getSession().findDecl(su.getQualName() + '.' + name)) != null) {
break;
}
}
return cur;
}
// needsRuntime
public final boolean needsRuntime()
{
return this.rtsFlag == true;
}
// parseDocs
void parseDocs()
{
super.parseDocs();
for (Decl d : this.decls) {
if (!(d instanceof Decl.EnumVal)) {
d.parseDocs();
}
}
if (this.creator != null) {
this.creator.parseDocs();
}
}
// pass1Check
void pass1Check()
{
if (this.curPass >= 1) {
return;
}
else {
this.curPass = 1;
}
for (Decl d : this.decls) {
String qn = this.getQualName() + '.' + d.getName();
if (!this.getSession().enterNode(qn, d)) {
ses.msg.error(d.name, "multiple declaration in current unit");
continue;
}
d.bindParent(this);
d.pass1Check();
if (!d.isMeta() && d.name.text.indexOf('$') != -1) {
ses.msg.error(d.name, "only metaonly feature names can contain a '$'");
}
if (d.name.text.equals("Module_State")) {
if (d instanceof Decl.Struct && d.isInternal()) {
d.quals.add(Qual.SYSTEM);
}
else {
ses.msg.error(d.name, "must be an internal struct");
}
}
if (d.name.text.equals("Instance_State")) {
if (d instanceof Decl.Struct && d.isInternal()) {
d.quals.add(Qual.SYSTEM);
}
else {
ses.msg.error(d.name, "must be an internal struct");
}
}
if (d.name.text.equals("Instance_State")) {
if (d instanceof Decl.Struct && d.isInternal()) {
d.quals.add(Qual.SYSTEM);
this.iobjFlag = true;
}
else {
ses.msg.error(d.name, "must be an internal struct");
}
}
}
}
// pass2Check
void pass2Check(boolean strict)
{
if (this.curPass >= 2) {
return;
}
else {
this.curPass = 2;
}
// System.out.println("pass2: " + this.getQualName());
ses.enterNode(this.getQualName(), this);
for (Import i : this.imps) {
i.resolve(this);
}
if (this.isa != null) {
this.isa.pass2Check(this);
if (this.isa.unit.isMod()) {
ses.msg.error(this.name, "can't inherit from a module");
}
if (this.isMeta() != this.isa.unit.isMeta()) {
ses.msg.error(this.name,
"can't inherit an interface with a different metaonly qualifier");
}
this.uses.add(this.isa.unit);
if (!this.isa.iid.text.equals("xdc.runtime.IModule")) {
this.inherits = true;
}
}
if (this.dlg != null) {
this.dlg.pass2Check(this);
if (this.dlg.unit.isInter()) {
ses.msg.error(this.name, "can't delegate to an interface");
}
if (this.dlg.unit.isProxy()) {
ses.msg.error(this.name, "can't delegate to a proxy");
}
if (this.isMeta() != this.dlg.unit.isMeta()) {
ses.msg.error(this.name,
"can't delegate to a module with a different metaonly qualifier");
}
boolean iflg = false;
for (Sup sup = this.dlg.unit.isa; sup != null; sup = sup.unit.isa) {
if ((iflg = (sup.unit == this.isa.unit))) {
break;
}
}
if (!iflg) {
ses.msg.error(this.name, "delegate must inherit from this module's interface");
}
this.uses.add(this.dlg.unit);
this.sizeFlag = this.dlg.unit.sizeFlag;
}
if (ses.msg.hasErrors()) {
return;
}
Unit u2 = this.getSuper();
if (u2 != null) {
List<Decl> dL = new ArrayList();
for (Decl d : u2.decls) {
if (d.isExternal()) {
dL.add(d);
}
}
dL.addAll(this.decls);
this.decls = dL;
if (u2.isInst()) {
this.quals.add(Qual.INSTANCE);
}
}
if (u2 != null && u2.isInter()) {
List<Attr> aL = u2.attrs;
if (aL != null) {
aL = new ArrayList(aL);
if (this.attrs != null) {
aL.addAll(this.attrs);
}
this.attrs = aL;
}
}
this.enterAttrs(Unit.reservedAttrs);
if (this.attrs != null) {
for (Attr a : this.attrs) {
if (a.val != null) {
a.val.resolve(this);
}
}
}
if (this.attrBool(Attr.A_Gated) && this.isMod() && !this.isProxy()) {
Decl.Proxy prx = new Decl.Proxy(
new Atom("Module_GateProxy"),
EnumSet.of(Qual.INTERNAL),
new Sup(new Atom("xdc.runtime.IGateProvider"))
);
this.decls.add(prx);
prx.bindParent(this);
prx.pass1Check();
}
if (!this.isMeta()) {
this.proxy |= this.attrBool(Attr.A_Proxy);
}
Pkg curPkg = this.getSession().curPkg();
if (curPkg.getName().equals(this.pkgName)) {
String s = this.attrString(Attr.A_Template);
if (s != null) {
curPkg.miscSrcs.add(s);
}
if (this.hasAttr(Attr.A_CustomHeader)) {
if (this.isMeta()) {
ses.msg.error(this.name, "@CustomHeader can't be used in metaonly units");
}
else {
this.custHdr = true;
curPkg.miscSrcs.add("./" + this.getName() +"__prologue.h");
curPkg.miscSrcs.add("./" + this.getName() +"__epilogue.h");
}
}
if (this.hasAttr(Attr.A_TargetHeader) && !this.isMeta()) {
ses.msg.error(this.name, "@TargetHeader must be used in metaonly units");
}
}
if (this.proxy && this.isInter()) {
ses.msg.error(this.name, "only modules can serve as proxies");
}
if (this.hasAttr(Attr.A_Facet) && !this.isMeta()) {
ses.msg.error(this.name, "@Facet units must be metaonly");
}
if (this.isMod() && this.isInst() && !this.isProxy() && !this.isMeta() && !this.isHeir()) {
if (this.getSession().findDecl(this, "Instance_State") == null) {
ses.msg.error(this.name, "missing internal Instance_State declaration");
}
}
for (Decl d : this.decls) {
boolean flg = d.getName().equals("ticksPerSecond");
if (d.parent != this && d instanceof Decl.AuxDef &&
!(d instanceof Decl.OverridableDef) && !(d instanceof Decl.Struct)) {
String qn = this.getQualName() + '.' + d.getName();
if (!this.getSession().enterNode(qn, d)) {
ses.msg.error(d.name, "multiple declaration in current unit");
continue;
}
}
if (d.parent == this) {
d.resolve(this);
this.checkOver(d, strict);
}
if (d instanceof Decl.Fxn) {
Decl.Fxn fxn = (Decl.Fxn) d;
if (fxn.type instanceof Type.Creator) {
this.creator = fxn;
continue;
}
if (fxn.isExternal()) {
this.fxns.add(fxn);
this.mbrs.add(fxn);
}
else {
this.ifxns.add(fxn);
}
}
else if (d instanceof Decl.Config) {
Decl.Config cfg = (Decl.Config) d;
this.cfgs.add(cfg);
if (cfg.isStatic()) {
this.scfgCnt++;
}
else {
this.icfgCnt++;
}
}
else if (d instanceof Decl.Proxy && !this.proxy) {
this.addProxy((Decl.Proxy) d, strict);
}
}
if (this.creator != null) {
this.decls.remove(this.creator);
}
else if (this.isa != null) {
this.creator = this.isa.unit.creator;
}
this.iobjFlag |= this.isMeta();
this.sizeFlag &= !this.proxy;
if (this.attrBool(Attr.A_NoRuntime)) {
this.rtsFlag = false;
this.uses.remove(this.ses.findUnit("xdc.runtime.IModule"));
for (Iterator<Decl> it = this.decls.iterator(); it.hasNext(); ) {
Decl d = it.next();
if (d.isSys()) {
it.remove();
if (d instanceof Decl.Config) {
this.cfgs.remove(d);
}
else if (d instanceof Decl.Fxn) {
this.fxns.remove(d);
this.mbrs.remove(d);
}
}
}
}
Impl.resolveUnit(this);
}
// queryFacet
public String queryFacet( String uName )
{
String res = null;
for (Decl.Config cfg : this.cfgs) {
if (cfg.hasAttr(Attr.A_Facet) && cfg.type.tspec().getRef().getNode().getQualName().equals(uName)) {
res = cfg.getName();
break;
}
}
return res;
}
}