import java.util.*; import java.awt.*; class TypeExp { /*The type expressions can be either a VarType e.g. a polymorphic type 'a or an OperType which can have arguments e.g. int (with no arguments) or -> (which has two arguments which may be of OperType or of VarType) These definitions follow the implementation in Cardelli's paper The VarType and OperType integers declared here aren't really used */ final int VarType = 1, OperType = 2; int typeoftypeclass ; public TypeExp() {}; public TypeExp(int i ) {typeoftypeclass = i;}; } class Exp { /* The class Exp is used to represent the grammar of the language, when any new structures are added to the language unless they're derived types, the a new Exp needs to be declared that extends the class Exp */ /* For each expression type information is stored. The ctype, ctypeinfo etc. store infomation that can be overridden by user-defined types. However the type, typeinfo etc. can not be overridden by the user. Any of the variables that begin with c are do to with the type of the copy. Again the integers to identify the Exp aren't used. */ final int Id = 1,Cond = 2,Lamb = 3,Appl = 4,Block = 5; TypeExp type; boolean uniferror;//Was the error identifed at this node String info;//A string to hold info about the unification error. TypeExp first,second;//These are to hold the two typesthat caused //the unification error. TypeExp ctype; TypeExp ctypeinfo; boolean cuniferror;//If the user supplies a different type and //a different type error arises, then this variable will //help identify which node it occurred at. String cinfo; TypeExp cfirst,csecond; boolean changedbelow;//This indicates if an assumed type is to be used here TypeExp below;//This is the assumed type that will be used depending on the changedbelow value int typeofexp;//NOT USED int Posn;//These positions are to help identify the correct nodes //when the user wishes to get a partial type int EndPosn; public Exp() { this.ctype = null;this.cinfo = null;this.cfirst = null;this.csecond = null; this.cuniferror = false; typeofexp = 0;this.type = null;this.uniferror = false;this.first = null;this.second = null;this.info = ""; this.changedbelow = false;this.below = null; this.ctypeinfo = null;} public Exp(int typeofexp,int Posn ){ this.typeofexp = typeofexp; this.Posn = Posn; this.EndPosn = 0; this.type = null; this.uniferror = false;this.first = null ;this.second = null;this.info = null; this.cuniferror = false; this.ctype = null;this.cinfo = null;this.cfirst = null;this.csecond = null; this.changedbelow = false;this.below = null; this.ctypeinfo = null; } public Exp(int typeofexp,int Posn,int EndPosn) { this.typeofexp = typeofexp;this.Posn = Posn; this.EndPosn = EndPosn;this.type = null; this.uniferror = false;this.first = null;this.second = null;this.info = null; this.cuniferror = false; this.changedbelow = false;this.below = null; this.ctypeinfo = null; } } class Constant extends Exp { //Constant Expression TypeExp te; String value; public Constant() {te = null;}; public Constant(TypeExp te,String value,int Posn,int EndPosn){ this.te = te; super.Posn = Posn; super.EndPosn = EndPosn; } } class Tuple extends Exp { //Tuple Expression Parameters p ; public Tuple(){ p = null; } public Tuple(Parameters p,int Posn,int EndPosn) { this.p = p;this.Posn = Posn;this.EndPosn = EndPosn; } } class Decl { //A Declaration Statement final int Def = 1,Seq = 2,Rec = 3; int typeofdecl; public Decl() {typeofdecl = 0; } public Decl(int i){typeofdecl = i; } } class IdeClass extends Exp { //Identifier Expression String ide ; public IdeClass(String ide,int Posn,int EndPosn) { this.ide = ide; super.Posn = Posn; super.EndPosn = EndPosn; super.typeofexp = 1; } } class CondClass extends Exp { //Condition expression Exp test, iftrue , iffalse; public CondClass(Exp test,Exp iftrue, Exp iffalse,int Posn,int EndPosn) { this.test = test; this.iftrue = iftrue; this.iffalse = iffalse; super.typeofexp = 2; super.Posn = Posn; super.EndPosn = EndPosn; } } class WhileClass extends Exp { //While Expression Exp test , body; public WhileClass(Exp test,Exp body,int Posn,int EndPosn) { this.test = test; this.body = body; super.Posn = Posn; super.EndPosn = EndPosn; } } class LambClass extends Exp { //A function expression String binder; Exp body; public LambClass(String binder,Exp body,int Posn,int EndPosn) { this.binder = binder; this.body = body; super.typeofexp = 3; super.Posn = Posn; super.EndPosn = EndPosn; } } class Parameters { /*The paramaters are stored as a simple list*/ Exp exp; Parameters tail; boolean uncurried; public Parameters() { this.exp = null; this.tail = null; this.uncurried = true; } public Parameters(Exp exp,Parameters tail,boolean uncurried) { this.exp = exp; this.tail = tail; this.uncurried = uncurried; } public void Extend(Exp expp,boolean uncurriedp) { if (exp == null) { exp = expp; uncurried = uncurriedp; } else if (tail == null) { Parameters temp = new Parameters(expp,null,uncurriedp); tail = temp; } else tail.Extend(expp,uncurriedp); } public int length() { if (exp == null) return 0; else if (tail == null) return 1; else return 1 + tail.length(); } } class Patterns { //Patterns for the pattern matching in functions stored as a linked list //Each pattern is made up of two expressions - the paramters and the body TypeExp exp1; TypeExp exp2; Patterns tail; public Patterns() { this.exp1 = null; this.tail = null; this.exp2 = null; } public Patterns(TypeExp exp1,TypeExp exp2,Patterns tail) { this.exp1 = exp1; this.tail = tail; this.exp2 = exp2;; } public void Extend(TypeExp expp1,TypeExp expp2) { if (exp1 == null) { exp1 = expp1; exp2 = expp2; } else if (tail == null) { Patterns temp = new Patterns(expp1,expp2,null); tail = temp; } else tail.Extend(expp1,expp2); } } class MiniFn extends Exp{ //One of the patterns in a function - consists of Parameters and a body Parameters Pattern; Exp Body; public MiniFn (){ this.Pattern = null; this.Body = null; } public MiniFn(Parameters Pattern,Exp Body) { this.Pattern = Pattern; this.Body = Body; } } class MiniFnList extends Exp{ //A list of patterns MiniFn head; MiniFnList tail; public MiniFnList() { this.head = null; this.tail = null; } public MiniFnList(MiniFn head,MiniFnList tail) { this.head =head; this.tail = tail; } public void Extend(MiniFn minifn) { if (head == null) { head = minifn; } else if (tail == null) { MiniFnList temp = new MiniFnList(minifn,null); tail = temp; } else tail.Extend(minifn); } } class Function extends Decl { //A function made up from a name and a list of one or more patterns. String namefn; MiniFnList function; public Function(){ this.namefn = null; this.function = null; } public Function(String namefn,MiniFnList function){ this.namefn = namefn; this.function = function; } } class Except extends Decl { //Exception classes String name; TypeExp arg; public Except () { this.name = ""; this.arg = null; } public Except (String name,TypeExp arg) { this.name = name; this.arg = arg; } } class raisecase extends Exp { //A raise (exception) expression Exp exc; public raisecase(Exp exc,int Posn,int EndPosn) { this.exc = exc; super.Posn = Posn; super.EndPosn = EndPosn; } } class handleclass extends Exp { //The handle exception case consisting of an expression //and the list of possible exceptions and actions to be taken //with them. Exp exp; MiniFnList match; public handleclass(Exp exp,MiniFnList match,int Posn,int EndPosn) { this.exp = exp; this.match = match; this.Posn = Posn; this.EndPosn = EndPosn; } } class ApplClass extends Exp { //Function application expression to one argument Exp fun,arg; public ApplClass(Exp fun,Exp arg,int Posn,int EndPosn) { this.fun = fun; this.arg = arg; super.typeofexp = 4; super.Posn = Posn; super.EndPosn = EndPosn; } } class Appl2Class extends Exp { //Function application to multiple arguments Exp fun; Parameters param; public Appl2Class(Exp fun,Parameters param,int Posn,int EndPosn) { this.fun = fun; this.param = param; super.Posn = Posn; super.EndPosn = EndPosn; } } class CaseClass extends Exp { //Case expression - treated as a derived class Exp exp; MiniFnList mfl; public CaseClass() {this.mfl = null;} public CaseClass(Exp exp,MiniFnList mfl) {this.mfl = mfl;this.exp = exp;} } class BlockClass extends Exp { //Let declaration Decl decl;Exp scope; public BlockClass(Decl decl,Exp scope,int Posn,int EndPosn) { this.decl = decl; this.scope = scope; super.typeofexp = 5; super.Posn = Posn; super.EndPosn = EndPosn; } } class DefClass extends Decl { //Definition Declaration String binder;Exp def; public DefClass(String binder,Exp def) { this.binder = binder; this.def = def; super.typeofdecl = 1; } } class SeqClass extends Decl { //A sequence of declarations Decl first, second; public SeqClass(Decl first,Decl second) { this.first = first; this.second = second; super.typeofdecl =2; } } class RecClass extends Decl { //A recursive declaration Decl rec; public RecClass(Decl rec) { this.rec = rec; super.typeofdecl = 3; } } class ParametersList { boolean brackets;//This was to be used if curried or uncurried functions //were to be recognised. However I don't think it was used. Exp head; ParametersList tail; public ParametersList (){ brackets = false; head = null; tail = null; } public ParametersList (boolean bracketes,Exp head,ParametersList tail) { this.brackets = brackets; this.head = head; this.tail = tail; } public void Extend (Exp newhead){ ParametersList newtail = new ParametersList(brackets,head,tail); this.head = newhead; this.tail = newtail; } public int length() { if (head == null) return 0; else if (tail == null) return 1; else return 1 + tail.length(); } } class ArgList { //A list of arguments - used in datatypes. It consists of a name of an argument //it's type and a list of the remaining arguments. //The last element of the list is recognised with "" as the namefn. String namefn; TypeExp type; ArgList tail; public ArgList() { this.namefn = ""; this.type = null; this.tail = null; } public ArgList (String namefn, TypeExp type,ArgList tail){ this.namefn = namefn; this.type = type; this.tail = tail; } public int length() { if (namefn.equals("")) return 0; else if (tail == null) return 1; else return ( 1 + tail.length()); } public void Extend(String namefn1,TypeExp type1 ){ if (namefn.equals("")) { namefn = namefn1; type = type1; } else { ArgList temp = new ArgList(namefn,type,tail); namefn = namefn1; type = type1; tail = temp; } } public TypeExp Retrieve(String name) { if (namefn.equals(name)) return type; else if (tail == null) return null; else return tail.Retrieve(name); } } class DataType extends Decl { //Datatype declaration String name;//The name of the datatype; ArgList parameters;//The parameters of the datatype. ArgList Pattern; int IsEqType;//Just to store whether it's an equality type //0 means not set //1 means it is assuming that it's arguments are //2 means it's not in any case public DataType() { this.name = null; this.parameters = null; this.Pattern = null; this.IsEqType = 0; } public DataType(String name,ArgList parameters,ArgList Pattern) { this.name = name; this.parameters = parameters; this.Pattern = Pattern; this.IsEqType = 0; } public DataType(String name,ArgList parameters,ArgList Pattern,int IsEqType) { this.name = name; this.parameters = parameters; this.Pattern = Pattern; this.IsEqType = IsEqType; } } class AndDecl extends Decl { //And declaration - I don't think this was working correctly - //I think it just behaved like a "then" declaration Decl decl1; AndDecl tail; public AndDecl() { this.decl1 = null; this.tail = null; } public AndDecl(Decl decl1 ,AndDecl tail) { this.decl1 = decl1; this.tail = tail; } public void Extend(Decl decl) { if (decl1 == null) { decl1 = decl; } else if (tail == null) { AndDecl temptail = new AndDecl(decl,null); tail = temptail; } else { tail.Extend(decl); } } } interface EqTypesInter { public boolean IsEqType(DataType dt); } class EqTypes implements EqTypesInter { //To allow for eqtypes a further class needed to be introduced //to store the types that were EqTypes - this included some //standard types and new types were added if appropriate when //a new datatype declaration is made //This assumes that datatype names are unique //If a datypes name is present in the eqtpyes that only means //that it's an eqtype if it's arguments are. //If a polymorphic type is checked then it's restricted to be an eqtype //from then on. DataType datatype; EqTypes tail; public EqTypes() { this.datatype = null; this.tail = null; } public EqTypes(DataType datatype1,EqTypes tail) { this.datatype = datatype1; this.tail = tail; } public boolean Present (String nameofeqtype) { //just to check if the given datatype can be member of eqtypes if (datatype == null ) return false; else if (nameofeqtype.equals(datatype.name)){return true;} else if (tail != null) { return tail.Present(nameofeqtype); } else return false; } public boolean PresentArity (String nameofeqtype,int arity) { //This is to check that the number of parameters of the //datatype matches. if (datatype == null ) return false; else if (nameofeqtype.equals(datatype.name)){ if (datatype.parameters == null) return ( 0 == arity); if ( (datatype.parameters).length() == arity ) return true; else return false; } else if (tail != null) { return tail.PresentArity(nameofeqtype,arity); } else return false; } public DataType Retrieve(String nameofeqtype) { //check if it's present if (datatype == null ) return null; else if (nameofeqtype.equals(datatype.name)){return datatype;} else if (tail != null) { return tail.Retrieve(nameofeqtype); } else return null; } public void Extend(DataType datatype2) { //add a new eqtype to the list if (datatype == null) { datatype = datatype2; } else { EqTypes temp = new EqTypes(datatype,tail); datatype = datatype2; tail = temp; } } public void Extend2(DataType datatype3) { if (datatype == null) { datatype = datatype3; } else { EqTypes temp = new EqTypes(datatype,tail); datatype = datatype3; tail = temp; } } public boolean IsEqType(DataType dt){return true;} } //to have a datatype,a boolean and an eqtypes class SimpleList { /* This is a list of datatypes - some that are present from the start - e.g. int, bool etc. The other datatypes present are the ones that are added as datatype declarations are made. It also stores whether or not a datatype is an eqyuality type. */ DataType dt; boolean iseqtype; EqTypes eqt; SimpleList tail; public SimpleList (){ this.dt = null; this.iseqtype = false; eqt = null; tail = null; } public void Extend(DataType dt1,boolean iseqtype1,EqTypes eqt1){ if (dt == null) { dt = dt1;iseqtype = iseqtype1;eqt = eqt1; } else if (tail == null) { SimpleList temp = new SimpleList(); temp.dt = dt1;temp.iseqtype = iseqtype1;temp.eqt = eqt1; tail = temp; } else tail.Extend(dt1,iseqtype1,eqt1); } public boolean Find(DataType dt1,boolean iseqtype1) { if (dt == null) { iseqtype = false; return false; } else if (dt == dt1) { iseqtype1 = iseqtype; return true; } else return tail.Find(dt1,iseqtype1); } } class Miscell { int i; public Miscell () { i = 0; }; public boolean IsEqTypeTE(TypeExp te,EqTypes eq) { //in this case it's up to the parser to make sure that the only //vartypaes come from the arguments - could maybe check if it's on //the parameters list if (te instanceof VarType) { if (((VarType)(te)).instance == null) return true; else { return IsEqTypeTE(((VarType)(te)).instance,eq); } } else if (te instanceof OperType) { String temp = ((OperType)(te)).ide; if (temp.equals("->")) return false; else { //for convenince * is to be added to the datatype env DataType dt = eq.Retrieve(temp); if (dt == null) return false; else if (dt.IsEqType == 2) return false; else if ((dt.IsEqType == 1) || (dt.IsEqType == 0)) { boolean iseq = true; TypeList otte = ((OperType)(te)).args; while (otte != null) { if (otte.head == null) return true && iseq; iseq = IsEqTypeTE(otte.head,eq) && iseq; otte = otte.tail; } return iseq; } } } else return true; return true; //return false; } public boolean IsEqTypeTEforand(TypeExp te,EqTypes eq,EqTypes eqlist) { if (te instanceof VarType) { if (((VarType)(te)).instance == null) return true; else return IsEqTypeTE(((VarType)(te)).instance,eq); //can put it has to be present in a typelist } else if (te instanceof OperType) { String temp = ((OperType)(te)).ide; if (temp.equals("->")) return false; else { DataType dt = eq.Retrieve(temp); if (dt == null) return false; else if (dt.IsEqType == 2) return false; else if ((dt.IsEqType == 1) || (dt.IsEqType == 0)) { if (dt.IsEqType == 0) eqlist.Extend(dt); //in her can add it to the lsit for ones not yet decided boolean iseq = true; TypeList otte = ((OperType)(te)).args; while (otte != null) { if (otte.head == null) return true && iseq; iseq = IsEqTypeTE(otte.head,eq) && iseq; otte = otte.tail; } return iseq; } } } else return true; return false; } //definitely check that this is making the changes public void makeEqType(TypeExp te) { //This function restricts any variable types in the type expression to be //equality types. if (te instanceof VarType) { if (! (((VarType)(te)).IsEqType)) { ((VarType)(te)).SetEqType(); } if (((VarType)(te)).instance != null) makeEqType(((VarType)(te)).instance); } else if (te instanceof OperType) { TypeList otte = ((OperType)(te)).args; while (otte != null) { if (otte.head == null) return; makeEqType(otte.head); otte = otte.tail; } } } public boolean IsEqType(DataType dt,EqTypes eq) { //check whether a datatype is an eqtype int setiseqtype = 0; ArgList temp = dt.Pattern; eq.Extend(dt);//make sure when you update it, it's updated here boolean iseqtype = true; while (!((temp.namefn).equals(""))) { iseqtype = iseqtype && (IsEqTypeTE(temp.type,eq) );; if (temp.tail == null) break; temp = temp.tail; } return iseqtype; } public boolean IsEqTypeforand(AndDecl anddecl,EqTypes eq) { //want to create a list here //to have a datatype,a boolean and an eqtypes SimpleList list = new SimpleList(); int setiseqtype = 0; if (! (anddecl.decl1 instanceof DataType) ) return false; DataType Decl1 = (DataType)(anddecl.decl1); AndDecl tail = (AndDecl)(anddecl.tail); do { eq.Extend(Decl1);System.out.print("Adding ");System.out.print(Decl1.name); if (tail == null) break; if (tail == null) break; if (tail.decl1 == null) break; if (! (tail.decl1 instanceof DataType)) break; Decl1 = (DataType)(tail.decl1); tail = tail.tail; } while (Decl1 != null); Decl1 = (DataType)(anddecl.decl1); tail = anddecl.tail; do { EqTypes tempeq = new EqTypes(); ArgList temp = Decl1.Pattern; eq.Extend(Decl1);//make sure when you update it, it's updated here //maybe do this later in the function boolean iseqtype = true; while (!((temp.namefn).equals(""))) { System.out.print("in the while"); iseqtype = iseqtype && (IsEqTypeTEforand(temp.type,eq,tempeq) ); if (temp.tail == null) break; temp = temp.tail; } list.Extend(Decl1,iseqtype,tempeq); System.out.print("Extend ");System.out.print(Decl1.name);if (iseqtype) System.out.print(" true ");System.out.print(" false "); if (tail == null) break; if (tail.decl1 == null) break; if (! (tail.decl1 instanceof DataType)) break; Decl1 = (DataType)(tail.decl1); tail = tail.tail; } while (Decl1 != null); boolean onechanged = false; SimpleList tlist = list; do { onechanged = false; while (tlist.dt != null) { //if (tlist.dt == null) break; if ((tlist.iseqtype == false) && (tlist.dt.IsEqType != 2)) { tlist.dt.IsEqType = 2; System.out.print(tlist.dt.name); onechanged = true; } tlist= tlist.tail; if (tlist == null) break; } tlist = list; boolean notset = false; while (tlist.dt != null) { if (tlist.dt == null) break; //look at the eqtypes if any are false i.e. == 2 EqTypes eqtypes = tlist.eqt; while (eqtypes.datatype != null) { if (eqtypes.datatype.IsEqType == 2){ if (tlist.dt.IsEqType != 2) onechanged = true; tlist.dt.IsEqType = 2; break;} if (eqtypes.datatype.IsEqType == 1){notset = true;} if (eqtypes.tail == null) break; eqtypes = eqtypes.tail; } if (tlist.tail == null) break; tlist = tlist.tail; } } while (onechanged); SimpleList rlist = list; while (rlist.dt != null) { if (rlist.dt.IsEqType == 0) {rlist.dt.IsEqType = 1; } // if (rlist.iseqtype == true) { // rlist.dt.IsEqType = 0;System.out.print("Set to true ");System.out.print(rlist.dt.name); // } rlist = rlist.tail; if (rlist == null) break; } return true; } } //don't need an IsEqType for the typeExp it's just a matter of unifying them - however if //it's an instance of an Oper Type class TypeList { // A list of types TypeExp head; TypeList tail; public TypeList() { head = null; tail = null; } public static TypeList Extend(TypeExp head1,TypeList tail1){ TypeList temp = new TypeList(); temp.head = head1; temp.tail = tail1; return temp; } public int length() { if (head == null) return 0; else if (tail == null )return 1 ; else return (1 + tail.length()); } public void ExtendProper(TypeExp head2) { TypeList temp = new TypeList(); temp.head = head; temp.tail = tail; head = head2; tail = temp; } public void Extend(TypeExp newte) { if (head == null) { head =newte; } else if (tail == null) { TypeList temptail = new TypeList(); temptail.head = newte; tail = temptail; } else tail.ExtendProper(newte); } }; class exn extends TypeExp { //The exception type TypeExp instance; public exn(){ this.instance = null; } } class overload extends TypeExp { //The overload type TypeExp instance; public overload(){ this.instance = null; } public overload(TypeExp instance) { this.instance = instance; } } class VarType extends TypeExp { //The variable type has it's instance class - in addition it has two //boolean values to record if a variable type is an instance of an equality //type or if it's an overloaded type TypeExp instance; boolean IsEqType ; boolean overload; public VarType() { this.instance = null; super.typeoftypeclass = 1; this.IsEqType = false; this.overload = false; }; public VarType(TypeExp instance){ this.instance = instance; super.typeoftypeclass = 1; this.IsEqType = false; this.overload = false; } public VarType(boolean IsEqType) { this.instance = null; super.typeoftypeclass = 1; this.IsEqType = IsEqType; this.overload = false; } public void SetEqType() { IsEqType = true; } public void SetOverLoad(){ overload = true; } } class EqType extends VarType { //The equality type class public EqType() { super.instance = null; } public EqType(TypeExp te) { super.instance = te; } } class OperType extends TypeExp { //The Operation Type contains an identifier for the operation - //It also contains the args for the operator if appropriate which //is a list of types. String ide; TypeList args; public OperType() { this.ide = null; this.args = null; this.typeoftypeclass = 2; } public OperType(String ide,TypeList args) { this.ide = ide; this.args = args; super.typeoftypeclass = 2; } } class TypeExp2 { int typeoftypeclass2; VarType vartype; OperType opertype; public TypeExp2(){typeoftypeclass2 = 0;vartype = null;opertype = null;} public TypeExp2(int type,VarType vartype,OperType opertype){ this.typeoftypeclass2 = type; this.vartype = vartype; this.opertype = opertype; } } class UnifException extends Exception { //This is a class for the exception thrown when an error occurs during the process //of unification. It reccords the message and the two type expressions involved in //the unification error. String message; TypeExp first; TypeExp second; public UnifException(String message,TypeExp first,TypeExp second) { this.message = message; this.first = first; this.second = second; } } class Table { ///////////////////////////////////////// TypeExp original; TypeExp current; Table tail; public Table() { this.original = null; this.current = null; this.tail = null; } public Table( TypeExp original,TypeExp current,Table tail) { this.original = original; this.current = current; this.tail = tail; } public void clearcurrent() { if (original == null) return; else if (tail == null) { current = null; return; } else { current = null; tail.clearcurrent(); } } public void Extend(TypeExp originalo,TypeExp currento) { if (original == null) { original = originalo; current = currento; } else if (tail == null) { tail = new Table(originalo,currento,null); } else { tail.Extend(originalo,currento); } } public boolean PresentO(TypeExp originalo) { //checking to see if originalo is in the table - only checks the original entries if (original == null) { return false; } else if (((original)) == ((originalo))) { return true; } else if (tail == null) { return false; } else return tail.PresentO(originalo); } public boolean PresentC(TypeExp currento) { //checking to see if originalo is in the table - only checks the current entries if (current == null) { return false; } else if (((current)) == ((currento))) { return true; } else if (tail == null) { return false; } else return tail.PresentC(currento); } public TypeExp SetC(TypeExp originalo,TypeExp currento) { if (original == null) { return null; } else if ((/*(VarType)*/(original)) == (/*(VarType)*/(originalo))) { if (current == null) {//System.out.print("in this"); current = currento; return currento; } else {return current;} } else if (tail == null ) return null; else return tail.SetC(originalo,currento); } public TypeExp RetrieveifC(TypeExp currento) { if (current == null) { return null;//not found } else if (((VarType)(current)) == ((VarType)(currento))) { return original; } else return tail.RetrieveifC(currento); } public TypeExp RetrieveifO(TypeExp originalo) { if (original == null) { return null;//not found } else if (((VarType)(original)) == ((VarType)(originalo))) { return current; } else return tail.RetrieveifO(originalo); } } interface Misc { public boolean OccursInType(TypeExp typeVar,TypeExp typeExp); public boolean OccursInTypelist(TypeExp typeVar, TypeList list) ; public void UnifyType(TypeExp typeExp1,TypeExp typeExp2,EqTypes eq ) throws Exception,UnifException; public void UnifyArgs(TypeList list1,TypeList list2,EqTypes eq)throws Exception,UnifException; } class TypeFns implements Misc { int i; public TypeFns() { this.i = 0; }; public static TypeExp Prune(TypeExp typeExp) //Eliminate redundant instantiated varaibles at the top of typeExp //The result of Prune is a non-instantiated type variable or a type operator { if (typeExp instanceof VarType) { if (((VarType)(typeExp)).instance == null ) { return typeExp; } else { ((VarType)(typeExp)).instance = Prune(((VarType)(typeExp)).instance); return ((VarType)(typeExp)).instance; }; } else if (typeExp instanceof OperType) { return typeExp;} else if (typeExp instanceof exn) {return typeExp;} else if (typeExp instanceof overload) { if (((overload)(typeExp)).instance == null) return typeExp; else ((overload)(typeExp)).instance = Prune(((overload)(typeExp)).instance); return typeExp; } return new VarType();//was typeexp } public static boolean SameType(TypeExp typeexp1,TypeExp typeexp2) //Are two type expressions the same { return typeexp1 == typeexp2; } public boolean OccursInType(TypeExp typeVar,TypeExp typeExp){ //checks that typeVar does not occur in typeExp typeExp = Prune(typeExp); //check that you don't have to do anything here for overload if (typeExp instanceof VarType) return SameType(typeVar,typeExp); else if (typeExp instanceof OperType) return OccursInTypelist(typeVar,((OperType)(typeExp)).args); return false; }; public boolean OccursInTypelist(TypeExp typeVar, TypeList list) //check that typeVar does not occur in the type expression of any element of list { if (list == null) return false; if (OccursInType(typeVar,list.head)) return true; return OccursInTypelist(typeVar,list.tail); } public void UnifyType(TypeExp typeExp1,TypeExp typeExp2,EqTypes eq) throws Exception,UnifException { //This function and the function UnifyArgs form the basis for the unification //algorithm - based initially on the functions in Cardellis paper and //extended to deal with the extra semantics that were added if ((typeExp1 == null) || (typeExp2 == null)) { Exception un = new Exception("null pointer"); throw un; } typeExp1 = Prune(typeExp1); typeExp2 = Prune(typeExp2); if (typeExp1 instanceof VarType) { if (typeExp2 instanceof exn) ((VarType)(typeExp1)).instance = typeExp2; if (OccursInType(typeExp1,typeExp2)) { if (!(SameType(typeExp1,typeExp2))) { //maybe look into outputting the types that don't match UnifException e = new UnifException("Can't unify",typeExp1,typeExp2); throw e; } } else { if ( ((VarType)(typeExp1)).IsEqType) { //put a special case here to deal with it if (typeExp2 instanceof exn){ throw new UnifException("exn is not an eqtpye ",typeExp1,typeExp2); } else if ( typeExp2 instanceof overload) { ((VarType)(typeExp1)).instance = typeExp2; } else { Miscell m = new Miscell(); if (m.IsEqTypeTE(typeExp2,eq)) { m.makeEqType(typeExp2); ((VarType)(typeExp1)).instance = typeExp2; } else throw new UnifException("The second is not an eqtype",typeExp1,typeExp2); } } else ((VarType)(typeExp1)).instance = typeExp2; } } else if (typeExp1 instanceof overload) { if (typeExp2 instanceof VarType) { ((VarType)(typeExp2)).instance = typeExp1; } else if (typeExp2 instanceof exn) throw new UnifException("You need an exception type",typeExp1,typeExp2); else if (typeExp2 instanceof OperType) { if (((((OperType)(typeExp2)).ide).equals("char") || (((OperType)(typeExp2)).ide).equals("int")) ) //&& { if ( ((overload)(typeExp1)).instance == null ) { ((overload)(typeExp1)).instance = typeExp2; } else { TypeExp temp = ((overload)(typeExp1)).instance ; if (((overload)(typeExp1)).instance instanceof OperType) { if ( !( (((OperType)(((overload)(typeExp1)).instance)).ide).equals(((OperType)(typeExp2)).ide) ) ) { throw new UnifException("OverLoading",typeExp1,typeExp2); } } } } else { throw new UnifException("expected a real or an int",typeExp1,typeExp2); } } } else if (typeExp1 instanceof exn) { if (typeExp2 instanceof exn) { return; } else if ((typeExp2 instanceof VarType) && !((VarType)(typeExp2)).IsEqType) ((VarType)(typeExp2)).instance = new exn(); else throw new UnifException("This must have type exn",typeExp1,typeExp2); } else if (typeExp1 instanceof OperType) { if (typeExp2 instanceof exn) throw new UnifException("You need an exeption type",typeExp1,typeExp2); else if (typeExp2 instanceof VarType) UnifyType(typeExp2,typeExp1,eq); else if (typeExp2 instanceof overload) UnifyType(typeExp2,typeExp1,eq); else if ( typeExp2 instanceof OperType) { //need tos sort out a test here for inttypes etc if ((((OperType)(typeExp1)).ide).equals(((OperType)(typeExp2)).ide)) UnifyArgs(((OperType)(typeExp1)).args,((OperType)(typeExp2)).args,eq); else { UnifException ex = new UnifException("Not the same type - can't be unified",typeExp1,typeExp2); throw ex; } } } else { StringBuffer s = new StringBuffer(typeExp1.toString()); s.append(typeExp2.toString());System.out.print(s); } } public void UnifyArgs(TypeList list1,TypeList list2,EqTypes eq) throws Exception,UnifException { //Unifies the arguments of OperType typeexps if ((list1 == null) && (list2 == null)) return ; //This is the case where the number of arguments matches if ((list1 == null) || (list2 == null)) { //These two type expressions can't be unifed as they don;t have matching //arguments - just checks which exception to throw VarType v = new VarType(); if (list1 != null) throw new UnifException("The number of aguments don't match",list1.head,v); else throw new UnifException("The number of arguments don't match",list2.head,v); } else { //Otherwise it unifies the first argument of each type expression //and then continues matching the remaining arguments UnifyType(list1.head,list2.head,eq); UnifyArgs(list1.tail,list2.tail,eq); } } } class CopyEnv { TypeExp oldty,newty; CopyEnv tail; public CopyEnv(){ this.oldty = null; this.newty = null; this.tail = null; }; public CopyEnv(TypeExp oldty,TypeExp newty,CopyEnv tail) { this.oldty = oldty; this.newty = newty; this.tail = tail; } public void Extend(TypeExp oldty2,TypeExp newty2) { CopyEnv temp = new CopyEnv(oldty,newty,tail); oldty = oldty2; newty = newty2; tail = temp; } }; interface Misc2 { public TypeExp Fresh(TypeExp typeExp,TypeList list,CopyEnv env); public TypeList FreshList(TypeList args,TypeList list,CopyEnv env); public TypeExp FreshSpecial(TypeExp typeExp,TypeList list,CopyEnv env,Table t,boolean reverse); public TypeList FreshListSpecial(TypeList args,TypeList list,CopyEnv env,Table t,boolean reverse); } class GenericVarMod implements Misc2 { //Extend should really use the fact that it's automatically supplied with an arg - check that this isn't recursive and that I've got the right def int i; public GenericVarMod() { i = 0; } public TypeList Extend(TypeExp head ,TypeList tail) { return TypeList.Extend(head,tail); } public boolean IsGeneric(TypeExp typeVar,TypeList list) { //This function checks whether a given variable occurs in a list of non-generic variables TypeFns t = new TypeFns(); return !(t.OccursInTypelist(typeVar,list)); } public CopyEnv ExtendCopyEnv(TypeExp oldty,TypeExp newty,CopyEnv tail) { CopyEnv r = new CopyEnv(oldty,newty,tail); return r; }; //the env here is a variable parameter public TypeExp FreshVar(TypeExp typeVar,CopyEnv scan,CopyEnv env){ if (scan == null) { TypeExp newTypeVar; if ((typeVar instanceof VarType) && ((VarType)(typeVar)).IsEqType) { newTypeVar = new VarType(true); } else if (typeVar instanceof VarType) newTypeVar = new VarType(); else if (typeVar instanceof overload) { if (((overload)(typeVar)).instance == null) newTypeVar = new overload(); else newTypeVar = new overload(((overload)(typeVar)).instance); //assume in this case only ever opertype of real or int; } else newTypeVar = null; env.Extend(typeVar,newTypeVar); return newTypeVar; } else if (TypeFns.SameType(typeVar,scan.oldty)) { return scan.newty; } else { return FreshVar(typeVar,scan.tail,env); } } public CopyEnv CopyCopyEnv(CopyEnv env) { //Returns a copy of env if (env.oldty != null) { if (env.tail == null) { return new CopyEnv(env.oldty,env.newty,null); } else { CopyEnv tail = CopyCopyEnv(env.tail); return ExtendCopyEnv(env.oldty,env.newty,tail); } } else return new CopyEnv(); }; //yet again env is a variable parameter - check what to do public TypeExp Fresh(TypeExp typeExp,TypeList list,CopyEnv env){ typeExp = TypeFns.Prune(typeExp); if (typeExp instanceof VarType) { if (IsGeneric(typeExp,list)) { CopyEnv scan = CopyCopyEnv(env); TypeExp returnE = FreshVar(typeExp,scan,env); if (env.oldty == null) { }return returnE; } else { return typeExp; }; } else if (typeExp instanceof OperType) { return new OperType(((OperType)(typeExp)).ide,FreshList(((OperType)(typeExp)).args,list,env)); } else if (typeExp instanceof overload) { CopyEnv scan = CopyCopyEnv(env); return FreshVar(typeExp,scan,env); } else if (typeExp instanceof exn) return typeExp;//mighn't need new return typeExp; }; public TypeList FreshList(TypeList args,TypeList list,CopyEnv env){ //This returns a fresh type list - a fresh type expression is returned for each of the //elements of the list as described in FreshType. if (args == null) return null; return TypeList.Extend(Fresh(args.head,list,env),FreshList(args.tail,list,env)); } public TypeExp FreshType(TypeExp typeExp,TypeList list) { //This returns a fresh variable for typeVar, where the generic variables are copied, //while the non-generic ones are shared. CopyEnv env = new CopyEnv(); return Fresh(typeExp,list,env); } public TypeExp FreshVarSpecial(TypeExp typeVar,CopyEnv scan,CopyEnv env,Table t,boolean reverse){ if (scan == null) { TypeExp newTypeVar; if (reverse ) { if (t.PresentC(typeVar)) { newTypeVar = t.RetrieveifC(typeVar); } else { newTypeVar = new VarType(); } } else { if ((typeVar instanceof VarType) && ((VarType)(typeVar)).IsEqType) { newTypeVar = new VarType(true); } else if (typeVar instanceof VarType) newTypeVar = new VarType(); else if (typeVar instanceof overload) { if (((overload)(typeVar)).instance == null) newTypeVar = new overload(); else newTypeVar = new overload(((overload)(typeVar)).instance); //assume in this case only ever opertype of real or int; } else newTypeVar = null; if (t.PresentO(typeVar)) { newTypeVar = t.SetC(typeVar,newTypeVar); } else { t.Extend(typeVar,newTypeVar) ; } } env.Extend(typeVar,newTypeVar); return newTypeVar; } else if (TypeFns.SameType(typeVar,scan.oldty)) { return scan.newty; } else { return FreshVarSpecial(typeVar,scan.tail,env,t,reverse); } } public TypeExp FreshTypeSpecial(TypeExp typeExp,TypeList list,Table t,boolean reverse) { CopyEnv env = new CopyEnv(); return FreshSpecial(typeExp,list,env,t,reverse); } public TypeExp FreshSpecial(TypeExp typeExp,TypeList list,CopyEnv env,Table t,boolean reverse){ typeExp = TypeFns.Prune(typeExp); if (typeExp instanceof VarType) { if (IsGeneric(typeExp,list)) { CopyEnv scan = CopyCopyEnv(env); TypeExp returnE = FreshVarSpecial(typeExp,scan,env,t,reverse); if (env.oldty == null) { }return returnE; } else { return typeExp; }; } else if (typeExp instanceof OperType) { return new OperType(((OperType)(typeExp)).ide,FreshListSpecial(((OperType)(typeExp)).args,list,env,t,reverse)); } else if (typeExp instanceof exn) return new exn();//mighn't need new else if (typeExp instanceof overload) { CopyEnv scan = CopyCopyEnv(env); return FreshVarSpecial(typeExp,scan,env,t,reverse); } return typeExp;//to get rid of the objection }; //check that this is the right extend public TypeList FreshListSpecial(TypeList args,TypeList list,CopyEnv env,Table t,boolean reverse){ if (args == null) return null; return TypeList.Extend(FreshSpecial(args.head,list,env,t,reverse),FreshListSpecial(args.tail,list,env,t,reverse)); } } class BoolTypeExp { boolean bool; TypeExp te; public BoolTypeExp (boolean bool,TypeExp te) { this.bool = bool; this.te = te; } } class Env { //The environments associate type expressions with identifiers. //For each identifier the type is stored and a true type is stored //also. This type will remain unaltered by any type changes etc. that //are applied to the expression. //is dtcons stores whether or not it's a datatype ??? String ide; TypeExp typeExp; TypeExp truetype; boolean isdtcons; Env tail; public Env() { this.ide = null; this.isdtcons = false; this.typeExp = null; this.tail = null; this.truetype = null; } public void Refresh() { ide = null; typeExp = null; tail = null; truetype = null; } //Different Extends depending on what data needs to be added to the //environment. public void Extend(String iden,TypeExp typeExpr,boolean isdtconsr,TypeExp truetyper) { if (tail == null ) { Env tempenv = new Env(); tempenv.ide = ide; tempenv.isdtcons = isdtcons; tempenv.typeExp = typeExp; tempenv.truetype = truetype; tail = tempenv; ide = iden; typeExp = typeExpr; isdtcons = isdtconsr; truetype = truetyper; } else { tail.Extend(ide,typeExp,isdtcons,truetype); ide = iden; typeExp = typeExpr; isdtcons = isdtconsr; truetype = truetyper; } } public void Extend(String iden,TypeExp typeExpr,boolean isdtconsr) { if (tail == null ) { Env tempenv = new Env(); tempenv.ide = ide; tempenv.isdtcons = isdtcons; tempenv.typeExp = typeExp; tempenv.truetype = truetype; tail = tempenv; ide = iden; typeExp = typeExpr; isdtcons = isdtconsr; truetype = null; } else { tail.Extend(ide,typeExp,isdtcons,truetype); ide = iden; typeExp = typeExpr; isdtcons = isdtconsr; truetype = null; } } public void Extend(String iden,TypeExp typeExpr) { if (tail == null ) { Env tempenv = new Env(); tempenv.ide = ide; tempenv.isdtcons = isdtcons; tempenv.typeExp = typeExp; tail = tempenv; ide = iden; typeExp = typeExpr; isdtcons = false; } else { tail.Extend(ide,typeExp,isdtcons,truetype); ide = iden; typeExp = typeExpr; isdtcons = false; } } public boolean Present(String iden) { //This checks whether or not an identifier is in the environment if (ide == null) { return false; } else if (iden.equals(ide)) { return true; } else { return tail.Present(iden); } } public String PresentType(TypeExp TE) { //This checks whether or not a particular type expression is in the environment. //It returns "" if TE is not present. if (typeExp == null) { return ""; } else if (TE == typeExp) { return ide; } else { return tail.PresentType(TE); } } public int Number() { //Return the size of the environment if (ide == null) return 0; else if (tail == null) return 1; else return (1 + tail.Number()); } public TypeExp Retrieve(String iden,TypeList list){ //Search for an identifier in the environment and return a "fresh" copy of //the associated type - return null if not found. if (ide == null) { return null; } else if (iden.equals(ide)) { GenericVarMod g = new GenericVarMod(); return g.FreshType(typeExp,list); } else { return tail.Retrieve(iden,list); } } public BoolTypeExp RetrieveDT(String iden,TypeList list){ //Returns the value of isdtcons for iden. if (ide == null) { //if not found then return false return new BoolTypeExp(false,null); } else if (iden.equals(ide)) { GenericVarMod g = new GenericVarMod(); return new BoolTypeExp(isdtcons,g.FreshType(typeExp,list)); } else { return tail.RetrieveDT(iden,list); } } public TypeExp RetrieveOriginal(String iden) { //This retrieves the type associated with the identifier - this is the //original type that can't change. if (ide == null) {return null;} else if (iden.equals(ide)) { return typeExp;} else return tail.RetrieveOriginal(iden); } public TypeExp RetrieveTrueType(String iden) { //This retrieves the truetype associated with the identifier. if (ide == null) {return null;} else if (iden.equals(ide)) { return truetype;} else return tail.RetrieveTrueType(iden); } } class ExExcept extends Exception { //The class ExExcept is an expception class that carries a type and a string explaining the error TypeExp te; String error; public ExExcept(String error,TypeExp te) { this.te = te; this.error = error; // Exception(error); } } class posnException extends Exception { //The class posnException class can store two integers representing hte start and end position. int first,second; public posnException(int first,int second) { this.first = first; this.second = second; } } class ChangePartialType { boolean tobechanged;//does it need to be changed TypeExp type;//the type to be assumed if a change is to be made. int posn; public ChangePartialType() { this.tobechanged = false; this.type = null; this.posn = 0; } public ChangePartialType(boolean tobechanged,TypeExp type,int posn) { this.tobechanged = tobechanged; this.type = type; this.posn = posn; } } class TwoTypes { //A class to allow two types to be returned from a function simultaneously etc. //This is used in the intial typechecking function, AnalyzeExp. TypeExp returnExp,creturnExp; public TwoTypes() {this.returnExp = null;this.creturnExp = null;} public TwoTypes(TypeExp returnExp,TypeExp creturnExp) { this.returnExp = returnExp; this.creturnExp = creturnExp; } } class TwoEnvs { //A class to allow two environments to be dealt with at the same time. //This is used in the initial typecjecking function AnalyzeDecl. Env env1,env2; public TwoEnvs() {this.env1 = null;this.env2 = null;} public TwoEnvs(Env env1,Env env2) { this.env1 = env1; this.env2 = env2; } } class returnExp { //A class that returns a type expression and whether or not it //has changed. TypeExp typeexp; boolean ifchanged; public returnExp(){this.typeexp = null;this.ifchanged = false;}; public returnExp(TypeExp typeexp,boolean ifchanged) {this.typeexp = typeexp;this.ifchanged = ifchanged;}; } class firstError { //This class is to record information about the first error that occurred, as that is the one //that stopped the typechecking. boolean errorfound;//Was an error found ? String info;//Information about the error. TypeExp te1,te2;//The two type expressions that failed to unify. int StartPosn, EndPosn;//The start and end positions where the error was detected. public firstError() { errorfound = false; info = null; te1 = null;te2 = null; } public void setinfo(String pinfo ,TypeExp pte1,TypeExp pte2,int pStartPosn,int pEndPosn){ errorfound = true; info = pinfo; te1 = pte1;te2 = pte2; StartPosn = pStartPosn;EndPosn = pEndPosn; } } interface TCI { public void AnalParseErr(Exp exp) throws Exception,UnifException; public void AnalParseErrD(Decl decl) throws Exception,UnifException; public TwoTypes AnalyzeExp(Exp exp,Env envp,TypeList list,Env cloneEnv,TypeList cloneList,Env errorenv,firstError fe) throws ExExcept,Exception,UnifException; public TwoEnvs AnalyzeDecl(Decl decl,Env envp,TypeList list,Env cloneEnv,TypeList cloneList,Env errorenv,firstError fe)throws ExExcept,Exception,UnifException; public void AnalyzeRecDeclBind(Decl del,Env envp,TypeList list, Env cloneEnv,TypeList cloneList,Env errorenv,firstError fe);//check about variable parameters public void AnalyzeRecDecl(Decl decl,Env envp, TypeList list,Env cloneEnv,TypeList cloneList,Env errorenv,firstError fe) throws ExExcept,Exception,UnifException; public TypeExp CartType(TypeExp first,TypeExp second); public TypeExp FunType( TypeExp dom ,TypeExp cod); public void AnalyzeExpParsed(Exp exp,int StartPosn,int EndPosn,int change,boolean insidechange) throws ExExcept,Exception,UnifException; public void AnalyzeDeclParsed(Decl decl,int StartPosn,int EndPosn,int change,boolean insidechange)throws ExExcept,Exception,UnifException; public returnExp AnalExpChange(Exp exp,Env changeenv,int StartPosn,int EndPosn,TypeExp tochangeto,TypeList list,boolean changed,firstError fe,Env errorenv,boolean focus)throws ExExcept,Exception,UnifException; public Env AnalDeclChange(Decl decl,Env changeenv,TypeList list,int StartPosn,int EndPosn,TypeExp tobechangedto,boolean changed,firstError fe,Env errorenv,boolean focus) throws ExExcept,Exception,UnifException; } class TypecheckMod implements TCI { //create the basic types TypeExp BoolType = new OperType(("bool"),null); TypeExp IntType = new OperType(("int"),null); //Initialise the relevant vaialbes TypeFns tf = new TypeFns(); GenericVarMod gv = new GenericVarMod(); Env env; Env ExcEnv; EqTypes dt;//This is a list containing the information what type expressions //are equality types. Table t; int i; public TypecheckMod() { env = new Env(); ExcEnv = new Env(); t = new Table(); dt = new EqTypes(); TypeExp ol = new overload(); TypeExp plus = FunType(CartType(ol,ol),ol);env.Extend("plus",plus); TypeExp minus = FunType(CartType(ol,ol),ol);env.Extend("minus",minus); //Adding some basic functions and varaibles to the initial environment TypeExp trueval = BoolType;env.Extend("true",trueval); TypeExp falseval = BoolType;env.Extend("false",falseval); TypeExp eq = new VarType(true); TypeExp equals = FunType(CartType(eq,eq),BoolType);env.Extend("equals",equals); TypeExp succ = FunType(IntType,IntType);env.Extend("succ",succ); TypeExp pred = FunType(IntType,IntType);env.Extend("pred",pred); TypeExp iszero = FunType(IntType,BoolType);env.Extend("zero",iszero); TypeExp zero = IntType;env.Extend("0",zero); TypeExp one = IntType;env.Extend("1",one); TypeExp two = IntType;env.Extend("2",two); TypeExp three = IntType;env.Extend("3",three); TypeExp four = IntType;env.Extend("4",four); TypeExp five = IntType;env.Extend("5",five); TypeExp six = IntType;env.Extend("6",six); TypeExp seven = IntType;env.Extend("7",seven); TypeExp eight = IntType;env.Extend("8",eight); TypeExp nine = IntType;env.Extend("9",nine); TypeExp Type1 = new VarType(); TypeExp Type2 = new VarType(); TypeExp pair = FunType(Type1,FunType(Type2,CartType(Type1,Type2)));env.Extend("pair",pair); TypeExp Type11 = new VarType();TypeExp Type21 = new VarType(); TypeExp fst = FunType(CartType(Type11,Type21),Type11);env.Extend("fst",fst); TypeExp Type12 = new VarType();TypeExp Type22 = new VarType(); TypeExp snd = FunType(CartType(Type12,Type22),Type22);env.Extend("snd",snd); TypeExp Type13 = new VarType(); TypeExp alist = new OperType(("list"),TypeList.Extend(Type13,null)); TypeExp nil = alist;env.Extend("nil",nil,true); TypeExp cons = FunType(CartType(Type13,alist),alist);env.Extend("cons",cons,true); TypeExp hd = FunType(alist,Type13);env.Extend("hd",hd); TypeExp tl = FunType(alist,alist);env.Extend("tl",tl); TypeExp nulllist = FunType(alist,BoolType);env.Extend("null",nulllist); TypeExp andalso = FunType(CartType(BoolType,BoolType),BoolType);env.Extend("andalso",andalso); TypeExp orelse = FunType(CartType(BoolType,BoolType),BoolType);env.Extend("orelse",orelse); DataType bool2 = new DataType("bool",null,null,1);dt.Extend(bool2); DataType int2 = new DataType("int",null,null,1);dt.Extend(int2); DataType char2 = new DataType("char",null,null,1);dt.Extend(char2); DataType string2 = new DataType("string",null,null,1);dt.Extend(string2); TypeExp type2 = new VarType(); TypeExp type3 = new VarType(); ArgList params1 = new ArgList(); params1.Extend("'a",type2);params1.Extend("'b",type3); DataType cart = new DataType("*",params1,null,1);dt.Extend(cart); ArgList args = new ArgList(); ArgList params = new ArgList(); args.Extend("nil",alist); args.Extend("cons",CartType(Type13,alist)); params.Extend("'a",Type13); DataType list2 = new DataType("list",params,args,1);dt.Extend(list2); } public void AnalParseErr(Exp exp) throws Exception,UnifException{ //This is used to traverse the expression tree in such a way as //to return the first error - i.e. the one that would have stopped the //typechecking from continuing. It does this by throwing an exception. if (exp.uniferror == true) { throw new UnifException(exp.info,exp.first,exp.second); } //maybe look at passing some additional positiona; data with this if (exp instanceof IdeClass) { return; } else if (exp instanceof CondClass) { AnalParseErr(((CondClass)(exp)).test); AnalParseErr(((CondClass)(exp)).iftrue); AnalParseErr(((CondClass)(exp)).iffalse); } else if (exp instanceof WhileClass) { AnalParseErr(((WhileClass)(exp)).test); AnalParseErr(((WhileClass)(exp)).body); } else if (exp instanceof LambClass) { AnalParseErr(((LambClass)(exp)).body); } else if (exp instanceof ApplClass) { AnalParseErr(((ApplClass)(exp)).fun); AnalParseErr(((ApplClass)(exp)).arg); } else if (exp instanceof BlockClass) { AnalParseErrD(((BlockClass)(exp)).decl); AnalParseErr(((BlockClass)(exp)).scope); } else if (exp instanceof MiniFn) { Parameters params = ((MiniFn)(exp)).Pattern; do { if (params.exp == null) break; AnalParseErr(params.exp); params = params.tail; } while (params != null); AnalParseErr(((MiniFn)(exp)).Body); } else if (exp instanceof MiniFnList) { MiniFnList mfl = ((MiniFnList)(exp)); do { if (mfl == null) break; if (mfl.head == null) break; AnalParseErr(mfl.head); mfl = mfl.tail; } while (mfl != null); } else if (exp instanceof Appl2Class) { AnalParseErr(((Appl2Class)(exp)).fun); Parameters param = ((Appl2Class)(exp)).param; do { if (param.exp == null) break; AnalParseErr(param.exp); param = param.tail; } while (param != null); } } public void AnalParseErrD(Decl decl) throws Exception { //This along with AnalParseErr traverses the Expression tree to find //the first error encountered during the typechecking. if (decl instanceof DefClass) { AnalParseErr(((DefClass)(decl)).def); } else if (decl instanceof SeqClass) { AnalParseErrD(((SeqClass)(decl)).first); AnalParseErrD(((SeqClass)(decl)).second); } else if (decl instanceof RecClass) { AnalParseErrD(((RecClass)(decl)).rec); } } public Env CopyEnvir(Env env){ //This makes a copy of an environment and returns it //Is this used ? Env retenv = new Env(); if (env.ide != null) { retenv.ide = env.ide; retenv.typeExp = env.typeExp; retenv.isdtcons = env.isdtcons; if (env.tail != null) retenv.tail = CopyEnvir(env.tail); else retenv.tail = null; } return retenv; } public TypeList CopyList(TypeList list ){ //This makes a copy of a list of type expressions and returns it TypeList retlist = new TypeList(); if (list == null) return new TypeList(); else { if (list.head != null) { retlist.head = list.head; if (list.tail != null) { retlist.tail = CopyList(list.tail); } else retlist.tail = null; } return retlist; } } public TypeExp CartType(TypeExp first,TypeExp second) { //create a cartesian product type expression using the first and second as the relevant arguments TypeExp r = new OperType(("*"),TypeList.Extend(first,TypeList.Extend(second,null))); return r; } public TypeExp FunType( TypeExp dom ,TypeExp cod) { //create a function using the dom(aim) and cod(omain) as the relevnat arguments TypeExp r = new OperType(("->"),TypeList.Extend(dom,TypeList.Extend(cod,null))); return r; } public returnExp AnalParamsChange(Env minibodyenv,TypeList minibodylist,Exp exp,int StartPosn,int EndPosn,TypeExp tochangeto,boolean cb,firstError fe,Env errorenv,boolean focus) throws Exception , ExExcept,UnifException{ //This is used in conjunction with AnalExpChanged and AnalDeclChanged to //evaluate the type of an expression when a particular node is given //a particualr type. boolean changedbelow = exp.changedbelow || ((exp.Posn == StartPosn ) && (exp.EndPosn == EndPosn) ) || (cb); returnExp ret = null; if (exp instanceof Constant) { ret = new returnExp(exp.ctype,false); } else if (exp instanceof IdeClass) { //if the identifier is in the environment - then return the type in the //environment. String name = ((IdeClass)(exp)).ide; TypeExp rett = minibodyenv.Retrieve(name,minibodylist); //will have to check that it's a constructor if (rett != null){ exp.ctype = rett; ret = new returnExp(rett,true); } else{ //CHECK YOU DON'T NEED TO SOMETHING DIFFERENT FOR FOCUS //otherwise it's added to the environment TypeExp tempret; if (exp.ctypeinfo == null) tempret = exp.ctype; else tempret = gv.FreshTypeSpecial(exp.ctypeinfo,new TypeList(),t,false); if ( (exp.ctypeinfo != null) && (exp.ctypeinfo instanceof VarType)) { if (((VarType)(exp.ctypeinfo)).instance == null){ minibodyenv.Extend(name,tempret); minibodylist.Extend(tempret); } } exp.ctype = tempret; ret = new returnExp(tempret,false); } } else if (exp instanceof Appl2Class) { Exp fun1 = ((Appl2Class)(exp)).fun; if (fun1 instanceof IdeClass) { TypeExp fun = (AnalExpChange(fun1,minibodyenv,StartPosn,EndPosn,tochangeto,minibodylist,changedbelow,fe,errorenv,focus)).typeexp; Parameters params = ((Appl2Class)(exp)).param; TypeExp returnparams = null; //will have to take account of the currying in this case and use fun //deal with the paramters if (params != null) { //loop through the parameters, building up the new expression //to be returned. do { if (params.exp == null) break; TypeExp param1 = (AnalParamsChange(minibodyenv,minibodylist,params.exp,StartPosn,EndPosn,tochangeto,changedbelow,fe,errorenv,focus)).typeexp; if (returnparams == null) { returnparams = param1; } else { TypeList temptl = new TypeList(); temptl.Extend(param1); temptl.Extend(returnparams); returnparams = new OperType("*",TypeList.Extend(returnparams,TypeList.Extend(param1,null))); } if (params.tail == null) break; params = params.tail; } while ( params != null) ; TypeExp tempvt = gv.FreshTypeSpecial(exp.ctypeinfo,new TypeList(),t,false);// new VarType(); if (returnparams == null) throw new Exception("null parameters"); //If it's not been changed, or it's not going to be changed, //then give them fresh types and unify the parameters with //the function type - otherwise leave them alone. if (! ( changedbelow || ( (exp.Posn == StartPosn) && (exp.EndPosn == EndPosn)) ) ) { boolean uniferr = false; try { TypeExp total = FreshType("",FunType(returnparams,fun),new Env(),new TypeList()); TypeExp rp = ((OperType)(total)).args.head; //FreshType("",returnparams,cloneEnv,cloneList); TypeExp f = ((OperType)(total)).args.tail.head; //FreshType("",fun,cloneEnv,cloneList); TypeExp tvt = new VarType(); tf.UnifyType(FunType(rp,tvt),f,dt); exp.cuniferror = false; } catch (UnifException uni) { exp.cuniferror = true; exp.cinfo = uni.message; exp.cfirst = uni.first; exp.csecond= uni.second; uniferr = true; if (!fe.errorfound) fe.setinfo(uni.message,uni.first,uni.second,exp.Posn,exp.EndPosn); } if (!uniferr) { try { tf.UnifyType(FunType(returnparams,tempvt),fun,dt); } catch (UnifException u1) { exp.cuniferror = true; exp.cinfo = u1.message; exp.cfirst = u1.first; exp.csecond= u1.second; if (!fe.errorfound) fe.setinfo(u1.message,u1.first,u1.second,exp.Posn,exp.EndPosn); } } } exp.ctype = tempvt; ret = new returnExp(tempvt,true); } } else System.out.print("It's not an IdeClass"); } //If the expression is to be changed here then adjust the relevant //variables if ((exp instanceof IdeClass) && (exp.Posn == StartPosn) && (exp.EndPosn == EndPosn)) { exp.below = tochangeto; exp.changedbelow = true; if ( (exp.ctypeinfo != null) && (exp.ctypeinfo instanceof VarType)) { if (((VarType)(exp.ctypeinfo)).instance == null){ minibodyenv.Extend(((IdeClass)(exp)).ide,tochangeto); minibodylist.Extend(tochangeto); } } TypeExp rtochangeto = gv.FreshTypeSpecial(tochangeto,new TypeList(),t,false); return new returnExp(rtochangeto,true); } if ((exp.Posn == StartPosn) && (exp.EndPosn == EndPosn)) { exp.below = tochangeto; exp.changedbelow = true; TypeExp rtochangeto = gv.FreshTypeSpecial(tochangeto,new TypeList(),t,false); return new returnExp(rtochangeto,true); } if (exp.changedbelow) { return new returnExp(gv.FreshTypeSpecial(exp.below,new TypeList(),t,false),true); } return ret; } //ifchanged typeexp //may have to maintain two ifchanged below to take account of the two different types of changes //if you want to be able to reversse them public boolean changed ( boolean change ,Exp exp,int StartPosn ,int EndPosn) { return change || (StartPosn == exp.Posn) && (EndPosn == exp.EndPosn); } public Env AnalDeclChange(Decl decl,Env changeenv,TypeList list,int StartPosn,int EndPosn,TypeExp tobechangedto,boolean changedbelow,firstError fe,Env errorenv,boolean focus) throws ExExcept,Exception{ //This along with AnalExpChange retypechecks the expression, making the necessary type substitution. //It behaves like AnalDecl only it just deals with the clones of the types. //The int in the paramter list identify where the type substitution has to be made !!!!! if( decl instanceof DefClass) { Env retenv = CopyEnvir(changeenv); TypeList CL = CopyList(list); returnExp temp = AnalExpChange(((DefClass)(decl)).def,retenv,StartPosn,EndPosn,tobechangedto,list,changedbelow,fe,errorenv,focus); //Extend the error environment if an error was encoutnered in this definition if ((((DefClass)(decl)).def).cuniferror) {errorenv.Extend(((DefClass)(decl)).binder,new VarType());} retenv.Extend(((DefClass)(decl)).binder,temp.typeexp); return retenv; } else if (decl instanceof SeqClass) { //will need to pass a copy of envp to this TypeList l = CopyList(list); Env retenv2 = CopyEnvir(changeenv); return AnalDeclChange(((SeqClass)(decl)).second,AnalDeclChange(((SeqClass)(decl)).first,retenv2,l,StartPosn,EndPosn,tobechangedto,changedbelow,fe,errorenv,focus),l,StartPosn,EndPosn,tobechangedto,changedbelow,fe,errorenv,focus); } else if (decl instanceof RecClass){ Env retenv3 = CopyEnvir(changeenv); TypeList copylist = CopyList(list);//was a copylist in these twos spots AnalyzeRecDeclBindChange(((RecClass)(decl)).rec,retenv3,copylist,StartPosn,EndPosn,tobechangedto,changedbelow,fe,errorenv,focus);//this will have changed so pass the changed one on AnalyzeRecDeclChange(((RecClass)(decl)).rec,retenv3,copylist,StartPosn,EndPosn,tobechangedto,changedbelow,fe,errorenv,focus); return retenv3; } else if (decl instanceof AndDecl) { //This is only a sequential statement ! Decl first = ((AndDecl)(decl)).decl1; AndDecl tail = ((AndDecl)(decl)).tail; TypeList copylist = CopyList(list); Env retenv4 = CopyEnvir(changeenv); while (first != null) { AnalyzeRecDeclBindChange(first,retenv4,copylist,StartPosn,EndPosn,tobechangedto,changedbelow,fe,errorenv,focus); if (tail == null) break; first = tail.decl1; tail = tail.tail; } Decl first1 = ((AndDecl)(decl)).decl1; AndDecl tail1 = ((AndDecl)(decl)).tail; while (first1 != null) { AnalyzeRecDeclChange(first1,retenv4,copylist,StartPosn,EndPosn,tobechangedto,changedbelow,fe,errorenv,focus); if (tail1 == null) break; first1 = tail1.decl1; tail1 = tail1.tail; } return retenv4; } return changeenv; }; public void AnalyzeRecDeclBindChange(Decl decl,Env envp,TypeList list,int StartPosn,int EndPosn,TypeExp tochangeto,boolean changedbelow,firstError fe,Env errorenv,boolean focus){ //This is used with the AnalyzeRecDeclChange to typecheck recursive functions. //It creates a new set of non-generic type variables and associates them with identifiers. //Again it is the same as the AnalyzeRecDeclBind, only it just deals with the clones of the types. if (decl instanceof DefClass) { TypeExp newTypeVar = new VarType(); envp.Extend(((DefClass)(decl)).binder,newTypeVar); list.Extend(newTypeVar); } if (decl instanceof SeqClass){ AnalyzeRecDeclBindChange(((SeqClass)(decl)).first,envp,list,StartPosn,EndPosn,tochangeto,changedbelow,fe,errorenv,focus);//both env and list should be changed AnalyzeRecDeclBindChange(((SeqClass)(decl)).second,envp,list,StartPosn,EndPosn,tochangeto,changedbelow,fe,errorenv,focus); } if (decl instanceof RecClass) { AnalyzeRecDeclBindChange(((RecClass)(decl)).rec,envp,list,StartPosn,EndPosn,tochangeto,changedbelow,fe,errorenv,focus); } } public void AnalyzeRecDeclChange(Decl decl,Env envp, TypeList list,int StartPosn,int EndPosn,TypeExp tochangeto,boolean changedbelow,firstError fe,Env errorenv,boolean focus)throws ExExcept,Exception ,UnifException{ //This analyzes the declarations and calls on UnifyType to ensure the recursive type constraints. //Again this behaves similarly to the AnalyzeRecDecl, only it just deals with the clones of the types. //To try and get the most accurate error information, and to be able to continue typechecking after an error //it is necessary to catch the exceptions immediately after they arise. Env copyenv = CopyEnvir(envp); TypeList copylist = CopyList(list); if (decl instanceof DefClass) { TypeExp orig = copyenv.Retrieve(((DefClass)(decl)).binder,copylist); TypeExp res = (AnalExpChange(((DefClass)(decl)).def,envp,StartPosn,EndPosn,tochangeto,list,changedbelow,fe,errorenv,focus)).typeexp; boolean uniferr = false; //no harm in this merely setting a value to something if (!((DefClass)(decl)).def.cuniferror) { //This is just to try an catch the first error - if there's an //error with the identifier then there's no point in trying to unify it . try { TypeExp total = FreshType("",FunType(orig,res),new Env(),new TypeList()); TypeExp o = ((OperType)(total)).args.head; TypeExp r = ((OperType)(total)).args.tail.head;; tf.UnifyType(o,r,dt); (((DefClass)(decl)).def).cuniferror = false; } catch (UnifException e) { (((DefClass)(decl)).def).cuniferror = true; (((DefClass)(decl)).def).cinfo = e.message; (((DefClass)(decl)).def).cfirst = e.first; (((DefClass)(decl)).def).csecond= e.second; uniferr = true; } if (! uniferr) { try { tf.UnifyType(orig,res,dt); (((DefClass)(decl)).def).cuniferror = false; } catch (UnifException u1) { (((DefClass)(decl)).def).cuniferror = true; (((DefClass)(decl)).def).cinfo = u1.message; (((DefClass)(decl)).def).cfirst = u1.first; (((DefClass)(decl)).def).csecond= u1.second; } } } } if (decl instanceof SeqClass) { AnalyzeRecDeclChange(((SeqClass)(decl)).first,envp,copylist,StartPosn,EndPosn,tochangeto,changedbelow,fe,errorenv,focus); AnalyzeRecDeclChange(((SeqClass)(decl)).second,envp,copylist,StartPosn,EndPosn,tochangeto,changedbelow,fe,errorenv,focus); } if (decl instanceof RecClass) { AnalyzeRecDeclChange(((RecClass)(decl)).rec,envp,copylist,StartPosn,EndPosn,tochangeto,changedbelow,fe,errorenv,focus); } } public returnExp AnalExpChange(Exp exp,Env changeenv,int StartPosn,int EndPosn,TypeExp tochangeto,TypeList list,boolean cb,firstError fe,Env errorenv,boolean focus) throws ExExcept,Exception { //This is the equivalent of the AnalExp, only it only deals with the clones ofthe types . boolean changedbelow = cb || exp.changedbelow ||( (exp.Posn == StartPosn) && (exp.EndPosn == EndPosn)); TypeExp toreturn; returnExp rereturnExp = null; //need to catch uni errors as this shouldn't be here if (exp instanceof IdeClass) { //This is to make sure that any identifiers that have an error in the declaration are //recognised as having an error. Because the typechecking contines after an error has //been detected it means that the user can access information about the type later on //if the identifier is used again. So it's important to be able to recognise that there's //an error in it. if (errorenv.Present(((IdeClass)(exp)).ide)) { exp.cuniferror = true; exp.cinfo = "There's an error in the declaration of this id"; rereturnExp = new returnExp(exp.ctype,true); } else { //WILL HAVE TO SET THESE TO SET UNIFERRORS BACK TO 0 //If this has already been encoutered in the typechecking then //use the value if (changeenv.Present(((IdeClass)(exp)).ide)) {exp.cuniferror = false; exp.ctype = changeenv.Retrieve(((IdeClass)(exp)).ide,list);; rereturnExp = new returnExp(exp.ctype,true);//new returnExp(changeenv.Retrieve(((IdeClass)(exp)).ide,list),true);//need to sort out the list } else { //If focus is true, then nothing is done to the type. if (focus) { rereturnExp = new returnExp(exp.ctype,true); } else { try{ //Otherwise return a fresh type if (exp.ctypeinfo == null) exp.ctype = exp.ctype; else exp.ctype = gv.FreshTypeSpecial(exp.ctypeinfo,new TypeList(),t,false); rereturnExp = new returnExp(exp.ctype,false); } catch (Exception e) { System.out.print(e.getMessage()); } } //slight mistake if (exp.cuniferror && (!changedbelow) && (exp.cinfo).equals("The id is not declared")) { if (!fe.errorfound) {//will already have been set if it's a errorenv System.out.println("Setting for " + ((IdeClass)(exp)).ide); fe.setinfo("The id is not declared",null,null,exp.Posn,exp.EndPosn); } } else if (!changedbelow) exp.cuniferror = false; } } } else if (exp instanceof Constant) rereturnExp = new returnExp(exp.ctype,false); else if (exp instanceof raisecase) { TypeExp raiseexp = (AnalExpChange(((raisecase)(exp)).exc,changeenv,StartPosn,EndPosn,tochangeto,list,changedbelow,fe,errorenv,focus)).typeexp; exp.cuniferror = false; boolean uniferr = false; try { tf.UnifyType(FreshType("",raiseexp,new Env(),new TypeList()),new exn() , dt); } catch (UnifException e) { uniferr = true; exp.cuniferror = true;exp.cinfo = e.message; exp.cfirst = e.first;exp.csecond = e.second; if (!fe.errorfound) { fe.setinfo(e.message,e.first,e.second,exp.Posn,exp.EndPosn); } } if (!uniferr) { try { tf.UnifyType(raiseexp,new exn(),dt); } catch(UnifException e) { exp.cuniferror = true;exp.cinfo = e.message; exp.cfirst = e.first;exp.csecond = e.second; if (!fe.errorfound) { fe.setinfo(e.message,e.first,e.second,exp.Posn,exp.EndPosn); } } } exp.ctype = new VarType(); rereturnExp = new returnExp(new VarType(),true); //creturnTypeExp = gv.FreshTypeSpecial(exp.ctypeinfo,new TypeList(),t,false); } else if (exp instanceof CondClass) { //A similar structure is followed for all the other expressions such as //while, case , handle etc. exp.cuniferror = false; returnExp condtype = AnalExpChange(((CondClass)(exp)).test,changeenv,StartPosn,EndPosn,tochangeto,list,changedbelow,fe,errorenv,focus); returnExp typeOfThen = AnalExpChange(((CondClass)(exp)).iftrue,changeenv,StartPosn,EndPosn,tochangeto,list,changedbelow,fe,errorenv,focus); returnExp typeOfElse = AnalExpChange(((CondClass)(exp)).iffalse,changeenv,StartPosn,EndPosn,tochangeto,list,changedbelow,fe,errorenv,focus); if (((CondClass)(exp)).test.cuniferror == true || ((CondClass)(exp)).iftrue.cuniferror == true || ((CondClass)(exp)).iffalse.cuniferror == true) { exp.cuniferror = true;exp.cinfo = "There's an error in the cond or the body"; } else exp.cuniferror =false; if (!changed(changedbelow,exp,StartPosn,EndPosn)) { //This chack is made to ensure that if a type has been assumed //at this expression or an enclosing expression then no //unification will take place. //In this case - each of the if statements are evaluated separately //and if an error is found at any one of them, then the rest are ignored. if (!exp.cuniferror) { boolean unifex = false; try { TypeExp total = FreshType("",FunType(condtype.typeexp,FunType(typeOfThen.typeexp,typeOfElse.typeexp)),new Env(),new TypeList()); TypeExp FreshCond = ((OperType)(total)).args.head; TypeExp FreshThen = ((OperType)(((OperType)(total)).args.tail.head)).args.head; TypeExp FreshElse = ((OperType)(((OperType)(total)).args.tail.head)).args.tail.head; tf.UnifyType(FreshCond,BoolType,dt); tf.UnifyType(FreshThen,FreshElse,dt); } catch (UnifException e) { unifex = true;exp.cuniferror = true; exp.cinfo = e.message;exp.cfirst = e.first; exp.csecond = e.second; if (!fe.errorfound) { fe.setinfo(e.message,e.first,e.second,exp.Posn,exp.EndPosn); } } catch (Exception e2) {exp.cuniferror = true;unifex = true;} if (!unifex){ //These try catch statements are used to try and pinpoint //the unification error more accurately. try { tf.UnifyType(condtype.typeexp,BoolType,dt); }catch (UnifException e1) { exp.cuniferror = true; exp.cinfo = e1.message;exp.cfirst = e1.first; exp.csecond = e1.second; if (!fe.errorfound) { fe.setinfo(e1.message,e1.first,e1.second,exp.Posn,exp.EndPosn); } } try { tf.UnifyType(typeOfThen.typeexp,typeOfElse.typeexp,dt); } catch (UnifException e2) { exp.cuniferror = true; exp.csecond = e2.second;exp.cinfo = e2.message;exp.cfirst = e2.first; if (!fe.errorfound) { fe.setinfo(e2.message,e2.first,e2.second,exp.Posn,exp.EndPosn); } } } } } exp.ctype = typeOfThen.typeexp; rereturnExp = new returnExp(typeOfThen.typeexp,true); } else if (exp instanceof WhileClass) { exp.cuniferror = false; returnExp typeoftest = AnalExpChange(((WhileClass)(exp)).test,changeenv,StartPosn,EndPosn,tochangeto,list,changedbelow,fe,errorenv,focus); returnExp typeofbody = AnalExpChange(((WhileClass)(exp)).body,changeenv,StartPosn,EndPosn,tochangeto,list,changedbelow,fe,errorenv,focus); if (((WhileClass)(exp)).test.cuniferror == true || ((WhileClass)(exp)).body.cuniferror == true){ exp.cuniferror = true;exp.cinfo = "There's an error in the cond or the body"; } try { if (!changed(changedbelow,exp,StartPosn,EndPosn) ) { //Again to make sure that no unifcation takes place if //a chaneg has been made further down the tree. if (!exp.cuniferror) { boolean unifex = false; try { TypeExp FreshCond = FreshType("",typeoftest.typeexp,new Env(),new TypeList()); tf.UnifyType(FreshCond,BoolType,dt); } catch (UnifException e) { unifex = true; exp.cuniferror = true; exp.cinfo = e.message;exp.cfirst = e.first; exp.csecond = e.second; if (!fe.errorfound) { fe.setinfo(e.message,e.first,e.second,exp.Posn,exp.EndPosn); } } catch (Exception e2) {exp.cuniferror = true;unifex = true;} if ( ! unifex ) { try { tf.UnifyType(typeoftest.typeexp,BoolType,dt); } catch (UnifException e1) { unifex = true; exp.cuniferror = true; exp.cinfo = e1.message;exp.cfirst = e1.first; exp.csecond = e1.second; if (!fe.errorfound) { fe.setinfo(e1.message,e1.first,e1.second,exp.Posn,exp.EndPosn); } } } } } } catch (Exception e) { exp.cuniferror = true; } exp.ctype = typeofbody.typeexp; rereturnExp = new returnExp(typeofbody.typeexp,true); } else if (exp instanceof handleclass) { TypeExp theexp = (AnalExpChange(((handleclass)(exp)).exp,changeenv,StartPosn,EndPosn,tochangeto,list,changedbelow,fe,errorenv,focus)).typeexp; TypeExp thematch = (AnalExpChange(((handleclass)(exp)).match,changeenv,StartPosn,EndPosn,tochangeto,list,changedbelow,fe,errorenv,focus)).typeexp; //need to put in the trial unify boolean uniferr = false; try { TypeExp t = FreshType("",FunType(theexp, thematch),new Env(),new TypeList()); TypeExp e = ((OperType)(t)).args.head; TypeExp m = ((OperType)(t)).args.tail.head; tf.UnifyType(FunType(new exn(),e),m,dt); System.out.print("after unfiy"); } catch(UnifException e) { exp.cuniferror = true;exp.cinfo = e.message; exp.cfirst = e.first;exp.csecond = e.second; uniferr = true; if (!fe.errorfound) { fe.setinfo(e.message,e.first,e.second,exp.Posn,exp.EndPosn); fe.errorfound = true; } } if (!uniferr){ try { tf.UnifyType(FunType(new exn(),theexp),thematch,dt); } catch(UnifException e) { exp.cuniferror = true;exp.cinfo = e.message; exp.cfirst = e.first;exp.csecond = e.second; if (!fe.errorfound) { fe.setinfo(e.message,e.first,e.second,exp.Posn,exp.EndPosn); } } } exp.ctype = theexp; rereturnExp = new returnExp(theexp,true); } else if (exp instanceof MiniFn) { Env copyenv = CopyEnvir(changeenv); TypeList copytl = CopyList(list); Parameters params = ((MiniFn)(exp)).Pattern; TypeExp te = new TypeExp(); TypeExp firstpartoffun = null; exp.cuniferror = false; do { //check each paramter individually building up the //type expression for them. An error in any one of //the parameters means an error overall. if (params.exp == null) break; te = (AnalParamsChange(copyenv,copytl,params.exp,StartPosn,EndPosn,tochangeto,changedbelow,fe,errorenv,focus)).typeexp; if (params.exp.cuniferror && !exp.cuniferror ) { exp.cuniferror = true; exp.cinfo = "There's an error with one of the parameters"; } if (firstpartoffun == null) firstpartoffun = te; else firstpartoffun = CartType(firstpartoffun,te); params = params.tail; } while (params != null); TypeExp typeofminifnbody = (AnalExpChange(((MiniFn)(exp)).Body,copyenv,StartPosn,EndPosn,tochangeto,copytl,changedbelow,fe,errorenv,focus)).typeexp; if (((MiniFn)(exp)).Body.cuniferror && ! exp.cuniferror) { exp.cuniferror = true; exp.cinfo = "There's a unificcation error in the body"; } TypeExp returnTypeExp = FunType(firstpartoffun,typeofminifnbody); exp.ctype = returnTypeExp; rereturnExp = new returnExp(returnTypeExp,true); } else if (exp instanceof MiniFnList) { TypeExp fntype = new VarType(); exp.cuniferror = false;//had it at true TypeExp returnTypeExpt = null; MiniFnList mfl = ((MiniFnList)(exp)); Patterns patterns = new Patterns(); TypeExp tempfntype = new VarType(); boolean uniferr = false; try { do { if (mfl == null) break; if (mfl.head == null) break; returnTypeExpt = (AnalExpChange(mfl.head,changeenv,StartPosn,EndPosn,tochangeto,list,changedbelow,fe,errorenv,focus)).typeexp; patterns.Extend(returnTypeExpt,returnTypeExpt); exp.cuniferror = exp.cuniferror || mfl.head.cuniferror; uniferr = uniferr || mfl.head.cuniferror; if (!changed(changedbelow,exp,StartPosn,EndPosn) ) { if (!uniferr){ try { tf.UnifyType(tempfntype,FreshType("",returnTypeExpt,new Env(),new TypeList()),dt); } catch (UnifException u) { uniferr = true; mfl.head.cuniferror = true;mfl.head.cinfo = u.message; mfl.head.cfirst = u.first;mfl.head.csecond = u.second; if (!fe.errorfound) { fe.setinfo(u.message,u.first,u.second,exp.Posn,exp.EndPosn); } } } } mfl = mfl.tail; } while (mfl != null); exp.cuniferror = uniferr; if (!uniferr) { do { if (patterns == null) break; if (patterns.exp1 == null) break; returnTypeExpt = patterns.exp1;//new TwoTypes(patterns.exp1,patterns.exp2);//AnalyzeExp(mfl.head,minibodyenv,minibodylist,cminibodyenv,cminibodylist,errorenv); try { tf.UnifyType(fntype,returnTypeExpt,dt); } catch (UnifException u) { exp.cuniferror = true; exp.cinfo = u.message; exp.cfirst = u.first; exp.csecond= u.second; } catch (Exception e) { exp.uniferror = true; } patterns = patterns.tail; } while (patterns != null);//System.out.print(" out here "); } } catch (Exception e) { exp.cuniferror = true; } //should have exp.ctype = fntype exp.ctype = fntype; TypeExp returnTypeExp = fntype; rereturnExp = new returnExp(returnTypeExp,true); } else if (exp instanceof Appl2Class) { exp.cuniferror = false; returnExp typeOfFun = AnalExpChange(((Appl2Class)(exp)).fun,changeenv,StartPosn,EndPosn,tochangeto,list,changedbelow,fe,errorenv,focus); boolean iserrorinbody = ((Appl2Class)(exp)).fun.cuniferror; TypeExp typeOfRes = new VarType(); Parameters param = ((Appl2Class)(exp)).param; TypeExp parameters = null; //A loop to analyse the paramters and if any one of the paramters //has an error then iserrorinbody is set to true do { if (param.exp == null) break; returnExp paramhead = AnalExpChange(param.exp,changeenv,StartPosn,EndPosn,tochangeto,list,changedbelow,fe,errorenv,focus); if (param.exp.cuniferror) iserrorinbody = true; if (parameters == null) parameters = paramhead.typeexp; else parameters = new OperType("*",TypeList.Extend(parameters,TypeList.Extend(paramhead.typeexp,null))); param = param.tail; } while (param != null); if (parameters == null) throw new Exception("no parameters"); //This to check whether the expression is to be unified - if //it's inside the assumed type then it won't be. if (!changed(changedbelow,exp,StartPosn,EndPosn) ) { boolean uniferror = iserrorinbody; if (!uniferror) { try { TypeExp total = FreshType("",FunType(parameters,typeOfFun.typeexp),new Env(),new TypeList()); TypeExp p = ((OperType)(total)).args.head; TypeExp f = ((OperType)(total)).args.tail.head;; TypeExp r = new VarType(); tf.UnifyType(FunType(p,r),f,dt); } catch (UnifException uni) { exp.cuniferror = true; exp.cinfo = uni.message; exp.cfirst = uni.first; exp.csecond= uni.second; uniferror = true; if (!fe.errorfound) { fe.setinfo(uni.message,uni.first,uni.second,exp.Posn,exp.EndPosn); } } } else {exp.cuniferror = true;exp.cinfo = "There's an error in the parameters or the body";} if (! uniferror) { try { tf.UnifyType(FunType(parameters,typeOfRes),typeOfFun.typeexp,dt); } catch (UnifException un) { exp.cuniferror = true; exp.cinfo = un.message; exp.cfirst = un.first; exp.csecond= un.second; uniferror = true; if (!fe.errorfound) { fe.setinfo(un.message,un.first,un.second,exp.Posn,exp.EndPosn); } } catch (Exception e) { exp.cuniferror = true; } } } exp.ctype = typeOfRes; rereturnExp = new returnExp(typeOfRes,true); } else if (exp instanceof Tuple) { Parameters param = ((Tuple)(exp)).p; TypeExp cparameters = null; boolean uniferror = false; exp.cuniferror = false; //loop through the paramters to typechecking each one and //adding it on to the cparameters. If there's an error in //one of the parameters then there's an error overall. do { if (param.exp == null) break; TypeExp paramhead = (AnalExpChange(param.exp,changeenv,StartPosn,EndPosn,tochangeto,list,changedbelow,fe,errorenv,focus)).typeexp; uniferror = uniferror || (param.exp.cuniferror); if (cparameters == null) { cparameters = paramhead; } else { cparameters = new OperType("*",TypeList.Extend(cparameters,TypeList.Extend(paramhead,null))); } param = param.tail; } while (param != null); if (uniferror) { exp.cuniferror = true; exp.cinfo = ("There's a unif error in the body of the tuple"); } exp.ctype = cparameters; rereturnExp = new returnExp(cparameters,false); } else if (exp instanceof BlockClass) { Env errorenv1 = CopyEnvir(errorenv); Env env1 = AnalDeclChange(((BlockClass)(exp)).decl,changeenv,list,StartPosn,EndPosn,tochangeto,changedbelow,fe,errorenv1,focus); returnExp temp = AnalExpChange(((BlockClass)(exp)).scope,env1,StartPosn,EndPosn,tochangeto,list,changedbelow,fe,errorenv1,focus); if (((BlockClass)(exp)).scope.cuniferror ) { exp.cuniferror = true;exp.cinfo = "There's a unifcation error in the let"; } else exp.cuniferror = false; exp.ctype = temp.typeexp; rereturnExp = temp; } else { rereturnExp = null; } if ((exp.Posn == StartPosn) && (exp.EndPosn == EndPosn)) { //If the current position in the expression matches the //positions specified in the parameters then the assumed type is //stored on the tree. exp.changedbelow = true; exp.below = tochangeto; TypeExp rtochangeto = gv.FreshTypeSpecial(tochangeto,new TypeList(),t,false); return new returnExp(rtochangeto,true); } if (exp.changedbelow) { TypeExp rtochangeto = gv.FreshTypeSpecial(exp.below,new TypeList(),t,false); return new returnExp(rtochangeto,true); } return rereturnExp; } //no need to actually return a type here public void AnalyzeExpParsed(Exp exp,int StartPosn,int EndPosn,int change,boolean insidechange) throws ExExcept,Exception,UnifException{ //This along with a few other functions is used to traverse the tree so as to get to a particular node. When //that node is reached, depending on the particular value of Change a //number of operations may be carried out. //Depending on the parameter used it returns different values, usually using an exception. //If change = 0 then it tells you the original type caluclated throws an exception if an error is recorded at that node //If change = 1 then it finds the type you've assumed for the expression enclosed by those positions. //If change = 2 then the type of the copeid expression is returned. //If change = 3 is used to try and make a change inside of an expression that has an assumed type. //If change = 4 then the assumed type is removed from the node boolean changebelow= insidechange; if (exp.changedbelow) {changebelow = true;} if ((change == 0) && (StartPosn ==exp.Posn) && (EndPosn == exp.EndPosn)){ if (exp.uniferror) { throw new UnifException(exp.info,exp.first,exp.second); } else throw new ExExcept("",exp.type); } if ((change == 1) && (exp.Posn == StartPosn) && (exp.EndPosn == EndPosn) ) { if (exp.changedbelow) { throw new ExExcept("This is the type you've assumed for this expression",exp.below); } if (exp.cuniferror) { throw new UnifException(exp.cinfo,exp.cfirst,exp.csecond); } if (changebelow) throw new ExExcept("This subexpression is inside an assumed type ",exp.ctype); throw new ExExcept("",exp.ctype);//was below } if (change == 2 && (exp.Posn == StartPosn) && (exp.EndPosn == EndPosn) ) { if (exp.ctypeinfo != null) throw new ExExcept("",exp.ctypeinfo);//was below } if ((change == 3) && (exp.Posn == StartPosn) && (exp.EndPosn == EndPosn)) { boolean reset = false; if (exp.changedbelow) {exp.changedbelow = false; reset = true;} firstError fe = new firstError();try{ returnExp re = AnalExpChange(exp,new Env(),-1,-1,new TypeExp(),new TypeList(),false,fe,new Env(),true); } catch(UnifException e) { exp.cuniferror = true;if (reset) exp.changedbelow = true; throw e;}//set the rest; if (reset) exp.changedbelow = true; if (fe.errorfound) throw new UnifException(fe.info,fe.te1,fe.te2); throw new ExExcept("The type for focus ",exp.ctype); } if ((change == 4) && (exp.Posn == StartPosn) && (exp.EndPosn == EndPosn)) { exp.changedbelow = false; return; } if ( exp instanceof IdeClass) { } else if ( exp instanceof CondClass) { AnalyzeExpParsed(((CondClass)(exp)).test,StartPosn,EndPosn,change,changebelow); AnalyzeExpParsed(((CondClass)(exp)).iftrue,StartPosn,EndPosn,change,changebelow); AnalyzeExpParsed(((CondClass)(exp)).iffalse,StartPosn,EndPosn,change,changebelow); } else if (exp instanceof WhileClass) { AnalyzeExpParsed(((WhileClass)(exp)).test,StartPosn,EndPosn,change,changebelow); AnalyzeExpParsed(((WhileClass)(exp)).body,StartPosn,EndPosn,change,changebelow); } else if (exp instanceof raisecase) { AnalyzeExpParsed(((raisecase)(exp)).exc,StartPosn,EndPosn,change,changebelow); } else if (exp instanceof handleclass) { AnalyzeExpParsed(((handleclass)(exp)).exp,StartPosn,EndPosn,change,changebelow); AnalyzeExpParsed(((handleclass)(exp)).match,StartPosn,EndPosn,change,changebelow); } else if (exp instanceof Tuple) { Parameters param = ((Tuple)(exp)).p; do { if (param.exp == null) break; AnalyzeExpParsed(param.exp,StartPosn,EndPosn,change,changebelow); param = param.tail; } while (param != null); } else if (exp instanceof MiniFn) { Parameters params = ((MiniFn)(exp)).Pattern; do { if (params.exp == null) break; AnalyzeExpParsed(params.exp,StartPosn,EndPosn,change,changebelow); params = params.tail; } while (params != null); AnalyzeExpParsed(((MiniFn)(exp)).Body,StartPosn,EndPosn,change,changebelow); } else if (exp instanceof MiniFnList) { MiniFnList mfl = ((MiniFnList)(exp)); do { if (mfl == null) break; if (mfl.head == null) break; AnalyzeExpParsed(mfl.head,StartPosn,EndPosn,change,changebelow); mfl = mfl.tail; } while (mfl != null); } else if ( exp instanceof LambClass) { //binder need to figure out the type of binder AnalyzeExpParsed(((LambClass)(exp)).body,StartPosn,EndPosn,change,changebelow); } else if (exp instanceof ApplClass) { AnalyzeExpParsed(((ApplClass)(exp)).fun,StartPosn,EndPosn,change,changebelow); AnalyzeExpParsed(((ApplClass)(exp)).arg,StartPosn,EndPosn,change,changebelow); } else if (exp instanceof Appl2Class) { AnalyzeExpParsed(((Appl2Class)(exp)).fun,StartPosn,EndPosn,change,changebelow); Parameters param = ((Appl2Class)(exp)).param; do { if (param.exp == null) break; AnalyzeExpParsed(param.exp,StartPosn,EndPosn,change,changebelow); param = param.tail; } while (param != null); } else if ( exp instanceof BlockClass){ AnalyzeDeclParsed(((BlockClass)(exp)).decl,StartPosn,EndPosn,change,changebelow); AnalyzeExpParsed(((BlockClass)(exp)).scope,StartPosn,EndPosn,change,changebelow); } if ((change == 5) && (exp.Posn >= StartPosn) && (exp.EndPosn <= EndPosn)){ throw new posnException(exp.Posn,exp.EndPosn); } if ((exp.Posn == StartPosn) && (exp.EndPosn == EndPosn)) { ExExcept newex = new ExExcept("no error",exp.type);//System.out.print("throwing exc"); throw newex; } } public void AnalyzeDeclParsed(Decl decl,int StartPosn,int EndPosn,int change,boolean changebelow)throws ExExcept,Exception,UnifException{ //This is used in conjunction with AnalyzeExpParsed as described in AnalyzeExpParsed. if( decl instanceof DefClass) { AnalyzeExpParsed(((DefClass)(decl)).def,StartPosn,EndPosn,change,changebelow);} else if (decl instanceof SeqClass) { AnalyzeDeclParsed(((SeqClass)(decl)).first,StartPosn,EndPosn,change,changebelow); AnalyzeDeclParsed(((SeqClass)(decl)).second,StartPosn,EndPosn,change,changebelow); } else if (decl instanceof RecClass){ AnalyzeDeclParsed(((RecClass)(decl)).rec,StartPosn,EndPosn,change,changebelow); } else if (decl instanceof AndDecl) { Decl first = ((AndDecl)(decl)).decl1; AndDecl tail = ((AndDecl)(decl)).tail; while (first != null) { if (first instanceof RecClass) AnalyzeDeclParsed(((RecClass)(first)).rec,StartPosn,EndPosn,change,changebelow); else AnalyzeDeclParsed(first,StartPosn,EndPosn,change,changebelow); if (tail == null) break; first = tail.decl1; tail = tail.tail; } } } public TypeExp FreshType(String name,TypeExp te,Env cloneEnv,TypeList cloneList) { TypeExp clone = null; if (!name.equals("")) clone = cloneEnv.Retrieve(name,cloneList ) ; if (clone == null) { Env temporary = new Env(); env.Extend("temp",te); TypeList temporarylist = new TypeList(); TypeExp tempret = env.Retrieve("temp",temporarylist); return tempret; } else return clone; } //The following function AnalyseParameters, AnalyzeExp and AnalyzeDecl are //resonsible for assigning hte original types. Two types are //assigned to each node. These should be the same- they will only change //after some changes are made. //Alot of the cases are quite long because there are a lot of try ctach statements to catch //errors. This is becuase the typechecking was to continue after an error. //However because the two types are being calculted, the functions look very //longwinded. public TwoTypes AnalyzeParameters(Env minibodyenv,TypeList minibodylist,Exp exp,Env cloneEnv, TypeList cloneList,Env errorenv,firstError fe) throws Exception{ //will have to check here that it's not a constant //This function is used to analyse the paramters - it returns two types //the type of the expression and a copy of this type. if (exp instanceof Constant) { exp.type = ((Constant)(exp)).te; exp.ctype = ((Constant)(exp)).te; exp.ctypeinfo = exp.ctype; return new TwoTypes(((Constant)(exp)).te,((Constant)(exp)).te); } else if (exp instanceof IdeClass) { boolean isdt = false; String name = ((IdeClass)(exp)).ide; if (name.equals("_")) { exp.type = new VarType(); exp.ctypeinfo = new VarType(); exp.ctype = gv.FreshTypeSpecial(exp.ctypeinfo,new TypeList(),t,false); return new TwoTypes(exp.type,exp.ctype); } BoolTypeExp bret = minibodyenv.RetrieveDT(name,minibodylist); TypeExp ret = bret.te; if (ret != null){ //NEED TO PUT THIS BACK IN AND CHECK FOR EXCEPTIONS // if (!bret.bool ) throw new Exception("It's not a datatype"); exp.type = ret; TypeExp ctype,ctypeinfo; //had ret2 = //exp.ctypeinfo = FreshType(name,ret,cloneEnv,cloneList); if (cloneEnv.Present(name) ){ ctype = cloneEnv.Retrieve(name,cloneList); ctypeinfo = gv.FreshTypeSpecial(ctype,new TypeList(),t,true); } else { ctypeinfo = FreshType(/*name*/"",ret,cloneEnv,cloneList); ctype = gv.FreshTypeSpecial(ctypeinfo,new TypeList(),t,false); } exp.ctypeinfo = ctypeinfo; exp.ctype = ctype; return new TwoTypes(ret,ctype); } //not allowing other functions here and datatypes can't be wrong so at the minute don't need to change here TypeExp temp = new VarType(); TypeExp ctypeinfo = new VarType(); TypeExp ctemp = gv.FreshTypeSpecial(ctypeinfo,new TypeList(),t,false); minibodyenv.Extend(name,temp); minibodylist.Extend(temp); cloneEnv.Extend(name,ctemp,false,ctypeinfo);cloneList.Extend(ctemp); exp.ctype = ctemp; exp.type = temp; exp.ctypeinfo = ctypeinfo; return new TwoTypes(temp,ctemp); } else if (exp instanceof Appl2Class) { Exp fun1 = ((Appl2Class)(exp)).fun; if (fun1 instanceof IdeClass) { boolean isdt = false; BoolTypeExp bfun = minibodyenv.RetrieveDT(((IdeClass)(fun1)).ide,minibodylist); TypeExp fun = bfun.te; TypeExp cfuninfo,cfun; //need to check that it's not a constructor //FIX THIS UP // if ( (! bfun.bool )) throw new Exception("It's not a datatype constructor"); if (cloneEnv.Present(((IdeClass)(fun1)).ide) ){ cfun = cloneEnv.Retrieve(((IdeClass)(fun1)).ide,cloneList); cfuninfo = gv.FreshTypeSpecial(cfun,new TypeList(),t,true); } else { cfuninfo = FreshType(((IdeClass)(fun1)).ide,fun,cloneEnv,cloneList); cfun = gv.FreshTypeSpecial(cfuninfo,new TypeList(),t,false); } // cfuninfo = FreshType(((IdeClass)(fun1)).ide,fun,cloneEnv,cloneList); // cfun = FreshType(((IdeClass)(fun1)).ide,cfuninfo,cloneEnv,cloneList); fun1.type = fun; fun1.ctype = cfun; fun1.ctypeinfo = cfuninfo; Parameters params = ((Appl2Class)(exp)).param; TypeExp returnparams = null; TypeExp creturnparams = null; //will have to take account of the currying in this case and use fun if (params != null) { do { if (params.exp == null) break; TwoTypes param1 = AnalyzeParameters(minibodyenv,minibodylist,params.exp,cloneEnv,cloneList,errorenv,fe); if (returnparams == null) { returnparams = param1.returnExp; creturnparams = param1.creturnExp; } else { returnparams = new OperType("*",TypeList.Extend(returnparams,TypeList.Extend(param1.returnExp,null))); creturnparams = new OperType("*",TypeList.Extend(creturnparams,TypeList.Extend(param1.creturnExp,null))); } params = params.tail; } while ( params != null) ; TypeExp tempvt = new VarType(); TypeExp ctempinfo = new VarType();//wasn't here TypeExp ctempvt = gv.FreshTypeSpecial(ctempinfo,new TypeList(),t,false);//new VarType(); boolean uniferr = false; try { TypeExp total = FreshType("",FunType(returnparams,fun),cloneEnv,cloneList); TypeExp rp = ((OperType)(total)).args.head; //FreshType("",returnparams,cloneEnv,cloneList); TypeExp f = ((OperType)(total)).args.tail.head; //FreshType("",fun,cloneEnv,cloneList); TypeExp tvt = new VarType(); tf.UnifyType(FunType(rp,tvt),f,dt); } catch (UnifException uni) { exp.uniferror = true; exp.info = uni.message; exp.first = uni.first; exp.second= uni.second; exp.cuniferror = true; exp.cinfo = uni.message; exp.cfirst = uni.first; exp.csecond= uni.second; uniferr = true; if (!fe.errorfound) fe.setinfo(uni.message,uni.first,uni.second,exp.Posn,exp.EndPosn); fe.errorfound = true; } if (!uniferr) { try { tf.UnifyType(FunType(returnparams,tempvt),fun,dt); } catch (UnifException u) { exp.uniferror = true; exp.info = u.message; exp.first = u.first; exp.second= u.second; } catch (Exception e1){ System.out.print("Unification error"); } try { tf.UnifyType(FunType(creturnparams,ctempvt),cfun,dt); } catch (UnifException u1) { exp.cuniferror = true; exp.cinfo = u1.message; exp.cfirst = u1.first; exp.csecond= u1.second; } catch (Exception e2){ System.out.print("Unification error"); } exp.type = tempvt; exp.ctypeinfo = ctempinfo; exp.ctype = ctempvt; } return new TwoTypes(tempvt,ctempvt); } } else System.out.print("It's not an IdeClass"); } return null; } public TwoTypes AnalyzeExp(Exp exp,Env envp,TypeList list,Env cloneEnv,TypeList cloneList,Env errorenv,firstError fe) throws ExExcept,Exception,UnifException{ //This is the main typechecking function - as we're keeping a copy of all the typing information, //all the typechecking is done twice and stored twice. Any fo the variables beginning with c //are copies. So two types are returned from this function. TypeExp returnTypeExp ,creturnTypeExp; returnTypeExp = null; creturnTypeExp = null; try { if (exp instanceof IdeClass) {//System.out.print("in the AnalExp I d"); if (errorenv.Present(((IdeClass)(exp)).ide)) { exp.cuniferror = true; exp.uniferror = true; exp.info = "error in the decl of this identifier"; exp.cinfo = exp.info; } else { returnTypeExp = envp.Retrieve(((IdeClass)(exp)).ide,list); creturnTypeExp = null; if (returnTypeExp == null){ if (!fe.errorfound) { fe.setinfo("This id is not declared",null,null,exp.Posn,exp.EndPosn); } exp.cuniferror = true; exp.cinfo = ("The id is not declared"); exp.uniferror = true;exp.info = exp.cinfo; } else { //need a clone nev for parameters and let bound variables // creturnTypeExp = FreshType(((IdeClass)(exp)).ide,returnTypeExp,cloneEnv,cloneList); // exp.ctypeinfo = FreshType(((IdeClass)(exp)).ide,returnTypeExp,cloneEnv,cloneList); if (cloneEnv.Present(((IdeClass)(exp)).ide) ) { creturnTypeExp = cloneEnv.Retrieve(((IdeClass)(exp)).ide,cloneList); exp.ctypeinfo = cloneEnv.RetrieveTrueType(((IdeClass)(exp)).ide); //exp.ctypeinfo = gv.FreshTypeSpecial(creturnTypeExp,new TypeList(),t,true); } else { exp.ctypeinfo = FreshType(((IdeClass)(exp)).ide,returnTypeExp,cloneEnv,cloneList); if (exp.ctypeinfo == null) System.out.print("it's nulllllllll"); creturnTypeExp = gv.FreshTypeSpecial(exp.ctypeinfo,new TypeList(),t,false); } } // if (returnTypeExp == null) System.out.print("nothing retrueved in the env"); } } else if (exp instanceof Constant) { returnTypeExp = ((Constant)(exp)).te; exp.ctypeinfo = returnTypeExp; creturnTypeExp = returnTypeExp; } else if (exp instanceof raisecase) { TwoTypes raiseexp = AnalyzeExp(((raisecase)(exp)).exc,envp,list,cloneEnv,cloneList,errorenv,fe); boolean uniferr = false; try { tf.UnifyType(FreshType("",raiseexp.creturnExp,new Env(),new TypeList()),new exn() , dt); } catch (UnifException e) { uniferr = true; exp.uniferror = true;exp.cuniferror = true; exp.info = e.message;exp.cinfo = e.message; exp.first = e.first;exp.cfirst = e.first; exp.second = e.second;exp.csecond = e.second; if (!fe.errorfound) { fe.setinfo(e.message,e.first,e.second,exp.Posn,exp.EndPosn); } } if (!uniferr) { try { tf.UnifyType(raiseexp.returnExp,new exn(),dt); tf.UnifyType(raiseexp.creturnExp,new exn(),dt); } catch(UnifException e) { exp.uniferror = true;exp.cuniferror = true; exp.info = e.message;exp.cinfo = e.message; exp.first = e.first;exp.cfirst = e.first; exp.second = e.second;exp.csecond = e.second; if (!fe.errorfound) { fe.setinfo(e.message,e.first,e.second,exp.Posn,exp.EndPosn); fe.errorfound = true; } } } exp.ctypeinfo = new VarType(); returnTypeExp = new VarType(); creturnTypeExp = gv.FreshTypeSpecial(exp.ctypeinfo,new TypeList(),t,false); } else if (exp instanceof CondClass) { TwoTypes condtype = AnalyzeExp(((CondClass)(exp)).test,envp,list,cloneEnv,cloneList,errorenv,fe); TwoTypes typeOfThen = AnalyzeExp(((CondClass)(exp)).iftrue,envp,list,cloneEnv,cloneList,errorenv,fe); TwoTypes typeOfElse = AnalyzeExp(((CondClass)(exp)).iffalse,envp,list,cloneEnv,cloneList,errorenv,fe); if ((((CondClass)(exp)).iftrue).uniferror == true || (((CondClass)(exp)).iffalse).uniferror == true || (((CondClass)(exp)).test).uniferror == true) { exp.cuniferror = true; exp.uniferror = true; exp.info = "There is an error in the cond, then or else part"; exp.cinfo = exp.info; } else { boolean unifex = false; try { TypeExp total = FreshType("",FunType(condtype.creturnExp,FunType(typeOfThen.creturnExp,typeOfElse.creturnExp)),cloneEnv,cloneList); TypeExp FreshCond = ((OperType)(total)).args.head; TypeExp FreshThen = ((OperType)(((OperType)(total)).args.tail.head)).args.head; TypeExp FreshElse = ((OperType)(((OperType)(total)).args.tail.head)).args.tail.head; tf.UnifyType(FreshCond,BoolType,dt); tf.UnifyType(FreshThen,FreshElse,dt); } catch (UnifException e) { unifex = true; exp.cuniferror = true;exp.uniferror = true; exp.info = e.message;exp.cinfo = e.message; exp.first = e.first;exp.cfirst = e.first; exp.csecond = e.second;exp.second = e.second; if (!fe.errorfound) { fe.setinfo(e.message,e.first,e.second,exp.Posn,exp.EndPosn); fe.errorfound = true; } } if (unifex == false ) { try {tf.UnifyType(condtype.creturnExp,BoolType,dt); } catch (UnifException e1) { exp.cuniferror = true;exp.cinfo = e1.message; exp.csecond = e1.second;exp.cfirst = e1.first; } catch (Exception e2) {exp.cuniferror = true;} try { tf.UnifyType(condtype.returnExp,BoolType,dt); } catch (UnifException u) { exp.uniferror = true; exp.info = u.message; exp.first = u.first; exp.second= u.second; //System.out.print("In bool"); } catch (Exception e) { exp.uniferror = true; } try { tf.UnifyType(typeOfThen.creturnExp,typeOfElse.creturnExp,dt); } catch (UnifException u1) { exp.cuniferror = true; exp.cinfo = u1.message; exp.cfirst = u1.first; exp.csecond = u1.second; } catch (Exception ex) { exp.uniferror = true; } try { tf.UnifyType(typeOfThen.returnExp,typeOfElse.returnExp,dt); } catch (UnifException u1) { exp.uniferror = true; exp.info = u1.message; exp.first = u1.first; exp.second= u1.second; } catch (Exception ex) { exp.uniferror = true; } returnTypeExp = typeOfThen.returnExp; creturnTypeExp = typeOfThen.creturnExp; } } } else if (exp instanceof WhileClass) { TwoTypes condtype = AnalyzeExp(((WhileClass)(exp)).test,envp,list,cloneEnv,cloneList,errorenv,fe); TwoTypes typeOfBody = AnalyzeExp(((WhileClass)(exp)).body,envp,list,cloneEnv,cloneList,errorenv,fe); if ((((WhileClass)(exp)).test).uniferror == true || (((WhileClass)(exp)).body).uniferror == true) { exp.uniferror = true;exp.cuniferror = true; exp.info = "There's a unif error in the test or the body"; exp.cinfo = exp.info; } else { boolean unifex = false; try { TypeExp FreshCond = FreshType("",condtype.creturnExp,cloneEnv,cloneList); tf.UnifyType(FreshCond,BoolType,dt); } catch (UnifException e) { unifex = true; exp.cuniferror = true;exp.uniferror = true; exp.cinfo = e.message;exp.info = e.message; exp.first = e.first;exp.cfirst = e.first; exp.csecond = e.second;exp.second = e.second; if (!fe.errorfound) { fe.setinfo(e.message,e.first,e.second,exp.Posn,exp.EndPosn); fe.errorfound = true; } } if ( ! unifex ) { try { tf.UnifyType(condtype.creturnExp,BoolType,dt); } catch (UnifException u1) { exp.cuniferror = true; exp.cinfo = u1.message; exp.cfirst = u1.first; exp.csecond= u1.second; } catch (Exception e) { exp.cuniferror = true; } try { tf.UnifyType(condtype.returnExp,BoolType,dt); } catch (UnifException u) { exp.uniferror = true; exp.info = u.message; exp.first = u.first; exp.second= u.second; } catch (Exception e) { exp.uniferror = true; } returnTypeExp = typeOfBody.returnExp; creturnTypeExp = typeOfBody.creturnExp; } } } else if (exp instanceof MiniFn) { Env minibodyenv = CopyEnvir(envp); TypeList minibodylist = CopyList(list); Env cminibodyenv = CopyEnvir(cloneEnv); TypeList cminibodtlist = CopyList(cloneList); Parameters params = ((MiniFn)(exp)).Pattern; TypeExp firstpartoffun = null; TypeExp cfirstpartoffun = null; do { if (params.exp == null) break; TwoTypes te = AnalyzeParameters(minibodyenv,minibodylist,params.exp,cloneEnv,cloneList,errorenv,fe); if (params.exp.uniferror == true ) { exp.cuniferror = true;exp.uniferror = true; exp.info = "There's a unif error with the parameters"; exp.cinfo = exp.info; } if (firstpartoffun == null) { firstpartoffun = te.returnExp; cfirstpartoffun = te.creturnExp; } else { firstpartoffun = CartType(firstpartoffun,te.returnExp); cfirstpartoffun = CartType(cfirstpartoffun,te.creturnExp); } params = params.tail; } while (params != null); TwoTypes typeofminifnbody = AnalyzeExp(((MiniFn)(exp)).Body,minibodyenv,minibodylist,cloneEnv,cloneList,errorenv,fe); if (exp.uniferror == false) { if (((MiniFn)(exp)).Body.uniferror == true) { exp.cuniferror = true;exp.uniferror = true; exp.info = "There's a unif error with the body"; exp.cinfo = exp.info; } } returnTypeExp = new OperType("->",TypeList.Extend(firstpartoffun,TypeList.Extend(typeofminifnbody.returnExp,null))); creturnTypeExp = new OperType("->",TypeList.Extend(cfirstpartoffun,TypeList.Extend(typeofminifnbody.creturnExp,null))); } else if (exp instanceof MiniFnList) { Env minibodyenv = CopyEnvir(envp); TypeList minibodylist = CopyList(list); Env cminibodyenv = CopyEnvir(cloneEnv); TypeList cminibodylist = CopyList(cloneList); TypeExp fntype = new VarType(); TwoTypes returnTypeExpt = null; TypeExp cfntype = new VarType(); //make a list of these check it on the original clones first and then on the lsit //of the originals TypeExp tempfntype = new VarType(); MiniFnList cmfl = ((MiniFnList)(exp)); boolean uniferrinhere = false; Patterns patterns = new Patterns(); do { if (cmfl == null) break; if (cmfl.head == null) break; TwoTypes r = AnalyzeExp(cmfl.head,minibodyenv,minibodylist,cminibodyenv,cminibodylist,errorenv,fe); patterns.Extend(r.returnExp,r.creturnExp); if (cmfl.head.uniferror) {uniferrinhere = true; } if (!uniferrinhere ) {//unify them try { tf.UnifyType(tempfntype,FreshType("",r.creturnExp,cminibodyenv,cminibodylist),dt); } catch (UnifException u) { uniferrinhere = true; cmfl.head.cuniferror = true;cmfl.head.uniferror = true; cmfl.head.cinfo = u.message;cmfl.head.cinfo = u.message; cmfl.head.first = u.first;cmfl.head.cfirst = u.first; cmfl.head.csecond = u.second;cmfl.head.second = u.second; if (!fe.errorfound) { fe.setinfo(u.message,u.first,u.second,exp.Posn,exp.EndPosn); } } } cmfl = cmfl.tail; } while (cmfl != null);//System.out.print(" out here "); if (!uniferrinhere) { //MiniFnList mfl = ((MiniFnList)(exp)); do { if (patterns == null) break; if (patterns.exp1 == null) break; returnTypeExpt = new TwoTypes(patterns.exp1,patterns.exp2);//AnalyzeExp(mfl.head,minibodyenv,minibodylist,cminibodyenv,cminibodylist,errorenv); try { tf.UnifyType(fntype,returnTypeExpt.returnExp,dt); } catch (UnifException u) { exp.uniferror = true; exp.info = u.message; exp.first = u.first; exp.second= u.second; } catch (Exception e) { exp.uniferror = true; } try { tf.UnifyType(cfntype,returnTypeExpt.creturnExp,dt); } catch (UnifException u1) { exp.cuniferror = true; exp.cinfo = u1.message; exp.cfirst = u1.first; exp.csecond= u1.second; } catch (Exception e1) { exp.cuniferror = true; } patterns = patterns.tail; } while (patterns != null); returnTypeExp = fntype; creturnTypeExp = cfntype; } else { exp.cuniferror = true;exp.uniferror = true; exp.info = "There's an error inside the funciton"; exp.cinfo = exp.info; } } else if (exp instanceof handleclass) { TwoTypes theexp = AnalyzeExp(((handleclass)(exp)).exp,envp,list,cloneEnv,cloneList,errorenv,fe); TwoTypes thematch = AnalyzeExp(((handleclass)(exp)).match,envp,list,cloneEnv,cloneList,errorenv,fe); //need to put in the trial unify boolean uniferr = false; try { TypeExp t = FreshType("",FunType(theexp.creturnExp, thematch.creturnExp),new Env(),new TypeList()); TypeExp e = ((OperType)(t)).args.head; TypeExp m = ((OperType)(t)).args.tail.head; tf.UnifyType(FunType(new exn(),e),m,dt); } catch(UnifException e) { exp.cuniferror = true;exp.uniferror = true; exp.info = e.message;exp.cinfo = e.message; exp.first = e.first;exp.cfirst = e.first; exp.second = e.second;exp.csecond = e.second; uniferr = true; if (!fe.errorfound) { fe.setinfo(e.message,e.first,e.second,exp.Posn,exp.EndPosn); fe.errorfound = true; } } if (!uniferr) { try { tf.UnifyType(FunType(new exn(),theexp.returnExp),thematch.returnExp,dt); tf.UnifyType(FunType(new exn(),theexp.creturnExp),thematch.creturnExp,dt); } catch(UnifException e) { exp.cuniferror = true;exp.uniferror = true; exp.info = e.message;exp.cinfo = e.message; exp.first = e.first;exp.cfirst = e.first; exp.second = e.second;exp.csecond = e.second; if (!fe.errorfound) { fe.setinfo(e.message,e.first,e.second,exp.Posn,exp.EndPosn); fe.errorfound = true; } } } returnTypeExp = theexp.returnExp; creturnTypeExp = theexp.creturnExp; } else if (exp instanceof ApplClass) { TwoTypes typeOfFun = AnalyzeExp(((ApplClass)(exp)).fun,envp,list,cloneEnv,cloneList,errorenv,fe); TwoTypes typeOfArg = AnalyzeExp(((ApplClass)(exp)).arg,envp,list,cloneEnv,cloneList,errorenv,fe); TypeExp typeOfRes = new VarType(); TypeExp ctypeOfRes = new VarType(); if (((ApplClass)(exp)).fun.uniferror == true || (((ApplClass)(exp)).arg).uniferror == true) { exp.uniferror = true;exp.info = "The arg or the body have a unif error "; exp.cuniferror = true;exp.cinfo = exp.info; } else { boolean uniferr = false; try { TypeExp total = FreshType("",FunType(typeOfArg.creturnExp,typeOfFun.creturnExp),cloneEnv,cloneList); TypeExp typeofa = ((OperType)(total)).args.head; TypeExp typeoff = ((OperType)(total)).args.tail.head;; TypeExp typeofr = new VarType(); tf.UnifyType(FunType(typeofa,typeofr),typeoff,dt); } catch (UnifException un) { exp.uniferror = true; exp.info = un.message; exp.first = un.first; exp.second= un.second; exp.cuniferror = true; exp.cinfo = un.message; exp.cfirst = un.first; exp.csecond= un.second; uniferr = true; if (!fe.errorfound) { fe.setinfo(un.message,un.first,un.second,exp.Posn,exp.EndPosn); } } if (uniferr) { try { tf.UnifyType(FunType(typeOfArg.returnExp,typeOfRes),typeOfFun.returnExp,dt); } catch (UnifException u) { exp.uniferror = true; exp.info = u.message; exp.first = u.first; exp.second= u.second; } catch (Exception exc) { exp.uniferror = true; } try { tf.UnifyType(FunType(typeOfArg.creturnExp,ctypeOfRes),typeOfFun.creturnExp,dt); } catch (UnifException u1) { exp.cuniferror = true; exp.cinfo = u1.message; exp.cfirst = u1.first; exp.csecond= u1.second; } catch (Exception exc) { exp.cuniferror = true; } returnTypeExp = typeOfRes; creturnTypeExp = ctypeOfRes; } } } else if (exp instanceof Appl2Class) { TwoTypes typeOfFun = AnalyzeExp(((Appl2Class)(exp)).fun,envp,list,cloneEnv,cloneList,errorenv,fe); TypeExp typeOfRes = new VarType(); TypeExp ctypeOfRes = new VarType(); Parameters param = ((Appl2Class)(exp)).param; TypeExp parameters = null; TypeExp cparameters = null; boolean uniferror = ((Appl2Class)(exp)).fun.uniferror; do { if (param.exp == null) break; TwoTypes paramhead = AnalyzeExp(param.exp,envp,list,cloneEnv,cloneList,errorenv,fe); uniferror = uniferror && (param.exp.uniferror); if (parameters == null) { parameters = paramhead.returnExp; cparameters = paramhead.creturnExp; } else { parameters = new OperType("*",TypeList.Extend(parameters,TypeList.Extend(paramhead.returnExp,null))); cparameters = new OperType("*",TypeList.Extend(cparameters,TypeList.Extend(paramhead.creturnExp,null))); } param = param.tail; } while (param != null); if (parameters == null) throw new Exception("no parameters"); if (uniferror) { exp.uniferror = true;exp.cuniferror = true; exp.info = ("There's a unif error in the function or the parameters"); } else { uniferror = false; try { TypeExp total = FreshType("",FunType(parameters,typeOfFun.creturnExp),cloneEnv,cloneList); TypeExp p = ((OperType)(total)).args.head; TypeExp f = ((OperType)(total)).args.tail.head;; TypeExp r = new VarType(); tf.UnifyType(FunType(p,r),f,dt); } catch (UnifException uni) { exp.uniferror = true; exp.info = uni.message; exp.first = uni.first; exp.second= uni.second; exp.cuniferror = true; exp.cinfo = uni.message; exp.cfirst = uni.first; exp.csecond= uni.second; uniferror = true; if (!fe.errorfound) { fe.setinfo(uni.message,uni.first,uni.second,exp.Posn,exp.EndPosn); fe.errorfound = true; } } if ( ! uniferror ) { try { tf.UnifyType(FunType(parameters,typeOfRes),typeOfFun.returnExp,dt); } catch (UnifException u) { exp.uniferror = true; exp.info = u.message; exp.first = u.first; exp.second= u.second; } catch (Exception exc) { exp.uniferror = true; } try { tf.UnifyType(FunType(cparameters,ctypeOfRes),typeOfFun.creturnExp,dt); } catch (UnifException u1) { exp.cuniferror = true; exp.cinfo = u1.message; exp.cfirst = u1.first; exp.csecond= u1.second; } catch (Exception exc) { exp.cuniferror = true; } returnTypeExp = typeOfRes; creturnTypeExp = ctypeOfRes; } } } else if (exp instanceof Tuple) { Parameters param = ((Tuple)(exp)).p; TypeExp parameters = null; TypeExp cparameters = null; boolean uniferror = false; do { if (param.exp == null) break; TwoTypes paramhead = AnalyzeExp(param.exp,envp,list,cloneEnv,cloneList,errorenv,fe); uniferror = uniferror || (param.exp.uniferror); if (parameters == null) { parameters = paramhead.returnExp; cparameters = paramhead.creturnExp; } else { parameters = new OperType("*",TypeList.Extend(parameters,TypeList.Extend(paramhead.returnExp,null))); cparameters = new OperType("*",TypeList.Extend(cparameters,TypeList.Extend(paramhead.creturnExp,null))); } param = param.tail; } while (param != null); if (parameters == null) throw new Exception("no parameters"); if (uniferror) { exp.uniferror = true;exp.cuniferror = true; exp.info = ("There's a unif error in the body of the tuple"); exp.cinfo = exp.info; } returnTypeExp = parameters; creturnTypeExp = cparameters; } else if (exp instanceof BlockClass) { TwoEnvs declEnv = AnalyzeDecl(((BlockClass)(exp)).decl,envp,list,cloneEnv,cloneList,errorenv,fe); TwoTypes tempr = AnalyzeExp(((BlockClass)(exp)).scope,declEnv.env1,list,declEnv.env2,cloneList,errorenv,fe); if ((((BlockClass)(exp)).scope.uniferror)) { exp.uniferror = true;exp.cuniferror = true; exp.info = "There's a unif error in the body";exp.cinfo = exp.info; if (!fe.errorfound) { fe.setinfo(exp.info,null,null,exp.Posn,exp.EndPosn); fe.errorfound = true; } } else { returnTypeExp = tempr.returnExp; creturnTypeExp = tempr.creturnExp; } } else { returnTypeExp = null; creturnTypeExp = null; } } catch (ClassCastException e1) { System.out.print("CLASS CAST IN THE MAIN PART"); System.out.print(e1.getMessage()); } catch (UnifException u) { exp.uniferror = true; exp.cuniferror = true; exp.info = u.message; exp.cinfo = u.message; exp.first = u.first; exp.cfirst = u.first; exp.second= u.second; exp.csecond = u.second; } catch (Exception e) { if ((e.getMessage()).equals("UnifError")) { exp.uniferror = true;exp.cuniferror = true; } else System.out.print(e.toString()); } if (returnTypeExp != null) { exp.type = returnTypeExp; } if (creturnTypeExp != null) { exp.ctype = creturnTypeExp; } return new TwoTypes(returnTypeExp,creturnTypeExp); } public boolean IsDataType(TypeExp te) { //This checks whether a given type expression is a datatype. Between //the dt variable and the predefined datatypes int, bool etc. it should //be able to tell if a type expreesion is a datatype. if (te instanceof VarType) { if ( ((VarType)(te)).instance == null ) return true; else return IsDataType(((VarType)(te)).instance ); } else if (te instanceof OperType) { String ide = ((OperType)(te)).ide; if (ide.equals("bool") || ide.equals("int") || ide.equals("string") || ide.equals("char") || ide.equals("real")) { if ( (((OperType)(te)).args == null) || ((OperType)(te)).args.length() == 0 ) return true; else return false; } else if (ide.equals("*") || ide.equals("->")) { if (((OperType)(te)).args.length() != 2) return false; else { TypeList tl = ((OperType)(te)).args; boolean isdt = true; do{ if (tl == null) break; if (tl.head == null) break; isdt = isdt && IsDataType(tl.head); tl = tl.tail; } while (tl != null); return isdt; } } else { TypeList tl = ((OperType)(te)).args; if (tl == null) return dt.PresentArity(ide,0); if (dt.PresentArity(ide,((OperType)(te)).args.length()) ){ boolean isdt = true; do{ if (tl == null) break; if (tl.head == null) break; isdt = isdt && IsDataType(tl.head); tl = tl.tail; } while (tl != null); return isdt; } else return false; } } else return true;//should take care of the overload } //The analexpparsed is just used to traverse the tree without making any changes to the tree //will need to return a copy of the return env back again public TwoEnvs AnalyzeDecl(Decl decl,Env envp,TypeList list,Env cloneEnv,TypeList cloneList,Env errorenv,firstError fe) throws ExExcept,Exception,UnifException{ /*Typecheck a declaration w.r.t. an environment, and return an environment that has been extended to contain the types of the identifiers introduced by the declaration. In this case because you want to store the type twice a cloneEnv and cloneList need to be passed ass well */ TypeList copylist = CopyList(list); TypeList ccopylist = CopyList(cloneList); if (decl instanceof DefClass) { //new copy envp and return it extended Env retenv = CopyEnvir(envp); //check which way this is vp);//think it's ok to have envp below - check Env cretenv = CopyEnvir(cloneEnv); TwoTypes tt = AnalyzeExp(((DefClass)(decl)).def,envp,copylist,cloneEnv,cloneList,errorenv,fe); if ((((DefClass)(decl)).def).uniferror) {errorenv.Extend(((DefClass)(decl)).binder,new VarType());} retenv.Extend(((DefClass)(decl)).binder,tt.returnExp); cretenv.Extend(((DefClass)(decl)).binder,tt.creturnExp); return new TwoEnvs(retenv,cretenv); } else if (decl instanceof Except) { //not allowing poly types in Exceptions Env retenv = CopyEnvir(envp); Env cretenv = CopyEnvir(cloneEnv); Except exc = (Except)(decl); TypeExp except; if ((exc.arg == null )){ except = new exn(); } else { except = FunType(exc.arg,new exn()); } retenv.Extend(exc.name,except); cretenv.Extend(exc.name,except);//will need to change fresh ype return new TwoEnvs(retenv,cretenv); } else if (decl instanceof SeqClass) { //will need to pass a copy of envp to this Env retenv2 = CopyEnvir(envp); Env cretenv2 = CopyEnvir(cloneEnv); TwoEnvs tes = AnalyzeDecl(((SeqClass)(decl)).first,retenv2,copylist,cretenv2,ccopylist,errorenv,fe); return AnalyzeDecl(((SeqClass)(decl)).second,tes.env1,copylist,tes.env2,ccopylist,errorenv,fe); } //seeing as I'm not allowing any chnages to be made to the datatypes //don't need to make any changes here else if (decl instanceof DataType) { //In the case of a datatype - all the possible cases are just added to //the environemnt. No changes are allowed to be made tot them later on. Miscell m = new Miscell(); //Setting the equality type of the datatype. if (m.IsEqType(((DataType)(decl)),dt)) { ((DataType)(decl)).IsEqType = 1; } else { ((DataType)(decl)).IsEqType = 2; } TypeExp nameofdatatype; Env retenv6 = CopyEnvir(envp); Env cretenv6 = CopyEnvir(cloneEnv); if ( ((DataType)(decl)).parameters == null ) nameofdatatype = new OperType(((DataType)(decl)).name,null); else {System.out.print("for 'a types"); TypeList temptl = new TypeList(); ArgList tail = ((DataType)(decl)).parameters; while (! (tail.namefn).equals("")) { temptl.Extend(tail.type); if (tail.tail == null) break; else tail = tail.tail; } nameofdatatype = new OperType(((DataType)(decl)).name,temptl); } ArgList pattern = ((DataType)(decl)).Pattern; if (pattern == null) System.out.print("it's null"); while (! (pattern.namefn).equals("")) {System.out.print("inside pattern"); if (pattern.type == null) {System.out.print("Extending 1"); //should realistically check that these are proper dt retenv6.Extend(pattern.namefn,nameofdatatype,true); cretenv6.Extend(pattern.namefn,nameofdatatype,true); } else { if (! IsDataType(pattern.type)) throw new Exception("it's not a datatype "); retenv6.Extend(pattern.namefn,FunType(pattern.type,nameofdatatype),true); cretenv6.Extend(pattern.namefn,FunType(pattern.type,nameofdatatype),true); // System.out.print("Extending 2"); } if (pattern.tail == null) break; pattern = pattern.tail; } return new TwoEnvs(retenv6,cretenv6); } else if (decl instanceof RecClass){ //will need to pass a copy to this a s well Env retenv3 = CopyEnvir(envp); Env cretenv3 = CopyEnvir(cloneEnv); AnalyzeRecDeclBind(((RecClass)(decl)).rec,retenv3,copylist,cretenv3,ccopylist,errorenv,fe);//this will have changed so pass the changed one on AnalyzeRecDecl(((RecClass)(decl)).rec,retenv3,copylist,cretenv3,ccopylist,errorenv,fe); return new TwoEnvs(retenv3,cretenv3); } else if (decl instanceof AndDecl) { //Just works as a sequential declaration. if ( ! (((AndDecl)(decl)).decl1 instanceof DataType) ){ Decl first = ((AndDecl)(decl)).decl1; AndDecl tail = ((AndDecl)(decl)).tail; Env cretenv3 = CopyEnvir(cloneEnv); Env retenv4 = CopyEnvir(envp); try { while (first != null) { if (first instanceof RecClass) AnalyzeRecDeclBind(((RecClass)(first)).rec,retenv4,copylist,cretenv3,ccopylist,errorenv,fe); else AnalyzeRecDeclBind(first,retenv4,copylist,cretenv3,ccopylist,errorenv,fe); if (tail == null) break; first = tail.decl1; tail = tail.tail; } Decl first1 = ((AndDecl)(decl)).decl1; AndDecl tail1 = ((AndDecl)(decl)).tail; while (first1 != null) { if (first1 instanceof RecClass) AnalyzeRecDecl(((RecClass)(first1)).rec,retenv4,copylist,cretenv3,ccopylist,errorenv,fe); else AnalyzeRecDecl(first1,retenv4,copylist,cretenv3,ccopylist,errorenv,fe); if (tail1 == null) break; first1 = tail1.decl1; tail1 = tail1.tail; } } catch (Exception e) { System.out.print(e.getMessage()); } return new TwoEnvs(retenv4,cretenv3); } else if (((AndDecl)(decl)).decl1 instanceof DataType) { System.out.print("in the proper part"); //the problem here is to check about eqtypes Miscell m = new Miscell(); boolean eqtpye = m.IsEqTypeforand(((AndDecl)(decl)),dt); // throw new Exception("new"); //for each of them add to the env // System.out.print("in the proper "); Env retenv6 = CopyEnvir(envp); Env cretenv6 = CopyEnvir(cloneEnv); Decl temp = ((AndDecl)(decl)).decl1; DataType datatype1; if (temp instanceof DataType) datatype1 = ((DataType)(temp)); else throw new Exception(" this should be a datatype decl"); AndDecl adtail = ((AndDecl)(decl)).tail; do { TypeExp nameofdatatype;//System.out.print(((DataType)(decl)).name); if ( datatype1.parameters == null ) nameofdatatype = new OperType(datatype1.name,null); else {//System.out.print("for 'a types"); TypeList temptl = new TypeList(); ArgList tail = datatype1.parameters; while (! (tail.namefn).equals("")) { temptl.Extend(tail.type); if (tail.tail == null) break; else tail = tail.tail; } nameofdatatype = new OperType(datatype1.name,temptl); } // System.out.print("before pattern"); ArgList pattern = datatype1.Pattern; //if (pattern == null) System.out.print("it's null"); while (! (pattern.namefn).equals("")) {//System.out.print("inside pattern"); if (pattern.type == null) {//System.out.print("Extending 1"); //should realistically check that these are proper dt retenv6.Extend(pattern.namefn,nameofdatatype,true); cretenv6.Extend(pattern.namefn,nameofdatatype,true); } else {//put in the name of the dt if (! IsDataType(pattern.type)) throw new Exception("it's not a datatype "); //need to check here all members of dt or of type name retenv6.Extend(pattern.namefn,FunType(pattern.type,nameofdatatype),true); cretenv6.Extend(pattern.namefn,FunType(pattern.type,nameofdatatype),true); // System.out.print("Extending 2"); } if (pattern.tail == null) break; pattern = pattern.tail; } if (adtail == null) break; Decl headdt = adtail.decl1; adtail = adtail.tail; datatype1 = null; if (headdt == null) break;//System.out.print(headdt); if (headdt instanceof DataType) datatype1 = ((DataType)(headdt)); else throw new Exception("it's not a datatype"); // System.out.print("end of data types"); } while ( datatype1 != null); //throw new Exception("end"); return new TwoEnvs(retenv6,cretenv6); } } return null; }; public void AnalyzeRecDeclBind(Decl decl,Env envp,TypeList list,Env cloneEnv,TypeList cloneList,Env errorenv,firstError fe){ /*This and AnalyzeRecDecl are used to typecheck recursive declarations This function creates a new set of non-generic type variables and associates them with identifiers. */ if (decl instanceof DefClass) { TypeExp newTypeVar = new VarType(); envp.Extend(((DefClass)(decl)).binder,newTypeVar); list.Extend(newTypeVar); TypeExp cnewTypeVar = new VarType(); cloneEnv.Extend(((DefClass)(decl)).binder,cnewTypeVar); cloneList.Extend(cnewTypeVar); } if (decl instanceof SeqClass){ AnalyzeRecDeclBind(((SeqClass)(decl)).first,envp,list,cloneEnv,cloneList,errorenv,fe);//both env and list should be changed AnalyzeRecDeclBind(((SeqClass)(decl)).second,envp,list,cloneEnv,cloneList,errorenv,fe); } if (decl instanceof RecClass) { AnalyzeRecDeclBind(((RecClass)(decl)).rec,envp,list,cloneEnv,cloneList,errorenv,fe); } } public void AnalyzeRecDecl(Decl decl,Env envp, TypeList list,Env cloneEnv,TypeList cloneList,Env errorenv,firstError fe)throws ExExcept,Exception ,UnifException{ /* This function analyzes the declarations and makes calls to UnifyType to ensure the recursive constraints. */ TypeList copylist = CopyList(list); TypeList ccopylist = CopyList(cloneList); if (decl instanceof DefClass) { boolean uniferr = false; //make sure if there's a problem with an identifer then anywhere //that's is used contains the error. if (errorenv.Present(((DefClass)(decl)).binder)) {uniferr = true;} TypeExp orig = envp.Retrieve(((DefClass)(decl)).binder,copylist); TwoTypes res = AnalyzeExp(((DefClass)(decl)).def,envp,copylist,cloneEnv,ccopylist,errorenv,fe); if (((DefClass)(decl)).def.uniferror) uniferr =true; if (uniferr) { (((DefClass)(decl)).def).uniferror = true; (((DefClass)(decl)).def).info = "unification error"; } else { uniferr = false; try{ TypeExp total = FreshType("",FunType(orig,res.returnExp),cloneEnv,cloneList); TypeExp o = ((OperType)(total)).args.head; TypeExp r = ((OperType)(total)).args.tail.head;; tf.UnifyType(o,r,dt); } catch (UnifException e) { (((DefClass)(decl)).def).uniferror = true; (((DefClass)(decl)).def).info = e.message; (((DefClass)(decl)).def).first = e.first; (((DefClass)(decl)).def).second= e.second; (((DefClass)(decl)).def).cuniferror = true; (((DefClass)(decl)).def).cinfo = e.message; (((DefClass)(decl)).def).cfirst = e.first; (((DefClass)(decl)).def).csecond= e.second; uniferr = true; } if (! uniferr) { try { tf.UnifyType(orig,res.returnExp,dt); } catch (UnifException u) { (((DefClass)(decl)).def).uniferror = true; (((DefClass)(decl)).def).info = u.message; (((DefClass)(decl)).def).first = u.first; (((DefClass)(decl)).def).second= u.second; } catch (Exception e) { ((DefClass)(decl)).def.uniferror = true; } try { tf.UnifyType(FreshType(((DefClass)(decl)).binder,orig,cloneEnv,ccopylist),res.creturnExp,dt); } catch (UnifException u1) { (((DefClass)(decl)).def).cuniferror = true; (((DefClass)(decl)).def).cinfo = u1.message; (((DefClass)(decl)).def).cfirst = u1.first; (((DefClass)(decl)).def).csecond= u1.second; } catch (Exception e1) { ((DefClass)(decl)).def.cuniferror = true; } } } if (uniferr) {errorenv.Extend(((DefClass)(decl)).binder,new VarType());} } if (decl instanceof SeqClass) { AnalyzeRecDecl(((SeqClass)(decl)).first,envp,copylist,cloneEnv,ccopylist,errorenv,fe); AnalyzeRecDecl(((SeqClass)(decl)).second,envp,copylist,cloneEnv,ccopylist,errorenv,fe); } if (decl instanceof RecClass) { AnalyzeRecDecl(((RecClass)(decl)).rec,envp,copylist,cloneEnv,ccopylist,errorenv,fe); } } }; //to make a copy of a string tokenizer //doesn't work class TwoStringTokenizer { //A class that stores two StringTokenizers StringTokenizer first; StringTokenizer second; public TwoStringTokenizer() { first = null; second = null; } public TwoStringTokenizer(StringTokenizer first,StringTokenizer second) { this.first = first; this.second = second; } } interface ParserI { public Exp Parse(String stringp,int number) throws Exception; public Exp ParseIf()throws Exception; public Exp ParseFun()throws Exception; public Exp ParseLet()throws Exception; public Decl ParseRec()throws Exception; public Exp ParseExp()throws Exception; public Decl ParseDecl()throws Exception; } class TS { TypeExp te; StringTokenizer st; public TS(TypeExp te,StringTokenizer st) { this.te = te; this.st = st; } } class pair { //This is used in the TokenTable to record positions. int first,second; public pair(int first,int second){ this.first = first; this.second = second; } } class Parser implements ParserI { StringTokenizer st ; public Parser(){ st = null; } public static TwoStringTokenizer CopyST(StringTokenizer st) { //couldn't find a way of copying the stream of tokens - so it's just //written into a string buffer and make into a strema of tokens twice. //Alternatively this could be done at the very beginning. StringBuffer sb = new StringBuffer(); while (st.hasMoreTokens()) { String s = st.nextToken(); sb.append(s); sb.append(" "); } System.out.print(" "); String retstr = sb.toString(); StringTokenizer retst1 = new StringTokenizer(retstr); StringTokenizer retst2 = new StringTokenizer(retstr); TwoStringTokenizer rettst = new TwoStringTokenizer(retst1,retst2); return rettst; } public void eat(String exp) throws Exception{ //If exp matches the next token nothing happens - otherwise an exception is raised if ((st.hasMoreTokens()) && ((st.nextToken()).equals(exp))) { } else { StringBuffer temp = new StringBuffer("Expected : "); temp.append(exp); Exception e = new Exception(temp.toString()); throw e; } }; public String adjust(String exp) { //To save heving to do any lexical analysis - the string tokenizer in java was used. //However this meant that first spaces had to be inserted between any control characters //to enable them to be recognized. You can addd more control characters to the string //tokenizer - however it keeps no record of what exactly the control character was. StringBuffer Adjust = new StringBuffer(""); int i = 0; while (i < exp.length() - 1) { if ((exp.charAt(i) == '(' ) || (exp.charAt(i) == ')' )|| (exp.charAt(i) == '=') || (exp.charAt(i) == ',') || (exp.charAt(i) == '"' )) { //add a space before and after Adjust.append(" "); Adjust.append(exp.charAt(i)); Adjust.append(" "); } else Adjust.append(exp.charAt(i)); i = i + 1; } if ((exp.charAt(i) == '(' ) || (exp.charAt(i) == ')' )|| (exp.charAt(i) == '=') || (exp.charAt(i) == ',') || (exp.charAt(i) == '"')) { Adjust.append(" "); Adjust.append(exp.charAt(i)); } else Adjust.append(exp.charAt(i)); return Adjust.toString(); } public pair[] TokenTable(String exp,int length){ //Token Table just returns an array of pairs that of tokens to positions pair pairarray[] = new pair[length + 10]; int i = 0; int j = 0; while (i < exp.length() - 1) {//System.out.print("in here i = " + i); char current = exp.charAt(i); if ((exp.charAt(i) == '(' ) || (exp.charAt(i) == ')' )|| (exp.charAt(i) == '=') || (exp.charAt(i) == ',') || (exp.charAt(i) == '"' )) { pairarray[j] = new pair(i,i+1); j++;i++; } else if ((exp.charAt(i) == ' ') || (exp.charAt(i) == '\t') || (exp.charAt(i) == '\n') || (exp.charAt(i) == '\r') ) { i ++; } else { int start = i; while ((i < exp.length() -1 ) && ! ( ((exp.charAt(i) == ' ') || (exp.charAt(i) == '\t') || (exp.charAt(i) == '\n') || (exp.charAt(i) == '\r') ) || ((exp.charAt(i) == '(' ) || (exp.charAt(i) == ')' )|| (exp.charAt(i) == '=') || (exp.charAt(i) == ',') || (exp.charAt(i) == '"' )) )) { i++; } pairarray[j] = new pair(start,i);j++; // i++; } } return pairarray; } public int adjustbefore(String exp,int posn) { //This function adjusts the string so that exactly the same changes //are applied to the string that were appplied in parsing //This is to enable the correct token position to be calculated StringBuffer Adjust = new StringBuffer(exp); int adposn = posn; int i = 0; while ((i < (posn)) && (i < Adjust.length())) {//watch here was < if ((Adjust.charAt(i) == '(' ) || (Adjust.charAt(i) == ')' )|| (Adjust.charAt(i) == '=') || (Adjust.charAt(i) == ',') ) { adposn = adposn + 2; i = i + 2; } else i = i + 1; } if ((i < Adjust.length()) &&((Adjust.charAt(i) == '(' ) || (Adjust.charAt(i) == ')' )|| (Adjust.charAt(i) == '=') || (Adjust.charAt(i) == ','))) { adposn = adposn + 1; } return adposn; } public int ReturnTokensRemaining(String exp,int posn,boolean before) { //Tells you how many tokens are left in from the position supplied //to the end of the text. String Remains = exp.substring(posn); String temp = adjust(Remains); StringTokenizer temptoken = new StringTokenizer(adjust(Remains)); if (!before) { if ((Remains.charAt(0) == '(') || (Remains.charAt(0) == ')' )|| (Remains.charAt(0) == ',') || (Remains.charAt(0) == ' ') || (Remains.charAt(0) == '=') || (Remains.charAt(0) == '"') || (Remains.charAt(0) == '\n') || (Remains.charAt(0) == '\r')) return temptoken.countTokens(); else return temptoken.countTokens() -1; } else { return temptoken.countTokens() - 1; } } public int ReturnTokenNo(String exp, int posn) { //returns the token number givn a string and a poistion int tokenno = 0; int properposn = adjustbefore(exp,posn); int index = 0; String tempstr = adjust(exp); //these are the boundary poistions. if (properposn >= tempstr.length() - 1) return 0; if (properposn > tempstr.length()) properposn = tempstr.length(); while (index < properposn) { if ((tempstr.charAt(index) == ' ') || (tempstr.charAt(index) == '\t') || (tempstr.charAt(index) == '\r') || (tempstr.charAt(index) == '\n')) { tokenno = tokenno + 1; index = index + 1; while ( (index < properposn) && ((tempstr.charAt(index) == ' ') || (tempstr.charAt(index) == '\t') || (tempstr.charAt(index) == '\r') || (tempstr.charAt(index) == '\n')) ) { index = index + 1; } } else index = index +1 ; } return tokenno; } //THE PARSING FUNCTIONS ARE REASONABLY SELF-EXPLANATORY. A LEXICAL //ANALYSER WAS NOT USED. INSTEAD A STRING TOKENIZER WS USED, BUT THIS MEANT THAT //BEFORE A STRING WAS PARSED, SPACES WERE INSERTED BEFORE AND AFTER ANY CONTROL //CHARACTER TO MAKE SURE IT BECAME A TOKEN ON ITS OWN. //THIS WAS PROBABLY NOT THE BEST WAY OF DOING IT. //FOR TE SYNTAX OF THE LANGUAGE THAT CAN BE RECOGNISED BY THESE FUNCTIONS //SEE THE ONE OF THE APPENDICES IN THE PROJECT WRITE UP. public Exp Parse(String stringp,int number) throws Exception { //This is the main parse function - it adjusts the string - then uses the string tokenizer //to make a stream of tokens and the applies the parses. st = new StringTokenizer(adjust(stringp)); number = st.countTokens(); return ParseExp(); } public boolean IsDigit(char c) { return ( (c == '1') || (c == '2') || (c == '3') || (c == '4') || (c == '5') || (c == '6') || (c == '7') || (c == '8') || (c == '9') || (c == '0')); } public Exp ParseExp() throws Exception { //Keeps parsing until the end of the stream of tokens is reached and then an expression tree is returned while (st.hasMoreTokens()) { Exp returnTypeExp; String temp = st.nextToken(); int tokensrem = st.countTokens(); if (temp.equals("if")) { returnTypeExp = ParseIf(); } else if (temp.equals("fn")) { returnTypeExp = ParseFun(); } else if (temp.equals("let")) { returnTypeExp = ParseLet(); } else if (temp.equals("(")){ Parameters p = ParseParameters(true); eat(")"); returnTypeExp = new Tuple(p,tokensrem,st.countTokens()); } else if (temp.equals("while")){ returnTypeExp = ParseWhile(); } else if (temp.equals("case")) { returnTypeExp = ParseCase(); } else if (temp.equals("raise")) { Exp exc = ParseExp(); returnTypeExp = new raisecase(exc,tokensrem,st.countTokens()); } //Checks for all the keywords first then it assumes it's got an identifier. else { //Parsing strings - the type is assigned here for strings if (temp.equals("\"")) {//nottaking account of quotes in the string StringBuffer constantvalue = new StringBuffer(temp); String temp1 = st.nextToken();constantvalue.append(temp1); while (( !(temp1.equals("\""))) && (st.hasMoreTokens())) { temp1 = st.nextToken();constantvalue.append(temp1); } TypeExp String = new OperType("string",null); returnTypeExp = new Constant(String,constantvalue.toString(),tokensrem,st.countTokens()); } else if (temp.equals("#")) { //parsing characters - needs a few more restrictions inposed to be striclty correct eat("\""); String temp1 = st.nextToken(); StringBuffer constval = new StringBuffer("#\""); constval.append(temp1);constval.append("\""); eat("\""); TypeExp Char = new OperType("char",null); returnTypeExp = new Constant(Char,constval.toString(),tokensrem,st.countTokens()); } else if ((temp.charAt(0) == '~') || (IsDigit(temp.charAt(0)) )) { //parsing numbers TypeExp Int = new OperType("int",null); returnTypeExp = new Constant(Int,temp,tokensrem,st.countTokens()); } else { //otherwise it's an identifier class returnTypeExp = new IdeClass(temp,tokensrem,st.countTokens()); } } //checking for the case of function applications etc. TwoStringTokenizer twost = CopyST(st); st = twost.first; StringTokenizer stcopy = twost.second; if (stcopy.hasMoreTokens()) { String tempnt = stcopy.nextToken(); if (tempnt.equals("(")) { //An application Parameters params = new Parameters(); eat("("); String controltoken = ""; do { Exp returnTypeExp2 = ParseExp(); params.Extend(returnTypeExp2,true); TwoStringTokenizer twost1 = CopyST(st); st = twost1.first; StringTokenizer stcopy1 = twost1.second; if (stcopy1.hasMoreTokens()) { controltoken = stcopy1.nextToken(); if (controltoken.equals(",") ) eat(","); } else controltoken = " "; } while (controltoken.equals(",")); eat(")");////System.out.print("in the appl");//System.out.print(tokensrem); ////System.out.print(st.countTokens()); int i; if (st.countTokens() < 1) i = 0; else i = st.countTokens() ; Exp returnApplClass = new Appl2Class(returnTypeExp,params,tokensrem,i);//will need to change this for other applications return returnApplClass; } else if (tempnt.equals("andalso") || tempnt.equals("orelse")) { //An "and" or "or" expression boolean and;if (tempnt.equals("andalso")) and = true; else and = false; if (and) eat("andalso"); else eat("orelse"); int ide = st.countTokens(); Exp secarg = ParseExp(); int j ; if (st.countTokens() < 1) j = 0; else j = st.countTokens() ; Exp funname;//System.out.print("the id is ");//System.out.print(ide); if (and) funname = new IdeClass("andalso",ide,ide); else funname = new IdeClass("orelse",ide,ide); Parameters params = new Parameters(); params.Extend(returnTypeExp,true); params.Extend(secarg,true); Exp returnApplClass = new Appl2Class(funname,params,tokensrem,j); return returnApplClass; } else if (tempnt.equals("handle")) { //handle exception case eat("handle"); Exp exc = ParseFun();//need to be parsing a match here if (exc instanceof MiniFnList) { return new handleclass(returnTypeExp,((MiniFnList)(exc)),tokensrem,st.countTokens()); } } } return returnTypeExp; }; return null; } public Exp ParseIf() throws Exception { int tokensrem = st.countTokens(); Exp test = ParseExp(); eat("then"); Exp ifclause = ParseExp(); eat("else"); Exp elseclause = ParseExp(); CondClass temp = new CondClass(test,ifclause,elseclause,tokensrem,st.countTokens()); return temp; } public Exp ParseWhile() throws Exception { int tokensrem = st.countTokens(); Exp test = ParseExp(); eat("do"); Exp body = ParseExp(); WhileClass temp = new WhileClass(test,body,tokensrem,st.countTokens()); return temp; } public Exp ParseLet() throws Exception { int tokensrem = st.countTokens(); Decl tempDecl = ParseDecl(); eat("in"); Exp tempExp = ParseExp(); BlockClass tempret = new BlockClass(tempDecl,tempExp,tokensrem,st.countTokens()); return tempret; } public Decl ParseRec() throws Exception { RecClass temp = new RecClass(ParseDecl()); return temp; } //is st being changed public Decl ParseDataType() throws Exception { DataType DataTyper = new DataType(); String nextToken = st.nextToken(); if (nextToken.charAt(0) == '\'') { //System.out.print("Starts with ' "); //will need to deal with equality types here TypeExp tempvt = new VarType();//System.out.print(nextToken); ArgList param = new ArgList(nextToken,tempvt,null); System.out.print(nextToken); DataTyper.parameters = param; nextToken = st.nextToken(); } else if (nextToken.equals("(")) {//System.out.print("Starts with ("); ArgList param1 = new ArgList(); do { nextToken = st.nextToken();//System.out.print(nextToken); TypeExp tempvt1 = new VarType(); param1.Extend(nextToken,tempvt1); nextToken = st.nextToken(); } while (nextToken.equals(",")); if (! nextToken.equals(")") ) throw new Exception("Expected ) "); nextToken = st.nextToken(); DataTyper.parameters = param1; } else DataTyper.parameters = new ArgList(); DataTyper.name = nextToken; eat("="); ArgList PatternList = new ArgList(); do{ String name = st.nextToken(); //need to make the copy here TwoStringTokenizer copytok = CopyST(st); st = copytok.first; StringTokenizer copytok2 = copytok.second; nextToken = copytok2.nextToken();//System.out.print("in type"); if (nextToken.equals("of")) {//can't actually assign types here at //modify the ParseType so it won't adversely affectst eat("of"); TypeExp temp = ParseType(DataTyper.parameters); PatternList.Extend(name,temp); if (st.hasMoreTokens()) { TwoStringTokenizer copytok3 = CopyST(st); st = copytok3.first; StringTokenizer copytok4 = copytok3.second; nextToken = copytok4.nextToken();} //else System.out.print("no tokens"); } else PatternList.Extend(name,null); if (nextToken.equals("|")) nextToken = st.nextToken(); } while ( nextToken.equals("|") ); DataTyper.Pattern = PatternList; //System.out.print("outside of the loop"); if (nextToken.equals("and")) { AndDecl tempand = new AndDecl(); eat("and"); Decl temp1 = DataTyper; tempand.Extend(temp1); Decl temp2 = ParseDataType(); if (temp2 instanceof DataType) tempand.Extend(temp2); else if (temp2 instanceof AndDecl) { AndDecl ad = ((AndDecl)(temp2)); Decl hd = ad.decl1; AndDecl tail = ad.tail; while (hd != null) { tempand.Extend(hd); if (tail == null) break; hd = tail.decl1; tail = tail.tail; } } else throw new Exception("In the parser part"); // tempqand.Extend(temp2); //find out next token while it's and add it to the list return tempand; } return ((Decl)(DataTyper)); } public Parameters ParseParameters(boolean uncurried) throws Exception{ //need to check what to do for unit maybe if nextToken = ) then assign unit Parameters retpar = new Parameters(); if (uncurried) { String copytk; do { Exp applid = ParseExp(); retpar.Extend(applid,uncurried); TwoStringTokenizer twost = CopyST(st); st = twost.first; StringTokenizer copy = twost.second; copytk = copy.nextToken(); if (copytk.equals(",")) eat(","); } while (copytk.equals(",")); } else { String copytk2; do {//System.out.print("in here2"); Exp applid2 = ParseExp(); retpar.Extend(applid2,uncurried); TwoStringTokenizer twost = CopyST(st); st = twost.first; StringTokenizer copy = twost.second; if (!(st.hasMoreTokens())) break; copytk2 = copy.nextToken();//System.out.print(copytk2); } while ( (! (copytk2.equals("="))) && (st.hasMoreTokens())); } return retpar; } public Decl ParseFn() throws Exception { int tokensrem = st.countTokens(); String funname = new String(""); MiniFnList newmfl = new MiniFnList(); String controlloop = ""; Parameters paramlist; do { String name = st.nextToken(); int start = st.countTokens(); if (funname.equals("")) {funname = name;} else if (!(funname.equals(name))) { StringBuffer error = new StringBuffer("The name expected is "); error.append(funname); error.append(" not "); error.append(name); Exception e = new Exception(error.toString()); throw e; } TwoStringTokenizer TST = CopyST(st); st = TST.first; StringTokenizer TST1 = TST.second; String nextToken = TST1.nextToken(); if (nextToken.equals("(")) { eat("("); paramlist = ParseParameters(true); eat(")"); paramlist.uncurried = true; } else {paramlist = ParseParameters(false); if (paramlist.length() > 1) paramlist.uncurried = true; paramlist.uncurried = true; } eat("="); Exp body = ParseExp();//System.out.print("body");//System.out.print(st.countTokens()); TwoStringTokenizer copyst2 = CopyST(st); st = copyst2.first; StringTokenizer secondcopy = copyst2.second; controlloop = secondcopy.nextToken(); int EndPosn = st.countTokens(); if (controlloop.equals("|")) eat("|"); MiniFn minifn = new MiniFn(paramlist,body); minifn.Posn = start; minifn.EndPosn = EndPosn; newmfl.Extend(minifn);//System.out.print("Adding here "); } while (controlloop.equals("|")); //if (controlloop.equals("and") will have to deal with and here newmfl.Posn = tokensrem; newmfl.EndPosn = st.countTokens(); DefClass defclass = new DefClass(funname,newmfl); RecClass recclass = new RecClass(defclass); return recclass; } public Exp ParseCase() throws Exception { //System.out.print("inside of parse case"); int tokensrem = st.countTokens(); Exp exp = ParseExp(); eat("of"); MiniFnList newmfl = new MiniFnList(); String controlloop = ""; Parameters paramlist; do { int start = st.countTokens(); TwoStringTokenizer TST = CopyST(st); st = TST.first; StringTokenizer TST1 = TST.second; String nextToken = TST1.nextToken(); if (nextToken.equals("(")) { eat("("); paramlist = ParseParameters(true); eat(")"); paramlist.uncurried = true; } else {paramlist = ParseParameters(false); if (paramlist.length() > 1) paramlist.uncurried = true; paramlist.uncurried = true; } eat("="); eat(">"); Exp body = ParseExp();//System.out.print("body");//System.out.print(st.countTokens()); TwoStringTokenizer copyst2 = CopyST(st); st = copyst2.first; StringTokenizer secondcopy = copyst2.second; if (secondcopy.hasMoreTokens()) controlloop = secondcopy.nextToken(); else controlloop = " "; int EndPosn = st.countTokens(); if (controlloop.equals("|")) eat("|"); MiniFn minifn = new MiniFn(paramlist,body); minifn.Posn = start; minifn.EndPosn = EndPosn; newmfl.Extend(minifn);//System.out.print("Adding here "); } while (controlloop.equals("|")); //if (controlloop.equals("and") will have to deal with and here newmfl.Posn = tokensrem; newmfl.EndPosn = st.countTokens(); Parameters p = new Parameters(exp,null,false); Appl2Class caseclass = new Appl2Class(newmfl,p,tokensrem,st.countTokens()); return caseclass; } public Exp ParseFun() throws Exception { //System.out.print("inside of parse case"); int tokensrem = st.countTokens(); MiniFnList newmfl = new MiniFnList(); String controlloop = ""; Parameters paramlist; do { int start = st.countTokens(); TwoStringTokenizer TST = CopyST(st); st = TST.first; StringTokenizer TST1 = TST.second; String nextToken = TST1.nextToken(); if (nextToken.equals("(")) { eat("("); paramlist = ParseParameters(true); eat(")"); paramlist.uncurried = true; } else {paramlist = ParseParameters(false); if (paramlist.length() > 1) paramlist.uncurried = true; paramlist.uncurried = true; } eat("="); eat(">"); Exp body = ParseExp();//System.out.print("body");//System.out.print(st.countTokens()); TwoStringTokenizer copyst2 = CopyST(st); st = copyst2.first; StringTokenizer secondcopy = copyst2.second; if (secondcopy.hasMoreTokens()) controlloop = secondcopy.nextToken(); else controlloop = " "; int EndPosn = st.countTokens(); if (controlloop.equals("|")) eat("|"); MiniFn minifn = new MiniFn(paramlist,body); minifn.Posn = start; minifn.EndPosn = EndPosn; newmfl.Extend(minifn);//System.out.print("Adding here "); } while (controlloop.equals("|")); //if (controlloop.equals("and") will have to deal with and here newmfl.Posn = tokensrem; newmfl.EndPosn = st.countTokens(); return newmfl; } public Decl ParseException() throws Exception{//may have to take accout of compund names in modules //at the minute not allowing and for decl String name = st.nextToken(); TwoStringTokenizer twost = CopyST(st); st = twost.first; StringTokenizer stcopy3 = twost.second; String token; if (stcopy3.hasMoreTokens()) token = stcopy3.nextToken(); else token = " "; TypeExp arg = null; if (token.equals("of") ) { eat("of"); //can you read in polymorhic paramters for the exns arg = ParseType(new ArgList());//can't have polymorphic exceptions } return new Except(name,arg); } public Decl ParseDecl() throws Exception { //This function parses a declaration statement. String temp = st.nextToken(); Decl retDecl; if (temp.equals("fun")) { retDecl = ParseFn();//need to adjust to take account of the reeec part //System.out.print("outside of parse fun"); } else if (temp.equals("rec")) {//System.out.print("Parse rec "); retDecl = ParseRec(); } else if (temp.equals("datatype")) { retDecl = ParseDataType(); } else if (temp.equals("(")) {//System.out.print("Parse brack d "); retDecl = ParseDecl(); eat(")"); } else if (temp.equals("exception") ) { retDecl = ParseException(); } else { TwoStringTokenizer twost = CopyST(st); st = twost.first; StringTokenizer stcopy3 = twost.second; String token = stcopy3.nextToken(); if (token.equals("=")) {//System.out.print("Parse def "); eat("="); Exp retExpr = ParseExp(); DefClass retDExp = new DefClass(temp,retExpr); retDecl = retDExp; } else retDecl = null; } TwoStringTokenizer twost1 = CopyST(st); st = twost1.first; StringTokenizer stcopy4 = twost1.second; String next = stcopy4.nextToken(); if (next.equals("then")) { //System.out.print("Parse def appl "); eat("then"); Decl retDecl1 = ParseDecl(); Decl retDecls = new SeqClass(retDecl,retDecl1); return retDecls; } else if (next.equals("and")) { eat("and"); Decl finalret; Decl retDecl1 = ParseDecl(); if (retDecl1 instanceof AndDecl) { finalret = new AndDecl(retDecl,(AndDecl)(retDecl1)); } else { AndDecl tempdecl = new AndDecl(); tempdecl.Extend(retDecl1); finalret = new AndDecl(retDecl,tempdecl); } return finalret; } return retDecl; } public StringTokenizer eattype(StringTokenizer token,String tokenexpected) throws Exception { if ((token.nextToken()).equals(tokenexpected)) { // System.out.print(tokenexpected); return token; } else { StringBuffer temp = new StringBuffer(tokenexpected); temp.append(" is expected "); throw new Exception(temp.toString()); } } public String AdjustType(String typeexp) throws Exception { //This function puts spaces before any control characters to //make sure that they are separated by the string tokenizer. StringBuffer Adjust = new StringBuffer(typeexp); int i = 0; while (i < Adjust.length()) { if ((Adjust.charAt(i) == '(') || (Adjust.charAt(i) == ')') || (Adjust.charAt(i) == '*') ){ Adjust.insert(i," "); Adjust.insert(i +2 ," "); i = i + 3;//check all these aren't one less } else if ((Adjust.charAt(i) == '-')) { Adjust.insert(i," "); i = i + 2; } else if (Adjust.charAt(i) == '>') { Adjust.insert(i+1," "); i = i + 2; } else i = i +1 ; } return Adjust.toString(); } public TS ParseType(StringTokenizer tok,Env UserEnv,Env CompEnv,ArgList Parameters,Table t)throws Exception{ //This function parses a type expression - the types are automatically assigned here and //can't be changed later. //This was probably a bad decision as the types should not be dealt with here !!! String FirstToken = tok.nextToken(); if (FirstToken.equals("(")) { TypeExp overallret = null; TypeExp returnType; TypeList temptl = new TypeList(); String nexttoken = ""; do { TS ts = ParseType(tok,UserEnv,CompEnv,Parameters,t);returnType = ts.te; tok = ts.st; if (temptl == null) { overallret = returnType; temptl.Extend(returnType); } else { temptl.Extend(returnType); overallret = returnType; } TwoStringTokenizer copytok = CopyST(tok); tok = copytok.first; StringTokenizer toktemp1 = copytok.second; if (toktemp1.hasMoreTokens()) { nexttoken = toktemp1.nextToken(); if (nexttoken.equals(",")) tok = eattype(tok,","); } else {nexttoken = "";} TwoStringTokenizer cp = CopyST(tok);tok = cp.first; } while (nexttoken.equals(",")); returnType = overallret; // String temptok = tok.nextToken();if (!temptok.equals(")")) throw new Exception("PArse"); tok = eattype(tok,")"); TwoStringTokenizer copytok1 = CopyST(tok); tok = copytok1.first; StringTokenizer toktemp11 = copytok1.second; if (toktemp11.hasMoreTokens()) { String next = toktemp11.nextToken(); if (next.equals("in") || next.equals("and") || next.equals("then") || next.equals("|")) return new TS(returnType,tok); if (next.equals("->")) { tok = eattype(tok,"->"); TS ts1 = ParseType(tok,UserEnv,CompEnv,Parameters,t);TypeExp return2 = ts1.te; tok = ts1.st; return new TS(new OperType("->",TypeList.Extend(returnType,TypeList.Extend(return2,null))),tok); } else if (next.equals("*")) { tok = eattype(tok,"*"); TS ts2 = ParseType(tok,UserEnv,CompEnv,Parameters,t);TypeExp returntype2 = ts2.te; tok = ts2.st; return new TS(new OperType("*",TypeList.Extend(returnType,TypeList.Extend(returntype2,null))),tok); } else {//will have to put in a while loop to take care of 'a list list list etc if ((! (next.equals("then") || next.equals("and") || next.equals(")") || next.equals("|") || next.equals("in")))) { tok.nextToken();//eattype(tok,"list"); //if (currentTE == null) currentTE return new TS( new OperType(next,temptl),tok); } } } return new TS(returnType,tok); } else { TypeExp returntype3; StringBuffer first = new StringBuffer(FirstToken); TypeExp overallret = null; String next = " "; // do { if (first.charAt(0) == '\'') { if (true) { if (CompEnv.Present(FirstToken)) { returntype3 = CompEnv.RetrieveOriginal(FirstToken); } else if (UserEnv.Present(FirstToken)) { returntype3 = UserEnv.RetrieveOriginal(FirstToken); } // else if ( else { TypeExp temp; if ((FirstToken.charAt(0) == '\'') && (FirstToken.charAt(1) == '\'')) temp = new VarType(true); else temp = new VarType(); UserEnv.Extend(FirstToken,temp); //MAY HAVE TO REMOVE THIS t.Extend(temp,null); returntype3 = temp; } } else { TypeExp tempte = Parameters.Retrieve(FirstToken); if (tempte == null) { returntype3 = tempte; } else returntype3 = new VarType(); } } else { returntype3 = new OperType(FirstToken,null); } TwoStringTokenizer copytok2 = CopyST(tok); tok = copytok2.first; StringTokenizer toktemp2 = copytok2.second; if (toktemp2.hasMoreTokens()){ next = toktemp2.nextToken(); } else next = ""; if (! (next.equals(""))){ // next = toktemp2.nextToken(); if (next.equals("in") || next.equals("and") || next.equals("then") || next.equals("|") || next.equals(")") || next.equals(",")) {return new TS(returntype3,tok);} if (next.equals("->")) { tok = eattype(tok,"->"); TS ts3 = ParseType(tok,UserEnv,CompEnv,Parameters,t);TypeExp return22 = ts3.te; tok = ts3.st; return new TS(new OperType("->",TypeList.Extend(returntype3,TypeList.Extend(return22,null))),tok); } else if (next.equals("*")) { tok = eattype(tok,"*"); TS ts4 = ParseType(tok,UserEnv,CompEnv,Parameters,t);TypeExp returntype23 = ts4.te; tok = ts4.st; return new TS(new OperType("*",TypeList.Extend(returntype3,TypeList.Extend(returntype23,null))),tok); } else { if ((! (next.equals("then") || next.equals("and") || next.equals(")") || next.equals("|") || next.equals("in")))) { tok.nextToken();//eattype(tok,"list"); //if (currentTE == null) currentTE return new TS(new OperType(next,TypeList.Extend(returntype3,null)),tok); } } } return new TS(returntype3,tok); } //return null; } ; public TypeExp ParseType(ArgList Parameters)throws Exception{ //This function parses at type - The ArgList in the paramters is used //to maintain consistency between vartypes that are declared. String FirstToken = st.nextToken(); if (FirstToken.equals("(")) { TypeExp overallret = null; TypeExp returnType; TypeList temptl = new TypeList(); String nexttoken = ""; do { returnType = ParseType(Parameters); if (temptl == null) { overallret = returnType; temptl.Extend(returnType); } else { temptl.Extend(returnType); overallret = returnType; } TwoStringTokenizer copytok = CopyST(st); st = copytok.first; StringTokenizer toktemp1 = copytok.second; if (toktemp1.hasMoreTokens()) { nexttoken = toktemp1.nextToken(); if (nexttoken.equals(",")) eat(","); } else {nexttoken = "";} } while (nexttoken.equals(",")); returnType = overallret; eat(")"); TwoStringTokenizer copytok1 = CopyST(st); st = copytok1.first; StringTokenizer toktemp11 = copytok1.second; if (toktemp11.hasMoreTokens()) { String next = toktemp11.nextToken(); if (next.equals("in") || next.equals("and") || next.equals("then") || next.equals("|")) return (returnType); if (next.equals("->")) { eat("->"); TypeExp return2 = ParseType(Parameters); return (new OperType("->",TypeList.Extend(returnType,TypeList.Extend(return2,null)))); } else if (next.equals("*")) { eat("*"); TypeExp returntype2 = ParseType(Parameters); return (new OperType("*",TypeList.Extend(returnType,TypeList.Extend(returntype2,null)))); } else {//will have to put in a while loop to take care of 'a list list list etc if ((! (next.equals("then") || next.equals("and") || next.equals(")") || next.equals("|") || next.equals("in")))) { st.nextToken();//eattype(tok,"list"); //if (currentTE == null) currentTE return ( new OperType(next,temptl)); } } } return (returnType); } else { TypeExp returntype3; StringBuffer first = new StringBuffer(FirstToken); TypeExp overallret = null; String next = " "; if (first.charAt(0) == '\'') { TypeExp tempte = Parameters.Retrieve(FirstToken); if (tempte != null) { returntype3 = tempte; } else {returntype3 = new VarType(); } } else { returntype3 = new OperType(FirstToken,null); } TwoStringTokenizer copytok2 = CopyST(st); st = copytok2.first; StringTokenizer toktemp2 = copytok2.second; if (toktemp2.hasMoreTokens()){ next = toktemp2.nextToken(); } else next = ""; if (! (next.equals(""))){ if (next.equals("in") || next.equals("and") || next.equals("then") || next.equals("|") || next.equals(")") || next.equals(",")) {return (returntype3);} if (next.equals("->")) { eat("->"); TypeExp return22 = ParseType(Parameters); return (new OperType("->",TypeList.Extend(returntype3,TypeList.Extend(return22,null)))); } else if (next.equals("*")) { eat("*"); TypeExp returntype23= ParseType(Parameters); return (new OperType("*",TypeList.Extend(returntype3,TypeList.Extend(returntype23,null)))); } else { if ((! (next.equals("then") || next.equals("and") || next.equals(")") || next.equals("|") || next.equals("in")))) { st.nextToken(); return (new OperType(next,TypeList.Extend(returntype3,null))); } } } return (returntype3); } //return null; } ; } class ListFocus { //This class was used to try and implement a focus facility. //It contains a list of positions for expressions, indicating //the position of each successive focus. int StartPosn, EndPosn; ListFocus next; public ListFocus(int StartPosn,int EndPosn) { this.StartPosn = StartPosn;this.EndPosn = EndPosn; this.next = null; } public void Extend(int Posn1,int Posn2){ if (next == null) { next = new ListFocus(Posn1,Posn2); } else next.Extend(Posn1,Posn2); } } class OutputTable { //To output variable types it is necessary to assign an identifier to them - this table is used to //make sure the identifiers assigned are used consistently. Env userenv; Env compenv = new Env(); public OutputTable() { userenv = new Env(); compenv = new Env(); } public char Convert(int i) { //convert a digit to a letter for output - probably a much simpler way of doing it ! char ch; switch(i) { case 0: ch = 'a';break;case 1: ch = 'b';break;case 2: ch = 'c';break;case 3: ch ='d';break;case 4: ch = 'e';break; case 5: ch = 'f';break;case 6: ch = 'g';break;case 7: ch = 'h';break;case 8: ch ='i';break;case 9: ch = 'j';break; case 10: ch = 'k';break;case 11: ch = 'l';break;case 12: ch = 'm';break;case 13: ch ='n';break;case 14: ch = 'o';break; case 15: ch = 'p';break;case 16: ch = 'q';break;case 17: ch = 'r';break;case 18: ch ='s';break;case 19: ch = 't';break; case 20: ch = 'u';break;case 21: ch = 'v';break;case 22: ch = 'w';break;case 23: ch ='x';break;case 24: ch = 'y';break; case 25: ch = 'z';break;default : ch = 'Z';break; } return ch; } public String FindString(){ //Returns the next free identifier int i = compenv.Number();//System.out.print(i); StringBuffer s = new StringBuffer("'"); int j = i / 26; int k = i % 26; if (j <= 25 && ( j > 0)) {s.append(Convert(j));s.append(Convert(k));} else s.append(Convert(i)); return s.toString(); } public String GetValueNO(TypeExp tex) { //This finds the identifier for this type expression - if it's in the table it returns the value in //the table, otherwise it assigns a new identifier to the name and this is stored in the table //and returned. if (tex instanceof VarType){ String i; if (compenv == null) return "errrrr"; else{ String s = compenv.PresentType(tex); if (s.equals("")) { i = FindString(); if (((VarType)(tex)).IsEqType) { StringBuffer sb = new StringBuffer("'"); sb.append(i); i = sb.toString(); } compenv.Extend(i,tex); } else i = s; } VarType vt = ((VarType)(tex)); return i; } else return "error"; } } class Temp extends Frame {//implements ActionListener { ExExcept trialex; TextArea textarea1,textarea2,textarea3,textarea4; TextField tf , tf2; Class c; boolean focuson; Button partial,okay,change,partial1,partial2,focus,focusclear,remove; OutputTable OT = new OutputTable(); Parser P = new Parser(); ListFocus LF = new ListFocus(0,0); TypecheckMod TC = new TypecheckMod(); Exp temp = null; pair[] pairarray; int numberoftokens; Panel newpanel = new Panel(); Panel npanel = new Panel(); Panel newPanel1 = new Panel(); Panel newPanel2 = new Panel(); Panel newPanel3 = new Panel(); Panel newPanel4 = new Panel(); Panel newPanel5 = new Panel(); Panel newPanel6 = new Panel(); Panel newPanel7 = new Panel(); Panel newPanel8 = new Panel(); Panel buttonPanel = new Panel(); String S = null; Table t= null; //will need to check if it's being parsed correctly public Temp(String title) { //Initialise the Screen super(title); Font f = new Font("TimesRoman",1,12); this.setFont(f); this.setBackground(Color.white); this.setLayout(new BorderLayout(10,10)); int startx,starty; startx = 25; starty = 40; Panel pp = new Panel(); pp.setLayout(null); //due to problems trying to poistion the textareas the textareas //were manually redrawn as follows : textarea1 = new TextArea(6,50);textarea1.setEditable(true); textarea1.reshape(startx,starty,350,200); textarea2 = new TextArea(4,50);textarea2.setEditable(true); textarea2.reshape(startx + 400 , starty , 250, 150); textarea3 = new TextArea(4,50);textarea3.setEditable(true); textarea3.reshape(startx ,starty + 250,250,150); textarea4 = new TextArea(4,50);textarea4.setEditable(false); Button focus = new Button("Focus"); Button focusclear = new Button("Focus C"); focus.reshape(startx + 275 + 70,starty + 250,60,30); focusclear.reshape(startx + 275 + 70,starty + 250 + 55 ,60,30); add(focus); add(focusclear); Button okay = new Button("Okay"); Button quit = new Button("Quit"); quit.reshape(startx +275 + 60 + 10 + 205 , starty + 250 + 55 * 2,60,30); okay.reshape(startx + 400,starty + 175,60,30); add(quit); Button partial = new Button("Partial"); partial.reshape(startx + 400 + 60 + 25,starty + 175,60,30); add(okay); Button remove = new Button("Remove"); remove.reshape(startx + 275,starty + 250 + 55,60,30); add(remove); Button partial1 = new Button("Partial C"); Button truetype = new Button("True Type"); truetype.reshape(startx + 400 + 60 + 25 + 60 + 25,starty + 175,60,30); add(truetype); partial1.reshape(startx + 275,starty + 250,60,30); Button change = new Button("Change"); change.reshape(startx + 275, starty + 250 + 55 + 55,60,30); add(change); tf = new TextField(60); tf.reshape(startx + 275 + 60 + 10,starty + 250 + 55 + 55,200,30); add(tf); add(partial1); add(partial); add(textarea1);add(textarea2);add(textarea3); } public boolean action(Event evt, Object arg) { //depending on the button pressed a different action is taken try { if ("Quit".equals(arg)) System.exit(0); else if ("Focus C".equals(arg)) {focuson = false; firstError fe = new firstError(); TypeExp te = (TC.AnalExpChange(temp,new Env(),-1,-1,new TypeExp(),new TypeList(),false,fe,new Env(),false)).typeexp; } else if ("Partial".equals(arg) || "Partial C".equals(arg) || "True Type".equals(arg) || "Focus".equals(arg) || "Remove".equals(arg) ){ //Because all of these buttons use the same function //except with the CHANGE paramter set to a different //value they're all dealt with in here. int CHANGE; //Set the change paramter if (arg.equals("Partial")) CHANGE = 0; else if (arg.equals("Partial C")) CHANGE = 1; else if (arg.equals("True Type"))CHANGE = 2; else if (arg.equals("Remove")) CHANGE = 4; else CHANGE = 3; boolean sioobex = false; //Find the relevant token numbers for the text selected int I = textarea1.getSelectionStart(); int posnend,end; end = textarea1.getSelectionEnd(); if ( (I > S.length()) ) {I = S.length();} if ((end > S.length())) {end = S.length();} int posn = 0; TypeExp temp3; if ( I == S.length()) posn = 0; else {posn = P.ReturnTokensRemaining(S,I,true); } if (I == end) {posnend = posn;} else {if (end == S.length()) posnend = 0; else posnend = P.ReturnTokensRemaining(S,end,false); } try { TC.AnalyzeExpParsed(temp,posn,posnend,5,false); } catch (posnException p) { posn = p.first; posnend = p.second; } //These are used to identify the first enclosing expression for //the text the user selected. pair p = GetText(posn,posnend);int p1 = p.first;int p2 = p.second; textarea2.select(p1,p2); String tooutput = S.substring(p1,p2); if (CHANGE == 3) { if (focuson) LF.Extend(posn,posnend); else {LF = new ListFocus(posn,posnend);focuson = true;} } try { //may need to adjust the table if (CHANGE != 3) { TC.AnalyzeExpParsed(temp,posn,posnend,CHANGE,false); if (CHANGE == 4) { //Want to remove an asssumed type firstError fe = new firstError(); (TC.t).clearcurrent(); TypeExp temp4 = (TC.AnalExpChange(temp,new Env(),-1,-1,new TypeExp(),new TypeList(),false,fe,new Env(),false)).typeexp; t = TC.t; if (fe.errorfound) throw new UnifException(fe.info,fe.te1,fe.te2); throw new ExExcept("The type is ",temp4); } } if (CHANGE != 3) TC.AnalyzeExpParsed(temp,posn,posnend,CHANGE,false); else { //The case of the Focus //A list is maintained for each of the Focus steps. if (LF.next == null) { //If the list is empty then it's straightforward TC.AnalyzeExpParsed(temp,posn,posnend,CHANGE,false); } else { //Otherwise you haveto perform the analysis for each of the //focus steps that have already been carried out, to ensure the //conditions are met. ListFocus next = LF; do { try { TC.AnalyzeExpParsed(temp,next.StartPosn,next.EndPosn,CHANGE,false); } catch (Exception e){ } next = next.next; } while ((next != null) && (next.next != null)); TC.AnalyzeExpParsed(temp,next.StartPosn,next.EndPosn,CHANGE,false); } } } //The exceptions are used to ouptut the results. catch (UnifException u) { StringBuffer s = new StringBuffer(tooutput + "\n" + "\n"); s.append(u.message); if (u.first != null) { s.append("\nCan't Unify : "); s.append(OutPutType(u.first,0)); } if (u.second != null) { s.append("\nwith : "); s.append(OutPutType(u.second,0)); } if (CHANGE == 0 || CHANGE == 2) textarea2.setText(s.toString()); else if (CHANGE == 1) textarea3.setText(s.toString()); else textarea3.setText(s.toString()); } catch (ExExcept ex) { temp3 = ex.te; StringBuffer s = new StringBuffer(tooutput + "\n" + "\n"); s.append(ex.error); s.append("\n"); s.append((OutPutType(temp3,0)).toString()); if (CHANGE == 0 || CHANGE == 2) textarea2.setText(s.toString()); else if (CHANGE == 1) textarea3.setText(s.toString()); else textarea3.setText(s.toString()); } catch (ClassCastException e1) { System.out.print("Class Cast"); } catch (Exception exc) { textarea3.setText(exc.getMessage()); System.out.print("catching exception"); } } else if ("Change".equals(arg)) { boolean caughtexcep = false; String T = tf.getText(); if (T != null) { String adjustT = P.AdjustType(T); // textarea1.setText(adjustT); StringTokenizer strtok = new StringTokenizer(adjustT); Env tempenv = new Env(); TypeExp tempte = (P.ParseType(strtok,OT.userenv,OT.compenv,new ArgList(),TC.t)).te; //As above, the first enclosing expression needs to be found. int I2 = textarea1.getSelectionStart(); int end2 = textarea1.getSelectionEnd(); (TC.t).clearcurrent(); if ( (I2 > S.length()) ) { I2 = S.length(); } if ((end2 > S.length())) { end2 = S.length(); } int posn2 = 0; int posnend2 = 0; if (I2 == S.length()) posn2 = 0; else { posn2 = P.ReturnTokensRemaining(S,I2,true); } if (I2== end2) { posnend2 = posn2; } else { if (end2 == S.length()) posnend2 = 0; else posnend2 = P.ReturnTokensRemaining(S,end2,false); } try { TC.AnalyzeExpParsed(temp,posn2,posnend2,5,false); } catch (posnException p) { posn2 = p.first; posnend2 = p.second; } pair p = GetText(posn2,posnend2);int p1 = p.first;int p2 = p.second; textarea2.select(p1,p2); String tooutput = S.substring(p1,p2); TypeExp temp4 = null; boolean uniferror = false; try { TypeList tl = new TypeList(); Env env = new Env(); firstError fe = new firstError(); if (focuson) {//focusson try { temp4 = (TC.AnalExpChange(temp,env,posn2,posnend2,tempte,tl,false,fe,new Env(),false)).typeexp; } catch (Exception e){} //The focus facility is being used. if (LF.next == null) { TC.AnalyzeExpParsed(temp,posn2,posnend2,3,false); } else { ListFocus next = LF; do { try { TC.AnalyzeExpParsed(temp,next.StartPosn,next.EndPosn,3,false); } catch (Exception e){ } next = next.next; } while ((next != null) && (next.next != null)); TC.AnalyzeExpParsed(temp,next.StartPosn,next.EndPosn,3,false); } } else { temp4 = (TC.AnalExpChange(temp,env,posn2,posnend2,tempte,tl,false,fe,new Env(),false)).typeexp; } t = TC.t; //The output section if (fe.errorfound) { //need to get the position here and outout it StringBuffer s = new StringBuffer("Changed the type of " + tooutput + "\n" + "to have type " + T + "\n"); //need to find the positions here pair ppp = GetText(fe.StartPosn,fe.EndPosn);int ppp1 = ppp.first;int ppp2 = ppp.second; String tooutputerr = S.substring(ppp1,ppp2); s.append("\n" + tooutputerr + "\n"); s.append(fe.info); if (fe.te1 != null) { s.append("\nCan't Unify : "); s.append(OutPutType(fe.te1,0)); } if (fe.te2 != null) { s.append("\nwith : "); s.append(OutPutType(fe.te2,0)); } textarea3.setText(s.toString()); } else textarea3.setText("Changed the type of : " + tooutput + "\nto " + T + "\n\n" + ((OutPutType(temp4,0)).toString())); } catch (UnifException u) { StringBuffer s = new StringBuffer("Changed the type of : " + tooutput + "\nto " + "\n" + "\n"); s.append(u.message); s.append("\nCan't match : "); s.append(OutPutType(u.first,0)); s.append("\nwith : "); s.append(OutPutType(u.second,0)); textarea3.setText(s.toString()); } catch (ExExcept ex) { StringBuffer s = new StringBuffer(tooutput + "\n"); s.append((OutPutType(ex.te,0)).toString()); textarea3.setText(s.toString()); //temp4 = ex.te; } } } else if ("Okay".equals(arg)) { //In the case of equals, the inital parsing and typechecking needs to be carried out. S = textarea1.getText(); textarea2.setText(""); textarea3.setText(""); //textarea4.setText(""); OT = new OutputTable(); EqType eq = new EqType(); TypeExp te = eq; StringTokenizer st1 = new StringTokenizer(P.adjust(S)); numberoftokens = st1.countTokens();//System.out.println("THe number of tokens is " + st1.countTokens()); temp = P.Parse(S,0); pairarray = P.TokenTable(S,numberoftokens); TwoTypes temp22; Env t1 = new Env(); Env err = new Env(); TypeList t2 = new TypeList(); boolean uniferror = false; firstError fe = new firstError(); temp22 = TC.AnalyzeExp(temp,TC.env,null,t1,t2,err,fe); t = TC.t; boolean caughtexc = false; //Output the result if (fe.errorfound == false) { if (temp22 != null ) { textarea2.setText("The type of the above expression is " + "\n" + (OutPutType(temp22.returnExp,0)).toString()); } else textarea2.setText("No type"); } else { pair p = GetText(fe.StartPosn,fe.EndPosn);int p1 = p.first;int p2 = p.second; textarea2.select(p1,p2); String tooutput = S.substring(p1,p2); StringBuffer s = new StringBuffer(tooutput + "\n" + fe.info); s.append("\nCan't Unify : "); s.append(OutPutType(fe.te1,0)); s.append("\nwith : "); s.append(OutPutType(fe.te2,0)); textarea2.setText(s.toString()); } } } catch (UnifException u) { StringBuffer s = new StringBuffer(u.message); s.append("\nCan't Unify : "); s.append(OutPutType(u.first,0)); s.append("\nwith : "); s.append(OutPutType(u.second,0)); textarea2.setText(s.toString()); } catch ( Exception exec ) { textarea2.setText(exec.getMessage()); } return true; } public pair GetText(int posn2,int posnend2) { //Given two token numbers find the relevant poistion in the text //This uses the token table int first,last; int i = numberoftokens - posn2 - 1; int j = numberoftokens - posnend2 -1 ; if (i <= pairarray.length - 1 && (pairarray[i] != null) ) { first = pairarray[i].first; } else first = S.length() ; if (j <= pairarray.length -1 && (pairarray[j] != null) ) { last = pairarray[j].second; } else last = S.length(); return new pair(first,last); } public StringBuffer OutPutType(TypeExp typeexp,int level){ //This function formats the type expression into a stringbuffer //for output StringBuffer returnsb = new StringBuffer(" "); if (typeexp instanceof overload) { //if the overloaded operator is not instantiated the put a //keyword in it's place "over //Otherwise oputput it's instance if (((overload)(typeexp)).instance == null) returnsb = returnsb.append("over"); else returnsb = returnsb.append(OutPutType(((overload)(typeexp)).instance,level)); } else if (typeexp instanceof exn) { returnsb.append(" exn"); } else if (typeexp instanceof VarType) { if (((VarType)(typeexp)) != null) { if (((VarType)(typeexp)).instance != null) { //if the vartype is instanatiated then apply OutPutType //to it's instance returnsb = returnsb.append(OutPutType(((VarType)(typeexp)).instance,level)); } else { //If this vartype has been used before then retrieve the //string that's already been applied to it. if (t.PresentC(typeexp)) { TypeExp tt = t.RetrieveifC(typeexp); String TT = OT.GetValueNO(tt); String T = OT.GetValueNO((typeexp)); returnsb = returnsb.append(TT); } else { //Otherwise get a value for this vartype and append it to //the stringbuffer String T = OT.GetValueNO((typeexp)); returnsb = returnsb.append(T); } } } else { //If VarType typeexp is null then get the string value - //if the typeexp has already been encountered - retrieve the //value used. Otherwise assign a new value to the typeexp. if (t.PresentC(typeexp)) { TypeExp tt1 = t.RetrieveifC(typeexp); String TT1 = OT.GetValueNO(tt1); String S = OT.GetValueNO((typeexp)); returnsb = returnsb.append(TT1); } else { String S = OT.GetValueNO((typeexp)); returnsb = returnsb.append(S); } } } else if (typeexp instanceof OperType) { if (((OperType)(typeexp)) != null) { String ide = new String(); if (((OperType)(typeexp)) == null) ide = ""; else if (((OperType)(typeexp)).ide == null) ide = ""; else ide = ((OperType)(typeexp)).ide; if (ide .equals("->") || ide.equals("*") ) { if (level > 0 ) returnsb.append("("); //only considering -> and * as operators with two arguments if (((OperType)(typeexp)).args.head != null) returnsb = returnsb.append(OutPutType(((OperType)(typeexp)).args.head,level + 1)); returnsb = returnsb.append(ide); if (((OperType)(typeexp)).args.tail != null) { returnsb = returnsb.append(OutPutType(((OperType)(typeexp)).args.tail.head,level + 1)); } if (level > 0) returnsb.append(")"); } else { if (((OperType)(typeexp)).args != null) { TypeExp head = (((OperType)(typeexp)).args.head); TypeList tail = (((OperType)(typeexp)).args.tail); if (head != null) { if ((tail != null) && (tail.head != null) ){ returnsb = returnsb.append("("); } if ((head instanceof VarType) && (((VarType)(head)).instance == null)){ if (t.PresentC(head)) { TypeExp tt1 = t.RetrieveifC(head); String TT1 = OT.GetValueNO(tt1); returnsb = returnsb.append(TT1); } else { String S = OT.GetValueNO((head)); returnsb = returnsb.append(S); } returnsb = returnsb.append(" "); } else { returnsb = returnsb.append(OutPutType(head,level)); } boolean tailex = false; if ((tail != null) && (tail.head != null)) tailex = true; else { returnsb = returnsb.append(" "); returnsb = returnsb.append(ide); returnsb = returnsb.append(" "); } while (tail != null) { head = tail.head; tail = tail.tail; if (tail != null) returnsb.append(" , "); if ((head instanceof VarType) && (((VarType)(head)).instance == null)){ if (t.PresentC(head)) { TypeExp tt1 = t.RetrieveifC(head); String TT1 = OT.GetValueNO(tt1); returnsb = returnsb.append(TT1); } else { String S = OT.GetValueNO((head)); returnsb = returnsb.append(S); } returnsb = returnsb.append(" "); } else { returnsb = returnsb.append(OutPutType(head,level)); } } if (tailex) { returnsb = returnsb.append(" ) "); returnsb = returnsb.append(ide); } } } else returnsb = returnsb.append(ide); } } } return returnsb; } public static void main(String[] args){ Frame f = new Temp("MSc Project"); f.pack(); f.show(); } }