blob: feb39c7c041b54c6a822d0ad10c6f8933ccf0a29 [file] [log] [blame]
package xdc.services.spec;
import java.util.*;
public class Impl {
static private Unit unit;
static private Session ses;
static private HashMap<String,Decl.Arg> scope;
static private Body curBody;
// Assign
static public class Assign {
private Expr.Path lval;
private Expr rval;
private boolean isFinal;
private boolean isAccum;
Assign( Expr.Path lval, Expr rval, boolean isFinal, boolean isAccum )
{
this.lval = lval;
this.rval = rval;
this.isFinal = isFinal;
this.isAccum = isAccum;
}
public final Expr.Path getLval() { return this.lval; }
public final Expr getRval() { return this.rval; }
public final boolean isAccum() { return this.isAccum; }
public final boolean isFinal() { return this.isFinal; }
void resolve( Unit u )
{
if (this.lval == null) {
return;
}
((Expr)this.getLval()).resolve(u);
this.getRval().resolve(u);
if (this.isAccum) {
Cat cat = this.lval.getCat();
if (!(cat instanceof Cat.Arr || cat.getCode().equals("n") || cat.getCode().equals("s"))) {
Impl.ses.msg.error(((Expr)this.lval).getAtom(), "lval must be an array, number, or string");
}
}
}
}
// Body
static public class Body
{
private Atom name;
private List<Decl.Arg> args;
private Stmt.Block body;
private List<Expr.Var> locals = new ArrayList<Expr.Var>();
private Decl.Fxn fxn;
Body( Atom name, List<Decl.Arg> args, Stmt.Block body )
{
this.name = name;
this.args = args;
this.body = body;
}
public final List<Decl.Arg> getArgs() { return this.args; }
public final Stmt.Block getBody() { return this.body; }
public final Decl.Fxn getFxn() { return this.fxn; }
public final List<Expr.Var> getLocals() { return this.locals; }
void resolve( Unit u )
{
String fn = this.name.getText();
Decl d = Impl.ses.findDecl(u.getQualName() + '.' + fn);
if (d == null) {
for (Unit iu : u.getInherits()) {
String qn = iu.getQualName() + '.' + fn;
d = Impl.ses.findDecl(qn);
if (d != null) {
break;
}
}
}
if (d == null || !(d instanceof Decl.Fxn)) {
Impl.ses.msg.error(this.name, "not a target function");
return;
}
this.fxn = (Decl.Fxn)d;
if (this.fxn.isStruct()) {
this.args.add(0, new Decl.Arg(new Atom("this"), null, null));
}
if (this.fxn.getArgs().size() != this.args.size()) {
Impl.ses.msg.error(this.name, "wrong number of arguments");
return;
}
int k = 0;
for (Decl.Arg a : this.args) {
Impl.scope.put(a.getName(), this.fxn.getArgs().get(k++));
}
if (!this.fxn.isInst()) {
// TODO
}
this.body.resolve();
}
}
static void addSysFxns( Unit u )
{
Session ses = u.getSession();
Decl.Fxn fxn;
if (u.hasAttr(Attr.A_ModuleStartup)) {
List<Decl.Arg> args = new ArrayList<Decl.Arg>();
args.add(new Decl.Arg(
new Atom("__a0"),
EnumSet.noneOf(Qual.class),
new Type.Declarator(
new Type.Spec(new Ref(Ref.GBL, new Atom("Int")), Type.INT, false, null),
new Atom("__a0")),
null
)
);
fxn = new Decl.Fxn(
new Atom("Module_startup"),
EnumSet.noneOf(Qual.class),
new Type.Declarator(
new Type.Spec(new Ref(Ref.GBL, new Atom("Int")), Type.INT, false, null),
new Atom("Module_startup")),
args,
false
);
ses.enterNode(u.getQualName() + ".Module_startup", fxn);
}
if (ses.lookup(u.getQualName() + ".Module_State") != null) {
List<Decl.Arg> args = new ArrayList<Decl.Arg>();
fxn = new Decl.Fxn(
new Atom("Module_State.init"),
EnumSet.of(Qual.METAONLY),
new Type.Declarator(
new Type.Spec(new Ref(Ref.GBL, new Atom("Void")), null, false, null),
new Atom("Module_startup")),
args,
false
);
ses.enterNode(u.getQualName() + ".Module_State.init", fxn);
fxn.resolve(u);
}
}
static boolean isMeta() { return Impl.curBody == null || Impl.curBody.fxn.isMeta(); }
static Cat lookup( String id, Expr.Select e )
{
if (id.equals("module")) {
return Cat.fromCode("PS!" + Impl.unit.getQualName() + ".Module_State");
}
Decl.Arg arg = Impl.scope.get(id);
if (arg != null) {
return Cat.fromDecl(arg);
}
for (Unit u = Impl.unit; u != null; u = u.getSuper()) {
Decl d = Impl.ses.findDecl(u, id);
if (d != null) {
if (!(d instanceof Decl.Imp)) {
e.setUnit(Impl.unit);
}
return Cat.fromDecl(d);
}
}
Unit u = Impl.ses.findUnit(Impl.unit.getPkgName() + '.' + id);
if (u != null) {
return Cat.fromUnit(u);
}
return null;
}
static void resolveAddr( Expr.Addr e )
{
Expr body = e.getBody();
Impl.resolveExpr(body);
if (!Impl.isMeta()) {
return;
}
List<Expr.Path> chain = new ArrayList<Expr.Path>();
((Expr.Path)body).buildChain(chain);
int k = chain.size();
if (chain.get(k - 1) instanceof Expr.Index) {
return;
}
if (k > 1 && chain.get(k - 2).getCat() instanceof Cat.Str) {
return;
}
Impl.ses.msg.error(e.getAtom(), "operator requires a struct field or array index");
}
static void resolveCall( Expr.Call e )
{
Expr efxn = e.getFxn();
efxn.resolve(Impl.unit);
for (Expr a : e.getArgs()) {
a.resolve(Impl.unit);
}
Cat fxncat = ((Expr.Path)efxn).getCat();
if (!(fxncat instanceof Cat.Fxn)) {
Impl.ses.msg.error(e.getAtom(), "operand is not a function");
return;
}
Decl.Fxn fxn = ((Cat.Fxn)fxncat).getDecl();
if (fxn != null && e.getArgs().size() < fxn.getMinArgc()) {
Impl.ses.msg.error(fxn.getAtom(), "too few arguments");
return;
}
e.setCat(((Cat.Fxn)fxncat).mkRetCat());
// System.out.println("call: " + e.getCat().getCode());
}
static void resolveIndex( Expr.Index e )
{
Expr arr = e.getArr();
arr.resolve(Impl.unit);
e.getIdx().resolve(Impl.unit);
Cat cat = ((Expr.Path)arr).getCat();
if (!(cat instanceof Cat.Indexed)) {
Impl.ses.msg.error(e.getAtom(), "operand of [] must be an array or map");
return;
}
if (cat instanceof Cat.Map && !Impl.isMeta()) {
Impl.ses.msg.error(e.getAtom(), "maps can only be used in bindings or meta-functions");
return;
}
e.setCat(((Cat.Indexed)cat).mkBaseCat());
// System.out.println("index: " + e.getCat().getCode());
}
static void resolveSelect( Expr.Select e )
{
Expr obj = e.getObj();
Atom sel = e.getSel();
Cat cat;
if (obj == null) {
cat = Impl.lookup(sel.getText(), e);
}
else {
obj.resolve(Impl.unit);
Cat objcat = ((Expr.Path)obj).getCat();
if (objcat instanceof Cat.Arr && sel.getText().equals("length")) {
if (Impl.isMeta()) {
e.setCat(Cat.fromCode("n"));
}
else {
Impl.ses.msg.error(sel, "can only be used in the meta-domain");
}
return;
}
if (!(objcat instanceof Cat.Obj)) {
Impl.ses.msg.error(sel, "must be applied to an object");
return;
}
cat = ((Cat.Obj)objcat).mkMbrCat(sel.getText());
}
if (cat == null) {
Impl.ses.msg.error(sel, "can't resolve identifier");
}
else {
e.setCat(cat);
}
// if (cat != null) System.out.println("select: " + e.getCat().getCode());
}
static void resolveVar( Expr.Var e )
{
Decl.Arg d = e.getDecl();
if (Impl.scope.containsKey(d.getName())) {
Impl.ses.msg.error(d.getAtom(), "identifer already defined in this scope");
return;
}
d.resolve(Impl.unit);
Impl.scope.put(d.getName(), d);
Impl.curBody.locals.add(e);
}
static void resolveExpr( Expr e )
{
if (Impl.unit != null) {
e.resolve(Impl.unit);
}
}
static void resolveUnit( Unit u )
{
Impl.unit = u;
Impl.ses = u.getSession();
Impl.scope = new HashMap<String,Decl.Arg>();
Cat.bindUnit(u);
if (u.cfgAssigns != null) {
for (Impl.Assign a : u.cfgAssigns) {
a.resolve(u);
}
}
if (u.fxnBodies == null) {
return;
}
Impl.addSysFxns(u);
for (Impl.Body f : u.fxnBodies) {
Impl.scope.clear();
Impl.curBody = f;
f.resolve(u);
}
}
}