CSC448: Type Checking: Clogs Implementation [18/18] Previous pageContents

Translation of type checking rules into code.

file:clogs/staticanalysis/TypeCheck.java [source] [doc-public] [doc-private]
00001: package clogs.staticanalysis;
00002: 
00003: import clogs.ast.*;
00004: import clogs.util.List;
00005: import clogs.util.Optional;
00006: 
00007: 
00008: public class TypeCheck 
00009: {
00010:   public class TypeCheckException extends Exception
00011:   {
00012:     TypeCheckException (String s)
00013:     {
00014:       super (s);
00015:     }
00016:   }
00017: 
00018: 
00019:   private final List<Decl> globalDecls;
00020:   private final List<FunDef> fundefsOnly;
00021:   private final List<FunDefSig> fundefsigs;
00022: 
00023: 
00024:   public TypeCheck (List<ExtDecl> edecls, List<FunDefSig> fundefsigs)
00025:   {
00026:     List<Decl> declsTmp = List.nil ();
00027:     List<FunDef> fundefsOnlyTmp = List.nil ();
00028:     List<FunDefSig> fundefsigsTmp = fundefsigs;
00029:     for (ExtDecl edecl : edecls) {
00030:       if (edecl instanceof Decl) {
00031:         Decl decl = (Decl) edecl;
00032:         declsTmp = declsTmp.snoc (decl);
00033: 
00034:       } else if (edecl instanceof FunDef) {
00035:         FunDef fundef = (FunDef) edecl;
00036:         fundefsOnlyTmp = fundefsOnlyTmp.snoc (fundef);
00037:         fundefsigsTmp = fundefsigsTmp.snoc (fundef);
00038: 
00039:       } else {
00040:         throw new RuntimeException ("Missing ExtDecl case: " + edecl.getClass ().getName ());
00041:       }
00042:     }
00043:     
00044:     this.globalDecls = declsTmp;
00045:     this.fundefsOnly = fundefsOnlyTmp;
00046:     this.fundefsigs = fundefsigsTmp;
00047:   }
00048: 
00049: 
00050:   // In comments, let S and T range over types and G over contexts.
00051:   // Contexts have the form:
00052:   //
00053:   // G ::= empty
00054:   //     | G,x:T                (variable declaration)
00055:   //     | G,f:(S1,...,Sn)->T   (function declaration)
00056:   //
00057:   // The judgments are written:
00058:   //
00059:   //   |- extdecl1 ... extdecln : Program
00060:   // G |- extdecl : Declaration
00061:   // G |- stat : Statement<declaredReturnType>
00062:   // G |- exp : T
00063:   //   |- exp is lvalue
00064:   //
00065: 
00066: 
00067:   // To check a bunch of global variable and function declarations, we
00068:   // put them in the context, then start checking them; this allows
00069:   // mutually recursive definitions.
00070:   //
00071:   // context(extdecl1 ... extdecln) |- extdecl1 : Declaration
00072:   // ...
00073:   // context(extdecl1 ... extdecln) |- extdecln : Declaration
00074:   // ------------------------------------------------------------------
00075:   //                                |- extdecl1 ... extdecln : Program
00076:   //
00077:   public List<ExtDecl> check ()
00078:     throws TypeCheckException
00079:   {
00080:     Context context = Context.emptyContext;
00081: 
00082:     context = context.addGlobalVariables (globalDecls);
00083:     context = context.addFunDefSigs (fundefsigs);
00084: 
00085:     List<Decl> declsNew = checkDecls (context, globalDecls);
00086:     List<FunDef> fundefsOnlyNew = checkFunDefSigs (context);
00087: 
00088:     List<ExtDecl> result = List.nil ();
00089:     for (Decl decl : declsNew) {
00090:       result = result.snoc (decl);
00091:     }
00092:     for (FunDef fundef : fundefsOnlyNew) {
00093:       result = result.snoc (fundef);
00094:     }
00095: 
00096:     return result;
00097:   }
00098: 
00099: 
00100:   // To check a variable declaration, we just need to make sure that
00101:   // the initializer has the correct type:
00102:   //
00103:   // ------------------------------
00104:   // G |- (T x;) : Declaration
00105:   //
00106:   // G |- exp : T
00107:   // -------------------------------
00108:   // G |- (T x = exp;) : Declaration
00109:   // 
00110:   List<Decl> checkDecls (Context context, List<Decl> decls)
00111:     throws TypeCheckException
00112:   {
00113:     List<Decl> result = List.nil ();
00114:     for (Decl decl : decls) {
00115:       if (decl.eo.isEmpty ()) {
00116:         result = result.snoc (decl);
00117:       } else {
00118:         Exp exp = checkExp (context, decl.eo.get ());
00119:         if (!matchesDeclaredType (decl.type, exp)) {
00120:           throw new TypeCheckException ("Declared type " + decl.type + " does not match computed type for " + exp);
00121:         }
00122:         result = result.snoc (new Decl (decl.type, decl.name, new Optional<Exp> (exp)));
00123:       }
00124:     }
00125:     return result;
00126:   }
00127: 
00128:   
00129:   // To check a function declaration, we check the body:
00130:   //
00131:   // G,x1:S1,...,xn:Sn |- compoundStat : T
00132:   // -------------------------------------------------------
00133:   // G |- (T f (S1 x1,...,Sn xn) compoundStat) : Declaration
00134:   //
00135:   List<FunDef> checkFunDefSigs (Context context)
00136:     throws TypeCheckException
00137:   {
00138:     List<FunDef> fundefsOnlyNew = List.nil ();
00139:     for (FunDef fundef : fundefsOnly) {
00140:       StatCompound bodyNew = checkStatCompound (context.addFunParams (fundef), fundef.type, fundef.body);
00141:       FunDef fundefNew = new FunDef (fundef.type, fundef.name, fundef.params, bodyNew);
00142:       fundefsOnlyNew = fundefsOnlyNew.snoc (fundefNew);
00143:     }
00144:     return fundefsOnlyNew;
00145:   }
00146: 
00147: 
00148:   // To check a compound statement, check each statement and initializer
00149:   // G,x1:T1,...,xn:Tn |- (T1 x1 = exp1;) : Declaration
00150:   // ...
00151:   // G,x1:T1,...,xn:Tn |- (Tn xn = expn;) : Declaration
00152:   // G,x1:T1,...,xn:Tn |- stat1 : Statement<T>
00153:   // ...
00154:   // G,x1:T1,...,xn:Tn |- statm : Statement<T>
00155:   // -----------------------------------------------------------------------
00156:   // G |- { T1 x1 = exp1; ... Tn xn = expn; stat1 ... statm } : Statement<T>
00157:   //
00158:   StatCompound checkStatCompound (Context context, Type declaredReturnType, StatCompound statC)
00159:     throws TypeCheckException
00160:   {
00161:     context = context.addLocalVariables (statC.decls);
00162:     List<Decl> declsNew = checkDecls (context, statC.decls);
00163:     List<Stat> statsNew = List.nil ();
00164:     for (Stat stat : statC.stats) {
00165:       Stat statNew = checkStat (context, declaredReturnType, stat);
00166:       statsNew = statsNew.snoc (statNew);
00167:     }
00168:     return new StatCompound (declsNew, statsNew);
00169:   }
00170: 
00171: 
00172:   // To check a statment, do a case analysis.
00173:   Stat checkStat (Context context, Type declaredReturnType, Stat stat)
00174:     throws TypeCheckException
00175:   {
00176:     if (stat instanceof StatCompound) {
00177:       // G,decls |- stats : Statement<T>
00178:       // ------------------------------------
00179:       // G |- { decls stats } : Statement<T>
00180:       //
00181:       StatCompound statC = (StatCompound) stat;
00182:       return checkStatCompound (context, declaredReturnType, statC).addLabels (stat.labels);
00183: 
00184:     } else if (stat instanceof StatExp) {
00185:       // G |- exp : S    (for some type S)
00186:       // ---------------------------------------
00187:       // G |- (exp;) : Statement<T>
00188:       //
00189:       StatExp statE = (StatExp) stat;
00190:       return new StatExp (checkExp (context, statE.exp)).addLabels (stat.labels);
00191: 
00192:     } else if (stat instanceof StatGoto) {
00193:       // -----------------------------------
00194:       // G |- (goto l;) : Statement<T>
00195:       //
00196:       return stat;
00197: 
00198:     } else if (stat instanceof StatIf) {
00199:       // G |- exp : int
00200:       // G |- statT : Statement<T>
00201:       // G |- statF : Statement<T>
00202:       // -----------------------------------------------------
00203:       // G |- (if (exp) statT else statF) : Statement<T>
00204:       //
00205:       StatIf statI = (StatIf) stat;
00206:       Exp expNew = checkExp (context, statI.exp);
00207:       if (!matchesDeclaredType (new TypeInt (), expNew)) {
00208:         throw new TypeCheckException ("Expression in conditional has non-integer type " + expNew);
00209:       }
00210:       return new StatIf (expNew, checkStat (context, declaredReturnType, statI.statT), checkStat (context, declaredReturnType, statI.statF)).addLabels (stat.labels);
00211: 
00212:     } else if (stat instanceof StatReturn) {
00213:       // ---------------------------------------
00214:       // G |- (return;) : Statement<void>
00215:       //
00216:       // G |- exp : T
00217:       // ---------------------------------------
00218:       // G |- (return exp;) : Statement<T>
00219:       //
00220:       StatReturn statR = (StatReturn) stat;
00221:       if (statR.oe.isEmpty ()) {
00222:         if (!testTypeEquality (declaredReturnType, new TypeVoid ())) {
00223:           throw new TypeCheckException ("Empty return for function with non-void type");
00224:         }
00225:         return statR;
00226:       } else {
00227:         Exp expNew = checkExp (context, statR.oe.get ());
00228:         if (!matchesDeclaredType (declaredReturnType, expNew)) {
00229:           throw new TypeCheckException ("Declared return type " + declaredReturnType + " does not match computed type for " + expNew);
00230:         }
00231:         return new StatReturn (new Optional<Exp> (expNew)).addLabels (stat.labels);
00232:       }
00233: 
00234:     } else if (stat instanceof StatSkip) {
00235:       // ---------------------------------
00236:       // G |- (skip;) : Statement<T>
00237:       return stat;
00238: 
00239:     } else if (stat instanceof StatWhile) {
00240:       // G |- exp : int
00241:       // G |- statW : Statement<T>
00242:       // -----------------------------------------------------
00243:       // G |- (while (exp) statW) : Statement<T>
00244:       //
00245:       StatWhile statW = (StatWhile) stat;
00246:       Exp expNew = checkExp (context, statW.exp);
00247:       if (!matchesDeclaredType (new TypeInt (), expNew)) {
00248:         throw new TypeCheckException ("Expression in while has non-integer type " + expNew);
00249:       }
00250:       return new StatWhile (expNew, checkStat (context, declaredReturnType, statW.stat)).addLabels (stat.labels);
00251: 
00252:     } else {
00253:       throw new RuntimeException ("Missing Stat case: " + stat.getClass ().getName ());
00254:     }
00255:   }
00256: 
00257: 
00258:   // To check an expression, do a case analysis.
00259:   Exp checkExp (Context context, Exp exp)
00260:     throws TypeCheckException
00261:   {
00262:     Exp result;
00263: 
00264:     if (exp instanceof ExpArrayAccess) {
00265:       // G |- array : T[]
00266:       // G |- index : int
00267:       // -----------------------------
00268:       // G |- (array[index]) : T
00269:       //
00270:       ExpArrayAccess expA = (ExpArrayAccess) exp;
00271:       Exp exp1 = checkExp (context, expA.array);
00272:       Exp exp2 = checkExp (context, expA.index);
00273:       assert (!exp1.to.isEmpty ());
00274:       Type type1 = exp1.to.get ();
00275:       if (!(type1 instanceof TypeArray)) {
00276:         throw new TypeCheckException ("Array expression has non-array type " + exp1);
00277:       }
00278:       Type typeResult = ((TypeArray) type1).type;
00279:       if (!matchesDeclaredType (new TypeInt (), exp2)) {
00280:         throw new TypeCheckException ("Array index expression has non-integer type " + exp2);
00281:       }
00282:       result = new ExpArrayAccess (exp1, exp2).setType (typeResult);
00283: 
00284:     } else if (exp instanceof ExpAssign) {
00285:       // G |- left : T
00286:       // G |- right : T
00287:       //   |- left is lval
00288:       // ------------------------------
00289:       // G |- (left = right) : T
00290:       //
00291:       ExpAssign expA = (ExpAssign) exp;
00292:       Exp exp1 = checkExp (context, expA.left);
00293:       Exp exp2 = checkExp (context, expA.right);
00294:       assert (!exp1.to.isEmpty ());
00295:       assert (!exp2.to.isEmpty ());
00296:       if (!testTypeEquality (exp1.to.get (), exp2.to.get ())) {
00297:         throw new TypeCheckException ("Unequal types in assignment from " + exp2 + " to " + exp1);
00298:       }
00299:       if (!isLValue (exp1)) {
00300:         throw new TypeCheckException ("Assignment to non-lvalue " + exp1);
00301:       }
00302:       result = new ExpAssign (exp1, exp2).setType (exp2.to.get ());
00303: 
00304:     } else if (exp instanceof ExpBinOp) {
00305:       // G |- left : int
00306:       // G |- right : int
00307:       // -----------------------------------
00308:       // G |- (left binop right) : int
00309:       //
00310:       ExpBinOp expB = (ExpBinOp) exp;
00311:       Exp exp1 = checkExp (context, expB.left);
00312:       Exp exp2 = checkExp (context, expB.right);
00313:       // At present, all binary operators have type "int * int ->
00314:       // int", so we do not need to perform a case analysis on the
00315:       // operator.
00316:       if (!matchesDeclaredType (new TypeInt (), exp1)) {
00317:         throw new TypeCheckException ("Argument to " + expB.op + " has non-integer type " + exp1);
00318:       }
00319:       if (!matchesDeclaredType (new TypeInt (), exp2)) {
00320:         throw new TypeCheckException ("Argument to " + expB.op + " has non-integer type " + exp2);
00321:       }
00322:       result = new ExpBinOp (expB.op, exp1, exp2).setType (new TypeInt ());
00323: 
00324:     } else if (exp instanceof ExpComma) {
00325:       // G |- left : S
00326:       // G |- right : T
00327:       // -----------------------------
00328:       // G |- (left , right) : T
00329:       //
00330:       ExpComma expC = (ExpComma) exp;
00331:       Exp exp1 = checkExp (context, expC.left);
00332:       Exp exp2 = checkExp (context, expC.right);
00333:       assert (!exp2.to.isEmpty ());
00334:       result = new ExpComma (exp1, exp2).setType (exp2.to.get ());
00335: 
00336:     } else if (exp instanceof ExpFunCall) {
00337:       // G(name) = (S1,...,Sn)->T
00338:       // G |- arg1 : S1
00339:       // ...
00340:       // G |- argn : Sn
00341:       // ------------------------------------
00342:       // G |- (name(arg1,...,argn)) : T
00343:       //
00344:       ExpFunCall expF = (ExpFunCall) exp;
00345:       if (!context.containsFunDefSig (expF.name)) {
00346:         throw new TypeCheckException ("Function " + expF.name + " not found in context " + context);
00347:       }
00348:       FunDefSig fundefsig = context.getFunDefSig (expF.name);
00349:       if (fundefsig.params.size () != expF.args.size ()) {
00350:         throw new TypeCheckException ("Function " + expF.name + " requires " + fundefsig.params.size () + " arguments, " + 
00351:                                       "but " + expF.args.size () + " arguments were given in " + expF);
00352:       }
00353:       List<Decl> decls = fundefsig.params;
00354:       List<Exp> argsNew = List.nil ();
00355:       for (Exp arg : expF.args) {
00356:         Exp argNew = checkExp (context, arg);
00357:         if (!matchesDeclaredType (decls.head ().type, argNew)) {
00358:           throw new TypeCheckException ("Function " + expF.name + " parameter type " + decls.head () + " does not match computed type for " + arg);
00359:         }
00360:         argsNew = argsNew.snoc (argNew);
00361:         decls = decls.tail ();
00362:       }
00363:       result = new ExpFunCall (expF.name, argsNew).setType (fundefsig.type);
00364: 
00365:     } else if (exp instanceof ExpInt) {
00366:       // ------------
00367:       // G |- n : int
00368:       //
00369:       ExpInt expI = (ExpInt) exp;
00370:       result = expI.setType (new TypeInt ());
00371: 
00372:     } else if (exp instanceof ExpNew) {
00373:       // G |- size : int
00374:       // --------------------------------------------
00375:       // G |- (new contentType[size]) : contentType[]
00376:       //
00377:       ExpNew expN = (ExpNew) exp;
00378:       Exp exp1 = checkExp (context, expN.size);
00379:       if (!matchesDeclaredType (new TypeInt (), exp1)) {
00380:         throw new TypeCheckException ("Argument to new " + expN + " has non-integer type " + exp1);
00381:       }
00382:       result = new ExpNew (expN.contentType, exp1).setType (new TypeArray (expN.contentType));
00383: 
00384:     } else if (exp instanceof ExpString) {
00385:       // --------------------
00386:       // G |- "value" : int[]
00387:       //
00388:       ExpString expS = (ExpString) exp;
00389:       result = expS.setType (new TypeArray (new TypeInt ()));
00390: 
00391:     } else if (exp instanceof ExpUnOp) {
00392:       // G |- exp : int
00393:       // ---------------------
00394:       // G |- (unop exp) : int
00395:       //
00396:       ExpUnOp expU = (ExpUnOp) exp;
00397:       Exp exp1 = checkExp (context, expU.exp);
00398:       // At present, all unary operators have type "int -> int", so we
00399:       // do not need to perform a case analysis on the operator.
00400:       if (!matchesDeclaredType (new TypeInt (), exp1)) {
00401:         throw new TypeCheckException ("Argument to " + expU.op + " has non-integer type " + exp1);
00402:       }
00403:       result = new ExpUnOp (expU.op, exp1).setType (new TypeInt ());
00404: 
00405:     } else if (exp instanceof ExpVar) {
00406:       // G(x) = T
00407:       // ----------
00408:       // G |- x : T
00409:       //
00410:       ExpVar expV = (ExpVar) exp;
00411:       if (!context.containsVariable (expV.name)) {
00412:         throw new TypeCheckException ("Variable " + expV.name + " not found in context " + context);
00413:       } 
00414:       result = expV.setType (context.getVariableType (expV.name));
00415: 
00416:     } else {
00417:       throw new RuntimeException ("Missing Exp case: " + exp.getClass ().getName ());
00418:     }
00419: 
00420:     if (!exp.to.isEmpty () && !matchesDeclaredType (exp.to.get (), result)) {
00421:       throw new TypeCheckException ("Declared type for expression " + exp + " does not match computed type for expression " + result);
00422:     }
00423:     
00424:     return result;
00425:   }
00426: 
00427: 
00428:   boolean matchesDeclaredType (Type declared, Exp exp)
00429:   {
00430:     assert (!exp.to.isEmpty ());
00431:     Type computed = exp.to.get ();
00432:     return testTypeEquality (declared, computed);
00433:   }
00434: 
00435:   
00436:   boolean testTypeEquality (Type t1, Type t2) 
00437:   {
00438:     if ((t1 instanceof TypeVoid) && (t2 instanceof TypeVoid)) {
00439:       return true;
00440:     } else if ((t1 instanceof TypeInt) && (t2 instanceof TypeInt)) {
00441:       return true;
00442:     } else if ((t1 instanceof TypeArray) && (t2 instanceof TypeArray)) {
00443:       TypeArray t1A = (TypeArray) t1;
00444:       TypeArray t2A = (TypeArray) t2;
00445:       return testTypeEquality (t1A.type, t2A.type);
00446:     } else {
00447:       return false;
00448:     }
00449:   }
00450: 
00451: 
00452:   // Every variable and array access is an lvalue.
00453:   // Nothing else is an lvalue.
00454:   boolean isLValue (Exp exp)
00455:   {
00456:     if (exp instanceof ExpArrayAccess) {
00457:       // -------------------------
00458:       // |- (array[index]) is lvalue
00459:       //
00460:       return true;
00461:     } else if (exp instanceof ExpVar) {
00462:       // --------------
00463:       // |- x is lvalue
00464:       //
00465:       return true;
00466:     } else {
00467:       return false;
00468:     }
00469:   }
00470: }
00471: 

file:clogs/staticanalysis/Context.java [source] [doc-public] [doc-private]
00001: package clogs.staticanalysis;
00002: 
00003: import java.util.NoSuchElementException;
00004: 
00005: import clogs.ast.*;
00006: import clogs.codegen.CodeGen;
00007: import clogs.util.List;
00008: import clogs.util.Map;
00009: import clogs.util.Optional;
00010: 
00011: 
00012: public class Context
00013: {
00014:   protected final Map<String, Type> variableTypes;
00015:   protected final Map<String, FunDefSig> fundefsigs;
00016:   protected final Map<String, String> variableLocations;
00017:   protected final int paramCounter;
00018:   protected final int localVariableCounter;
00019: 
00020: 
00021:   public static final Context emptyContext = 
00022:     new Context (Map.<String, Type>empty (), Map.<String, FunDefSig>empty (), Map.<String, String>empty (), 2, -1);
00023: 
00024: 
00025:   protected Context (Map<String, Type> variableTypes, Map<String, FunDefSig> fundefsigs, Map<String, String> variableLocations, 
00026:                      int paramCounter, int localVariableCounter)
00027:   {
00028:     this.variableTypes = variableTypes;
00029:     this.fundefsigs = fundefsigs;
00030:     this.variableLocations = variableLocations;
00031:     this.paramCounter = paramCounter;
00032:     this.localVariableCounter = localVariableCounter;
00033:   }
00034: 
00035: 
00036:   public String getVariableLocation (String name)
00037:   {
00038:     String location = variableLocations.get (name);
00039:     if (location == null) {
00040:       throw new NoSuchElementException ("Variable " + name + " not found in context " + this);
00041:     }
00042:     return location;
00043:   }
00044:   
00045: 
00046:   public boolean containsVariable (String name)
00047:   {
00048:     Type type = variableTypes.get (name);
00049:     return type != null;
00050:   }
00051: 
00052: 
00053:   public Type getVariableType (String name)
00054:   {
00055:     Type type = variableTypes.get (name);
00056:     if (type == null) {
00057:       throw new NoSuchElementException ("Variable " + name + " not found in context " + this);
00058:     }
00059:     return type;
00060:   }
00061:   
00062: 
00063:   public boolean containsFunDefSig (String name)
00064:   {
00065:     FunDefSig fundefsig = fundefsigs.get (name);
00066:     return fundefsig != null;
00067:   }
00068: 
00069: 
00070:   public FunDefSig getFunDefSig (String name)
00071:   {
00072:     FunDefSig fundefsig = fundefsigs.get (name);
00073:     if (fundefsig == null) {
00074:       throw new NoSuchElementException ("Function definition signature " + name + " not found in context " + this);
00075:     }
00076:     return fundefsig;
00077:   }
00078: 
00079: 
00080:   public Context addGlobalVariables (List<Decl> decls)
00081:   {
00082:     Map<String, Type> variableTypesNew = variableTypes;
00083:     Map<String, String> variableLocationsNew = variableLocations;
00084:     for (Decl decl : decls) {
00085:       if (variableTypesNew.get (decl.name) != null) {
00086:         throw new RuntimeException ("Variable " + decl.name + " already found in context " + this);
00087:       }
00088:       variableTypesNew = variableTypesNew.add (decl.name, decl.type);
00089:       variableLocationsNew = variableLocationsNew.add (decl.name, decl.name);
00090:     }
00091:     return new Context (variableTypesNew, fundefsigs, variableLocationsNew, paramCounter, localVariableCounter);
00092:   }
00093: 
00094: 
00095:   public Context addFunParams (FunDefSig fundefsig)
00096:   {
00097:     assert (paramCounter == 2);
00098:     int paramCounterTmp = paramCounter;
00099:     Map<String, Type> variableTypesNew = variableTypes;
00100:     Map<String, String> variableLocationsNew = variableLocations;
00101:     for (Decl decl : fundefsig.params) {
00102:       if (variableTypesNew.get (decl.name) != null) {
00103:         throw new RuntimeException ("Variable " + decl.name + " already found in context " + this);
00104:       }
00105:       variableTypesNew = variableTypesNew.add (decl.name, decl.type);
00106:       variableLocationsNew = variableLocationsNew.add (decl.name, (CodeGen.intSize * paramCounterTmp++) + "(%ebp)");
00107:     }
00108:     return new Context (variableTypesNew, fundefsigs, variableLocationsNew, paramCounterTmp, localVariableCounter);
00109:   }
00110: 
00111: 
00112:   public Context addLocalVariables (List<Decl> decls)
00113:   {
00114:     int localVariableCounterTmp = localVariableCounter;
00115:     Map<String, Type> variableTypesNew = variableTypes;
00116:     Map<String, String> variableLocationsNew = variableLocations;
00117:     for (Decl decl : decls) {
00118:       if (variableTypesNew.get (decl.name) != null) {
00119:         throw new RuntimeException ("Variable " + decl.name + " already found in context " + this);
00120:       }
00121:       variableTypesNew = variableTypesNew.add (decl.name, decl.type);
00122:       variableLocationsNew = variableLocationsNew.add (decl.name, (CodeGen.intSize * localVariableCounterTmp--) + "(%ebp)");
00123:     }
00124:     return new Context (variableTypesNew, fundefsigs, variableLocationsNew, paramCounter, localVariableCounterTmp);
00125:   }
00126: 
00127: 
00128:   public Context addFunDefSig (FunDefSig fundefsig)
00129:   {
00130:     if (fundefsigs.get (fundefsig.name) != null) {
00131:       throw new RuntimeException ("Function definition signature " + fundefsig.name + " already found in context " + this);
00132:     }
00133:     return new Context (variableTypes, fundefsigs.add (fundefsig.name, fundefsig), variableLocations, paramCounter, localVariableCounter);
00134:   }
00135: 
00136: 
00137:   public Context addFunDefSigs (List<FunDefSig> fundefsigs)
00138:   {
00139:     Context context = this;
00140:     for (FunDefSig fundefsig : fundefsigs) {
00141:       context = context.addFunDefSig (fundefsig);
00142:     }
00143:     return context;
00144:   }
00145: 
00146: 
00147:   public Context addFunDefs (List<FunDef> fundefs)
00148:   {
00149:     Context context = this;
00150:     for (FunDef fundef : fundefs) {
00151:       context = context.addFunDefSig (fundef);
00152:     }
00153:     return context;
00154:   }
00155: 
00156: 
00157:   public String toString ()
00158:   {
00159:     boolean first;
00160:     StringBuffer sb = new StringBuffer ();
00161:     first = true;
00162:     sb.append ("variables: ");
00163:     for (String var : variableTypes.keyList ()) {
00164:       if (!first) {
00165:         sb.append (", ");
00166:       }
00167:       first = false;
00168:       Type type = variableTypes.get (var);
00169:       String location = variableLocations.get (var);
00170:       sb.append (var);
00171:       sb.append (" :: ");
00172:       sb.append (type);
00173:       sb.append (" @ ");
00174:       sb.append (location);
00175:     }
00176:     sb.append ("; ");
00177:     first = true;
00178:     for (String funName : fundefsigs.keyList ()) {
00179:       if (!first) {
00180:         sb.append (", ");
00181:       }
00182:       first = false;
00183:       FunDefSig fundefsig = fundefsigs.get (funName);
00184:       sb.append (fundefsig.type);
00185:       sb.append (" "); 
00186:       sb.append (fundefsig.name);
00187:       sb.append (" ("); 
00188:       sb.append (fundefsig.params);
00189:       sb.append (")"); 
00190:     }
00191:     sb.append ("; paramCounter = ");
00192:     sb.append (paramCounter);
00193:     sb.append (")"); 
00194:     return sb.toString ();
00195:   }
00196: }
00197: 
00198: 

Previous pageContents