UNPKG

minigrace

Version:

A compiler for the Grace programming language

1,193 lines (1,192 loc) 488 kB
let gracecode_staticTypes_sourceFile = "/Users/black/Development/mg/gracelang/minigrace/modules/staticTypes.grace"; let gracecode_staticTypes_sha256 = "019a2def27cfaaada2c27d06108ce01f7230ddd53c92099f2e0fabb796a1b233"; let gracecode_staticTypes_minigraceRevision = "b57591d29fc5ee5270d114920bf671367b8c3ecb"; let gracecode_staticTypes_minigraceGeneration = "5171"; if (typeof gctCache !== "undefined") gctCache["staticTypes"] = "dialect:\n dialect\nfreshScopes:\n $102\nmethodTypes:$101:\n for(a:Unknown)doWithBreak(bl:Unknown) \u2192 Done\n for(a:Unknown)doWithContinue(bl:Unknown) \u2192 Done\n mixPartNamed(name':String)parameters(parameters':List\u27e6Param\u27e7) \u2192 MixPart\nmethodTypes:$102:\n name \u2192 String\n parameters \u2192 List\u27e6Param\u27e7\nmodules:\n ast\n dialect\n intrinsic\n util\npath:\n /Users/black/Development/mg/gracelang/minigrace/modules/staticTypes.grace\nscope:$101:\n MethodType type\n MixPart type\n ObjectType type\n Param type\n addVar(1)ofType(1) Unknown (mth) $scope_done confidential\n asDebugString String (go) $scope_string\n asString String (go) $scope_string\n basicAsString String (go) $scope_string\n check(1)against(1) ObjectType (mth) $scope_done confidential\n check(1)matches(1)inMethod(1) Done (mth) $scope_done confidential\n collectTypes(1) Done (mth) $scope_done confidential\n continue'(2) Done (mth) $scope_done confidential\n find(1)atScope(1) ObjectType (mth) $scope_done confidential\n for(1)doWithBreak(1) Done (mth) $scope_done\n for(1)doWithContinue(1) Done (mth) $scope_done\n isMe(1) Boolean (go) $scope_boolean\n isMember(1) Boolean (mth) $scope_done confidential\n mixPartNamed(1)parameters(1) MixPart (mth) $102\n myIdentityHash Number (go) $scope_number\n outerAt(1) ObjectType (mth) $scope_done confidential\n processBody(1) ObjectType (mth) $scope_done confidential\n thisDialect Unknown (def) $103 public\nscope:$102:\n asDebugString String (go) $scope_string\n asString String (go) $scope_string\n basicAsString String (go) $scope_string\n isMe(1) Boolean (go) $scope_boolean\n myIdentityHash Number (go) $scope_number\n name String (def) $scopeEmpty public\n parameters List (def) $scopeEmpty public\nscope:$103:\n asDebugString String (go) $scope_string\n asString String (go) $scope_string\n astChecker(1) Unknown (mth) $scope_done\n atEnd Unknown (mth) $scope_done\n atStart Unknown (mth) $scope_done\n basicAsString String (go) $scope_string\n isMe(1) Boolean (go) $scope_boolean\n myIdentityHash Number (go) $scope_number\nself:\n $101\ntypedec:$101.MethodType:\n type MethodType = interface {\n name \u2192 String\n signatureParts \u2192 List\u27e6MixPart\u27e7\n returnType \u2192 ObjectType\n isSpecialisationOf(other:MethodType) \u2192 Boolean}\ntypedec:$101.MixPart:\n type MixPart = interface {\n name \u2192 String\n parameters \u2192 List\u27e6Param\u27e7}\ntypedec:$101.ObjectType:\n type ObjectType = interface {\n methods \u2192 List\u27e6MethodType\u27e7\n getMethod(name:String) \u2192 MethodType | noSuchMethod\n isUnknown \u2192 Boolean\n isSubtypeOf(other:ObjectType) \u2192 Boolean\n |(other:ObjectType) \u2192 ObjectType\n &(other:ObjectType) \u2192 ObjectType}\ntypedec:$101.Param:\n type Param = interface {\n name \u2192 String\n typeAnnotation \u2192 ObjectType}\ntypes:\n $101.MethodType\n $101.MixPart\n $101.ObjectType\n $101.Param\n"; if (typeof originalSourceLines !== "undefined") { originalSourceLines["staticTypes"] = [ "#pragma noTypeChecks", "dialect \"dialect\"", "import \"ast\" as ast", "import \"util\" as util", "import \"intrinsic\" as intrinsic", "", "def TypeError = DialectError.refine \"TypeError\"", "", "type MethodType = interface {", " // Method signature information consisting of the name, list of MixParts,", " // return type and info on what types it specializes.", " name -> String", " signatureParts -> List⟦MixPart⟧", " returnType -> ObjectType", " isSpecialisationOf (other: MethodType) -> Boolean", "}", "", "type Param = interface {", " name -> String", " typeAnnotation -> ObjectType", "}", "", "// factory method to create parameters with given name and type", "def aParam = object {", " // create parameter with name': type'", " class withName (name': String) ofType (type': ObjectType) -> Param {", " def name: String is public = name'", " def typeAnnotation: ObjectType is public = type'", " method asString is override { \"{name}:{typeAnnotation}\" }", " }", "", " // create parameter with type', but use wildcard as name", " method ofType (type': Object) -> Param {", " withName \"_\" ofType (type')", " }", "}", "", "type MixPart = interface {", " name -> String", " parameters -> List⟦Param⟧", "}", "", "// create a mixPart from name and list of parameters", "class mixPartNamed (name': String)", " parameters (parameters': List⟦Param⟧) -> MixPart {", " def name: String is public = name'", " def parameters: List⟦Param⟧ is public = parameters'", "}", "", "// A factory object to create method types", "def aMethodType = object {", " // create method type from signatureParts and return type", " // The name is constructed by gluing together part names", " class signatureParts (signature': List⟦MixPart⟧)", " returnType (rType: ObjectType)-> MethodType {", " def signatureParts: List⟦MixPart⟧ is public = signature'", " def returnType: ObjectType is public = rType", "", " var name: String is readable:= \"\"", " var show: String:= \"\"", "", " def fst = signatureParts.at 1", "", " if (fst.parameters.size == 0) then {", " name := fst.name", " show := name", " } else {", " signatureParts.do { part ->", " name:= \"{name}{part.name}(\"", " show:= \"{show}{part.name}(\"", " part.parameters.do { param ->", " show := show ++ param", " name := name ++ \"_\"", " } separatedBy {", " show := show ++ \", \"", " name := name ++ \",\"", " }", " show := show ++ \")\"", " name := name ++ \")\"", " }", " }", "", " show := \"{show} -> {returnType}\"", "", " // Determines if this method is a specialisation of the given one.", " method isSpecialisationOf (other: MethodType) -> Boolean {", " if (self.isMe(other)) then {", " return true", " }", "", " if (name != other.name) then {", " return false", " }", "", " if (other.signatureParts.size != signatureParts.size) then {", " return false", " }", "", " for (signatureParts) and (other.signatureParts) do { part, part' ->", " if (part.name != part'.name) then {", " return false", " }", "", " for (part.parameters) and (part'.parameters) do { p, p' ->", " def pt = p.typeAnnotation", " def pt' = p'.typeAnnotation", "", " // Contravariant in parameter types.", " if (pt'.isSubtypeOf (pt).not) then {", " return false", " }", " }", " }", "", " return returnType.isSubtypeOf (other.returnType)", " }", "", " def asString: String is public, override = show", " }", "", " // create method type for methods without parameters", " method member (name: String) ofType (rType: ObjectType) -> MethodType {", " signatureParts ([mixPartNamed (name) parameters [ ] ]) returnType (rType)", " }", "", " // create method type from a node", " // Do obvious thing if method, class, or method signature", " // If it is a def or var, create method to return value", " method fromNode (node) -> MethodType {", " match (node) case { meth: Method | Class | MethodSignature ->", " def signatureParts = list []", "", " meth.signatureParts.do { part ->", " def params = list []", "", " part.params.do { param ->", " params.push (aParam.withName (param.value)", " ofType (objectType.fromDType (param.dtype)))", " }", "", " signatureParts.push (mixPartNamed (part.name) parameters (params))", " }", "", " def rType = match (meth) case { m: Method | Class ->", " m.dtype", " } case { m: MethodSignature ->", " meth.rtype", " } else { }", "", " return signatureParts (signatureParts)", " returnType (objectType.fromDType (rType))", " } case { defd: Def | Var ->", " def signatureParts = [mixPartNamed (defd.name.value) parameters [ ] ]", " def dtype = objectType.fromDType (defd.dtype)", " return signatureParts (signatureParts) returnType (dtype)", " } else {", " Exception.raise \"unrecognised method node\" with (node)", " }", " }", "", "}", "", "", "// Object type information.", "", "def noSuchMethod = singleton \"noSuchMethod\"", "", "type ObjectType = interface {", " // return list of methods", " methods -> List⟦MethodType⟧", " // return method type matching name, if it exists", " getMethod (name: String) -> MethodType | noSuchMethod", " // return whether type is unknown", " isUnknown -> Boolean", " // return if type is subytpe of other", " isSubtypeOf (other: ObjectType) -> Boolean", " // create new types using |, &", " |(other: ObjectType) -> ObjectType", " &(other: ObjectType) -> ObjectType", "}", "", "// Factory for creating object types", "def objectType = object {", "", " // return object type built from methods'", " class fromMethods (methods': List⟦MethodType⟧) -> ObjectType {", " def methods: List⟦MethodType⟧ is public = if (base == unknown)", " then { list [] } else { base.methods } ++ methods'", "", " method getMethod (name: String) -> MethodType | noSuchMethod {", " methods.do { meth ->", " if (meth.name == name) then {", " return meth", " }", " }", "", " return noSuchMethod", " }", "", " def isUnknown: Boolean is public = false", "", " // Necessary to prevent infinite loops of subtype testing.", " def currentlyTesting = list []", "", " method isSubtypeOf (other: ObjectType) -> Boolean {", " if (self.isMe(other)) then {", " return true", " }", "", " if (other.isUnknown) then {", " return true", " }", "", " // If this test is already being performed, assume it succeeds.", " if (currentlyTesting.contains (other)) then {", " return true", " }", "", " currentlyTesting.push (other)", "", " for (other.methods) doWithContinue { a, continue ->", " methods.do { b ->", " if (b.isSpecialisationOf (a)) then {", " continue.apply", " }", " }", "", " currentlyTesting.pop", " return false", " }", "", " currentlyTesting.pop", " return true", " }", "", " method |(other: ObjectType) -> ObjectType {", " if (self.isMe(other)) then { return self }", " if (other.isUnknown) then { return unknown }", "", " def combine = list []", "", " for (methods) doWithContinue { meth, continue ->", " other.methods.do { meth'->", " if (meth.name == meth'.name) then {", " if (meth.isSpecialisationOf (meth')) then {", " combine.push (meth)", " } elseif { meth'.isSpecialisationOf (meth) } then {", " combine.push (meth')", " } else {", " TypeError.raise (\"cannot produce intersection of \" ++", " \"incompatible types '{self}' and '{other}'\")", " }", "", " continue.apply", " }", " }", " }", "", " def hack = objectType", " return object {", " inherit hack.fromMethods (combine)", "", " method asString -> String is override {", " \"{outer} | {other}\"", " }", " }", " }", "", " method &(other: ObjectType) -> ObjectType {", " if (self.isMe(other)) then { return self }", " if (other.isUnknown) then { return unknown }", "", " def combine = list []", " def twice = list []", "", " for (methods) doWithContinue { meth, continue ->", " other.methods.do { meth' ->", " if (meth.name == meth'.name) then {", " if (meth.isSpecialisationOf (meth')) then {", " combine.push (meth)", " } elseif { meth'.isSpecialisationOf (meth) } then {", " combine.push (meth')", " } else {", " TypeError.raise (\"cannot produce union of \" ++", " \"incompatible types '{self}' and '{other}'\")", " }", "", " twice.push (meth.name)", "", " continue.apply", " }", " }", "", " combine.push (meth)", " }", "", " other.methods.do { meth ->", " if (twice.contains (meth.name).not) then {", " combine.push (meth)", " }", " }", "", " def hack = objectType", " object {", " inherit hack.fromMethods (combine)", "", " method asString -> String is override {", " \"{outer} & {other}\"", " }", " }", " }", "", " method asString -> String is override {", " if (methods.size == 3) then {", " return \"Object\"", " }", "", " var out:= \"\\{ \"", "", " methods.do { mtype ->", " if ([\"!=\", \"≠\", \"asString\", \"asDebugString\", \"::\"].contains (mtype.name).not) then {", " out:= \"{out}{mtype}; \"", " }", " }", "", " return \"{out}\\}\"", " }", " }", "", " class fromMethods (methods': List⟦MethodType⟧)", " withName (name: String) -> ObjectType {", " inherit fromMethods (methods')", " use identityEquality", "", " method asString is override { name }", " }", "", " method fromDType (dtype) -> ObjectType {", " match (dtype) case { (false) ->", " unknown", " } case { lit: TypeDeclaration ->", "// TODO: re-write this code to understand the syntax of type expressions", "// and type declarations, which are not the same!", " return unknown", " def intersection = lit.intersectionTypes", " if (intersection.size > 1) then {", " var oType:= fromDType (intersection.first)", "", " for (2..(intersection.size - 1)) do { i ->", " oType:= oType & fromDType (intersection.at (i))", " }", "", " return if (false ≠ lit.value) then {", " object {", "// inherit oType & fromDType (intersection.last)", " inherit AndType(oType, fromDType (intersection.last))", "", " method asString is override { lit.value }", " }", " } else {", " oType & fromDType (intersection.last)", " }", " }", "", " def union = lit.unionTypes", " if (union.size > 1) then {", " var oType:= fromDType (union.first)", "", " for (2..(union.size - 1)) do { i ->", " oType:= oType | fromDType (union.at (i))", " }", "", " return if (false ≠ lit.value) then {", " object {", "// inherit oType | fromDType (union.last)", " inherit BarType(oType, fromDType (union.last))", " def asString: String is public, override = lit.value", " }", " } else {", " oType | fromDType (union.last)", " }", " }", "", " def meths = list []", "", " lit.methods.do { mType ->", " meths.push (aMethodType.fromNode (mType))", " }", "", " if ((lit.value != false) && { lit.value.at (1) != \"<\" }) then {", " objectType.fromMethods (meths) withName (lit.value)", " } else {", " objectType.fromMethods (meths)", " }", " } case { ident: Identifier ->", " objectType.fromIdentifier (ident)", " } case { generic: Generic ->", "// TODO: figure out what to do here!", " objectType.fromIdentifier (generic.value)", " } else {", " ProgrammingError.raise \"No case for node {dtype.toGrace 0} of kind {dtype.kind}\" with (dtype)", " }", " }", "", " method fromIdentifier (ident: Identifier) -> ObjectType {", " scope.types.find (ident.value) butIfMissing { unknown }", " }", "", " method fromBlock (block) -> ObjectType {", " def bType = typeOf (block)", "", " if (bType.isUnknown) then { return unknown }", "", " def apply = bType.getMethod \"apply\"", "", " match (apply) case { (noSuchMethod) ->", " TypeError.raise (\"the expression `{block.toGrace (0)}` of \" ++", " \"type '{bType}' does not satisfy the type 'Procedure0'\") with (block)", " } case { meth: MethodType ->", " return meth.returnType", " } else { }", " }", "", " method fromBlockBody (body) -> ObjectType {", " if (body.size == 0) then {", " objectType.done", " } else {", " typeOf (body.last)", " }", " }", "", " def unknown:ObjectType is public = object {", " use identityEquality", " def methods is public = list []", " method getMethod (_: String) -> noSuchMethod { noSuchMethod }", " def isUnknown: Boolean is public = true", " method isSubtypeOf (_: ObjectType) -> Boolean { true }", " method |(_: ObjectType) -> unknown { unknown }", " method &(_: ObjectType) -> unknown { unknown }", " def asString: String is public, override = \"Unknown\"", " }", "", " method blockTaking (params: List⟦Parameter⟧)", " returning (rType: ObjectType) -> ObjectType {", " def signatureParts = [mixPartNamed \"apply\" parameters (params)]", " def meths = [aMethodType.signatureParts (signatureParts) returnType (rType)]", "", " fromMethods (meths) withName \"Procedure0\"", " }", "", " method blockReturning (rType: ObjectType) -> ObjectType {", " blockTaking [ ] returning (rType)", " }", "", " method addTo (oType: ObjectType) name (name': String)", " returns (rType: ObjectType) -> Done is confidential {", " def signatureParts = [mixPartNamed (name') parameters (list [ ]) ]", " oType.methods.push (aMethodType.signatureParts (signatureParts) returnType (rType))", " }", "", " method addTo (oType: ObjectType) name (name': String)", " params (ptypes:Collection⟦ObjectType⟧) returns (rType: ObjectType)", " -> Done is confidential {", " def parameters = list []", " ptypes.do { ptype ->", " parameters.push (aParam.ofType (ptype))", " }", "", " def signatureParts = [mixPartNamed (name') parameters (parameters)]", "", " oType.methods.push (aMethodType.signatureParts (signatureParts) returnType (rType))", " }", "", " method extend (this: ObjectType) with (that: ObjectType)", " -> Done is confidential {", " that.methods.do { mType ->", " this.methods.push (mType)", " }", " }", "", " var base: ObjectType is readable := unknown // to avoid a circularity", " def done: ObjectType is public = fromMethods (list [ ]) withName \"Done\"", " base := fromMethods (list [ ]) withName \"Object\"", "", " def pattern: ObjectType is public = fromMethods [ ] withName \"Pattern\"", " def iterator: ObjectType is public = fromMethods [ ] withName \"Iterator\"", " def binding: ObjectType is public = fromMethods [ ] withName \"Binding\"", " def boolean: ObjectType is public = fromMethods [ ] withName \"Boolean\"", " def number: ObjectType is public = fromMethods [ ] withName \"Number\"", " def string: ObjectType is public = fromMethods [ ] withName \"String\"", " def list: ObjectType is public = fromMethods [ ] withName \"List\"", " def point: ObjectType is public = fromMethods [ ] withName \"Point\"", "", " addTo (binding) name \"key\" returns (base)", " addTo (binding) name \"value\" returns (base)", "", " addTo (base) name \"≠(_)\" params [base] returns (boolean)", " addTo (base) name \"asDebugString\" returns (string)", " addTo (base) name \"asString\" returns (string)", " addTo (base) name \"::(_)\" returns (binding)", " addTo (base) name \"emptyList\" returns (list)", "", " addTo (done) name \"asDebugString\" returns (string)", " addTo (done) name \"asString\" returns (string)", "", " extend (pattern) with (base)", " addTo (pattern) name \"matches(_)\" params [base] returns (unknown)", " addTo (pattern) name \"|(_)\" params [pattern] returns (pattern)", " addTo (pattern) name \"&(_)\" params [pattern] returns (pattern)", "", " extend (iterator) with (base)", " addTo (iterator) name \"hasNext\" returns (boolean)", " addTo (iterator) name \"next\" returns (unknown)", "", " def shortCircuit = blockTaking ([aParam.ofType (blockReturning (unknown))])", " returning (base)", " extend (boolean) with (base)", " addTo (boolean) name \"&&(_)\" params [boolean] returns (boolean)", " addTo (boolean) name \"||(_)\" params [boolean] returns (boolean)", " addTo (boolean) name \"prefix!\" returns (boolean)", " addTo (boolean) name \"not\" returns (boolean)", "", " extend (number) with (base)", " addTo (number) name \"+(_)\" params [number] returns (number)", " addTo (number) name \"*(_)\" params [number] returns (number)", " addTo (number) name \"-(_)\" params [number] returns (number)", " addTo (number) name \"/(_)\" params [number] returns (number)", " addTo (number) name \"^(_)\" params [number] returns (number)", " addTo (number) name \"%(_)\" params [number] returns (number)", " addTo (number) name \"÷(_)\" params [number] returns (number)", " addTo (number) name \"@(_)\" params [number] returns (point)", " addTo (number) name \"hash\" returns (number)", " addTo (number) name \"++(_)\" params [base] returns (string)", " addTo (number) name \"<(_)\" params [number] returns (boolean)", " addTo (number) name \">(_)\" params [number] returns (boolean)", " addTo (number) name \"≤(_)\" params [number] returns (boolean)", " addTo (number) name \"≥(_)\" params [number] returns (boolean)", " addTo (number) name \"..(_)\" params [number] returns (list)", " addTo (number) name \"asInteger32\" returns (number)", " addTo (number) name \"prefix-\" returns (number)", " addTo (number) name \"inBase(_)\" params [number] returns (number)", " addTo (number) name \"truncated\" returns (number)", " addTo (number) name \"rounded\" returns (number)", " addTo (number) name \"prefix<\" returns (pattern)", " addTo (number) name \"prefix>\" returns (pattern)", "", " extend (point) with (base)", " addTo (point) name \"x\" returns (number)", " addTo (point) name \"y\" returns (number)", "", " extend (string) with (base)", " addTo (string) name \"++(_)\" params [base] returns (string)", " addTo (string) name \"at(_)\" params [number] returns (string)", " addTo (string) name \"iterator\" returns (base)", " addTo (string) name \"quoted\" returns (string)", " addTo (string) name \"size\" returns (number)", " addTo (string) name \"iterator\" returns (iterator)", " addTo (string) name \"ord\" returns (number)", " addTo (string) name \"substringFrom(_)to(_)\" params [number, number] returns (string)", " addTo (string) name \"replace()with(_)\" params [string, string] returns (string)", " addTo (string) name \"hash\" returns (string)", " addTo (string) name \"indices\" returns (list)", " addTo (string) name \"asNumber\" returns (number)", "", " def fold = blockTaking ([aParam.ofType (unknown), aParam.ofType (unknown)])", " returning (unknown)", " extend (list) with (base)", " addTo (list) name \"at(_)\" params [number] returns (unknown)", " addTo (list) name \"at(_)put(_)\" params [number, unknown] returns (done)", " addTo (list) name \"push(_)\" params [unknown] returns (done)", " addTo (list) name \"pop\" returns (unknown)", " addTo (list) name \"size\" returns (number)", " addTo (list) name \"iterator\" returns (iterator)", " addTo (list) name \"contains(_)\" params [unknown] returns (boolean)", " addTo (list) name \"indices\" returns (list)", " addTo (list) name \"first\" returns (unknown)", " addTo (list) name \"last\" returns (unknown)", " addTo (list) name \"add(_)\" params [unknown] returns (list)", " addTo (list) name \"addFirst(_)\" params [unknown] returns (list)", " addTo (list) name \"addAll(_)\" params [unknown] returns (list)", " addTo (list) name \"++(_)\" params [list] returns (list)", " addTo (list) name \"fold(_)startingWith(_)\" params [fold, unknown] returns (unknown)", "", " scope.types.at \"Unknown\" put (unknown)", " scope.types.at \"Done\" put (done)", " scope.types.at \"Object\" put (base)", " scope.types.at \"Pattern\" put (pattern)", " scope.types.at \"Boolean\" put (boolean)", " scope.types.at \"Number\" put (number)", " scope.types.at \"String\" put (string)", " scope.types.at \"List\" put (list)", " scope.types.at \"Point\" put (point)", "", " addVar \"Unknown\" ofType (pattern)", " addVar \"Dynamic\" ofType (pattern)", " addVar \"Done\" ofType (pattern)", " addVar \"Object\" ofType (pattern)", " addVar \"Pattern\" ofType (pattern)", " addVar \"Boolean\" ofType (pattern)", " addVar \"Number\" ofType (pattern)", " addVar \"String\" ofType (pattern)", " addVar \"List\" ofType (pattern)", " addVar \"Point\" ofType (pattern)", "", " addVar \"done\" ofType (self.done)", " addVar \"true\" ofType (boolean)", " addVar \"false\" ofType (boolean)", " addVar \"emptyList\" ofType (list)", "}", "", "method addVar (name: String) ofType (oType: ObjectType) is confidential {", " scope.variables.at (name) put (oType)", " scope.methods.at (name) put (aMethodType.member (name) ofType (oType))", "}", "", "", "// Object literals.", "", "def ObjectError = TypeError.refine \"ObjectError\"", "", "rule { obj: ObjectLiteral ->", " scope.enter { processBody (obj.value) }", "}", "", "", "// Simple literals.", "", "rule { _: NumberLiteral | OctetsLiteral ->", " objectType.number", "}", "", "rule { _: StringLiteral ->", " objectType.string", "}", "", "rule { _: ArrayLiteral ->", " objectType.list", "}", "", "", "// Method requests.", "", "def RequestError = TypeError.refine \"RequestError\"", "", "rule { req: Request ->", " match (req.receiver)", " case { innerReq: Request ->", " def rec = innerReq.receiver", " def rType = if (Identifier.matches (rec) && (rec.value == \"self\")) then {", " scope.types.find \"Self\" butIfMissing {", " Exception.raise \"type of self missing\" with (rec)", " }", " } else {", " typeOf (rec)", " }", "", " if (rType.isUnknown) then {", " objectType.unknown", " } else {", " def name = innerReq.canonicalName", "", " match (rType.getMethod (name))", " case { (noSuchMethod) ->", " RequestError.raise (\"no method `{name}` in \" ++", " \"`{rec.toGrace (0)}` of type `{rType}`\") with (innerReq)", " } case { meth: MethodType ->", " check (req) against (meth)", " }", " }", " } case { ident: Identifier ->", " find (req) atScope (scope.methods.stack.size)", " } case { outerObj: Outer ->", " objectType.unknown // we should be able to do better than that!", " } else {", " print \"receiver {req} is not a Request, an Identifier or an Outer node\"", " objectType.unknown", " }", "}", "", "method check (req: Request)", " against (meth: MethodType) -> ObjectType is confidential {", " def name = meth.name", "", " for (meth.signatureParts) and (req.parts) do { part, args' ->", " def params = part.parameters", " def args = args'.args", "", " def pSize = params.size", " def aSize = args.size", "", " if (aSize != pSize) then {", " def which = if (aSize > pSize) then { \"many\" } else { \"few\" }", " def location = if (aSize > pSize) then {", " args.at (pSize + 1)", " } else {", " // Can we get beyond the final argument?", " req.value", " }", "", " RequestError", " .raise (\"too {which} arguments to method part \" ++", " \"'{part.name}', expected {pSize} but got {aSize}\")", " with (location)", " }", "", " for (params) and (args) do { param, arg ->", " def pType = param.typeAnnotation", " def aType = typeOf (arg)", "", " if (typeOf (arg).isSubtypeOf (pType).not) then {", " RequestError.raise (\"the expression \" ++", " \"`{arg.toGrace (0)}` of type '{aType}' does not \" ++", " \"satisfy the type of parameter '{param}' in the \" ++", " \"method '{name}'\") with (arg)", " }", " }", " }", "", " return meth.returnType", "}", "", "method find (req: Request) atScope (i: Number) -> ObjectType is confidential {", " if (i == 0) then {", " return objectType.unknown", " }", "", " def sType = objectType.fromMethods (scope.methods.stack.at (i).values)", "", " return match (sType.getMethod (req.receiver.value)) case { (noSuchMethod) ->", " find (req) atScope (i - 1)", " } case { meth: MethodType ->", " check (req) against (meth)", " }", "}", "", "rule { memb: Member ->", " typeOf (ast.callNode.new (memb, [object {", " def name is public = memb.value", " def args is public = []", " }]))", "}", "", "rule { op: Operator ->", " def rec = op.left", " def rType = typeOf (rec)", "", " if (rType.isUnknown) then {", " objectType.unknown", " } else {", " def name = op.value", "", " match (rType.getMethod (name)) case { (noSuchMethod) ->", " RequestError.raise (\"no method '{name}' in \" ++", " \"`{rec.toGrace (0)}` of type '{rType}'\") with (op)", " } case { meth: MethodType ->", " def arg = op.right", " def params = meth.signatureParts.first.parameters", "", " if (params.size == 0) then {", " RequestError.raise (\"the definition of operator \" ++", " \"`{name}` is missing its parameter\") with (op)", " }", "", " def param = params.first", " def pType = param.typeAnnotation", "", " if (typeOf (arg).isSubtypeOf (pType).not) then {", " RequestError.raise (\"the expression \" ++", " \"`{arg.toGrace 0}` does not satisfy the type of \" ++", " \"parameter `{param}` in the method `{name}`\") with (arg)", " }", "", " meth.returnType", " }", " }", "}", "", "", "// Special cases.", "", "rule { req: If ->", " def cond = req.value", " if (typeOf (cond).isSubtypeOf (objectType.boolean).not) then {", " RequestError.raise (\"the condition `{cond.toGrace 0}` does not \" ++", " \"conform to type `Boolean`.\") with (cond)", " }", "", " def then = objectType.fromBlock (req.thenblock)", "", " def else = objectType.fromBlock (req.elseblock)", "", " then | else", "}", "", "rule { req: MatchCase ->", " def cases = req.cases", " var union := done", "", " cases.do { case ->", " def cType = objectType.fromBlock (case)", " union := if (done == union) then {", " cType", " } else {", " union | cType", " }", " }", " union", "}", "", "rule { req: TryCatch ->", " match (req.value) case { bl: BlockLiteral ->", " def params = bl.params", " if (params.size > 0) then {", " RequestError.raise \"too many parameters for try block\" with (bl)", " }", " }", "", " req.cases.do { eachCase ->", " match (eachCase) case { bl: BlockLiteral ->", " def params = bl.params", " if (params.size != 1) then {", " def which = if (params.size == 0)", " then { \"not enough\" } else { \"too many\" }", "", " RequestError.raise \"{which} parameters for catch block\" with (bl)", " }", " }", " }", "", " if (false ≠ req.finally) then {", " match (req.finally) case { bl: BlockLiteral ->", " def params = bl.params", " if (params.size > 0) then {", " RequestError.raise \"too many parameters to finally\" with (bl)", " }", " }", " }", "", " objectType.done", "}", "", "", "// Method declaration.", "", "def MethodError = TypeError.refine \"MethodError\"", "", "rule { meth: Method ->", " def name = meth.value.value", " def mType = aMethodType.fromNode (meth)", " def returnType = mType.returnType", "", " scope.enter {", " meth.signatureParts.do { part ->", " part.params.do { param ->", " scope.variables.at (param.value)", " put (objectType.fromDType (param.dtype))", " }", " }", "", " collectTypes (meth.body)", "", " meth.body.do { stmt ->", " checkTypes (stmt)", "", " stmt.accept (object {", " inherit ast.baseVisitor", "", " method visitReturn (ret) is override {", " check (ret.value) matches (returnType) inMethod (name)", " return false", " }", "", " method visitMethod (node) is override {", " false", " }", " })", " }", "", " if (meth.body.size == 0) then {", " if (objectType.done.isSubtypeOf (returnType).not) then {", " MethodError.raise (\"method `{name}` declares a \" ++", " \"result of type '{returnType}', but has no body\") with (meth)", " }", " } else {", " def lastNode = meth.body.last", " if (Return.matches (lastNode).not) then {", " def lastType = typeOf (lastNode)", " if (lastType.isSubtypeOf (returnType).not) then {", " TypeError.raise (\"method `{name}` declares a \" ++", " \"result of type `{returnType}`, but returns an \" ++", " \"expression of type `{lastType}`\") with (lastNode)", " }", " }", " }", " }", "", " if (isMember (mType)) then {", " scope.variables.at (name) put (returnType)", " }", "", " scope.methods.at (name) put (mType)", " objectType.done", "}", "", "method check (node) matches (eType: ObjectType)", " inMethod (name: String) -> Done is confidential {", " def aType = typeOf (node)", " if (aType.isSubtypeOf (eType).not) then {", " MethodError.raise (\"method `{name}` declares a result of \" ++", " \"type `{eType}`, but returns an expression of type \" ++", " \"`{aType}`\") with (node)", " }", "}", "", "", "// Class declaration.", "", "def ClassError = TypeError.refine \"ClassError\"", "", "rule { cls: Class ->", " def name = cls.name.value", " def dType = objectType.fromDType (cls.dtype)", " def cType = scope.enter {", " cls.signatureParts.do { part ->", " part.params.do { param ->", " scope.variables.at (param.value)", " put (objectType.fromDType (param.dtype))", " }", " }", "", " def aType = processBody (cls.value)", " if (aType.isUnknown) then {", " objectType.unknown", " } else {", " if (aType.isSubtypeOf (dType).not) then {", " ClassError.raise (\"class `{name}` declares a result \" ++", " \"of type `{dType}`, but constructs an object of type \" ++", " \"`{aType}`\") with (cls)", " }", "", " aType", " }", " }", "", " scope.variables.at (name)", " put (objectType.fromMethods ([aMethodType.fromNode (cls)]))", "", " if (dType.isUnknown) then {", " // Class type inference.", " cType", " } else {", " dType", " }", "}", "", "", "// Def and var declarations.", "", "def DefError = TypeError.refine \"DefError\"", "", "rule { defd: Def | Var ->", " var defType:= objectType.fromDType (defd.dtype)", "", " def value = defd.value", "", " if (value != false) then {", " def vType = typeOf (value)", "", " if (defType.isUnknown && (defd.kind == \"defdec\")) then {", " defType:= vType", " }", "", " if (vType.isSubtypeOf (defType).not) then {", " DefError.raise (\"the expression `{value.toGrace 0}` of type \" ++", " \"`{vType}` does not satisfy the type of {defd.kind} \" ++", " \"annotation `{defType}`\") with (value)", " }", " }", "", " def name = defd.name.value", " scope.variables.at (name) put (defType)", "", " defd.annotations.do { ann ->", " if (defd.isReadable) then {", " scope.methods.at (name) put (aMethodType.member (name) ofType (defType))", " }", "", " if (defd.isWritable) then {", " def name' = name ++ \":=\"", " def param = aParam.withName (name) ofType (defType)", " def sig = [mixPartNamed (name') parameters ([param])]", "", " scope.methods.at (name')", " put (aMethodType.signatureParts (sig) returnType (objectType.done))", " }", " }", " objectType.done", "}", "", "rule { bind: Bind ->", " def dest = bind.dest", " def dType = typeOf (dest)", "", " def value = bind.value", " def vType = typeOf (value)", "", " if (vType.isSubtypeOf (dType).not) then {", " DefError.raise (\"the expression `{value.toGrace 0}` of type \" ++", " \"`{vType}` does not satisfy the type `{dType}` of \" ++", " \"`{dest.toGrace 0}`\") with (value)", " }", " objectType.done", "}", "", "", "// Import declarations.", "", "rule { imp: Import ->", " scope.variables.at (imp.nameString) put (objectType.unknown)", " objectType.done", "}", "", "", "// Block expressions.", "", "rule { block: BlockLiteral ->", " def body = block.body", "", " scope.enter {", " block.params.do { param ->", " scope.variables.at (param.value)", " put (objectType.fromDType (param.dtype))", " }", "", " collectTypes (body)", "", " body.do { stmt ->", " checkTypes (stmt)", " }", " }", "", " def parameters = list []", " block.params.do { param ->", " parameters.push (aParam.withName (param.value)", " ofType (objectType.fromDType (param.dtype)))", " }", "", " objectType.blockTaking (parameters)", " returning (objectType.fromBlockBody (body))", "}", "", "", "// Identifier references.", "", "rule { ident: Identifier ->", " match (ident.value) case { \"outer\" ->", " outerAt (scope.size)", " } else {", " scope.variables.find (ident.value) butIfMissing { objectType.unknown }", " }", "}", "", "method outerAt (i: Number) -> ObjectType is confidential {", " // Required to cope with not knowing the dialect.", " if (i <= 1) then {", " return objectType.unknown", " }", "", " def vStack = scope.variables.stack", " def curr = vStack.at (i)", "", " return curr.atKey \"outer\" do { t -> t } else {", " def prev = outerAt (i - 1)", "", " def mStack = scope.methods.stack", "", " def vars = vStack.at (i - 1)", " def meths = mStack.at (i - 1).values", "", " def oType = objectType.fromMethods (meths)", " def mType = aMethodType.member \"outer\" ofType (oType)", "", " curr.at \"outer\" put (oType)", " mStack.at (i).at \"outer\" put (mType)", "", " oType", " }", "}", "", "", "// Typing methods.", "", "method processBody (body: List) -> ObjectType is confidential {", " // Collect the declarative types directly in the object body.", " collectTypes (body)", "", " // Inheritance typing.", " def hasInherits = (body.size > 0) && { Inherit.matches (body.first) }", " def superType = if (hasInherits) then {", " def inheriting = body.first.value", " inheriting.accept (object {", " inherit ast.baseVisitor", "", " def illegal = [\"self\"]", "", " method visitIdentifier (ident) {", " if (illegal.contains (ident.value)) then {", " ObjectError.raise (\"reference to `{ident.value}` \" ++", " \"in inheritance clause\") with (ident)", " }", " }", " })", "", " typeOf (inheriting)", " } else {", " objectType.base", " }", "", " scope.variables.at \"super\" put (superType)", "", " // If the super type is unknown, then we can't know anything about the", " // self type. TODO We actually can, because an object cannot have two", " // methods with the same name.", " def publicType = if (superType.isUnknown) then {", " scope.types.at \"Self\" put (superType)", " superType", " } else {", " // Collect the method types to add the two self types.", " def publicMethods = list []", " def allMethods = list []", "", " body.do { stmt ->", " match (stmt) case { meth: Method ->", " def mType = aMethodType.fromNode (meth)", " allMethods.push (mType)", " if (meth.isPublic) then {", " publicMethods.push (mType)", " }", "", " scope.methods.at (mType.name) put (mType)", " if (isMember (mType)) then {", " scope.variables.at (mType.name) put (mType.returnType)", " }", " } case { defd: Def | Var ->", " if (defd.isPublic) then {", " def mType = aMethodType.fromNode (defd)", " allMethods.push (mType)", " publicMethods.push (mType)", " }", " } else { }", " }", "", " scope.types.at \"Self\" put (objectType.fromMethods (allMethods))", " objectType.fromMethods (publicMethods)", " }", "", " scope.variables.at \"self\" put (publicType)", "", " // Type-check the object body.", " def indices = if (hasInherits) then {", " 2..body.size", " } else {", " body.indices", " }", "", " indices.do { i ->", " checkTypes (body.at (i))", " }", "", " return publicType", "}", "", "", "def TypeDeclarationError = TypeError.refine \"TypeDeclarationError\"", "", "// The first pass over a body, collecting all type declarations so that they can", "// reference one another declaratively.", "method collectTypes (nodes: List) -> Done is confidential {", " def names = list []", " def types = list []", " def placeholders = list []", "", " nodes.do { node ->", " match (node) case { td: TypeDeclaration ->",