| 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); | |
| } | |
| } | |
| } |