UNPKG

minigrace

Version:

A compiler for the Grace programming language

992 lines (991 loc) 657 kB
let gracecode_genjs_sourceFile = "/Users/black/Development/mg/gracelang/minigrace/genjs.grace"; let gracecode_genjs_sha256 = "474c58e8ebb40e6fff529a74974d1be615bf78b2ba69b6a2594840d367d5ab44"; let gracecode_genjs_minigraceRevision = "b57591d29fc5ee5270d114920bf671367b8c3ecb"; let gracecode_genjs_minigraceGeneration = "5171"; if (typeof gctCache !== "undefined") gctCache["genjs"] = "dialect:\n standard\nfreshScopes:\nmodules:\n ast\n errormessages\n identifierresolution\n io\n regularExpression\n shasum\n standard\n sys\n unixFilePath\n util\n xmodule\npath:\n /Users/black/Development/mg/gracelang/minigrace/genjs.grace\nscope:$100:\n addSuffix(1)to(1) Unknown (mth) $scope_done\n aliasList(1) Unknown (mth) $scope_done\n asDebugString String (go) $scope_string\n asString String (go) $scope_string\n assembleArguments(1) Unknown (mth) $scope_done\n basename(1) Unknown (mth) $scope_done\n basicAsString String (go) $scope_string\n clearLineNumber(1) Unknown (mth) $scope_done\n compile(4) Unknown (mth) $scope_done\n compileArgumentTypeChecks(1) Unknown (mth) $scope_done\n compileArguments(1) Unknown (mth) $scope_done\n compileBuildAndInitFunctions(1)inMethod(1) Unknown (mth) $scope_done\n compileBuildMethodFor(1)withFreshCall(1)inside(1) Unknown (mth) $scope_done\n compileBuildMethodFor(1)withObjCon(1)inside(1) Unknown (mth) $scope_done\n compileCallToBuildMethod(1)withArgs(1) Unknown (mth) $scope_done\n compileCheckThat(1)called(1)hasType(1)onLine(1) Unknown (mth) $scope_done\n compileDefaultsForTypeParameters(1)extraParams(1) Unknown (mth) $scope_done\n compileDummyAnnotationMethod(2) Unknown (mth) $scope_done\n compileDummyMethod(3) Unknown (mth) $scope_done\n compileEllipsis(1) Unknown (mth) $scope_done\n compileFreshMethod(2) Unknown (mth) $scope_done\n compileGuard(2) Unknown (mth) $scope_done\n compileInherit(1)forClass(1) Unknown (mth) $scope_done\n compileMetadata(3) Unknown (mth) $scope_done\n compileMethodBody(1) Unknown (mth) $scope_done\n compileMethodBodyWithTypecheck(1) Unknown (mth) $scope_done\n compileMethodBodyWithoutLast(1) Unknown (mth) $scope_done\n compileMethodPostamble(3) Unknown (mth) $scope_done\n compileMethodPreamble(3)withParams(1) Unknown (mth) $scope_done\n compileMethodsForInterface(1) Unknown (mth) $scope_done\n compileNativeCode(1) Unknown (mth) $scope_done\n compileNormalArguments(2) Unknown (mth) $scope_done\n compileNormalMethod(2) Unknown (mth) $scope_done\n compileNull(1) Unknown (mth) $scope_done\n compileOnceWrapper(3) Unknown (mth) $scope_done\n compileOtherRequest(2) Unknown (mth) $scope_done\n compileOuterRequest(2) Unknown (mth) $scope_done\n compileOwnInitialization(2) Unknown (mth) $scope_done\n compileParameterDebugFrame(2) Unknown (mth) $scope_done\n compilePrint(1) Unknown (mth) $scope_done\n compileReuseCall(1)forClass(1)aliases(1)exclusions(1) Unknown (mth) $scope_done\n compileSelfRequest(2) Unknown (mth) $scope_done\n compileSelfType(1) Unknown (mth) $scope_done\n compileSequence(1) Unknown (mth) $scope_done\n compileSignature(1) Unknown (mth) $scope_done\n compileSimpleAccessor(1) Unknown (mth) $scope_done\n compileSuperInitialization(1) Unknown (mth) $scope_done\n compileTypeArguments(2) Unknown (mth) $scope_done\n compileUninitializedCheck(1) Unknown (mth) $scope_done\n compileUnknown(1) Unknown (mth) $scope_done\n compileUse(1)in(1) Unknown (mth) $scope_done\n compileYourself(1) Unknown (mth) $scope_done\n compilebind(1) Unknown (mth) $scope_done\n compileblock(1) Unknown (mth) $scope_done\n compilecall(1) Unknown (mth) $scope_done\n compiledefdec(1) Unknown (mth) $scope_done\n compiledialect(1) Unknown (mth) $scope_done\n compileidentifier(1) Unknown (mth) $scope_done\n compileif(1) Unknown (mth) $scope_done\n compileimport(1) Unknown (mth) $scope_done\n compileinterfaceliteral(1)in(1) Unknown (mth) $scope_done\n compilematchcase(1) Unknown (mth) $scope_done\n compilemethodnode(1)in(1) Unknown (mth) $scope_done\n compilemethodtypes(2) Unknown (mth) $scope_done\n compilenode(1) Unknown (mth) $scope_done\n compileobjdefdec(2) Unknown (mth) $scope_done\n compileobject(2) Unknown (mth) $scope_done\n compileobjouter(2) Unknown (mth) $scope_done confidential\n compileobjvardec(2) Unknown (mth) $scope_done\n compileop(1) Unknown (mth) $scope_done\n compilereturn(1) Unknown (mth) $scope_done\n compiletrycatch(1) Unknown (mth) $scope_done\n compiletypedec(1)in(1) Unknown (mth) $scope_done\n compilevardec(1) Unknown (mth) $scope_done\n create(1)field(1)in(1) Unknown (mth) $scope_done\n debugModePrefix Unknown (mth) $scope_done\n debugModeSuffix Unknown (mth) $scope_done\n decreaseindent Unknown (mth) $scope_done\n emitBufferedOutput Unknown (mth) $scope_done\n escapeident(1) Unknown (mth) $scope_done\n escapestring(1) Unknown (mth) $scope_done\n exclusionList(1) Unknown (mth) $scope_done\n formatModname(1) Unknown (mth) $scope_done\n increaseindent Unknown (mth) $scope_done\n initializeCodeGenerator(1) Unknown (mth) $scope_done\n installLocalAttributesOf(1)into(1) Unknown (mth) $scope_done\n isMe(1) Boolean (go) $scope_boolean\n isSimpleAccessor(1) Unknown (mth) $scope_done\n literalList(1) Unknown (mth) $scope_done\n myIdentityHash Number (go) $scope_number\n noteLineNumber(1)comment(1) Unknown (mth) $scope_done\n out(1) Unknown (mth) $scope_done\n outUnnumbered(1) Unknown (mth) $scope_done\n outerProp(1) Unknown (mth) $scope_done\n outputGct Unknown (mth) $scope_done\n outputModuleDefinition(1) Unknown (mth) $scope_done\n outputModuleMetadata(1) Unknown (mth) $scope_done\n outputSource Unknown (mth) $scope_done\n parameterTypes(1) Unknown (mth) $scope_done\n paramlist(1) Unknown (mth) $scope_done\n partl(1) Unknown (mth) $scope_done\n printNodeTally Unknown (mth) $scope_done\n restoreInitializedVars(1) Unknown (mth) $scope_done\n runJsCode(2) Unknown (mth) $scope_done\n saveInitializedVars Unknown (mth) $scope_done\n scopeThatDefines(1)ifNone(1) Unknown (mth) $scope_done\n stringList(1) Unknown (mth) $scope_done\n stripLeadingZeros(1) Unknown (mth) $scope_done\n tallyNode(1) Unknown (mth) $scope_done\n typeFunBody(1)named(1) Unknown (mth) $scope_done\n typeParamlist(1) Unknown (mth) $scope_done\n uidWithPrefix(1) Unknown (mth) $scope_done\n varf(1) Unknown (mth) $scope_done\n withoutComma(1) Unknown (mth) $scope_done\n withoutDollarPrefix(1) Unknown (mth) $scope_done\n withoutTypeArgs(1) Unknown (mth) $scope_done\nself:\n $100\ntypes:\n"; if (typeof originalSourceLines !== "undefined") { originalSourceLines["genjs"] = [ "dialect \"standard\"", "import \"io\" as io", "import \"sys\" as sys", "import \"ast\" as ast", "import \"util\" as util", "import \"unixFilePath\" as filePath", "import \"xmodule\" as xmodule", "import \"errormessages\" as errormessages", "import \"identifierresolution\" as identifierresolution", "import \"shasum\" as shasum", "import \"regularExpression\" as regex", "", "def nodeTally = dictionary.empty", "def inBrowser = native \"js\" code ‹", " result = (typeof global === \"undefined\" ? GraceTrue : GraceFalse);", "›", "", "var indent := \"\"", "var verbosity := 30", "var pad1 := 1", "var auto_count := 0", "var constants := list []", "var output := list []", "var usedvars := list []", "var declaredvars := list []", "var initializedVars := set [\"$dialect\", \"$module\"]", "", "method saveInitializedVars {", " // returns the current set of initialized vars,", " // to be used in restoreInitializedVars", " def result = initializedVars", " initializedVars := set [\"$dialect\", \"$module\"]", " result", "}", "", "method restoreInitializedVars(savedState) {", " // restores the set of initialized vars to savedState,", " // the result of saveInitializedVars", " initializedVars := savedState", "}", "", "", "var bblock := \"entry\"", "", "var outfile", "var modname := \"main\"", "var buildtype := \"bc\"", "var inBlock := false", "var compilationDepth := 0", "def importedModules = set.empty", "var debugMode := false", "var priorLineSeen := 0", "var priorLineComment := \"\"", "var priorLineEmitted := 0", "var emitTypeChecks := true", "var emitUndefinedChecks := true", "var emitArgChecks := true", "var emitPositions := true", "var emod // the name of the module being compiled, escaped", " // so that it is a legal identifier", "var modNameAsString // the name of the module surrounded by quotes,", " // with internal special chars escaped.", "var thisModule // the register (string) that will refer to this module", "", "/////////////////////////////////////////////////////////////", "//", "// Utility methods", "//", "/////////////////////////////////////////////////////////////", "", "method increaseindent {", " indent := indent ++ \" \"", "}", "", "method decreaseindent {", " if(indent.size <= 2) then {", " indent := \"\"", " } else {", " indent := indent.substringFrom 3", " }", "}", "", "method formatModname(name) {", " \"gracecode_\" ++ escapeident (basename(name))", "}", "", "method basename(filepath) {", " var bnm := \"\"", " for (filepath) do {c->", " if (c == \"/\") then {", " bnm := \"\"", " } else {", " bnm := bnm ++ c", " }", " }", " bnm", "}", "", "method outerProp(node) { \"outer_\" ++ emod ++ \"_\" ++ node.line }", "", "method noteLineNumber(n)comment(c) {", " // remember the current line number, so that it can be generated if needed", " if (n ≠ 0) then {", " priorLineSeen := n", " priorLineComment := c", " }", "}", "", "method clearLineNumber(n) {", " // clear and reset the remembered line number.", " // Used at the start of a method", " priorLineComment := \"cleared on line {n}\"", " priorLineSeen := 0", " priorLineEmitted := 0", "}", "", "method out(s) {", " // output code, but first output code to set the line number", " if (emitPositions && (priorLineSeen != priorLineEmitted)) then {", " output.push \"{indent}setLineNumber({priorLineSeen}); // {priorLineComment}\"", " priorLineEmitted := priorLineSeen", " }", " output.push(indent ++ s)", " return done", "}", "", "method outUnnumbered(s) {", " // output code that does not correspond to any source line", " output.push(indent ++ s)", "}", "", "method emitBufferedOutput {", " for (output) do { o ->", " util.outprint(o)", " }", " outfile.close", "}", "", "def validIdChars = regex.fromString ‹[a-zA-Z0-9\\$]›", "", "method escapeident(vn) {", " // escapes characters not legal in an identifer using __«codepoint»__", " // must correspond to escapeident in the version of gracelib that will", " // be loaded with the code that we are generating — which may be different", " // from the version of gracelib that is supporting this execution of the", " // compiler. (That's why we don't just call the gracelib version here.)", " var result := \"\"", " vn.do { ch ->", " if (validIdChars.matches(ch)) then {", " result := result ++ ch", " } else {", " result := result ++ \"__{ch.ord}__\"", " }", " }", " result", "}", "", "method escapestring(s) {", " // escapes embedded double-quotes, backslashes, newlines and non-ascii chars", " native \"js\" code ‹return new GraceString(escapestring(var_s._value));›", "}", "method varf(vn) {", " \"var_\" ++ escapeident(vn)", "}", "method uidWithPrefix(str) {", " def myc = auto_count", " auto_count := auto_count + 1", " str ++ myc", "}", "", "/////////////////////////////////////////////////////////////", "//", "// Compilation methods for AST nodes", "//", "/////////////////////////////////////////////////////////////", "", "method compileSequence(o) {", " if (o.value.isEmpty) then {", " o.register := \"GraceEmptySequence\"", " } else {", " def reg = uidWithPrefix \"seq\"", " var vals := list []", " for (o.value) do { a -> vals.push(compilenode(a)) }", " out \"var {reg} = new GraceSequence({literalList(vals)});\"", " o.register := reg", " }", "}", "method compileobjouter(o, outerRef) is confidential {", " def outerPropName = outerProp(o)", " out \"this.closureKeys = this.closureKeys || [];\"", " out \"this.closureKeys.push(\\\"{outerPropName}\\\");\"", " out \"this.{outerPropName} = {outerRef};\"", "}", "method compileCheckThat(val) called (description)", " hasType (expectedType) onLine(lineNumber) {", " // Compiles a type check.", " // expectedType is an astNode representing the type expression;", " // val the register that holds the value to be type-checked;", " // description is a String describing the nature of val, such as", " // \"argument 2 to `foobaz(_)with(_)`\", which will be used in the error", " // message, and lineNumber the line on which the error occurred (or 0", " // if we don't want to emit a setLineNumber command).", "", " if (emitTypeChecks.not) then { return }", " if (false == expectedType) then { return }", " if (\"never returns\" == val) then { return } // Charlie on the MTA?", " if (expectedType.isUnknownType) then { return }", " if (\"Done\" == expectedType.value) then { return }", "", " def nm_t = compilenode(expectedType)", " if (lineNumber ≠ 0) then {", " noteLineNumber(lineNumber) comment \"typecheck\"", " }", " def typeDesc = withoutDollarPrefix(withoutTypeArgs(expectedType.toGrace 0.quoted))", " out \"assertTypeOrMsg({val}, {nm_t}, \\\"{description}\\\", \\\"{typeDesc}\\\");\"", "}", "method withoutDollarPrefix(str) {", " if (str.first == \"$\") then {", " def dotIx = str.indexOf \".\" ifAbsent { 0 }", " return str.substringFrom (dotIx + 1)", " }", " str", "}", "method withoutTypeArgs(str) {", " def leftBracketIx = str.indexOf \"⟦\" ifAbsent { return str }", " str.substringFrom 1 to (leftBracketIx - 1)", "}", "method compileobjdefdec(o, selfr) {", " o.register := \"GraceDone\"", " def val = if (o.isAnnotationDecl) then {", " \"annotation\"", " } else {", " compilenode(o.value)", " }", " def oName = o.name.value", " def nm = escapeident(oName)", " compileCheckThat (val) called \"value bound to {escapestring(oName)}\"", " hasType (o.dtype) onLine (o.line)", " out \"{selfr}.data.{nm} = {val};\"", "}", "method compileobjvardec(o, selfr) {", " o.register := \"GraceDone\"", " def oName = o.name.value", " def nm = escapeident(oName)", " if (false == o.value) then {", " out \"{selfr}.data.{nm} = undefined;\"", " return", " }", " def val = compilenode(o.value)", " compileCheckThat(val) called \"value assigned to {escapestring(oName)}\"", " hasType (o.dtype) onLine (o.line)", " out \"{selfr}.data.{nm} = {val};\"", "}", "", "method create (kind) field (o) in (objr) {", " // compile code that creates a field, and appropriate", " // accessor method(s), in objr, the object under construction", " def nm = escapestring(o.name.value)", " def nmi = escapeident(o.name.value)", " def rFun = uidWithPrefix \"reader\" ++ \"_\" ++ nmi", " def fieldName = if (o.parentKind == \"module\") then {", " \"var_{nmi}\" // this var_{nmi} variable must be declared by caller", " } else {", " out \"{objr}.data.{nmi} = undefined;\"", " \"{objr}.data.{nmi}\"", " }", " out \"var {rFun} = function() \\{ // reader method {nm}\"", " if (emitUndefinedChecks) then {", " out \" if ({fieldName} === undefined) raiseUninitializedVariable(\\\"{nm}\\\");\"", " }", " out \" return {fieldName};\"", " out \"};\"", " out \"{rFun}.is{kind.capitalized} = true;\"", " if (o.isReadable.not) then {", " out \"{rFun}.confidential = true;\"", " }", " out \"{objr}.methods[\\\"{nm}\\\"] = {rFun};\"", " if (kind == \"var\") then {", " def wFun = uidWithPrefix \"writer\" ++ \"_\" ++ nmi", " out \"var {wFun} = function(argcv, n) \\{ // writer method {nm}:=(_)\"", " increaseindent", " compileCheckThat \"n\" called \"argument to {nm}:=(_)\"", " hasType (o.dtype) onLine 0", " out \"{fieldName} = n;\"", " out \"return GraceDone;\"", " decreaseindent", " out \"\\};\"", " if (o.isWritable.not) then {", " out \"{wFun}.confidential = true;\"", " }", " out \"{objr}.methods[\\\"{nm}:=(1)\\\"] = {wFun};\"", " }", "}", "", "method installLocalAttributesOf(o) into (objr) {", " var mutable := false", "", " o.body.do { e ->", " if (e.isMethod) then {", " compilemethodnode(e) in (objr)", " } elseif { e.isFieldDec } then {", " create (e.description) field (e) in (objr)", " if (e.isVarDec) then { mutable := true }", " } elseif {e.isTypeDec } then {", " compiletypedec(e) in (objr)", " }", " }", " if (mutable) then {", " out \"{objr}.mutable = true;\"", " }", "}", "", "method compileOwnInitialization(o, selfr) {", " o.body.do { e ->", " if (e.isFieldDec) then {", " if (e.kind == \"vardec\") then {", " compileobjvardec(e, selfr)", " } elseif { e.kind == \"defdec\" } then {", " compileobjdefdec(e, selfr)", " }", " } elseif { e.isObject } then {", " compileobject(e, selfr)", " } elseif { e.isExecutable } then {", " compilenode(e)", " }", " }", "}", "", "method compileBuildAndInitFunctions(o) inMethod (methNode) {", " // o is an objectNode. In the compiled code, `this` references the current", " // object, which will become the outer object of `ouc`, the object here", " // under construction. methNode respresents the method containing o;", " // if o is not inside a method, methdNode is false.", "", " // The build function adds the attributes defined by o to `this`,", " // and returns as its result the init function, which, when called, will", " // initialize `this`", "", " var origInBlock := inBlock", " inBlock := false", "", " def ouc = uidWithPrefix \"obj\"", " o.register := ouc", " def inheritsStmt = o.superclass", " var params := \"\"", " var typeParams := \"\"", " if (false != methNode) then {", " params := paramlist(methNode)", " typeParams := typeParamlist(methNode)", " }", " out \"var {ouc}_build = function(ignore{params}, outerObj, aliases, exclusions{typeParams}) \\{\"", " // At execution time, `this` will be the object under construction.", " // `outerObj` will be the current object, which", " // will become the `outer` of the object under construction.", " // `aliases` and `exclusions` are JS arrays of aliases and method names,", " // ultimately from an `inherit` or `use` statement.", " increaseindent", " compileobjouter(o, \"outerObj\")", " out \"const inheritedExclusions = \\{ };\"", " // this object is used to save methods already in the ouc that", " // would be overridden by local methods, aliases or excluded methods, were", " // the excluded methods not excluded.", " out \"for (var eix = 0, eLen = exclusions.length; eix < eLen; eix ++) \\{\"", " out \" const exMeth = exclusions[eix];\"", " out \" inheritedExclusions[exMeth] = this.methods[exMeth]; \\};\"", " // some of these methods will be undefined; that's OK", " if (false != inheritsStmt) then {", " compileInherit(inheritsStmt) forClass (o.nameString)", " }", " o.usedTraits.do { t ->", " compileUse(t) in (o)", " }", " installLocalAttributesOf(o) into \"this\"", " out \"const overridenByAliases = \\{ };\"", " out \"for (let aix = 0, aLen = aliases.length; aix < aLen; aix ++) \\{\"", " out \" const a = aliases[aix];\"", " out \" const newNm = a.newName;\"", " out \" const oldNm = a.oldName;\"", " out \" overridenByAliases[newNm] = this.methods[newNm];\"", " out \" const m = confidentialVersion(overridenByAliases[oldNm] || this.methods[oldNm], newNm);\"", " out \" m.definitionLine = {o.line};\"", " out \" m.definitionModule = {modNameAsString};\"", " out \" this.methods[newNm] = m;\"", " out \"}\"", " out \"for (let exName in inheritedExclusions) \\{\"", " out \" if (inheritedExclusions.hasOwnProperty(exName)) \\{\"", " out \" if (inheritedExclusions[exName]) \\{\"", " out \" this.methods[exName] = inheritedExclusions[exName];\"", " out \" } else \\{\"", " out \" delete this.methods[exName];\"", " out \" }\"", " out \" }\"", " out \"}\"", " out \"var {ouc}_init = function() \\{ // init of object on line {o.line}\"", " // At execution time, `this` will be the object being initialized.", " increaseindent", " if (false != inheritsStmt) then {", " compileSuperInitialization(inheritsStmt)", " }", " compileOwnInitialization(o, \"this\")", " decreaseindent", " out \"\\};\" // end of _init function for object on line {o.line}", " out \"return {ouc}_init; // from compileBuildAndInitFunctions(_)inMethod(_)\"", " decreaseindent", " out \"\\};\" // end of build function", " inBlock := origInBlock", "}", "method compileobject(o, outerRef) {", " // compiles an object constructor, in all contexts except a fresh method.", " // Generates two JavaScript functions,", " // {o.register}_build, which creates the object and its methods and fields,", " // and {o.register}_init, which initializes the fields. The _init function", " // is returned from the _build funciton, so that it can close over the context.", " // The object constructor itself is implemented by calling these functions", " // in sequence, _except_ inside a fresh method, where the _build function may", " // instead need to add the object's contents to an existing object.", " compileBuildAndInitFunctions(o) inMethod (false)", " def objRef = o.register", " def objName = \"\\\"\" ++ o.name.quoted ++ \"\\\"\"", " out \"var {objRef} = emptyGraceObject({objName}, {modNameAsString}, {o.line});\"", " out \"var {objRef}_init = {objRef}_build.call({objRef}, null, {outerRef}, [], []);\"", " out \"{objRef}_init.call({objRef}); // end of compileobject\"", " objRef", "}", "method compileGuard(o, paramList) {", " if (o.aParametersHasATypeAnnotation) then {", " def matchFun = uidWithPrefix \"matches\"", " out \"var {matchFun} = function({paramList}) \\{\"", " increaseindent", " noteLineNumber(o.line) comment \"block matches function\"", " o.params.do { p ->", " if (false ≠ p.dtype) then {", " def pName = varf(p.value)", " def dtype = compilenode(p.dtype)", " out \"if (!Grace_isTrue(request({dtype}, \\\"matches(1)\\\", [1], {pName})))\"", " out \" return false;\"", " }", " }", " out \"return true;\"", " decreaseindent", " out \"};\"", " matchFun", " } else {", " \"jsTrue\" // the constant true function, defined in gracelib", " }", "}", "", "method compileblock(o) {", " def origInBlock = inBlock", " def oldInitializedVars = saveInitializedVars", " inBlock := true", " def blockId = uidWithPrefix \"block\"", " def nParams = o.params.size", " out \"var {blockId} = new GraceBlock(this, {o.line}, {nParams});\"", " var paramList := \"\"", " var paramTypes := list [ ]", " var someParamIsTyped := false", " var first := true", " for (o.params) do { each ->", " def dType = each.decType", " paramTypes.push(compilenode(dType))", " if (dType.isUnknownType.not) then {", " someParamIsTyped := true", " }", " if (first) then {", " paramList := varf(each.value)", " first := false", " } else {", " paramList := paramList ++ \", \" ++ varf(each.value)", " }", " }", " if (someParamIsTyped) then {", " out \"{blockId}.paramTypes = {literalList(paramTypes)};\"", " }", "", " out \"{blockId}.guard = {compileGuard(o, paramList)};\"", " out \"{blockId}.real = function {blockId}({paramList}) \\{\"", " increaseindent", " priorLineEmitted := 0", " noteLineNumber (o.line) comment (\"compileBlock\")", " var ret := \"GraceDone\"", " for (o.body) do {l->", " ret := compilenode(l)", " }", " if (\"never returns\" ≠ ret) then { out \"return {ret};\" }", " decreaseindent", " out \"\\};\"", " def applyMeth = blockId.replace \"block\" with \"applyMeth\"", " def applyMethName = if (nParams == 0) then { \"apply\" } else { \"apply({nParams})\" }", " if (nParams == 0) then {", " out \"let {applyMeth} = function apply (argcv) \\{\"", " out \" return this.real.apply(this.receiver);\"", " out \"\\};\"", " } else {", " out \"let {applyMeth} = function apply_{nParams} (argcv, ...args) \\{\"", " out \" if (this.guard.apply(this.receiver, args))\"", " out \" return this.real.apply(this.receiver, args);\"", " out \" badBlockArgs.apply(this, args);\"", " out \"\\};\"", " }", " compileMetadata(o, applyMeth, applyMethName)", " out \"{blockId}.methods[\\\"{applyMethName}\\\"] = {applyMeth};\"", " def matchesMeth = applyMeth.replace \"applyMeth\" with \"matchesMeth\"", " def matchesMethName = \"matches({nParams})\"", " if (nParams > 0) then {", " out \"let {matchesMeth} = function matches_{nParams} (argcv, ...args) \\{\"", " out \" return this.guard.apply(this.receiver, args) ? GraceTrue : GraceFalse;\"", " out \"\\};\"", " compileMetadata(o, matchesMeth, matchesMethName)", " out \"{blockId}.methods[\\\"{matchesMethName}\\\"] = {matchesMeth};\"", " }", " o.register := blockId", " restoreInitializedVars(oldInitializedVars)", " inBlock := origInBlock", "}", "method compiletypedec(o) in (obj) {", " // We compile type declarations as once methods. This allows the declarations", " // to appear in any order. Compiling them as defs won't work for types", " // with type parameters, or for types that are used before they are declared", " // (as must happen for mutually-recursive types)", "", " def s = o.scope", " def originalNode = s.node", " var reg := uidWithPrefix \"type\"", " def tName = o.nameString", " out \"// Type decl {tName}\"", " def rhs = o.value", " if (rhs.isInterface) then { rhs.name := tName }", " def typeMethod = ast.methodDec(", " [ast.signaturePart(o.nameString) params [].setScope(s)],", " typeFunBody (rhs) named (tName), ast.unknownLiteral, []).setScope(s)", " // Why do we make the type Unknown, rather than Type? Because the", " // latter will compile a check that the return value is indeed a type,", " // which causes a circularity. The check is subsumed by a call to", " // `isType` in the body of `setTypeName`", " typeMethod.isOnceMethod := true", " typeMethod.withTypeParams(o.typeParams)", " s.node := originalNode // gct generation will scan the ast after code is generated", " def typeFun = compilenode(typeMethod)", " o.register := reg", " reg", "}", "method typeFunBody(typeExpr) named (tName) {", " if (typeExpr.kind == \"op\") then {", " // this guard prevents us from renaming the rhs in decls like type A⟦T⟧ = B⟦T⟧", " [ ast.request(", " typeExpr,", " [ast.requestPart \"setTypeName\"", " withArgs[ ast.stringLiteral(tName) ] ]", " ).onSelf ]", " } else {", " [ typeExpr ]", " }", "}", "method compileinterfaceliteral(o) in (obj) {", " def reg = uidWithPrefix \"iface\"", " o.register := reg", " def escName = escapestring(o.name)", " out \"// interface literal \"", " out \"var {reg} = new GraceInterface(\\\"{escName}\\\");\"", " compileMethodsForInterface(o)", " reg", "}", "", "method compileMethodsForInterface(o) {", " def reg = o.register", " if (o.methods.anySatisfy { each -> each.kind == \"ellipsis\" }) then {", " out \"Object.defineProperty({reg}, 'typeMethods', \\{ get: ellipsisFun \\});\"", " } else {", " o.methods.do { meth -> compileSignature(meth) }", " out \"{reg}.typeMethods = \\{\"", " increaseindent", " var sep := \" \"", " o.methods.do { meth ->", " out \"{sep}\\\"{meth.nameString.quoted}\\\": {meth.register}\"", " if (\" \" == sep) then { sep := \", \" }", " }", " decreaseindent", " out \"};\"", " }", " if (o.hasTypeParams) then {", " out \"{reg}.typeParams = [{stringList(o.typeParams.map {p -> p.nameString})}];\"", " }", "}", "", "method compileSignature(m) {", " def reg = uidWithPrefix \"sig\"", " out \"{reg} = ({withoutComma(typeParamlist(m))}) => \\{\"", " increaseindent", " m.parameterTypes.do { each -> compilenode(each) }", " compilenode(m.decType)", " out (\"return new GraceSignature(\\\"{m.nameString.quoted}\\\",\" ++", " \" {stringList(m.parameterNames)},\" ++", " \" {stringList(m.typeParameterNames)},\" ++", " \" {literalList(m.parameterTypes.map { each -> each.register })},\" ++", " \" {m.decType.register});\")", " decreaseindent", " out \"}\"", "", " m.register := reg", " reg", "}", "", "method compileMethodPreamble(o, funcName, name) withParams (p) {", " out \"var {funcName} = function(argcv{p}) \\{ // method {name}, line {o.line}\"", " increaseindent", " out \"var returnTarget = invocationCount;\"", " out \"invocationCount++;\"", "}", "", "method compileMethodPostamble(o, funcName, name) {", " decreaseindent", " out \"\\}; // end of method {name}\"", " compilemethodtypes(funcName, o)", " if (o.isConfidential) then {", " out \"{funcName}.confidential = true;\"", " }", "}", "", "method compileParameterDebugFrame(o, name) {", " if (debugMode) then {", " out \"var myframe = new StackFrame(\\\"{name}\\\");\"", " for (o.signatureParts) do { part ->", " for (part.params) do { p ->", " def pName = p.nameString", " def varName = varf(pName)", " out \"myframe.addVar(\\\"{escapestring(pName)}\\\",\"", " out \" function() \\{return {varName};});\"", " }", " }", " }", "}", "", "method compileDefaultsForTypeParameters(o) extraParams (extra) {", " def tps = o.typeParams", " if (false ≠ tps) then {", " o.typeParams.do { g->", " def gName = varf(g.value)", " out \"if (! {gName}) {gName} = type_Unknown;\"", " }", " }", " if (emitArgChecks) then {", " def correction = if (extra == 0) then { \"1\" } else { \"{extra + 1}\" }", " // 1 for argcv, and extra for the arguments to $build methods", " out \"const numArgs = arguments.length - {correction};\"", " def np = o.numParams", " def ntp = o.numTypeParams", " def s = if (ntp == 1) then { \"\" } else { \"s\" }", " out \"if ((numArgs > {np}) && (numArgs !== {np + ntp})) \\{\"", " out \" raiseTypeArgError(\\\"{o.canonicalName}\\\", {ntp}, numArgs - {np});\"", " out \"\\}\"", " }", "}", "", "method compileArgumentTypeChecks(o) {", " if ( emitTypeChecks.not ) then { return }", " if (o.numParams == 1) then {", " def p = o.signatureParts.first.params.first", " def pName = p.value", " compileCheckThat (varf(pName))", " called \"argument to request of `{o.canonicalName}`\"", " hasType (p.dtype) onLine 0", " } else {", " var paramnr := 0", " o.parametersDo { p ->", " paramnr := paramnr + 1", " def pName = p.value", " compileCheckThat (varf(pName))", " called \"argument {paramnr} in request of `{o.canonicalName}`\"", " hasType (p.dtype) onLine 0", " // the line number is 0, because we want the error message to", " // refer to the call site, not the method definition.", " }", " }", "}", "method debugModePrefix {", " if (debugMode) then {", " out \"stackFrames.push(myframe);\"", " out(\"try \\{\")", " increaseindent", " }", "}", "method debugModeSuffix {", " if (debugMode) then {", " decreaseindent", " out \"\\} finally \\{\"", " out \" stackFrames.pop();\"", " out \"\\}\"", " }", "}", "method compileMethodBodyWithTypecheck(o) {", " def ret = compileMethodBody(o)", " def ln = if (o.body.isEmpty) then { o.end.line } else { o.resultExpression.line }", " compileCheckThat(ret) called \"result of method {o.canonicalName}\"", " hasType (o.decType) onLine (ln)", " ret", "}", "", "method compileFreshMethod(o, outerRef) {", " // compiles the methodNode o in a way that can be used with an `inherit`", " // statement. _Two_ methods are generated: one to build the new object,", " // and one to initialize it. The build method will also implement", " // the statements in the body of this method that preceed the final", " // (result) expression.", " // The final (result) expression of method o may be of two kinds:", " // (1) an object constructor,", " // (2) a request on another fresh method (which will return its init function).", "", " def resultExpr = o.resultExpression", " if (resultExpr.isObject) then { // case (1)", " compileBuildMethodFor(o) withObjCon (resultExpr) inside (outerRef)", " } else { // case (2)", " compileBuildMethodFor(o) withFreshCall (resultExpr) inside (outerRef)", " }", " return \"GraceDone\"", "}", "", "method compileMethodBody(methNode) {", " // compiles the body of method represented by methNode.", " // answers the register containing the result.", "", " var ret := \"GraceDone\"", " methNode.body.do { nd -> ret := compilenode(nd) }", " ret", "}", "", "method compileMethodBodyWithoutLast(methNode) {", " def body = methNode.body", " if (body.size > 1) then {", " def resultExpr = body.removeLast // remove result object", " compileMethodBody(methNode)", " body.addLast(resultExpr) // put result object back", " }", "}", "", "method stringList(strs) {", " // answers the contents of the collection strs of strings quoted", " // and between brackets.", " var res := \"[\"", " strs.do { s -> res := res ++ \"\\\"\" ++ s.quoted ++ \"\\\"\"}", " separatedBy { res := res ++ \", \" }", " res ++ \"]\"", "}", "", "method literalList(lits) {", " // answers the contents of the collection lits between brackets.", " var res := \"[\"", " lits.do { n -> res := res ++ n.asString }", " separatedBy { res := res ++ \", \" }", " res ++ \"]\"", "}", "", "method compileMetadata(o, funcName, name) {", " out \"{funcName}.methodName = \\\"{name}\\\";\"", " out \"{funcName}.paramCounts = {literalList(o.parameterCounts)};\"", " out \"{funcName}.paramNames = {stringList(o.parameterNames)};\"", " if (o.hasTypeParams) then {", " out \"{funcName}.typeParamNames = {stringList(o.typeParameterNames)};\"", " }", " out \"{funcName}.definitionLine = {o.line};\"", " out \"{funcName}.definitionModule = {modNameAsString};\"", "}", "", "method compilemethodnode(o) in (objref) {", " def oldusedvars = usedvars", " def olddeclaredvars = declaredvars", " def oldInitializedVars = saveInitializedVars", " clearLineNumber(o.line)", " o.register := uidWithPrefix \"func\"", " if (isSimpleAccessor(o)) then {", " compileSimpleAccessor(o)", " } elseif { o.isAbstract } then {", " compileDummyMethod(o, objref, \"abstract\")", " } elseif { o.isRequired } then {", " compileDummyMethod(o, objref, \"required\")", " } elseif { o.isAnnotationDecl } then {", " compileDummyAnnotationMethod(o, objref)", " } else {", " compileNormalMethod(o, objref)", " }", " usedvars := oldusedvars", " declaredvars := olddeclaredvars", " restoreInitializedVars(oldInitializedVars)", "}", "", "method isSimpleAccessor(o) {", " if (o.body.size ≠ 1) then { return false }", " if (o.isOnceMethod) then { return false }", " if (o.hasTypeParams) then { return false }", " if (o.hasParams) then { return false }", " if (o.decType.isUnknownType.not) then { return false }", " // to ensure that we compile a type check for the method's return type", " o.body.first.isIdentifier", "}", "", "method compileSimpleAccessor(o) {", " def oldEmitPositions = emitPositions", " emitPositions := false", " def canonicalMethName = o.canonicalName", " def funcName = o.register", " def name = escapestring(o.nameString)", " def ident = o.body.first", " def p = paramlist(o) ++ typeParamlist(o)", " out \"var {funcName} = function(argcv{p}) \\{ // accessor method {canonicalMethName}, line {o.line}\"", " increaseindent", " if (emitArgChecks) then {", " out \"const numArgs = arguments.length - 1;\"", " def np = o.numParams", " out \"if (numArgs > {np}) raiseTypeArgError(\\\"{canonicalMethName}\\\", 0, numArgs - {np});\"", " }", " out \"return {compilenode(ident)};\"", " compileMethodPostamble(o, funcName, canonicalMethName)", " out \"this.methods[\\\"{name}\\\"] = {funcName};\"", " compileMetadata(o, funcName, name)", " emitPositions := oldEmitPositions", "}", "", "method compileNormalMethod(o, selfobj) {", " def canonicalMethName = o.canonicalName", " def funcName = o.register", " priorLineEmitted := 0", " usedvars := list []", " declaredvars := list []", " def name = escapestring(o.nameString)", " compileMethodPreamble (o, funcName, canonicalMethName)", " withParams (paramlist(o) ++ typeParamlist(o))", " compileParameterDebugFrame(o, name)", " if (o.isOnceMethod.not) then {", " // it o is a once method, we compile the defaults in the wrapper", " compileDefaultsForTypeParameters(o) extraParams 0", " }", " compileArgumentTypeChecks(o)", " debugModePrefix", " if (o.isFresh) then {", " def argList = paramlist(o)", " def typeArgList = typeParamlist(o)", " out \"var ouc = emptyGraceObject(\\\"{o.ilkName}\\\", {modNameAsString}, {o.line});\"", " out \"var ouc_init = {selfobj}.methods[\\\"{name}$build(3)\\\"].call(this, null{argList}, ouc, [], []{typeArgList});\"", " out \"ouc_init.call(ouc);\"", " compileCheckThat \"ouc\" called \"object returned from {o.canonicalName}\"", " hasType (o.dtype) onLine (o.end.line);", " out \"return ouc;\"", " } else {", " def result = compileMethodBodyWithTypecheck(o)", " if (\"never returns\" ≠ result) then {", " out \"return {result};\"", " }", " }", " debugModeSuffix", " compileMethodPostamble(o, funcName, canonicalMethName)", " if (o.isOnceMethod) then {", " compileOnceWrapper(o, selfobj, name)", " } else {", " out \"{selfobj}.methods[\\\"{name}\\\"] = {funcName};\"", " }", " compileMetadata(o, funcName, name)", " if (o.isFresh) then {", " compileFreshMethod(o, selfobj)", " }", "}", "", "method compileOnceWrapper(o, selfobj, name) {", " def totalParams = o.numParams + o.numTypeParams", " def funcName = o.register", " def memoFuncName = \"memo\" ++ funcName", " if ( totalParams == 0 ) then {", " out \"function {memoFuncName}(argcv) \\{\"", " out \" if (! this.data[\\\"memo${name}\\\"]) // parameterless memo function\"", " out \" this.data[\\\"memo${name}\\\"] = {funcName}.call(this, argcv);\"", " out \" return this.data[\\\"memo${name}\\\"];\"", " out \"\\};\"", " } else {", " def commaParamNames = paramlist(o) ++ typeParamlist(o);", " def paramNames = withoutComma(commaParamNames)", " out \"function {memoFuncName}(argcv{commaParamNames}) \\{\"", " increaseindent", " compileDefaultsForTypeParameters(o) extraParams 0", " out \"let memoTable = this.data[\\\"memo${name}\\\"] ||\"", " out \" ( this.data[\\\"memo${name}\\\"] =\"", " out \" request(var_HashMap, 'empty', [0]) );\"", " if (totalParams == 1) then {", " out \"let tableKey = {paramNames};\"", " } else {", " out \"let tableKey = new GraceSequence([{paramNames}]);\"", " }", " out \"let absentBlock = new GraceBlock(this, {o.line}, 0);\"", " out \"absentBlock.guard = jsTrue;\"", " out \"absentBlock.real = function ifAbsentBlock() \\{\"", " out \" let newResult = {funcName}.call(this, argcv{commaParamNames});\"", " out \" request(memoTable, 'at(1)put(1)', [1,1], tableKey, newResult);\"", " out \" return newResult;\"", " out \"\\};\"", " out \"absentBlock.methods.apply = function apply (argcv) \\{\"", " out \" return this.real.apply(this.receiver);\"", " out \"\\};\"", " out \"return request(memoTable, 'at(1)ifAbsent(1)', [1,1], tableKey, absentBlock);\"", " decreaseindent", " out \"\\};\"", " }", " out \"{selfobj}.methods[\\\"{name}\\\"] = {memoFuncName};\"", " compileMetadata(o, memoFuncName, name)", "}", "", "method compileDummyMethod(o, selfobj, kind) {", " def canonicalMethName = o.canonicalName", " def funcName = o.register", " priorLineEmitted := 0", " def name = escapestring(o.nameString)", " out \"if (! {selfobj}.methods[\\\"{name}\\\"]) \\{\"", " increaseindent", " compileMethodPreamble (o, funcName, canonicalMethName)", " withParams (paramlist(o) ++ typeParamlist(o))", " compileParameterDebugFrame(o, name)", " compileDefaultsForTypeParameters(o) extraParams 0", " compileArgumentTypeChecks(o)", " noteLineNumber (o.line) comment \"{kind} method\"", " debugModePrefix", " out \"throw new GraceExceptionPacket(ProgrammingErrorObject,\"", " out \" new GraceString(\\\"{kind} method {canonicalMethName} \\\" +\"", " out \" \\\"was not supplied for \\\" + safeJsString(this)));\"", " debugModeSuffix", " compileMethodPostamble(o, funcName, canonicalMethName)", " out \"{selfobj}.methods[\\\"{name}\\\"] = {funcName};\"", " compileMetadata(o, funcName, name)", " decreaseindent", " out \"\\};\"", "}", "method compileDummyAnnotationMethod(o, selfobj) {", " def canonicalMethName = o.canonicalName", " def funcName = o.register", " priorLineEmitted := 0", " def name = escapestring(o.nameString)", " compileMethodPreamble (o, funcName, canonicalMethName)", " withParams (paramlist(o) ++ typeParamlist(o))", " compileParameterDebugFrame(o, name)", " noteLineNumber (o.line) comment \"annotation method\"", " debugModePrefix", " out \"raiseException(ProgrammingErrorObject,\"", " out \" \\\"{canonicalMethName} is an annotation; it cannot be requested as a method\\\");\"", " debugModeSuffix", " compileMethodPostamble(o, funcName, canonicalMethName)", " out \"{selfobj}.methods[\\\"{name}\\\"] = {funcName};\"", " compileMetadata(o, funcName, name)", "}", "method compileBuildMethodFor(methNode) withObjCon (objNode) inside (outerRef) {", " // the $build method for a fresh method executes the statements in the", " // body of the fresh method, and then calls the build function of the", " // object constructor. That build function will return the _init function", " // for the object expression that it tail-returns.", "", " def funcName = uidWithPrefix \"func\"", " def name = escapestring(methNode.nameString ++ \"$build(3)\")", " def cName = methNode.canonicalName ++ \"$build(_,_,_)\"", " def params = paramlist(methNode)", " def typeParams = typeParamlist(methNode)", " compileMethodPreamble (methNode, funcName, cName)", " withParams (params ++ \", inheritingObject, aliases, exclusions\" ++ typeParams)", " compileDefaultsForTypeParameters(methNode) extraParams 3", " compileArgumentTypeChecks(methNode)", " compileMethodBodyWithoutLast(methNode)", " compileBuildAndInitFunctions(objNode) inMethod (methNode)", " def objRef = objNode.register", " out \"var {objRef}_init = {objRef}_build.call(inheritingObject, null{params}, {outerRef}, aliases, exclusions{typeParams});\"", " out \"return {objRef}_init; // from compileBuildMethodFor(_)withObjCon(_)inside(_)\"", " compileMethodPostamble(methNode, funcName, cName)", " out \"this.methods[\\\"{name}\\\"] = {funcName};\"", " compileMetadata(methNode, funcName, name)", "}", "method compileBuildMethodFor(methNode) withFreshCall (callExpr) inside (outerRef) {", " // The build method will have three additional parameters:", " // `inheritingObject`, `aliases`, and `exclusions`. These", " // will be passed to it by the `inherit` statement.", "", " def funcName = uidWithPrefix \"func\"", " def name = escapestring(methNode.nameString ++ \"$build(3)\")", " def cName = escapestring(methNode.canonicalName ++ \"$build(_,_,_)\")", " compileMethodPreamble(methNode, funcName, cName)", " withParams( paramlist(methNode) ++ \", ouc, aliases, exclusions\")", " compileMethodBodyWithoutLast(methNode)", "", " // Now compile the call, with the three aditional arguments.", " // TODO: refactor compilecall so that it can handle this case, as well as", " // normal calls.",