firefly-compiler 0.5.79 → 0.5.80

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (105) hide show
  1. package/compiler/Builder.ff +31 -39
  2. package/compiler/Compiler.ff +14 -4
  3. package/compiler/DevelopMode.ff +406 -0
  4. package/compiler/Main.ff +73 -53
  5. package/compiler/ModuleCache.ff +5 -5
  6. package/core/.firefly/include/package.json +1 -1
  7. package/core/BuildSystem.ff +82 -11
  8. package/core/NodeSystem.ff +47 -30
  9. package/core/Path.ff +7 -2
  10. package/experimental/proxy/Main.ff +60 -0
  11. package/experimental/proxy/Runner.ff +11 -0
  12. package/experimental/proxy/Tcp.ff +162 -0
  13. package/experimental/random/Superdigit.ff +18 -0
  14. package/experimental/terrain/Main.ff +40 -0
  15. package/experimental/terrain/Terrain.ff +97 -0
  16. package/experimental/terrain/Terrain2.ff +109 -0
  17. package/fireflysite/Main.ff +0 -1
  18. package/fireflysite/assets/markdown/reference/statements-and-expressions.md +1 -1
  19. package/lsp/CompletionHandler.ff +2 -2
  20. package/output/js/ff/compiler/Builder.mjs +24 -48
  21. package/output/js/ff/compiler/Builder.mjs.map +7 -11
  22. package/output/js/ff/compiler/Compiler.mjs +66 -12
  23. package/output/js/ff/compiler/Compiler.mjs.map +18 -14
  24. package/output/js/ff/compiler/Dependencies.mjs.map +2 -2
  25. package/output/js/ff/compiler/DependencyLock.mjs.map +1 -1
  26. package/output/js/ff/compiler/Deriver.mjs.map +1 -1
  27. package/output/js/ff/compiler/DevelopMode.mjs +1049 -0
  28. package/output/js/ff/compiler/DevelopMode.mjs.map +183 -0
  29. package/output/js/ff/compiler/Dictionaries.mjs.map +1 -1
  30. package/output/js/ff/compiler/Environment.mjs.map +1 -1
  31. package/output/js/ff/compiler/Inference.mjs.map +1 -1
  32. package/output/js/ff/compiler/JsEmitter.mjs.map +1 -1
  33. package/output/js/ff/compiler/JsImporter.mjs.map +1 -1
  34. package/output/js/ff/compiler/LspHook.mjs.map +1 -1
  35. package/output/js/ff/compiler/Main.mjs +256 -105
  36. package/output/js/ff/compiler/Main.mjs.map +43 -38
  37. package/output/js/ff/compiler/ModuleCache.mjs +12 -8
  38. package/output/js/ff/compiler/ModuleCache.mjs.map +4 -3
  39. package/output/js/ff/compiler/Parser.mjs.map +1 -1
  40. package/output/js/ff/compiler/Patterns.mjs.map +1 -1
  41. package/output/js/ff/compiler/Resolver.mjs.map +1 -1
  42. package/output/js/ff/compiler/SourceMap.mjs.map +1 -1
  43. package/output/js/ff/compiler/Substitution.mjs.map +1 -1
  44. package/output/js/ff/compiler/Syntax.mjs.map +1 -1
  45. package/output/js/ff/compiler/Token.mjs.map +1 -1
  46. package/output/js/ff/compiler/Tokenizer.mjs.map +1 -1
  47. package/output/js/ff/compiler/Unification.mjs.map +1 -1
  48. package/output/js/ff/compiler/Wildcards.mjs.map +1 -1
  49. package/output/js/ff/compiler/Workspace.mjs.map +1 -1
  50. package/output/js/ff/core/Any.mjs.map +1 -1
  51. package/output/js/ff/core/Array.mjs.map +1 -1
  52. package/output/js/ff/core/AssetSystem.mjs.map +1 -1
  53. package/output/js/ff/core/Atomic.mjs.map +1 -1
  54. package/output/js/ff/core/Bool.mjs.map +1 -1
  55. package/output/js/ff/core/BrowserSystem.mjs.map +1 -1
  56. package/output/js/ff/core/Buffer.mjs.map +1 -1
  57. package/output/js/ff/core/BuildSystem.mjs +116 -12
  58. package/output/js/ff/core/BuildSystem.mjs.map +35 -6
  59. package/output/js/ff/core/Channel.mjs.map +1 -1
  60. package/output/js/ff/core/Char.mjs.map +1 -1
  61. package/output/js/ff/core/Core.mjs.map +1 -1
  62. package/output/js/ff/core/Crypto.mjs.map +1 -1
  63. package/output/js/ff/core/Date.mjs.map +1 -1
  64. package/output/js/ff/core/Duration.mjs.map +1 -1
  65. package/output/js/ff/core/Equal.mjs.map +1 -1
  66. package/output/js/ff/core/Error.mjs.map +1 -1
  67. package/output/js/ff/core/FileHandle.mjs.map +1 -1
  68. package/output/js/ff/core/Float.mjs.map +1 -1
  69. package/output/js/ff/core/HttpClient.mjs.map +1 -1
  70. package/output/js/ff/core/Int.mjs.map +1 -1
  71. package/output/js/ff/core/IntMap.mjs.map +1 -1
  72. package/output/js/ff/core/Js.mjs.map +1 -1
  73. package/output/js/ff/core/JsSystem.mjs.map +1 -1
  74. package/output/js/ff/core/JsValue.mjs.map +1 -1
  75. package/output/js/ff/core/Json.mjs.map +1 -1
  76. package/output/js/ff/core/List.mjs.map +1 -1
  77. package/output/js/ff/core/Lock.mjs.map +1 -1
  78. package/output/js/ff/core/Log.mjs.map +1 -1
  79. package/output/js/ff/core/Map.mjs.map +1 -1
  80. package/output/js/ff/core/NodeSystem.mjs +54 -20
  81. package/output/js/ff/core/NodeSystem.mjs.map +14 -6
  82. package/output/js/ff/core/Nothing.mjs.map +1 -1
  83. package/output/js/ff/core/Option.mjs.map +1 -1
  84. package/output/js/ff/core/Ordering.mjs.map +1 -1
  85. package/output/js/ff/core/Pair.mjs.map +1 -1
  86. package/output/js/ff/core/Path.mjs +30 -4
  87. package/output/js/ff/core/Path.mjs.map +8 -6
  88. package/output/js/ff/core/Queue.mjs.map +1 -1
  89. package/output/js/ff/core/Random.mjs.map +1 -1
  90. package/output/js/ff/core/RbMap.mjs.map +1 -1
  91. package/output/js/ff/core/Serializable.mjs.map +1 -1
  92. package/output/js/ff/core/Set.mjs.map +1 -1
  93. package/output/js/ff/core/Show.mjs.map +1 -1
  94. package/output/js/ff/core/SourceLocation.mjs.map +1 -1
  95. package/output/js/ff/core/Stream.mjs.map +1 -1
  96. package/output/js/ff/core/String.mjs.map +1 -1
  97. package/output/js/ff/core/StringMap.mjs.map +1 -1
  98. package/output/js/ff/core/Task.mjs.map +1 -1
  99. package/output/js/ff/core/Try.mjs.map +1 -1
  100. package/output/js/ff/core/Unit.mjs.map +1 -1
  101. package/output/js/ff/core/node_modules +1 -0
  102. package/package.json +1 -1
  103. package/vscode/package.json +1 -1
  104. package/webserver/.firefly/include/package.json +1 -1
  105. package/webserver/WebServer.ff +6 -3
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": [
4
- "../../../../../compiler/JsEmitter.ff"
4
+ "../../../../compiler/JsEmitter.ff"
5
5
  ],
6
6
  "sourcesContent": [
7
7
  "import Syntax\r\nimport Patterns\r\nimport JsImporter\r\nimport SourceMap from ff:compiler\r\n\r\nclass JsEmitter(\r\n otherModules: Map[String, Module]\r\n jsImporter: JsImporter\r\n emitTarget: EmitTarget\r\n isMainModule: Bool\r\n compilerModuleFileUrl: Option[String]\r\n moduleKey: ModuleKey\r\n mutable emittingAsync: Bool\r\n mutable tailCallUsed: Bool\r\n mutable writtenColumn: Int\r\n writtenStrings: Array[Array[String]]\r\n writtenSegments: Array[Array[List[Int]]]\r\n writtenAnchors: IntMap[List[String]]\r\n writtenNames: StringMap[Int]\r\n)\r\n\r\ndata EmitTarget {\r\n EmitNode\r\n EmitBrowser\r\n EmitBuild\r\n EmitExecutable\r\n}\r\n\r\nnew(\r\n otherModules: List[Module]\r\n emitTarget: EmitTarget\r\n isMainModule: Bool\r\n compilerModuleFileUrl: Option[String]\r\n moduleKey: ModuleKey\r\n): JsEmitter {\r\n JsEmitter(\r\n otherModules = otherModules.map {m =>\r\n Pair(m.moduleKey.qualifiedName(), m)\r\n }.toMap()\r\n jsImporter = JsImporter.new()\r\n emitTarget = emitTarget\r\n isMainModule = isMainModule\r\n compilerModuleFileUrl = compilerModuleFileUrl\r\n moduleKey = moduleKey\r\n emittingAsync = False\r\n tailCallUsed = False\r\n writtenColumn = 0\r\n writtenStrings = [[].toArray()].toArray()\r\n writtenSegments = [[].toArray()].toArray()\r\n writtenAnchors = IntMap.new()\r\n writtenNames = StringMap.new()\r\n )\r\n}\r\n\r\nfail[T](at: Location, message: String): T {\r\n throw(CompileError(at, message))\r\n}\r\n\r\nextend self: JsEmitter {\r\n \r\n writeUnmapped(text: String) {\r\n self.writtenStrings.grabLast().push(text)\r\n self.writtenSegments.grabLast().push(\r\n [self.writtenColumn]\r\n )\r\n self.writtenColumn += text.size()\r\n }\r\n\r\n writeMapped(at: Location, text: String) {\r\n self.writtenStrings.grabLast().push(text)\r\n self.writtenSegments.grabLast().push(\r\n [self.writtenColumn, 0, at.line - 1, at.column - 1]\r\n )\r\n self.writtenColumn += text.size()\r\n }\r\n\r\n writeNamed(name: String, at: Location, text: String) {\r\n let unqualified = name.reverse().takeWhile {c => c != '.' && c != '_'}.reverse()\r\n let nameIndex = self.writtenNames.getOrSet(unqualified) {self.writtenNames.size()}\r\n self.writtenStrings.grabLast().push(text)\r\n self.writtenSegments.grabLast().push(\r\n [self.writtenColumn, 0, at.line - 1, at.column - 1, nameIndex]\r\n )\r\n self.writtenColumn += text.size()\r\n }\r\n \r\n writeLine() {\r\n self.writtenStrings.push(Array.new())\r\n self.writtenSegments.push(Array.new())\r\n self.writtenColumn = 0\r\n }\r\n \r\n writeAnchor(): Int {\r\n self.writtenStrings.size() - 1\r\n }\r\n \r\n writeAnchorLines(anchor: Int, lines: List[String]) {\r\n if(self.writtenAnchors.has(anchor)) {\r\n self.writtenAnchors.set(anchor, [...self.writtenAnchors.grab(anchor), ...lines])\r\n } else {\r\n self.writtenAnchors.set(anchor, lines)\r\n }\r\n }\r\n \r\n makeOutput(): String {\r\n SourceMap.makeOutput(\r\n self.writtenStrings, self.writtenAnchors\r\n )\r\n }\r\n \r\n makeOutputAndSourceMap(fireflyFile: String, fireflySource: Option[String]): Pair[String, Json] {\r\n SourceMap.makeOutputAndSourceMap(\r\n fireflyFile\r\n fireflySource\r\n self.writtenStrings\r\n self.writtenSegments\r\n self.writtenAnchors\r\n self.writtenNames\r\n )\r\n }\r\n \r\n emitModule(module: Module) {\r\n let selfImport = self.emitImport(self.moduleKey)\r\n let imports = [\r\n self.compilerModuleFileUrl.map {\"import * as $firefly_compiler from '\" + _ + \"'\"}.toList()\r\n module.imports.sortBy {_.moduleKey}.map {self.emitImport(_.moduleKey)}\r\n ].flatten()\r\n let liner = Liner(self, True)\r\n if(!imports.any {_ == selfImport}) {\r\n liner.writeLines()\r\n self.writeUnmapped(selfImport)\r\n }\r\n imports.each {import =>\r\n liner.writeLines()\r\n self.writeUnmapped(import)\r\n }\r\n let anchor = self.writeAnchor()\r\n module.types.each {\r\n liner.writeLines()\r\n self.emitTypeDefinition(_)\r\n }\r\n module.lets.each {\r\n liner.writeLines()\r\n self.writeUnmapped(\"export \")\r\n self.emitLetDefinition(_, False, False)\r\n }\r\n module.functions.each {\r\n liner.writeLines()\r\n self.writeUnmapped(\"export \")\r\n self.emitFunctionDefinition(_, False)\r\n }\r\n self.withEmittingAsync {\r\n module.functions.each {\r\n liner.writeLines()\r\n self.writeUnmapped(\"export \")\r\n self.emitFunctionDefinition(_, True)\r\n }\r\n }\r\n module.extends.each {\r\n liner.writeLines()\r\n self.emitExtendsDefinition(_)\r\n }\r\n module.instances.each {\r\n liner.writeLines()\r\n self.emitInstanceDefinition(_)\r\n }\r\n let ignoreJsImports = if(self.emitTarget == EmitExecutable && self.moduleKey.packagePair.isCore()) {\r\n [\"esbuild\"]\r\n } else {\r\n []\r\n }\r\n let jsImports = self.jsImporter.generateImports(ignoreJsImports.toSet())\r\n if(!jsImports.isEmpty()) {\r\n self.writeAnchorLines(anchor, jsImports)\r\n }\r\n }\r\n\r\n emitImport(moduleKey: ModuleKey): String {\r\n let dots = \"../\".repeat(self.moduleKey.folders.size() + 2)\r\n let jsImportName = moduleKey.packagePair.groupName(\"_\") + \"_\" + \r\n moduleKey.folders.map {_ + \"_\"}.join() + moduleKey.name\r\n let jsImportFrom = dots + moduleKey.packagePair.groupName(\"/\") + \"/\" + \r\n moduleKey.folders.map {_ + \"/\"}.join() + moduleKey.name + \".mjs\"\r\n \"import * as \" + jsImportName + \" from \\\"\" + jsImportFrom + \"\\\"\"\r\n }\r\n \r\n withEmittingAsync[T](body: () => T): T {\r\n try {\r\n self.emittingAsync = True\r\n body()\r\n } finally {\r\n self.emittingAsync = False\r\n }\r\n }\r\n\r\n makeRun(moduleName: String, functions: List[DFunction], mainPackagePair: PackagePair, bootstrapping: Bool): List[String] {\r\n let buildMainFunction = functions.find {_.signature.name == \"buildMain\"}.filter {_ =>\r\n self.emitTarget != EmitBrowser && self.emitTarget != EmitExecutable\r\n }\r\n let willRunOnNode = self.emitTarget != EmitBrowser\r\n let targetMain = if(willRunOnNode) {\"nodeMain\"} else {\"browserMain\"}\r\n let mainFunction =\r\n functions.find {_.signature.name == targetMain}.orElse {functions.find {_.signature.name == \"main\"}}\r\n mainFunction.map {_.signature.name}.map {mainName => [[\r\n ...buildMainFunction.map {buildMain =>\r\n \"import {\" + escapeKeyword(buildMain.signature.name) + \"$} from './\" + moduleName + \".mjs'\"\r\n }.toList()\r\n \"import {\" + escapeKeyword(mainName) + \"$} from './\" + moduleName + \".mjs'\"\r\n \"export async function $run$(fireflyPath_, arguments_) {\"\r\n \"Error.stackTraceLimit = 50\"\r\n \"const $task = {controller_: new AbortController(), subtasks_: new Set(), promise_: new Promise(() => {}), started_: performance.now() * 0.001}\"\r\n ...if(self.emitTarget != EmitBrowser) {[\r\n \"let interval = setInterval(() => {}, 24 * 60 * 60 * 1000)\" // To prevent deadlocks from exiting node\r\n ]} else {[]}\r\n \"let system = {\"\r\n \"task_: $task,\"\r\n \"array_: arguments_,\"\r\n \"fireflyPath_: fireflyPath_,\"\r\n \"mainPackagePair_: {group_: \\\"\" + mainPackagePair.group + \"\\\", name_: \\\"\" + mainPackagePair.name + \"\\\"},\"\r\n \"executableMode_: \" + if(self.emitTarget == EmitExecutable) {\"true\"} else {\"false\"} + \",\"\r\n \"buildMode_: \" + if(self.emitTarget == EmitBuild) {\"true\"} else {\"false\"}\r\n \"}\"\r\n \"try {\"\r\n ...if(!buildMainFunction.isEmpty()) {[\r\n \"await buildMain_$(system, $task)\"]\r\n } else {[]}\r\n ...if(self.emitTarget != EmitBuild) {[\r\n \"await \" + mainName + \"_$(system, $task)\"\r\n ]} else {[]}\r\n ...if(self.emitTarget == EmitBuild) {[\r\n \"await $firefly_compiler.internalCreateExecutable_$(system, '.firefly/output/executable/Main.bundle.js', '.firefly/output', ['host'], system.assets_, $task)\"\r\n ]} else {[]}\r\n \"} finally {\"\r\n ...if(self.emitTarget != EmitBrowser) {[\r\n \"$task.controller_.abort()\"\r\n \"clearInterval(interval)\"\r\n ]} else {[]}\r\n \"}\"\r\n \"}\"\r\n ...self.emitTarget.{\r\n | EmitBrowser => [\r\n \"queueMicrotask(async () => {\"\r\n \"await $run$(null, [])\"\r\n \"})\"\r\n ]\r\n | EmitNode {bootstrapping} => [\r\n \"import * as path from 'node:path'\"\r\n \"queueMicrotask(async () => {\"\r\n \"let fireflyPath_ = path.dirname(path.dirname(path.dirname(path.dirname(path.dirname(process.argv[1])))))\"\r\n \"await $run$(fireflyPath_, process.argv.slice(2))\"\r\n \"})\"\r\n ]\r\n | EmitExecutable => [\r\n \"queueMicrotask(async () => {\"\r\n \"await $run$(null, process.argv.slice(2))\"\r\n \"})\"\r\n ]\r\n | _ => []\r\n }\r\n ].join(\"\\n\")]}.else {[]}\r\n }\r\n\r\n emitLetDefinition(definition: DLet, mutable: Bool, async: Bool) {\r\n self.writeMapped(definition.at, if(mutable) {\"let \"} else {\"const \"})\r\n self.writeNamed(definition.name, definition.at, escapeKeyword(definition.name))\r\n self.writeMapped(definition.at, \" = \") // TODO: No = value when the right hand side would be (void 0)\r\n self.emitTerm(definition.value, async)\r\n self.writeMapped(definition.at, \";\")\r\n }\r\n\r\n emitExtendsDefinition(definition: DExtend) {\r\n let typeName = extractTypeName(definition.type).reverse().takeWhile {_ != '.'}.reverse()\r\n let methods = definition.methods.map {method =>\r\n method.DFunction(\r\n signature = method.signature.Signature(\r\n name = typeName + \"_\" + method.signature.name\r\n )\r\n )\r\n }\r\n let liner = Liner(self, True)\r\n methods.each {\r\n liner.writeLines()\r\n self.writeMapped(definition.at, \"export \")\r\n self.emitFunctionDefinition(_, False)\r\n }\r\n self.withEmittingAsync {methods.each {\r\n liner.writeLines()\r\n self.writeMapped(definition.at, \"export \")\r\n self.emitFunctionDefinition(_, True)\r\n }}\r\n }\r\n\r\n emitInstanceDefinition(definition: DInstance) {\r\n let name = makeDictionaryName(definition.traitName, firstTypeName(definition.typeArguments))\r\n definition.constraints.{\r\n | [] =>\r\n self.writeMapped(definition.at, \"export const \")\r\n self.writeNamed(name, definition.at, name)\r\n self.writeMapped(definition.at, \" = \")\r\n | constraints =>\r\n let dictionaries = constraints.map {c =>\r\n makeDictionaryName(c.name, firstTypeName(c.generics))\r\n }\r\n self.writeMapped(definition.at, \"export function \")\r\n self.writeNamed(name, definition.at, name)\r\n self.writeMapped(definition.at, \"(\" + dictionaries.join(\", \") + \") { return \")\r\n }\r\n self.writeMapped(definition.at, \"{\")\r\n self.writeLine()\r\n definition.methods.each {\r\n self.emitFunctionDefinition(_, False, asMethod = True)\r\n self.writeMapped(definition.at, \",\")\r\n self.writeLine()\r\n }\r\n self.withEmittingAsync {\r\n definition.methods.map {\r\n self.emitFunctionDefinition(_, True, asMethod = True)\r\n self.writeMapped(definition.at, \",\")\r\n self.writeLine()\r\n }\r\n }\r\n self.writeMapped(definition.at, \"}\")\r\n definition.constraints.{\r\n | [] => self.writeMapped(definition.at, \";\")\r\n | _ => self.writeMapped(definition.at, \"}\")\r\n }\r\n }\r\n\r\n emitFunctionDefinition(definition: DFunction, async: Bool, suffix: String = \"\", asMethod: Bool = False): Unit {\r\n self.emitSignature(definition.signature, async, suffix, asMethod)\r\n self.writeMapped(definition.at, \" {\")\r\n self.writeLine()\r\n definition.body.{\r\n | Lambda(_, effect, [matchCase]) {\r\n matchCase.patterns.all {\r\n | PVariable(_, None) => True\r\n | _ => False\r\n }\r\n } =>\r\n self.emitTailCall {self.emitStatements(matchCase.body, True, False, async)}\r\n | Lambda(_, effect, cases) =>\r\n Patterns.convertAndCheck(self.otherModules, cases) // TODO no type errors in emitter\r\n self.emitTailCall {\r\n let liner = Liner(self, False)\r\n definition.signature.parameters.each {p =>\r\n liner.writeLines()\r\n self.writeMapped(p.at, \"const \")\r\n self.writeNamed(p.name, p.at, p.name + \"_a\")\r\n self.writeMapped(p.at, \" = \")\r\n self.writeNamed(p.name, p.at, escapeKeyword(p.name))\r\n self.writeMapped(p.at, \";\")\r\n }\r\n let argumentTerms = definition.signature.parameters.map {p => \r\n {self.writeNamed(p.name, p.at, p.name + \"_a\")}\r\n }\r\n cases.pairs().each {| Pair(i, c) =>\r\n liner.writeLines()\r\n let lastCase = i == cases.size() - 1\r\n self.emitCase(argumentTerms, c, [], [], True, True, False, lastCase, async)\r\n }\r\n }\r\n }\r\n self.writeLine()\r\n self.writeMapped(definition.at, \"}\")\r\n }\r\n\r\n emitTailCall(body: () => Unit) {\r\n let outerTailCallUsed = self.tailCallUsed\r\n self.tailCallUsed = False\r\n let anchor = self.writeAnchor()\r\n body()\r\n let tailCallUsed = self.tailCallUsed\r\n self.tailCallUsed = outerTailCallUsed\r\n if(tailCallUsed) {\r\n self.writeAnchorLines(anchor, [\"_tailcall: for(;;) {\"])\r\n self.writeLine()\r\n self.writeUnmapped(\"return\")\r\n self.writeLine()\r\n self.writeUnmapped(\"}\")\r\n }\r\n }\r\n\r\n emitSignature(signature: Signature, async: Bool, suffix: String = \"\", asMethod: Bool = False): Unit {\r\n let prefix = if(async) {\"async \"} else {\"\"}\r\n let asyncSuffix = if(async) {\"$\"} else {\"\"}\r\n let fullPrefix = prefix + if(asMethod) {\"\"} else {\"function \"}\r\n self.writeMapped(signature.at, fullPrefix)\r\n self.writeNamed(signature.name, signature.at, escapeKeyword(signature.name) + suffix + asyncSuffix)\r\n\r\n self.writeMapped(signature.at, \"(\")\r\n let comma = Comma(self)\r\n \r\n signature.parameters.each {\r\n comma.writeComma()\r\n self.emitParameter(_, async)\r\n }\r\n signature.constraints.each {c =>\r\n comma.writeComma()\r\n self.writeMapped(c.at, makeDictionaryName(c.name, firstTypeName(c.generics)))\r\n }\r\n if(async) {\r\n comma.writeComma()\r\n self.writeMapped(signature.at, \"$task\")\r\n }\r\n\r\n self.writeMapped(signature.at, \")\")\r\n }\r\n\r\n emitParameter(parameter: Parameter, async: Bool) {\r\n self.writeNamed(parameter.name, parameter.at, escapeKeyword(parameter.name))\r\n parameter.default.each {e => \r\n self.writeMapped(e.at, \" = \")\r\n self.emitTerm(e, async) \r\n }\r\n }\r\n\r\n emitTypeDefinition(definition: DType) {\r\n if(definition.newtype) {\r\n self.writeMapped(definition.at, \"// newtype \" + definition.name)\r\n } else {\r\n self.writeMapped(definition.at, \"// type \" + definition.name)\r\n self.writeLine()\r\n let liner = Liner(self, double = False)\r\n definition.variants.each {\r\n liner.writeLines()\r\n self.emitVariantDefinition(definition, _)\r\n }\r\n }\r\n }\r\n\r\n emitVariantDefinition(typeDefinition: DType, definition: Variant) {\r\n let allFields = [...typeDefinition.commonFields, ...definition.fields]\r\n function emitFields() {\r\n let comma = Comma(self)\r\n allFields.each {f => \r\n comma.writeComma()\r\n self.writeNamed(f.name, f.at, escapeKeyword(f.name))\r\n }\r\n }\r\n function emitConstructor() {\r\n self.writeMapped(definition.at, \"export function \")\r\n self.writeNamed(definition.name, definition.at, definition.name)\r\n self.writeMapped(definition.at, \"(\")\r\n emitFields()\r\n self.writeMapped(definition.at, \") {\")\r\n self.writeLine()\r\n }\r\n if(allFields.isEmpty()) {\r\n self.writeMapped(definition.at, \"const \")\r\n self.writeNamed(definition.name, definition.at, definition.name + \"$\")\r\n self.writeMapped(definition.at, \" = {\")\r\n self.writeNamed(definition.name, definition.at, definition.name)\r\n self.writeMapped(definition.at, \": true};\")\r\n self.writeLine()\r\n emitConstructor()\r\n self.writeMapped(definition.at, \"return \")\r\n self.writeNamed(definition.name, definition.at, definition.name + \"$\")\r\n self.writeMapped(definition.at, \";\")\r\n self.writeLine()\r\n self.writeMapped(definition.at, \"}\")\r\n } elseIf {typeDefinition.variants.size() == 1} {\r\n emitConstructor()\r\n self.writeMapped(definition.at, \"return {\")\r\n emitFields()\r\n self.writeMapped(definition.at, \"};\")\r\n self.writeLine()\r\n self.writeMapped(definition.at, \"}\")\r\n } else {\r\n emitConstructor()\r\n self.writeMapped(definition.at, \"return {\")\r\n self.writeNamed(definition.name, definition.at, definition.name)\r\n self.writeMapped(definition.at, \": true, \")\r\n emitFields()\r\n self.writeMapped(definition.at, \"};\")\r\n self.writeLine()\r\n self.writeMapped(definition.at, \"}\")\r\n }\r\n }\r\n\r\n emitTerm(term: Term, async: Bool, ignored: Bool = False) {term.{\r\n | EString(at, value) {value.startsWith(\"\\\"\\\"\\\"\")} =>\r\n self.writeMapped(at, \"\\\"\" + \r\n value.dropFirst(3).dropLast(3).replace(\"\\r\", \"\\\\r\").replace(\"\\n\", \"\\\\n\").replace(\"\\\"\", \"\\\\\\\"\") + \r\n \"\\\"\")\r\n | EString(at, value) => \r\n self.writeMapped(at, value)\r\n | EChar(at, value) => \r\n self.writeMapped(at, charLiteralToNumber(value))\r\n | EInt(at, value) => \r\n self.writeMapped(at, value)\r\n | EFloat(at, value) =>\r\n self.writeMapped(at, value)\r\n | EVariable(at, name) => \r\n self.writeNamed(name, at, escapeResolved(name))\r\n | EList(at, _, items) =>\r\n self.emitList(at, items, async)\r\n | EVariant(at, \"ff:core/Bool.False\", _, _) =>\r\n self.writeMapped(at, \"false\")\r\n | EVariant(at, \"ff:core/Bool.True\", _, _) =>\r\n self.writeMapped(at, \"true\")\r\n | EVariant(at, \"ff:core/Unit.Unit\", _, _) =>\r\n self.writeMapped(at, \"(void 0)\")\r\n | EVariant(at, name, _, arguments) =>\r\n let newtype = self.processVariant(name)\r\n if(newtype) {\r\n self.emitArgument(at, arguments.grab().grabFirst(), async)\r\n } else {\r\n self.writeNamed(name, at, escapeResolved(name))\r\n self.writeMapped(term.at, \"(\")\r\n let comma = Comma(self)\r\n arguments.toList().flatten().each {\r\n comma.writeComma()\r\n self.emitArgument(at, _, async)\r\n }\r\n self.writeMapped(term.at, \")\")\r\n }\r\n | EVariantIs(at, \"ff:core/Bool.False\", _) =>\r\n self.writeMapped(at, \"function(_v) { return !_v ? ff_core_Option.Some(_v) : ff_core_Option.None(); }\")\r\n | EVariantIs(at, \"ff:core/Bool.True\", _) =>\r\n self.writeMapped(at, \"function(_v) { return _v ? ff_core_Option.Some(_v) : ff_core_Option.None(); }\")\r\n | EVariantIs(at, \"ff:core/Unit.Unit\", _) =>\r\n self.writeMapped(at, \"function(_v) { return ff_core_Option.Some(_v); }\")\r\n | EVariantIs(at, name, _) =>\r\n let n = name.reverse().takeWhile {_ != '.'}.reverse()\r\n self.writeMapped(at, \"(function(_v) { return _v.\")\r\n self.writeNamed(n, at, escapeResolved(n))\r\n self.writeMapped(at, \" ? ff_core_Option.Some(_v) : ff_core_Option.None();})\")\r\n | ECopy(at, name, record, fields) =>\r\n self.writeMapped(at, \"{...\")\r\n let comma = Comma(self)\r\n comma.writeComma()\r\n self.emitTerm(record, async)\r\n fields.each {f => \r\n comma.writeComma()\r\n self.writeNamed(f.name, at, escapeKeyword(f.name))\r\n self.writeMapped(at, \" = \")\r\n self.emitTerm(f.value, async)\r\n }\r\n self.writeMapped(at, \"}\")\r\n | EField(at, newtype, record, field) =>\r\n if(newtype) {self.emitTerm(record, async)} else:\r\n self.emitTerm(record, async)\r\n self.writeMapped(at, \".\")\r\n self.writeNamed(field, at, escapeKeyword(field))\r\n | ELambda(at, Lambda(_, effect, [MatchCase(_, patterns, [], body)])) {\r\n patterns.all {| PVariable _ => True | _ => False }\r\n } =>\r\n let newAsync = self.emittingAsync && effectTypeIsAsync(effect)\r\n self.writeMapped(term.at, \"(\")\r\n if(newAsync) {self.writeMapped(term.at, \"async \")}\r\n self.writeMapped(term.at, \"(\")\r\n let comma = Comma(self)\r\n patterns.each {\r\n | PVariable(patternAt, Some(name)) => \r\n comma.writeComma()\r\n self.writeNamed(name, patternAt, escapeKeyword(name))\r\n | PVariable(patternAt, None) => \r\n comma.writeComma()\r\n self.writeMapped(patternAt, \"_\")\r\n | _ => \r\n throw(CompileError(at, \"Internal compiler error\"))\r\n }\r\n if(newAsync) {\r\n comma.writeComma()\r\n self.writeMapped(term.at, \"$task\")\r\n }\r\n self.writeMapped(term.at, \") => {\")\r\n self.writeLine()\r\n self.emitStatements(body, True, False, newAsync)\r\n self.writeLine()\r\n self.writeMapped(term.at, \"})\")\r\n | ELambda(at, Lambda(_, effect, cases)) =>\r\n Patterns.convertAndCheck(self.otherModules, cases)\r\n let arguments = cases.grab(0).patterns.pairs().map {| Pair(i, p) => Pair(p.at, \"_\" + (i + 1))}\r\n let newAsync = self.emittingAsync && effectTypeIsAsync(effect)\r\n\r\n self.writeMapped(term.at, \"(\")\r\n if(newAsync) {self.writeMapped(term.at, \"async \")}\r\n self.writeMapped(term.at, \"(\")\r\n let comma = Comma(self)\r\n arguments.each {a => \r\n comma.writeComma()\r\n self.writeMapped(a.first, a.second)\r\n }\r\n let argumentTerms = arguments.map {| Pair(at, n) => {self.writeMapped(at, n)}}\r\n if(newAsync) {\r\n comma.writeComma()\r\n self.writeMapped(term.at, \"$task\")\r\n }\r\n self.writeMapped(term.at, \") => {\")\r\n self.writeLine()\r\n let liner = Liner(self, double = False)\r\n cases.pairs().each {| Pair(i, c) =>\r\n liner.writeLines()\r\n let lastCase = i == cases.size() - 1\r\n self.emitCase(argumentTerms, c, [], [], True, True, False, lastCase, newAsync)\r\n }\r\n self.writeLine()\r\n self.writeMapped(term.at, \"})\")\r\n | EPipe(at, value, effect, function) =>\r\n let await = async && effectTypeIsAsync(effect)\r\n if(await) {self.writeMapped(term.at, \"(await \")}\r\n self.writeMapped(term.at, \"(\")\r\n self.emitTerm(function, async)\r\n self.writeMapped(term.at, \")\")\r\n self.writeMapped(term.at, \"(\")\r\n self.emitTerm(value, async)\r\n if(await) {self.writeMapped(term.at, \", $task\")}\r\n self.writeMapped(term.at, \")\")\r\n if(await) {self.writeMapped(term.at, \")\")}\r\n | _ {self.emitAssignment(term, async, ignored)} =>\r\n | ECall(at, StaticCall(name, _, _), _, _, arguments, dictionaries) {\r\n self.emitSpecialCall(term, async, name, arguments.map {_.value}, dictionaries)\r\n } =>\r\n | ECall(at, StaticCall(name, _, True), effect, typeArguments, arguments, dictionaries) =>\r\n let await = async && effectTypeIsAsync(effect)\r\n let dictionaryStrings = dictionaries.map {self.makeDictionary(_)}\r\n let ds = dictionaryStrings.dropFirst()\r\n let d = dictionaryStrings.grabFirst()\r\n let asyncSuffix = if(await) {\"$\"} else {\"\"}\r\n if(await) {self.writeMapped(term.at, \"(await \")}\r\n self.writeMapped(term.at, d)\r\n self.writeMapped(term.at, \".\")\r\n self.writeNamed(name, at, escapeKeyword(name.reverse().takeWhile {_ != '.'}.reverse()) + asyncSuffix)\r\n self.writeMapped(term.at, \"(\")\r\n let comma = Comma(self)\r\n arguments.each {\r\n comma.writeComma()\r\n self.emitArgument(at, _, async)\r\n }\r\n ds.each {\r\n comma.writeComma()\r\n self.writeMapped(term.at, _)\r\n }\r\n if(await) {\r\n comma.writeComma()\r\n self.writeMapped(term.at, \"$task\")\r\n }\r\n self.writeMapped(term.at, \")\")\r\n if(await) {self.writeMapped(term.at, \")\")}\r\n | ECall(at, StaticCall(name, _, _), effect, typeArguments, arguments, dictionaries) =>\r\n detectIfElse(term).{\r\n | [] =>\r\n let await = async && effectTypeIsAsync(effect)\r\n let dictionaryStrings = dictionaries.map {self.makeDictionary(_)}\r\n let asyncSuffix = if(await) {\"$\"} else {\"\"}\r\n if(await) {self.writeMapped(term.at, \"(await \")}\r\n self.writeNamed(name, at, escapeResolved(name) + asyncSuffix)\r\n self.writeMapped(term.at, \"(\")\r\n let comma = Comma(self)\r\n arguments.each {\r\n comma.writeComma()\r\n self.emitArgument(at, _, async)\r\n }\r\n dictionaryStrings.each {\r\n comma.writeComma()\r\n self.writeMapped(term.at, _)\r\n }\r\n if(await) {\r\n comma.writeComma()\r\n self.writeMapped(term.at, \"$task\")\r\n }\r\n self.writeMapped(term.at, \")\")\r\n if(await) {self.writeMapped(term.at, \")\")}\r\n | [Pair(EVariant(_, \"ff:core/Bool.True\", _, _), elseBody), ...list] =>\r\n self.writeMapped(term.at, \"(\")\r\n list.reverse().each {| Pair(condition, body) =>\r\n self.emitTerm(condition, async)\r\n self.writeLine()\r\n self.writeMapped(condition.at, \"? \")\r\n self.emitTerm(body, async)\r\n self.writeLine()\r\n self.writeMapped(condition.at, \": \")\r\n }\r\n self.emitTerm(elseBody, async)\r\n self.writeMapped(term.at, \")\")\r\n | list =>\r\n self.writeMapped(term.at, \"(\")\r\n list.reverse().each {| Pair(condition, body) =>\r\n self.emitTerm(condition, async)\r\n self.writeLine()\r\n self.writeMapped(term.at, \"? ff_core_Option.Some(\")\r\n self.emitTerm(body, async)\r\n self.writeMapped(term.at, \")\")\r\n self.writeLine()\r\n self.writeMapped(term.at, \": \")\r\n }\r\n self.writeMapped(term.at, \"ff_core_Option.None())\")\r\n }\r\n | ECall(at, DynamicCall(function, _), effect, typeArguments, arguments, dictionaries) =>\r\n let await = async && effectTypeIsAsync(effect)\r\n if(!dictionaries.isEmpty()) {fail(at, \"Internal error: Dictionaries in lambda call\")}\r\n if(await) {self.writeMapped(term.at, \"(await \")}\r\n self.emitTerm(function, async)\r\n self.writeMapped(term.at, \"(\")\r\n let comma = Comma(self)\r\n arguments.each {\r\n comma.writeComma()\r\n self.emitArgument(at, _, async)\r\n }\r\n if(await) {\r\n comma.writeComma()\r\n self.writeMapped(term.at, \"$task\")\r\n }\r\n self.writeMapped(term.at, \")\")\r\n if(await) {self.writeMapped(term.at, \")\")}\r\n | ERecord(at, fields) =>\r\n if(fields.isEmpty()) {\r\n self.writeMapped(term.at, \"{}\")\r\n } else {\r\n self.writeMapped(term.at, \"{\")\r\n self.writeLine()\r\n let comma = Comma(self)\r\n let liner = Liner(self, double = False)\r\n fields.each {f => \r\n comma.writeComma()\r\n liner.writeLines()\r\n self.writeNamed(f.name, f.at, escapeKeyword(f.name))\r\n self.writeMapped(f.at, \": \")\r\n self.emitTerm(f.value, async)\r\n }\r\n self.writeLine()\r\n self.writeMapped(term.at, \"}\")\r\n }\r\n | EWildcard(at, index) =>\r\n if(index == 0) {fail(at, \"Unbound wildcard\")}\r\n self.writeMapped(at, \"_w\" + index)\r\n | ESequential(_, ESequential(_, ESequential(_, before1, before2), before3), after) {\r\n safeCommable(before1) && safeCommable(before2) && safeCommable(before3) && safeCommable(after)\r\n } =>\r\n self.writeMapped(term.at, \"(\")\r\n self.emitTerm(before1, async, ignored = True)\r\n self.writeMapped(term.at, \", \")\r\n self.emitTerm(before2, async, ignored = True)\r\n self.writeMapped(term.at, \", \")\r\n self.emitTerm(before3, async, ignored = True)\r\n self.writeMapped(term.at, \", \")\r\n self.emitTerm(after, async, ignored)\r\n self.writeMapped(term.at, \")\")\r\n | ESequential(_, ESequential(_, before1, before2), after) {\r\n safeCommable(before1) && safeCommable(before2) && safeCommable(after)\r\n } =>\r\n self.writeMapped(term.at, \"(\")\r\n self.emitTerm(before1, async, ignored = True)\r\n self.writeMapped(term.at, \", \")\r\n self.emitTerm(before2, async, ignored = True)\r\n self.writeMapped(term.at, \", \")\r\n self.emitTerm(after, async, ignored)\r\n self.writeMapped(term.at, \")\")\r\n | ESequential(_, before, after) {\r\n safeCommable(before) && safeCommable(after)\r\n } =>\r\n self.writeMapped(term.at, \"(\")\r\n self.emitTerm(before, async, ignored = True)\r\n self.writeMapped(term.at, \", \")\r\n self.emitTerm(after, async, ignored)\r\n self.writeMapped(term.at, \")\")\r\n | _ {async} =>\r\n self.writeMapped(term.at, \"(await (async function() {\")\r\n self.writeLine()\r\n self.emitStatements(term, True, False, async)\r\n self.writeLine()\r\n self.writeMapped(term.at, \"})())\")\r\n | _ =>\r\n self.writeMapped(term.at, \"(function() {\")\r\n self.writeLine()\r\n self.emitStatements(term, True, False, async)\r\n self.writeLine()\r\n self.writeMapped(term.at, \"})()\")\r\n }}\r\n \r\n emitField(term: Term, async: Bool, dot: String = \".\") {\r\n term.{\r\n | EString(at, q) {safeBare(q) | Some(s)} => \r\n self.writeMapped(term.at, dot)\r\n self.writeNamed(s, at, s)\r\n | _ => \r\n self.writeMapped(term.at, \"[\")\r\n self.emitTerm(term, async)\r\n self.writeMapped(term.at, \"]\")\r\n }\r\n }\r\n\r\n makeDictionary(d: Dictionary): String {\r\n let m = if(d.moduleKey.name != \"\") {\r\n d.moduleKey.packagePair.groupName(\"_\") + \"_\" + \r\n d.moduleKey.folders.map {_ + \"_\"}.join() + \r\n d.moduleKey.name + \".\"\r\n } else {\"\"}\r\n let c = m + makeDictionaryName(d.traitName, d.typeName)\r\n if(d.dictionaries.isEmpty()) {\r\n c\r\n } else {\r\n c + \"(\" + d.dictionaries.map {self.makeDictionary(_)}.join(\", \") + \")\"\r\n }\r\n }\r\n\r\n emitStatements(term: Term, last: Bool, break: Bool, async: Bool) {\r\n term.{\r\n | EFunctions(at, functions, body) =>\r\n let liner = Liner(self, double = False)\r\n functions.each {f =>\r\n liner.writeLines()\r\n let newAsync = self.emittingAsync && effectTypeIsAsync(f.signature.effect)\r\n self.emitFunctionDefinition(f, newAsync)\r\n }\r\n liner.writeLines()\r\n self.emitStatements(body, last, break, async)\r\n | ELet(at, mutable, name, valueType, value, body) =>\r\n self.emitLetDefinition(DLet(at, name, valueType, value), mutable, async)\r\n self.writeLine()\r\n self.emitStatements(body, last, break, async)\r\n | EVariant(at, \"ff:core/Unit.Unit\", _, _) =>\r\n | ESequential(_, EVariant(_, \"ff:core/Unit.Unit\", _, _), after) =>\r\n self.emitStatements(after, last, break, async)\r\n | ESequential(_, before, EVariant(_, \"ff:core/Unit.Unit\", _, _)) =>\r\n self.emitStatements(before, False, break, async)\r\n | ESequential(at, before, after) =>\r\n self.emitStatements(before, False, False, async)\r\n self.writeMapped(term.at, \";\")\r\n self.writeLine()\r\n self.emitStatements(after, last, break, async)\r\n | ECall(at, StaticCall(name, True, instanceCall), effect, _, arguments, _) =>\r\n if(instanceCall) {throw(CompileError(at, \"Not yet implemented: Tail calls on trait methods.\"))}\r\n self.tailCallUsed = True\r\n self.writeMapped(term.at, \"{\")\r\n arguments.each {a =>\r\n self.writeLine()\r\n self.writeMapped(a.at, \"const \")\r\n self.writeNamed(a.name.grab(), a.at, escapeKeyword(a.name.grab() + \"_r\"))\r\n self.writeMapped(a.at, \" = \")\r\n self.emitTerm(a.value, async)\r\n self.writeMapped(a.at, \";\")\r\n }\r\n arguments.each {a =>\r\n self.writeLine()\r\n self.writeNamed(a.name.grab(), a.at, escapeKeyword(a.name.grab()))\r\n self.writeMapped(term.at, \" = \")\r\n self.writeNamed(a.name.grab(), a.at, escapeKeyword(a.name.grab() + \"_r\"))\r\n }\r\n self.writeLine()\r\n self.writeMapped(term.at, \"continue _tailcall\")\r\n self.writeLine()\r\n self.writeMapped(term.at, \"}\")\r\n | ECall(at, StaticCall(name, _, _), _, _, arguments, dictionaries) {\r\n self.emitSpecialStatement(term, last, async, name, arguments.map {_.value}, dictionaries)\r\n } =>\r\n | EPipe(at, value, _, ELambda(_, Lambda(_, _, cases))) =>\r\n Patterns.convertAndCheck(self.otherModules, cases)\r\n if(!last && !break) {self.writeMapped(term.at, \"do \")}\r\n self.writeMapped(term.at, \"{\")\r\n self.writeLine()\r\n self.writeMapped(term.at, \"const _1 = \")\r\n self.emitTerm(value, async)\r\n self.writeMapped(term.at, \";\")\r\n cases.pairs().each {| Pair(i, c) => \r\n self.writeLine()\r\n let lastCase = i == cases.size() - 1\r\n self.emitCase([{self.writeMapped(c.at, \"_1\")}], c, [], [], True, last, break, lastCase, async)\r\n }\r\n self.writeLine()\r\n self.writeMapped(term.at, \"}\")\r\n if(!last && !break) {self.writeMapped(term.at, \" while(false)\")}\r\n | _ {self.emitAssignment(term, async, True)} =>\r\n | _ =>\r\n detectIfElse(term).{\r\n | [] =>\r\n if(break) {\r\n self.writeMapped(term.at, \"if(!\")\r\n self.emitTerm(term, async)\r\n self.writeMapped(term.at, \") break\")\r\n } elseIf {last} {\r\n self.writeMapped(term.at, \"return \")\r\n self.emitTerm(term, async)\r\n } else {\r\n self.emitTerm(term, async, ignored = True)\r\n }\r\n | [Pair(EVariant(_, \"ff:core/Bool.True\", _, _), elseBody), ...list] =>\r\n list.reverse().each {| Pair(condition, body) =>\r\n self.writeMapped(condition.at, \"if(\")\r\n self.emitTerm(condition, async)\r\n self.writeMapped(condition.at, \") {\")\r\n self.writeLine()\r\n self.emitStatements(body, last, break, async)\r\n self.writeLine()\r\n self.writeMapped(condition.at, \"} else \")\r\n }\r\n self.writeMapped(term.at, \"{\")\r\n self.writeLine()\r\n self.emitStatements(elseBody, last, break, async)\r\n self.writeLine()\r\n self.writeMapped(term.at, \"}\")\r\n | list {!last} =>\r\n list.reverse().each {| Pair(condition, body) =>\r\n self.writeMapped(condition.at, \"if(\")\r\n self.emitTerm(condition, async)\r\n self.writeMapped(condition.at, \") {\")\r\n self.writeLine()\r\n self.emitStatements(body, last, break, async)\r\n self.writeLine()\r\n self.writeMapped(condition.at, \"} else \")\r\n }\r\n self.writeMapped(term.at, \"{}\")\r\n | list =>\r\n list.reverse().each {| Pair(condition, body) =>\r\n self.writeMapped(condition.at, \"if(\")\r\n self.emitTerm(condition, async)\r\n self.writeMapped(condition.at, \") {\")\r\n self.writeLine()\r\n self.writeMapped(condition.at, \"return ff_core_Option.Some(\")\r\n self.emitTerm(body, async)\r\n self.writeMapped(condition.at, \")\")\r\n self.writeLine()\r\n self.writeMapped(condition.at, \"} else \")\r\n }\r\n self.writeMapped(term.at, \"return ff_core_Option.None()\")\r\n \r\n }\r\n }\r\n }\r\n \r\n emitAssignment(\r\n term: Term\r\n async: Bool\r\n ignored: Bool\r\n ): Bool {\r\n let anchor = self.writeAnchor()\r\n let emitted = term.{\r\n | ECall(at, StaticCall(name, _, _), _, _, arguments, dictionaries) =>\r\n name.{\r\n | \"ff:core/JsValue.JsValue_set\" {arguments.map {_.value} | [e1, e2, e3]} =>\r\n self.emitTerm(e1, async)\r\n self.emitField(e2, async)\r\n self.writeMapped(term.at, \" = \")\r\n self.emitTerm(e3, async)\r\n True\r\n | \"ff:core/JsValue.JsValue_increment\" {arguments.map {_.value} | [e1, e2, e3]} =>\r\n self.emitTerm(e1, async)\r\n self.emitField(e2, async)\r\n self.writeMapped(term.at, \" += \")\r\n self.emitTerm(e3, async)\r\n True\r\n | \"ff:core/JsValue.JsValue_decrement\" {arguments.map {_.value} | [e1, e2, e3]} =>\r\n self.emitTerm(e1, async)\r\n self.emitField(e2, async)\r\n self.writeMapped(term.at, \" -= \")\r\n self.emitTerm(e3, async)\r\n True\r\n | \"ff:core/JsSystem.JsSystem_set\" {arguments.map {_.value} | [e1, EString(at, q), e3]} {\r\n noSideEffects(e1)} {safeBare(q) | Some(s)\r\n } =>\r\n self.writeNamed(s, at, s)\r\n self.writeMapped(term.at, \" = \")\r\n self.emitTerm(e3, async)\r\n True\r\n | \"ff:core/JsSystem.JsSystem_increment\" {arguments.map {_.value} | [e1, EString(at, q), e3]} {\r\n noSideEffects(e1)} {safeBare(q) | Some(s)\r\n } =>\r\n self.writeNamed(s, at, s)\r\n self.writeMapped(term.at, \" += \")\r\n self.emitTerm(e3, async)\r\n True\r\n | \"ff:core/JsSystem.JsSystem_decrement\" {arguments.map {_.value} | [e1, EString(at, q), e3]} {\r\n noSideEffects(e1)} {safeBare(q) | Some(s)\r\n } =>\r\n self.writeNamed(s, at, s)\r\n self.writeMapped(term.at, \" -= \")\r\n self.emitTerm(e3, async)\r\n True\r\n | \"ff:core/Js.set\" {arguments.map {_.value} | [EString(at, q), e2]} {safeBare(q) | Some(s)} =>\r\n self.writeNamed(s, at, s)\r\n self.writeMapped(term.at, \" = \")\r\n self.emitTerm(e2, async)\r\n True\r\n | \"ff:core/Js.increment\" {arguments.map {_.value} | [EString(at, q), e2]} {safeBare(q) | Some(s)} =>\r\n self.writeNamed(s, at, s)\r\n self.writeMapped(term.at, \" += \")\r\n self.emitTerm(e2, async)\r\n True\r\n | \"ff:core/Js.decrement\" {arguments.map {_.value} | [EString(at, q), e2]} {safeBare(q) | Some(s)} =>\r\n self.writeNamed(s, at, s)\r\n self.writeMapped(term.at, \" -= \")\r\n self.emitTerm(e2, async)\r\n True\r\n | _ => \r\n False\r\n }\r\n | EAssign(at, operator, name, value) =>\r\n self.writeNamed(name, at, escapeKeyword(name))\r\n self.writeMapped(term.at, \" \" + operator + \"= \")\r\n self.emitTerm(value, async)\r\n True\r\n | EAssignField(at, operator, record, field, value) =>\r\n self.emitTerm(record, async)\r\n self.writeMapped(term.at, \".\")\r\n self.writeNamed(field, at, escapeKeyword(field))\r\n self.writeMapped(term.at, \" \" + operator + \"= \")\r\n self.emitTerm(value, async)\r\n True\r\n | _ =>\r\n False\r\n }\r\n if(!ignored && emitted) {\r\n self.writeAnchorLines(anchor, [\"(\"])\r\n self.writeMapped(term.at, \", void 0)\")\r\n }\r\n emitted\r\n }\r\n \r\n emitSpecialCall(\r\n term: Term\r\n async: Bool\r\n name: String\r\n arguments: List[Term]\r\n dictionaries: List[Dictionary]\r\n ): Bool {\r\n name.{\r\n | operator {!operator.grabFirst().isAsciiLetter()} {arguments | [value]} =>\r\n self.writeMapped(term.at, \"(\")\r\n self.writeMapped(term.at, operator)\r\n self.emitTerm(value, async)\r\n self.writeMapped(term.at, \")\")\r\n True\r\n | operator {!operator.grabFirst().isAsciiLetter()} {arguments | [left, right]} =>\r\n self.writeMapped(term.at, \"(\")\r\n self.emitTerm(left, async) \r\n self.writeMapped(term.at, \" \")\r\n self.writeMapped(term.at, operator)\r\n self.writeMapped(term.at, \" \")\r\n self.emitTerm(right, async)\r\n self.writeMapped(term.at, \")\")\r\n True\r\n | \"ff:core/List.List_grab\" {arguments | [e1, e2]} {noSideEffects(e1) && noSideEffects(e2)} =>\r\n self.writeMapped(term.at, \"(\")\r\n self.emitTerm(e1, async)\r\n self.writeMapped(term.at, \"[\")\r\n self.emitTerm(e2, async)\r\n self.writeMapped(term.at, \"] ?? ff_core_List.List_grab(\")\r\n self.emitTerm(e1, async)\r\n self.writeMapped(term.at, \", \")\r\n self.emitTerm(e2, async)\r\n self.writeMapped(term.at, \"))\")\r\n True\r\n | \"ff:core/Array.Array_grab\" {arguments | [e1, e2]} {noSideEffects(e1) && noSideEffects(e2)} =>\r\n self.writeMapped(term.at, \"(\")\r\n self.emitTerm(e1, async)\r\n self.writeMapped(term.at, \".array[\")\r\n self.emitTerm(e2, async)\r\n self.writeMapped(term.at, \"] ?? ff_core_Array.Array_grab(\")\r\n self.emitTerm(e1, async)\r\n self.writeMapped(term.at, \", \")\r\n self.emitTerm(e2, async)\r\n self.writeMapped(term.at, \"))\")\r\n True\r\n | \"ff:core/List.List_size\" {arguments | [e]} =>\r\n self.emitTerm(e, async)\r\n self.writeMapped(term.at, \".length\")\r\n True\r\n | \"ff:core/Array.Array_size\" {arguments | [e]} =>\r\n self.emitTerm(e, async)\r\n self.writeMapped(term.at, \".array.length\")\r\n True\r\n | \"ff:core/String.String_size\" {arguments | [e]} =>\r\n self.emitTerm(e, async)\r\n self.writeMapped(term.at, \".length\")\r\n True\r\n | \"ff:core/Equal.equals\" {arguments | [left, right]} {dictionaries | [Dictionary(_, _, typeName, [])]} {\r\n primitiveTypes.contains(typeName) || typeName == \"ff:core/Ordering.Ordering\"\r\n } =>\r\n self.writeMapped(term.at, \"(\")\r\n self.emitTerm(left, async)\r\n self.writeMapped(term.at, \" === \")\r\n self.emitTerm(right, async)\r\n self.writeMapped(term.at, \")\")\r\n True\r\n | \"ff:core/Equal.notEquals\" {arguments | [left, right]} {dictionaries | [Dictionary(_, _, typeName, [])]} {\r\n primitiveTypes.contains(typeName) || typeName == \"ff:core/Ordering.Ordering\"\r\n } =>\r\n self.writeMapped(term.at, \"(\")\r\n self.emitTerm(left, async)\r\n self.writeMapped(term.at, \" !== \")\r\n self.emitTerm(right, async)\r\n self.writeMapped(term.at, \")\")\r\n True\r\n | \"ff:core/Ordering.before\" {arguments | [left, right]} {dictionaries | [Dictionary(_, _, typeName, [])]} {\r\n primitiveTypes.contains(typeName)\r\n } =>\r\n self.writeMapped(term.at, \"(\")\r\n self.emitTerm(left, async)\r\n self.writeMapped(term.at, \" < \")\r\n self.emitTerm(right, async)\r\n self.writeMapped(term.at, \")\")\r\n True\r\n | \"ff:core/Ordering.notBefore\" {arguments | [left, right]} {dictionaries | [Dictionary(_, _, typeName, [])]} {\r\n primitiveTypes.contains(typeName)\r\n } =>\r\n self.writeMapped(term.at, \"(\")\r\n self.emitTerm(left, async)\r\n self.writeMapped(term.at, \" >= \")\r\n self.emitTerm(right, async)\r\n self.writeMapped(term.at, \")\")\r\n True\r\n | \"ff:core/Ordering.after\" {arguments | [left, right]} {dictionaries | [Dictionary(_, _, typeName, [])]} {\r\n primitiveTypes.contains(typeName)\r\n } =>\r\n self.writeMapped(term.at, \"(\")\r\n self.emitTerm(left, async)\r\n self.writeMapped(term.at, \" > \")\r\n self.emitTerm(right, async)\r\n self.writeMapped(term.at, \")\")\r\n True\r\n | \"ff:core/Ordering.notAfter\" {arguments | [left, right]} {dictionaries | [Dictionary(_, _, typeName, [])]} {\r\n primitiveTypes.contains(typeName)\r\n } =>\r\n self.writeMapped(term.at, \"(\")\r\n self.emitTerm(left, async)\r\n self.writeMapped(term.at, \" <= \")\r\n self.emitTerm(right, async)\r\n self.writeMapped(term.at, \")\")\r\n True\r\n | \"ff:core/List.fillBy\" {term | ECall call} {arguments | [size, ELambda(at,\r\n Lambda(_, _, [MatchCase(_, [PVariable(variableAt, name)], [], body)@c])@l\r\n )]} {\r\n !effectTypeIsAsync(call.effect)\r\n } =>\r\n let n = name.map {escapeResolved(_)}.else {\"i\"}\r\n let newAsync = self.emittingAsync && effectTypeIsAsync(call.effect)\r\n if(newAsync) {self.writeMapped(term.at, \"await \")}\r\n self.writeMapped(term.at, \"((() => {\")\r\n self.writeLine()\r\n self.writeMapped(term.at, \"const size = \")\r\n self.emitTerm(size, async) // Not correct if async and body isn't\r\n self.writeMapped(term.at, \";\")\r\n self.writeLine()\r\n self.writeMapped(term.at, \"const result = [];\")\r\n self.writeMapped(term.at, \"for(let \")\r\n self.writeNamed(name.else {\"_\"}, variableAt, n)\r\n self.writeMapped(term.at, \" = 0; \")\r\n self.writeNamed(name.else {\"_\"}, variableAt, n)\r\n self.writeMapped(term.at, \" < size; \")\r\n self.writeNamed(name.else {\"_\"}, variableAt, n)\r\n self.writeMapped(term.at, \"++) {\")\r\n self.writeLine()\r\n self.writeMapped(term.at, \"result.push(\")\r\n self.emitTerm(body, newAsync)\r\n self.writeMapped(term.at, \");\")\r\n self.writeLine()\r\n self.writeMapped(term.at, \"}\")\r\n self.writeLine()\r\n self.writeMapped(term.at, \"return result;\")\r\n self.writeLine()\r\n self.writeMapped(term.at, \"})())\")\r\n True\r\n | \"ff:core/Js.import\" {arguments | [EString(at, url)]} =>\r\n self.emitTarget.{\r\n | EmitBrowser => \r\n self.writeMapped(at, \"(() => {throw new Error('Node.js imports are not supported in the browser')})()\")\r\n | _ => \r\n self.writeMapped(at, self.jsImporter.add(url.replace(\"\\\"\", \"\")))\r\n }\r\n True\r\n | \"ff:core/Js.browserImport\" {arguments | [EString(at, url)]} =>\r\n self.emitTarget.{\r\n | EmitBrowser => \r\n self.writeMapped(at, self.jsImporter.add(url.replace(\"\\\"\", \"\")))\r\n | _ => \r\n self.writeMapped(at, \"(() => {throw new Error('Browser imports are not supported in Node.js')})()\")\r\n }\r\n True\r\n | \"ff:core/Js.dynamicImport\" {arguments | [url]} =>\r\n self.writeMapped(term.at, \"import(\")\r\n self.emitTerm(url, async)\r\n self.writeMapped(term.at, \")\")\r\n True\r\n | \"ff:core/Js.await\" {arguments | [body]} =>\r\n if(async) {\r\n self.writeMapped(term.at, \"(await \")\r\n self.emitTerm(body, async)\r\n self.writeMapped(term.at, \")\")\r\n } else {\r\n self.emitTerm(body, async)\r\n }\r\n True\r\n | name {name.removeFirst(\"ff:core/Js.async\") | Some(n)} {n.all {_.isAsciiDigit()}} {\r\n arguments | [ELambda(at, Lambda(_, effect, [MatchCase(_, patterns, [], body)]))]\r\n } {\r\n patterns.all {| PVariable _ => True | _ => False }\r\n } =>\r\n let patternParameters = patterns.map {\r\n | PVariable p => p.name.map(escapeKeyword).else {\"_\"}\r\n | _ => panic(\"!\")\r\n }\r\n self.writeMapped(term.at, \"async (\" + patternParameters.join(\", \") + \") => {\")\r\n self.writeLine()\r\n self.emitStatements(body, True, False, False)\r\n self.writeLine()\r\n self.writeMapped(term.at, \"}\")\r\n True\r\n | name {name.startsWith(\"ff:core/Js.async\")} =>\r\n throw(CompileError(term.at, \"JS async functions must take a simple parameter list\"))\r\n | \"ff:core/Js.cancelled\" =>\r\n self.writeMapped(term.at, if(async) {\"$task.controller_.signal.aborted\"} else {\"false\"})\r\n True\r\n | \"ff:core/Js.throwIfCancelled\" =>\r\n if(async) {self.writeMapped(term.at, \"((() => ff_core_Task.Task_throwIfAborted($task))())\")}\r\n True\r\n | \"ff:core/Js.currentTask\" =>\r\n self.writeMapped(term.at, \"$task\")\r\n True\r\n | \"ff:core/Js.controller\" =>\r\n self.writeMapped(term.at, \"$task.controller_\")\r\n True\r\n | \"ff:core/Js.setController\" {arguments | [a]} =>\r\n self.writeMapped(term.at, \"($task.controller_ = \")\r\n self.emitTerm(a, async)\r\n self.writeMapped(term.at, \")\")\r\n True\r\n | \"ff:core/Js.inAsync\" =>\r\n self.writeMapped(term.at, if(self.emittingAsync) {\"true\"} else {\"false\"})\r\n True\r\n | \"ff:core/Js.inBrowser\" =>\r\n self.writeMapped(term.at, if(self.emitTarget == EmitBrowser) {\"true\"} else {\"false\"})\r\n True\r\n | \"ff:core/Js.inNode\" =>\r\n self.writeMapped(term.at, if(self.emitTarget == EmitNode) {\"true\"} else {\"false\"})\r\n True\r\n | \"ff:core/Js.inBuild\" =>\r\n self.writeMapped(term.at, if(self.emitTarget == EmitBuild) {\"true\"} else {\"false\"})\r\n True\r\n | \"ff:core/Js.value\" {arguments | [e]} =>\r\n self.emitTerm(e, async)\r\n True\r\n | \"ff:core/Js.fromValue\" {arguments | [e]} =>\r\n self.emitTerm(e, async)\r\n True\r\n | \"ff:core/Js.rawIdentifier\" {arguments | [EString(at, op)]} =>\r\n self.writeMapped(at, op.replace(\"\\\"\", \"\"))\r\n True\r\n | \"ff:core/Js.unaryOperator\" {arguments | [EString(at, op), a1]} =>\r\n self.writeMapped(term.at, \"(\")\r\n self.writeMapped(at, op.replace(\"\\\"\", \"\"))\r\n self.emitTerm(a1, async)\r\n self.writeMapped(term.at, \")\")\r\n True\r\n | \"ff:core/Js.binaryOperator\" {arguments | [EString(at, op), a1, a2]} =>\r\n self.writeMapped(term.at, \"(\")\r\n self.emitTerm(a1, async)\r\n self.writeMapped(term.at, \" \")\r\n self.writeMapped(at, op.replace(\"\\\"\", \"\"))\r\n self.writeMapped(term.at, \" \")\r\n self.emitTerm(a2, async)\r\n self.writeMapped(term.at, \")\")\r\n True\r\n | \"ff:core/Js.shortCircuitingOperator\" {arguments | [EString(at, op), a1, a2]} =>\r\n self.writeMapped(term.at, \"(\")\r\n self.emitTerm(a1, async)\r\n self.writeMapped(term.at, \" \")\r\n self.writeMapped(at, op.replace(\"\\\"\", \"\"))\r\n self.writeMapped(term.at, \" \")\r\n self.emitTerm(invokeImmediately(a2), async)\r\n self.writeMapped(term.at, \")\")\r\n True\r\n | \"ff:core/JsValue.JsValue_spreadToArray\" {arguments | [e1]} =>\r\n self.writeMapped(term.at, \"[...\")\r\n self.emitTerm(e1, async)\r\n self.writeMapped(term.at, \"]\")\r\n True\r\n | \"ff:core/JsValue.JsValue_typeof\" {arguments | [e]} =>\r\n self.writeMapped(term.at, \"(typeof \")\r\n self.emitTerm(e, async)\r\n self.writeMapped(term.at, \")\")\r\n True\r\n | \"ff:core/JsValue.JsValue_instanceof\" {arguments | [e1, e2]} =>\r\n self.writeMapped(term.at, \"(\")\r\n self.emitTerm(e1, async)\r\n self.writeMapped(term.at, \" instanceof \")\r\n self.emitTerm(e2, async)\r\n self.writeMapped(term.at, \")\")\r\n True\r\n | \"ff:core/JsValue.JsValue_get\" {arguments | [e1, e2]} =>\r\n self.emitTerm(e1, async)\r\n self.emitField(e2, async)\r\n True\r\n | \"ff:core/JsValue.JsValue_equals\" {arguments | [e1, e2]} =>\r\n self.writeMapped(term.at, \"(\")\r\n self.emitTerm(e1, async)\r\n self.writeMapped(term.at, \" === \")\r\n self.emitTerm(e2, async)\r\n self.writeMapped(term.at, \")\")\r\n True \r\n | \"ff:core/JsValue.JsValue_notEquals\" {arguments | [e1, e2]} =>\r\n self.writeMapped(term.at, \"(\")\r\n self.emitTerm(e1, async)\r\n self.writeMapped(term.at, \" !== \")\r\n self.emitTerm(e2, async)\r\n self.writeMapped(term.at, \")\")\r\n True \r\n | \"ff:core/Int.Int_bitAnd\" {arguments | [e1, e2]} =>\r\n self.writeMapped(term.at, \"(\")\r\n self.emitTerm(e1, async)\r\n self.writeMapped(term.at, \" & \")\r\n self.emitTerm(e2, async)\r\n self.writeMapped(term.at, \")\")\r\n True \r\n | \"ff:core/Int.Int_bitRightUnsigned\" {arguments | [e1, e2]} =>\r\n self.writeMapped(term.at, \"(\")\r\n self.emitTerm(e1, async)\r\n self.writeMapped(term.at, \" >>> \")\r\n self.emitTerm(e2, async)\r\n self.writeMapped(term.at, \")\")\r\n True \r\n | \"ff:core/Int.Int_bitRight\" {arguments | [e1, e2]} =>\r\n self.writeMapped(term.at, \"(\")\r\n self.emitTerm(e1, async)\r\n self.writeMapped(term.at, \" >> \")\r\n self.emitTerm(e2, async)\r\n self.writeMapped(term.at, \")\")\r\n True \r\n | name {name.removeFirst(\"ff:core/JsValue.JsValue_call\") | Some(n)} {n.all {_.isAsciiDigit()}} {\r\n arguments | [e1, e2, ...es]\r\n } =>\r\n self.emitTerm(e1, async)\r\n self.emitField(e2, async)\r\n self.writeMapped(term.at, \"(\")\r\n let comma = Comma(self)\r\n es.each {\r\n comma.writeComma()\r\n self.emitTerm(_, async)\r\n }\r\n self.writeMapped(term.at, \")\")\r\n True\r\n | name {name.removeFirst(\"ff:core/JsValue.JsValue_callValue\") | Some(n)} {n.all {_.isAsciiDigit()}} {\r\n arguments | [e1, ...es]\r\n } =>\r\n self.emitTerm(e1, async)\r\n self.writeMapped(term.at, \"(\")\r\n let comma = Comma(self)\r\n es.each {\r\n comma.writeComma()\r\n self.emitTerm(_, async)\r\n }\r\n self.writeMapped(term.at, \")\")\r\n True\r\n | name {name.removeFirst(\"ff:core/JsValue.JsValue_new\") | Some(n)} {n.all {_.isAsciiDigit()}} {\r\n arguments | [e1, ...es]\r\n } =>\r\n self.writeMapped(term.at, \"(new \")\r\n self.emitTerm(e1, async)\r\n self.writeMapped(term.at, \"(\")\r\n let comma = Comma(self)\r\n es.each {\r\n comma.writeComma()\r\n self.emitTerm(_, async)\r\n }\r\n self.writeMapped(term.at, \"))\")\r\n True\r\n | name {name == \"ff:core/JsValue.JsValue_with\" || name == \"ff:core/Json.Json_with\"} =>\r\n function go(e: Term, fields: List[Pair[Term, Term]]) {\r\n e.{\r\n | ECall(_, StaticCall(n, _, _), _, _, [a1, a2, a3], _) {n == name} =>\r\n go(a1.value, [Pair(a2.value, a3.value), ...fields])\r\n | ECall(_, StaticCall(n, _, _), _, _, as, _) {\r\n n == \"ff:core/JsSystem.JsSystem_object\" || \r\n n == \"ff:core/JsSystem.JsSystem_new0\" ||\r\n n == \"ff:core/Js.object\" || \r\n n == \"ff:core/Js.new0\" ||\r\n n == \"ff:core/Json.Json_object\" ||\r\n n == \"ff:core/Json.Json_new0\"\r\n } {\r\n as.all {noSideEffects(_.value)}\r\n } =>\r\n self.writeMapped(e.at, \"{\")\r\n let comma = Comma(self)\r\n fields.each {p =>\r\n comma.writeComma()\r\n self.emitField(p.first, async, dot = \"\")\r\n self.writeMapped(e.at, \": \")\r\n self.emitTerm(p.second, async)\r\n }\r\n self.writeMapped(e.at, \"}\")\r\n | _ =>\r\n self.writeMapped(e.at, \"{...\")\r\n self.emitTerm(e, async)\r\n fields.each {p =>\r\n self.writeMapped(e.at, \", \")\r\n self.emitField(p.first, async, dot = \"\")\r\n self.writeMapped(e.at, \": \")\r\n self.emitTerm(p.second, async)\r\n }\r\n self.writeMapped(e.at, \"}\")\r\n }\r\n }\r\n go(term, [])\r\n True\r\n | name {name.removeFirst(\"ff:core/JsSystem.JsSystem_call\") | Some(n)} {n.all {_.isAsciiDigit()}} {\r\n arguments | [e1, EString(at, q)@e2, ...es]\r\n } {noSideEffects(e1)} =>\r\n safeBare(q).{\r\n | Some(bare) => self.writeNamed(q, at, bare)\r\n | None => \r\n self.writeMapped(term.at, \"globalThis[\")\r\n self.emitTerm(e2, async)\r\n self.writeMapped(term.at, \"]\")\r\n }\r\n self.writeMapped(term.at, \"(\")\r\n let comma = Comma(self)\r\n es.each {\r\n comma.writeComma()\r\n self.emitTerm(_, async)\r\n }\r\n self.writeMapped(term.at, \")\")\r\n True\r\n | name {name.removeFirst(\"ff:core/JsSystem.JsSystem_function\") | Some(n)} {n.all {_.isAsciiDigit()}} {\r\n arguments | [e1, e2]\r\n } {noSideEffects(e1)} {term | ECall call} {!effectTypeIsAsync(call.effect)} =>\r\n self.emitTerm(e2, async)\r\n True\r\n | \"ff:core/JsSystem.JsSystem_get\" {arguments | [e1, EString(at, q)@e2]} {noSideEffects(e1)} =>\r\n safeBare(q).{\r\n | Some(bare) => self.writeNamed(q, at, bare)\r\n | None => \r\n self.writeMapped(term.at, \"globalThis[\")\r\n self.emitTerm(e2, async)\r\n self.writeMapped(term.at, \"]\")\r\n }\r\n True\r\n | \"ff:core/JsSystem.JsSystem_object\" {arguments | [e]} {noSideEffects(e)} =>\r\n self.writeMapped(term.at, \"{}\")\r\n True\r\n | \"ff:core/JsSystem.JsSystem_new0\" {arguments | [e]} {noSideEffects(e)} =>\r\n self.writeMapped(term.at, \"{}\")\r\n True\r\n | \"ff:core/JsSystem.JsSystem_null\" {arguments | [e]} {noSideEffects(e)} =>\r\n self.writeMapped(term.at, \"null\")\r\n True\r\n | \"ff:core/JsSystem.JsSystem_undefined\" {arguments | [e]} {noSideEffects(e)} =>\r\n self.writeMapped(term.at, \"(void 0)\")\r\n True\r\n | name {name.removeFirst(\"ff:core/Js.call\") | Some(n)} {n.all {_.isAsciiDigit()}} {\r\n arguments | [EString(at, q)@e1, ...es]\r\n } =>\r\n safeBare(q).{\r\n | Some(bare) => self.writeNamed(q, at, bare)\r\n | None => \r\n self.writeMapped(term.at, \"globalThis[\")\r\n self.emitTerm(e1, async)\r\n self.writeMapped(term.at, \"]\")\r\n }\r\n self.writeMapped(term.at, \"(\")\r\n let comma = Comma(self)\r\n es.each {\r\n comma.writeComma()\r\n self.emitTerm(_, async)\r\n }\r\n self.writeMapped(term.at, \")\")\r\n True\r\n | name {name.removeFirst(\"ff:core/Js.function\") | Some(n)} {n.all {_.isAsciiDigit()}} {\r\n arguments | [e1]\r\n } {term | ECall call} =>\r\n if(self.emittingAsync && effectTypeIsAsync(call.effect)) {\r\n let argumentCode = 1.to(n.grabInt()).map {\"a_\" + _}.join(\", \")\r\n let taskCode = if(argumentCode == \"\") {\"$task\"} else {\", $task\"}\r\n self.writeMapped(term.at, \"(async (\" + argumentCode + \") => await \")\r\n self.emitTerm(e1, async)\r\n self.writeMapped(term.at, \"(\" + argumentCode + taskCode + \"))\")\r\n } else {\r\n self.emitTerm(e1, async)\r\n }\r\n True\r\n | \"ff:core/Js.get\" {arguments | [EString(at, q)@e1]} =>\r\n safeBare(q).{\r\n | Some(bare) => self.writeNamed(q, at, bare)\r\n | None => \r\n self.writeMapped(term.at, \"globalThis[\")\r\n self.emitTerm(e1, async)\r\n self.writeMapped(term.at, \"]\")\r\n }\r\n True\r\n | \"ff:core/Js.object\" =>\r\n self.writeMapped(term.at, \"{}\")\r\n True\r\n | \"ff:core/Js.new0\" =>\r\n self.writeMapped(term.at, \"{}\")\r\n True\r\n | \"ff:core/Js.null\" =>\r\n self.writeMapped(term.at, \"null\")\r\n True\r\n | \"ff:core/Js.undefined\" =>\r\n self.writeMapped(term.at, \"(void 0)\")\r\n True\r\n | \"ff:core/Js.globalThis\" =>\r\n self.writeMapped(term.at, \"globalThis\")\r\n True\r\n | \"ff:core/BrowserSystem.BrowserSystem_js\" {arguments | [e]} {noSideEffects(e)} => \r\n self.writeMapped(term.at, \"globalThis\")\r\n True\r\n | \"ff:core/BuildSystem.BuildSystem_js\" {arguments | [e]} {noSideEffects(e)} => \r\n self.writeMapped(term.at, \"globalThis\")\r\n True\r\n | \"ff:core/NodeSystem.NodeSystem_js\" {arguments | [e]} {noSideEffects(e)} => \r\n self.writeMapped(term.at, \"globalThis\")\r\n True\r\n | \"ff:core/Js.jsSystem\" =>\r\n self.writeMapped(term.at, \"globalThis\")\r\n True\r\n | \"ff:core/Json.string\" {arguments | [e]} =>\r\n self.emitTerm(e, async)\r\n True\r\n | \"ff:core/Json.int\" {arguments | [e]} =>\r\n self.emitTerm(e, async)\r\n True\r\n | \"ff:core/Json.float\" {arguments | [e]} =>\r\n self.emitTerm(e, async)\r\n True\r\n | \"ff:core/Json.bool\" {arguments | [e]} =>\r\n self.emitTerm(e, async)\r\n True\r\n | \"ff:core/Json.array\" {arguments | [e]} =>\r\n self.emitTerm(e, async)\r\n True\r\n | \"ff:core/Json.null\" {arguments | [e]} =>\r\n self.writeMapped(term.at, \"null\")\r\n True\r\n | \"ff:core/Json.object\" {arguments | [e]} =>\r\n self.writeMapped(term.at, \"{}\")\r\n True\r\n | _ =>\r\n False\r\n }\r\n }\r\n \r\n emitSpecialStatement(\r\n term: Term \r\n last: Bool \r\n async: Bool \r\n name: String\r\n arguments: List[Term]\r\n dictionaries: List[Dictionary]\r\n ): Bool {\r\n name.{\r\n | \"ff:core/Core.while\" {arguments | [condition, body]} =>\r\n self.writeMapped(term.at, \"while\")\r\n self.writeMapped(term.at, \"(\")\r\n self.emitTerm(invokeImmediately(condition), async)\r\n self.writeMapped(term.at, \") {\")\r\n self.writeLine()\r\n self.emitStatements(invokeImmediately(body), False, False, async)\r\n self.writeLine()\r\n self.writeMapped(term.at, \"}\")\r\n True\r\n | \"ff:core/Core.doWhile\" {arguments | [doWhileBody]} {\r\n invokeImmediately(doWhileBody) | body\r\n } =>\r\n self.writeMapped(term.at, \"while\")\r\n self.writeMapped(term.at, \"(true) {\")\r\n self.writeLine()\r\n self.emitStatements(body, False, True, async)\r\n self.writeLine()\r\n self.writeMapped(term.at, \"}\")\r\n True\r\n | \"ff:core/Option.Option_each\" {arguments | [list, ELambda(_, Lambda(_, _, [\r\n MatchCase(_, [PVariable(nameAt, name)], [], body)\r\n ]))]} =>\r\n self.writeMapped(term.at, \"{\")\r\n self.writeLine()\r\n self.writeMapped(term.at, \"const if_o = \")\r\n self.emitTerm(list, async)\r\n self.writeLine()\r\n self.writeMapped(term.at, \"if(if_o.Some) {\")\r\n self.writeLine()\r\n name.each {n => \r\n self.writeMapped(term.at, \"const \")\r\n self.writeNamed(n, nameAt, escapeKeyword(n))\r\n self.writeMapped(term.at, \" = if_o.value_;\")\r\n self.writeLine()\r\n }\r\n self.emitStatements(body, last, False, async)\r\n self.writeLine()\r\n self.writeMapped(term.at, \"}\")\r\n self.writeLine()\r\n self.writeMapped(term.at, \"}\")\r\n True\r\n | n {n == \"ff:core/List.List_each\" || n == \"ff:core/List.List_eachWhile\"} {arguments | [\r\n ECall(_, StaticCall(r, _, _), _, _, [start, end], _)\r\n ELambda(_, Lambda(_, _, [MatchCase(_, [PVariable(nameAt, name)], [], body)]))\r\n ]} {r == \"ff:core/Int.Int_until\" || r == \"ff:core/Int.Int_to\"} =>\r\n self.writeMapped(term.at, \"for\")\r\n self.writeMapped(term.at, \"(let for_i = \")\r\n self.emitTerm(start.value, async)\r\n self.writeMapped(term.at, \", for_e = \")\r\n self.emitTerm(end.value, async)\r\n let op = if(r == \"ff:core/Int.Int_until\") {\"<\"} else {\"<=\"}\r\n self.writeMapped(term.at, \"; for_i \" + op + \" for_e; for_i++) {\")\r\n self.writeLine()\r\n name.each {n => \r\n self.writeMapped(term.at, \"const \")\r\n self.writeNamed(n, nameAt, escapeKeyword(n))\r\n self.writeMapped(term.at, \" = for_i;\")\r\n self.writeLine()\r\n }\r\n self.emitStatements(body, last, n.endsWith(\"eachWhile\"), async)\r\n self.writeLine()\r\n self.writeMapped(term.at, \"}\")\r\n True\r\n | n {n == \"ff:core/List.List_each\" || n == \"ff:core/List.List_eachWhile\"} {arguments | [\r\n ECall(_, StaticCall(\"ff:core/List.List_reverse\", _, _), _, _, [\r\n Argument(_, _, ECall(_, StaticCall(r, _, _), _, _, [start, end], _))\r\n ], _)\r\n ELambda(_, Lambda(_, _, [MatchCase(_, [PVariable(nameAt, name)], [], body)]))\r\n ]} {r == \"ff:core/Int.Int_until\" || r == \"ff:core/Int.Int_to\"} =>\r\n self.writeMapped(term.at, \"for\")\r\n self.writeMapped(term.at, \"(let for_e = \")\r\n self.emitTerm(start.value, async)\r\n self.writeMapped(term.at, \", for_i = \")\r\n self.emitTerm(end.value, async)\r\n if(r == \"ff:core/Int.Int_until\") {self.writeMapped(term.at, \" - 1\")}\r\n self.writeMapped(term.at, \"; for_i >= for_e; for_i--) {\")\r\n self.writeLine()\r\n name.each {n => \r\n self.writeMapped(term.at, \"const \")\r\n self.writeNamed(n, nameAt, escapeKeyword(n))\r\n self.writeMapped(term.at, \" = for_i;\")\r\n self.writeLine()\r\n }\r\n self.emitStatements(body, last, n.endsWith(\"eachWhile\"), async)\r\n self.writeLine()\r\n self.writeMapped(term.at, \"}\")\r\n True\r\n | n {n == \"ff:core/List.List_each\" || n == \"ff:core/List.List_eachWhile\"} {arguments | [\r\n ECall(_, StaticCall(\"ff:core/List.List_zip\", _, _), _, _, [list1, list2], _)\r\n ELambda(_, Lambda(_, _, [MatchCase(_, [\r\n PVariant(_, \"ff:core/Pair.Pair\", [PVariable(at1, name1), PVariable(at2, name2)])\r\n ], [], body)]))\r\n ]} =>\r\n self.writeMapped(term.at, \"for(let \")\r\n self.emitLightFusion(\"\", list1.value, n.startsWith(\"ff:core/Array.\"), async)\r\n self.writeMapped(term.at, \", \")\r\n self.emitLightFusion(\"2\", list2.value, n.startsWith(\"ff:core/Array.\"), async)\r\n self.writeMapped(term.at, \"; for_i < for_l && for_i2 < for_l2; for_i++, for_i2++) {\")\r\n self.writeLine()\r\n name1.each {\r\n self.writeMapped(at1, \"const \" + escapeKeyword(_) + \" = for_a[for_i];\")\r\n self.writeLine()\r\n }\r\n name2.each {\r\n self.writeMapped(at2, \"const \" + escapeKeyword(_) + \" = for_a2[for_i2];\")\r\n self.writeLine()\r\n }\r\n self.emitStatements(body, last, n.endsWith(\"eachWhile\"), async)\r\n self.writeLine()\r\n self.writeMapped(term.at, \"}\")\r\n True\r\n | n {n == \"ff:core/List.List_each\" || n == \"ff:core/List.List_eachWhile\"} {arguments | [\r\n ECall(_, StaticCall(\"ff:core/List.List_pairs\", _, _), _, _, [list1], _)\r\n ELambda(_, Lambda(_, _, [MatchCase(_, [\r\n PVariant(_, \"ff:core/Pair.Pair\", [PVariable(at1, name1), PVariable(at2, name2)])\r\n ], [], body)]))\r\n ]} =>\r\n self.writeMapped(term.at, \"for(let \")\r\n self.emitLightFusion(\"\", list1.value, n.startsWith(\"ff:core/Array.\"), async)\r\n self.writeMapped(term.at, \"; for_i < for_l; for_i++) {\")\r\n self.writeLine()\r\n name1.each {\r\n self.writeMapped(at1, \"const \" + escapeKeyword(_) + \" = for_i;\")\r\n self.writeLine()\r\n }\r\n name2.each {\r\n self.writeMapped(at2, \"const \" + escapeKeyword(_) + \" = for_a[for_i];\")\r\n self.writeLine()\r\n }\r\n self.emitStatements(body, last, n.endsWith(\"eachWhile\"), async)\r\n self.writeLine()\r\n self.writeMapped(term.at, \"}\")\r\n True\r\n | n {\r\n n == \"ff:core/List.List_each\" || n == \"ff:core/List.List_eachWhile\" || \r\n n == \"ff:core/Array.Array_each\" || n == \"ff:core/Array.Array_eachWhile\"\r\n } {\r\n arguments | [list1, ELambda(_, Lambda(_, _, [MatchCase(_, [PVariable(at1, name1)], [], body)]))]\r\n } =>\r\n self.writeMapped(term.at, \"for(let \")\r\n self.emitLightFusion(\"\", list1, n.startsWith(\"ff:core/Array.\"), async)\r\n self.writeMapped(term.at, \"; for_i < for_l; for_i++) {\")\r\n self.writeLine()\r\n name1.each {\r\n self.writeMapped(at1, \"const \" + escapeKeyword(_) + \" = for_a[for_i];\")\r\n self.writeLine()\r\n }\r\n self.emitStatements(body, last, n.endsWith(\"eachWhile\"), async)\r\n self.writeLine()\r\n self.writeMapped(term.at, \"}\")\r\n True\r\n | \"ff:core/Array.Array_push\" {arguments | [array, value]} =>\r\n self.emitTerm(array, async)\r\n self.writeMapped(array.at, \".array.push(\")\r\n self.emitTerm(value, async)\r\n self.writeMapped(array.at, \")\")\r\n True\r\n | \"ff:core/Core.if\" {arguments | [condition, body]} =>\r\n self.writeMapped(condition.at, \"if(\")\r\n self.emitTerm(condition, async)\r\n self.writeMapped(condition.at, \") {\")\r\n self.writeLine()\r\n if(last) {\r\n self.writeMapped(term.at, \"return ff_core_Option.Some(\")\r\n self.emitTerm(invokeImmediately(body), async)\r\n self.writeMapped(term.at, \")\")\r\n } else {\r\n self.emitStatements(invokeImmediately(body), False, False, async)\r\n }\r\n self.writeLine()\r\n self.writeMapped(term.at, \"}\")\r\n if(last) {self.writeMapped(term.at, \" else return ff_core_Option.None()\")}\r\n True\r\n | \"ff:core/Core.throw\" {term | ECall c} {c.arguments | [argument]} {dictionaries | [hasAnyTag, show]} =>\r\n self.writeMapped(term.at, \"throw ff_core_Js.initializeError_(\")\r\n self.emitArgument(term.at, argument, async)\r\n self.writeMapped(term.at, \", new Error(), \")\r\n self.writeMapped(term.at, self.makeDictionary(hasAnyTag))\r\n self.writeMapped(term.at, \", \")\r\n self.writeMapped(term.at, self.makeDictionary(show))\r\n self.writeMapped(term.at, \")\")\r\n True\r\n | \"ff:core/Core.throwWithMessage\" {term | ECall c} {c.arguments | [argument, message]} {dictionaries | [hasAnyTag]} =>\r\n self.writeMapped(term.at, \"throw ff_core_Js.initializeErrorKeepMessage_(\")\r\n self.emitArgument(term.at, argument, async)\r\n self.writeMapped(term.at, \", new Error(\")\r\n self.emitArgument(term.at, message, async)\r\n self.writeMapped(term.at, \"), \")\r\n self.writeMapped(term.at, self.makeDictionary(hasAnyTag))\r\n self.writeMapped(term.at, \")\")\r\n True\r\n | \"ff:core/Try.Try_catch\" {self.emitTryCatchFinally(term, last, async)} =>\r\n True\r\n | \"ff:core/Try.Try_catchAny\" {self.emitTryCatchFinally(term, last, async)} =>\r\n True\r\n | \"ff:core/Try.Try_finally\" {self.emitTryCatchFinally(term, last, async)} =>\r\n True\r\n | \"ff:core/Js.throwIfCancelled\" =>\r\n if(async) {self.writeMapped(term.at, \"ff_core_Task.Task_throwIfAborted($task)\")}\r\n True\r\n | \"ff:core/Js.throw\" {term | ECall c} {c.arguments | [argument]} =>\r\n self.writeMapped(term.at, \"throw \")\r\n self.emitTerm(argument.value, async)\r\n True\r\n | _ =>\r\n False\r\n }\r\n }\r\n \r\n emitLightFusion(\r\n suffix: String\r\n list: Term\r\n isArray: Bool\r\n async: Bool\r\n ) {\r\n function wrapUnlessInt(term: Term, before: String, after: String) {\r\n | EInt _, _, _ =>\r\n self.emitTerm(term, async)\r\n | _, _, _ =>\r\n if(before != \"\") {self.writeMapped(term.at, before)}\r\n self.emitTerm(term, async)\r\n if(after != \"\") {self.writeMapped(term.at, after)}\r\n }\r\n list.{\r\n | ECall(_, StaticCall(\"ff:core/List.List_dropFirst\", _, _), _, _, [a1, a2], _) =>\r\n self.writeMapped(list.at, \"for_a\" + suffix + \" = \")\r\n self.emitTerm(a1.value, async)\r\n if(isArray) {self.writeMapped(list.at, \".array\")}\r\n self.writeMapped(list.at, \", for_i\" + suffix + \" = \")\r\n wrapUnlessInt(a2.value, \"Math.max(\", \", 0)\")\r\n self.writeMapped(list.at, \", for_l\" + suffix + \" = \")\r\n self.writeMapped(list.at, \"for_a\" + suffix + \".length\")\r\n | ECall(_, StaticCall(\"ff:core/List.List_dropLast\", _, _), _, _, [a1, a2], _) =>\r\n self.writeMapped(list.at, \"for_a\" + suffix + \" = \")\r\n self.emitTerm(a1.value, async)\r\n if(isArray) {self.writeMapped(list.at, \".array\")}\r\n self.writeMapped(list.at, \", for_i\" + suffix + \" = 0\")\r\n self.writeMapped(list.at, \", for_l\" + suffix + \" = \")\r\n self.writeMapped(list.at, \"for_a\" + suffix + \".length - \")\r\n wrapUnlessInt(a2.value, \"Math.max(\", \", 0)\")\r\n | ECall(_, StaticCall(\"ff:core/List.List_takeFirst\", _, _), _, _, [a1, a2], _) =>\r\n self.writeMapped(list.at, \"for_a\" + suffix + \" = \")\r\n self.emitTerm(a1.value, async)\r\n if(isArray) {self.writeMapped(list.at, \".array\")}\r\n self.writeMapped(list.at, \", for_i\" + suffix + \" = 0\")\r\n self.writeMapped(list.at, \", for_l\" + suffix + \" = \")\r\n self.writeMapped(list.at, \"Math.min(\")\r\n wrapUnlessInt(a2.value, \"Math.max(\", \", 0)\")\r\n self.writeMapped(list.at, \", for_a\" + suffix + \".length)\")\r\n | ECall(_, StaticCall(\"ff:core/List.List_takeLast\", _, _), _, _, [a1, a2], _) =>\r\n self.writeMapped(list.at, \"for_a\" + suffix + \" = \")\r\n self.emitTerm(a1.value, async)\r\n if(isArray) {self.writeMapped(list.at, \".array\")}\r\n self.writeMapped(list.at, \", for_i\" + suffix + \" = \")\r\n self.writeMapped(list.at, \"Math.max(for_a\" + suffix + \".length - \")\r\n wrapUnlessInt(a2.value, \"Math.max(\", \", 0)\")\r\n self.writeMapped(list.at, \", 0), for_l\" + suffix + \" = \")\r\n self.writeMapped(list.at, \"for_a\" + suffix + \".length\")\r\n | _ => \r\n self.writeMapped(list.at, \"for_a\" + suffix + \" = \")\r\n self.emitTerm(list, async)\r\n if(isArray) {self.writeMapped(list.at, \".array\")}\r\n self.writeMapped(list.at, \", for_i\" + suffix + \" = 0\")\r\n self.writeMapped(list.at, \", for_l\" + suffix + \" = \")\r\n self.writeMapped(list.at, \"for_a\" + suffix + \".length\")\r\n } \r\n }\r\n\r\n emitTryCatchFinally(term: Term, last: Bool, async: Bool): Bool {\r\n function emitCatch(catchEffect: Type, cases: List[MatchCase]) {\r\n let catchAsync = self.emittingAsync && effectTypeIsAsync(catchEffect)\r\n Patterns.convertAndCheck(self.otherModules, cases)\r\n let arguments = [\r\n {self.writeMapped(term.at, \"_exception.value_\")}\r\n {self.writeMapped(term.at, \"_error\")}\r\n ]\r\n cases.{\r\n | [case] =>\r\n self.emitCase(arguments, case, [], [], False, last, False, True, catchAsync)\r\n | cs =>\r\n if(last) {\r\n self.writeMapped(term.at, \"do {\")\r\n self.writeLine()\r\n }\r\n let liner = Liner(self, double = False)\r\n cases.pairs().each {| Pair(i, c) =>\r\n liner.writeLines()\r\n let lastCase = i == cases.size() - 1\r\n self.emitCase(arguments, c, [], [], True, last, False, lastCase, catchAsync)\r\n }\r\n if(last) {\r\n self.writeLine()\r\n self.writeMapped(term.at, \"} while(false)\")\r\n } else {}\r\n }\r\n }\r\n term.{\r\n | ECall(_, StaticCall(\"ff:core/Try.Try_finally\", _, _), _, _, [\r\n Argument(_, _, ECall(_, StaticCall(\"ff:core/Core.try\", _, _), _, _, [\r\n Argument(_, _, ELambda(_, Lambda(_, tryEffect, [MatchCase(_, [], [], tryBody)])))\r\n ], _))\r\n Argument(_, _, ELambda(_, Lambda(_, finallyEffect, [MatchCase(_, [], [], finallyBody)])))\r\n ], _) =>\r\n let tryAsync = self.emittingAsync && effectTypeIsAsync(tryEffect)\r\n let finallyAsync = self.emittingAsync && effectTypeIsAsync(finallyEffect)\r\n self.writeMapped(term.at, \"try {\")\r\n self.writeLine()\r\n self.emitStatements(tryBody, last, False, tryAsync)\r\n self.writeLine()\r\n self.writeMapped(term.at, \"} finally {\")\r\n self.writeLine()\r\n self.emitStatements(finallyBody, last, False, finallyAsync)\r\n self.writeLine()\r\n self.writeMapped(term.at, \"}\")\r\n True\r\n | ECall(_, StaticCall(\"ff:core/Try.Try_catchAny\", _, _), _, _, [\r\n Argument(_, _, ECall(_, StaticCall(\"ff:core/Core.try\", _, _), _, _, [\r\n Argument(_, _, ELambda(_, Lambda(_, tryEffect, [MatchCase(_, [], [], tryBody)])))\r\n ], _))\r\n Argument(_, _, ELambda(_, Lambda(_, catchEffect, [\r\n MatchCase(_, [PVariable(nameAt, name)], [], catchBody)\r\n ])))\r\n ], _) =>\r\n let tryAsync = self.emittingAsync && effectTypeIsAsync(tryEffect)\r\n self.writeMapped(term.at, \"try {\")\r\n self.writeLine()\r\n self.emitStatements(tryBody, last, False, tryAsync)\r\n self.writeLine()\r\n self.writeMapped(term.at, \"} catch\")\r\n name.each {n =>\r\n self.writeMapped(nameAt, \"(\")\r\n self.writeNamed(n, nameAt, escapeKeyword(n))\r\n self.writeMapped(nameAt, \")\")\r\n }\r\n self.writeMapped(term.at, \" {\")\r\n self.writeLine()\r\n self.emitStatements(catchBody, last, False, tryAsync)\r\n self.writeLine()\r\n self.writeMapped(term.at, \"}\")\r\n True\r\n | ECall(_, StaticCall(\"ff:core/Try.Try_catch\", _, _), _, _, [\r\n Argument(_, _, ECall(_, StaticCall(\"ff:core/Core.try\", _, _), _, _, [\r\n Argument(_, _, ELambda(_, Lambda(_, tryEffect, [MatchCase(_, [], [], tryBody)])))\r\n ], _))\r\n Argument(_, _, ELambda(_, Lambda(_, catchEffect, cases)))\r\n ], [dictionary]) =>\r\n let tryAsync = self.emittingAsync && effectTypeIsAsync(tryEffect)\r\n let d = self.makeDictionary(dictionary)\r\n self.writeMapped(term.at, \"try {\")\r\n self.writeLine()\r\n self.emitStatements(tryBody, last, False, tryAsync)\r\n self.writeLine()\r\n self.writeMapped(term.at, \"} catch(_error) {\")\r\n self.writeLine()\r\n self.writeMapped(term.at, \"if(!_error.ffException) throw _error\")\r\n self.writeLine()\r\n self.writeMapped(term.at, \"const _exception = ff_core_Any.fromAny_(_error.ffException, \")\r\n self.writeMapped(term.at, d)\r\n self.writeMapped(term.at, \")\")\r\n self.writeLine()\r\n self.writeMapped(term.at, \"if(!_exception.Some) throw _error\")\r\n self.writeLine()\r\n emitCatch(catchEffect, cases)\r\n self.writeLine()\r\n self.writeMapped(term.at, \"}\")\r\n True\r\n | ECall(_, StaticCall(\"ff:core/Try.Try_finally\", _, _), _, _, [\r\n Argument(_, _, ECall(_, StaticCall(\"ff:core/Try.Try_catch\", _, _), _, _, [\r\n Argument(_, _, ECall(_, StaticCall(\"ff:core/Core.try\", _, _), _, _, [\r\n Argument(_, _, ELambda(_, Lambda(_, tryEffect, [MatchCase(_, [], [], tryBody)])))\r\n ], _))\r\n Argument(_, _, ELambda(_, Lambda(_, catchEffect, cases)))\r\n ], [dictionary]))\r\n Argument(_, _, ELambda(_, Lambda(_, finallyEffect, [MatchCase(_, [], [], finallyBody)])))\r\n ], _) =>\r\n let tryAsync = self.emittingAsync && effectTypeIsAsync(tryEffect)\r\n let finallyAsync = self.emittingAsync && effectTypeIsAsync(finallyEffect)\r\n let d = self.makeDictionary(dictionary)\r\n self.writeMapped(term.at, \"try {\")\r\n self.writeLine()\r\n self.emitStatements(tryBody, last, False, tryAsync)\r\n self.writeLine()\r\n self.writeMapped(term.at, \"} catch(_error) {\")\r\n self.writeLine()\r\n self.writeMapped(term.at, \"if(!_error.ffException) throw _error\")\r\n self.writeLine()\r\n self.writeMapped(term.at, \"const _exception = ff_core_Any.fromAny_(_error.ffException, \")\r\n self.writeMapped(term.at, d)\r\n self.writeMapped(term.at, \")\")\r\n self.writeLine()\r\n self.writeMapped(term.at, \"if(!_exception.Some) throw _error\")\r\n self.writeLine()\r\n emitCatch(catchEffect, cases)\r\n self.writeLine()\r\n self.writeMapped(term.at, \"} finally {\")\r\n self.writeLine()\r\n self.emitStatements(finallyBody, last, False, finallyAsync)\r\n self.writeLine()\r\n self.writeMapped(term.at, \"}\")\r\n True\r\n | _ =>\r\n False\r\n }\r\n }\r\n\r\n emitCase(\r\n arguments: List[() => Unit]\r\n matchCase: MatchCase\r\n conditions: List[() => Unit]\r\n variables: List[() => Unit]\r\n jump: Bool\r\n last: Bool\r\n break: Bool\r\n lastCase: Bool\r\n async: Bool\r\n ) {\r\n function emitWrapperStart() {\r\n if(conditions.isEmpty()) {\r\n self.writeMapped(matchCase.at, \"{\")\r\n } else {\r\n self.writeMapped(matchCase.at, \"if(\")\r\n conditions.pairs().each {| Pair(i, c) => \r\n c()\r\n if(i < conditions.size() - 1) {\r\n self.writeMapped(matchCase.at, \" && \")\r\n }\r\n }\r\n self.writeMapped(matchCase.at, \") {\")\r\n }\r\n self.writeLine()\r\n variables.each {_()}\r\n }\r\n\r\n function emitWrapperEnd() {\r\n self.writeLine()\r\n self.writeMapped(matchCase.at, \"}\")\r\n }\r\n\r\n Pair(matchCase.patterns, matchCase.guards).{\r\n | Pair([p, ...ps], _) =>\r\n self.emitPattern(\r\n arguments.grab(0)\r\n p\r\n arguments.dropFirst()\r\n matchCase.MatchCase(patterns = ps)\r\n conditions\r\n variables\r\n jump\r\n last\r\n break\r\n lastCase\r\n async\r\n )\r\n | Pair([], [MatchGuard(_, e, PVariant(_, \"ff:core/Bool.True\", _))]) {variables.isEmpty()} =>\r\n let newCase = matchCase.MatchCase(patterns = [], guards = [])\r\n self.emitCase([], newCase, [...conditions, {self.emitTerm(e, async)}], [], jump, last, break, lastCase, async)\r\n | Pair([], [MatchGuard(_, e, PVariant(_, \"ff:core/Bool.True\", _))]) =>\r\n let newCase = matchCase.MatchCase(patterns = [], guards = [])\r\n emitWrapperStart()\r\n self.emitCase([], newCase, [{self.emitTerm(e, async)}], [], jump, last, break, lastCase, async)\r\n emitWrapperEnd()\r\n | Pair([], [guard, ...guards]) =>\r\n let guardName = \"_guard\" + (guards.size() + 1)\r\n let newCase = matchCase.MatchCase(patterns = [guard.pattern], guards = guards)\r\n emitWrapperStart()\r\n self.writeMapped(guard.at, \"const \" + guardName + \" = \")\r\n self.emitTerm(guard.term, async)\r\n self.writeMapped(guard.at, \";\")\r\n self.writeLine()\r\n self.emitCase([{self.writeMapped(guard.at, guardName)}], newCase, [], [], jump, last, break, lastCase, async)\r\n emitWrapperEnd()\r\n | Pair([], []) =>\r\n emitWrapperStart()\r\n self.emitStatements(matchCase.body, last, break, async)\r\n let returns = self.writtenStrings.last().any {line => \r\n line.first().any {part => \r\n part.startsWith(\"return \") || \r\n part.startsWith(\"break \") ||\r\n part.startsWith(\"continue \") ||\r\n part.startsWith(\"return;\") || \r\n part.startsWith(\"break;\") ||\r\n part.startsWith(\"continue;\") ||\r\n part.startsWith(\"throw \")\r\n }\r\n }\r\n if(jump && last && !returns) {\r\n self.writeLine()\r\n self.writeMapped(matchCase.at, \"return\")\r\n } elseIf {jump && !returns && !lastCase} {\r\n self.writeLine()\r\n self.writeMapped(matchCase.at, if(break) {\"continue\"} else {\"break\"})\r\n }\r\n emitWrapperEnd()\r\n }\r\n }\r\n\r\n emitPattern(\r\n argument: () => Unit\r\n pattern: MatchPattern\r\n arguments: List[() => Unit]\r\n matchCase: MatchCase\r\n conditions: List[() => Unit]\r\n variables: List[() => Unit]\r\n jump: Bool\r\n last: Bool\r\n break: Bool\r\n lastCase: Bool\r\n async: Bool\r\n ) {\r\n function addUnaryCondition(at: Location, operator: String, right: () => Unit): List[() => Unit] {\r\n addCondition {\r\n self.writeMapped(at, operator)\r\n right()\r\n }\r\n }\r\n function addBinaryCondition(at: Location, operator: String, left: () => Unit, right: () => Unit): List[() => Unit] {\r\n addCondition {\r\n left()\r\n self.writeMapped(at, \" \" + operator + \" \")\r\n right()\r\n }\r\n }\r\n function addCondition(condition: () => Unit): List[() => Unit] {\r\n if(lastCase) {conditions} else {[...conditions, condition]}\r\n }\r\n pattern.{\r\n | PString(_, value) =>\r\n let newConditions = addBinaryCondition(pattern.at, \"===\", argument, {self.writeMapped(pattern.at, value)})\r\n self.emitCase(arguments, matchCase, newConditions, variables, jump, last, break, lastCase, async)\r\n | PInt(_, value) =>\r\n let newConditions = addBinaryCondition(pattern.at, \"===\", argument, {self.writeMapped(pattern.at, value)})\r\n self.emitCase(arguments, matchCase, newConditions, variables, jump, last, break, lastCase, async)\r\n | PChar(_, value) =>\r\n let newConditions = addBinaryCondition(pattern.at, \"===\", argument, {self.writeMapped(pattern.at, charLiteralToNumber(value))})\r\n self.emitCase(arguments, matchCase, newConditions, variables, jump, last, break, lastCase, async)\r\n | PVariable(_, None) =>\r\n self.emitCase(arguments, matchCase, conditions, variables, jump, last, break, lastCase, async)\r\n | PVariable(at, Some(name)) =>\r\n let newVariables = [...variables, {\r\n self.writeMapped(at, \"const \")\r\n self.writeNamed(name, at, escapeKeyword(name))\r\n self.writeMapped(at, \" = \")\r\n argument()\r\n self.writeMapped(at, \";\")\r\n self.writeLine()\r\n }]\r\n self.emitCase(arguments, matchCase, conditions, newVariables, jump, last, break, lastCase, async)\r\n | PVariant(at, \"ff:core/Bool.False\", []) =>\r\n self.emitCase(arguments, matchCase, addUnaryCondition(at, \"!\", argument), variables, jump, last, break, lastCase, async)\r\n | PVariant(_, \"ff:core/Bool.True\", []) =>\r\n self.emitCase(arguments, matchCase, addCondition(argument), variables, jump, last, break, lastCase, async)\r\n | PVariant(at, emptyOrLink, _) {emptyOrLink == \"List$Empty\" || emptyOrLink == \"List$Link\"} =>\r\n mutable restPattern = None\r\n function listPatterns(matchPattern: MatchPattern): List[MatchPattern] {\r\n | PVariant(_, \"List$Empty\", []) => \r\n []\r\n | PVariant(_, \"List$Link\", [head, tail]) =>\r\n [head, ...listPatterns(tail)]\r\n | p =>\r\n restPattern = Some(p)\r\n []\r\n }\r\n let patterns = listPatterns(pattern)\r\n let itemArguments = patterns.pairs().map {| Pair(i, _) => {\r\n argument()\r\n self.writeMapped(at, \"[\" + i + \"]\")\r\n }}\r\n let restArgument = restPattern.map {_ => {\r\n argument()\r\n self.writeMapped(at, \".slice(\" + patterns.size() + \")\")\r\n }}\r\n let newArguments = [...itemArguments, ...restArgument.toList(), ...arguments]\r\n let newMatchCase = matchCase.MatchCase(\r\n patterns = [...patterns, ...restPattern.toList(), ...matchCase.patterns]\r\n )\r\n let operator = restPattern.map {_ => \">=\"}.else {\"===\"}\r\n let newConditions = addBinaryCondition(at, operator\r\n {\r\n argument()\r\n self.writeMapped(at, \".length\")\r\n }\r\n {\r\n self.writeMapped(at, \"\" + patterns.size())\r\n }\r\n )\r\n self.emitCase(newArguments, newMatchCase, newConditions, variables, jump, last, break, lastCase, async)\r\n | PVariant(at, name, patterns) =>\r\n let processed = self.processVariantCase(at, name, argument)\r\n let newMatchCase = matchCase.MatchCase(patterns = [...patterns, ...matchCase.patterns])\r\n let newConditions = if(processed.loneVariant || lastCase) {conditions} else {\r\n [...conditions, {\r\n argument()\r\n self.writeMapped(at, \".\")\r\n self.writeNamed(processed.variantName, at, processed.variantName)\r\n }]\r\n }\r\n let newArguments = [...processed.arguments, ...arguments]\r\n self.emitCase(newArguments, newMatchCase, newConditions, variables, jump, last, break, lastCase, async)\r\n | PVariantAs(at, name, variableAt, variable) =>\r\n let processed = self.processVariantCase(at, name, argument)\r\n let newConditions = if(processed.loneVariant || lastCase) {conditions} else {\r\n [...conditions, {\r\n argument()\r\n self.writeMapped(at, \".\")\r\n self.writeNamed(processed.variantName, at, processed.variantName)\r\n }]\r\n }\r\n let newVariables = variable.map {x =>\r\n [...variables, {\r\n self.writeMapped(at, \"const \")\r\n self.writeNamed(x, at, escapeKeyword(x))\r\n self.writeMapped(at, \" = \")\r\n argument()\r\n self.writeMapped(at, \";\")\r\n self.writeLine()\r\n }]\r\n }.else {variables}\r\n self.emitCase(arguments, matchCase, newConditions, newVariables, jump, last, break, lastCase, async)\r\n | PAlias(at, pattern, variable) =>\r\n let newVariables = [...variables, {\r\n self.writeMapped(at, \"const \")\r\n self.writeNamed(variable, at, escapeKeyword(variable))\r\n self.writeMapped(at, \" = \")\r\n argument()\r\n self.writeMapped(at, \";\")\r\n self.writeLine() \r\n }]\r\n self.emitPattern(argument, pattern, arguments, matchCase, conditions, newVariables, jump, last, break, lastCase, async)\r\n }\r\n }\r\n\r\n emitList(at: Location, items: List[Pair[Term, Bool]], async: Bool) {\r\n self.writeMapped(at, \"[\")\r\n let comma = Comma(self)\r\n items.each {\r\n | Pair(item, False) => \r\n comma.writeComma()\r\n self.emitTerm(item, async)\r\n | Pair(item, True) => \r\n comma.writeComma()\r\n self.writeMapped(item.at, \"...\")\r\n self.emitTerm(item, async)\r\n }\r\n self.writeMapped(at, \"]\")\r\n }\r\n\r\n processVariantCase(at: Location, name: String, argument: () => Unit): ProcessedVariantCase {\r\n let variantNameUnqualified = name.reverse().takeWhile {_ != '.'}.reverse()\r\n let variantName = escapeKeyword(variantNameUnqualified)\r\n let moduleName = name.dropLast(variantNameUnqualified.size() + 1)\r\n let variantModule = self.otherModules.grab(moduleName)\r\n mutable newtype = False\r\n mutable loneVariant = False\r\n let newArguments = variantModule.types.collectFirst {definition =>\r\n definition.variants.find {_.name == variantName }.map {variant =>\r\n newtype = definition.newtype\r\n loneVariant = definition.variants.size() == 1\r\n [...definition.commonFields.map {_.name}, ...variant.fields.map {_.name}]\r\n }\r\n }.grab().map {field => if(newtype) {argument} else {{\r\n argument()\r\n self.writeMapped(at, \".\" + escapeKeyword(field))\r\n }}}\r\n ProcessedVariantCase(variantName, newtype, loneVariant, newArguments)\r\n }\r\n\r\n processVariant(name: String): Bool {\r\n if(name.startsWith(\"List$\")) {False} else:\r\n let variantNameUnqualified = name.reverse().takeWhile {_ != '.'}.reverse()\r\n let variantName = escapeKeyword(variantNameUnqualified)\r\n let moduleName = name.dropLast(variantNameUnqualified.size() + 1)\r\n let variantModule = self.otherModules.grab(moduleName)\r\n mutable newtype = False\r\n variantModule.types.collectFirst {definition =>\r\n definition.variants.find {_.name == variantName}.map {variant =>\r\n newtype = definition.newtype\r\n }\r\n }.grab()\r\n newtype\r\n }\r\n\r\n emitArgument(callAt: Location, argument: Argument, async: Bool) {\r\n argument.value.{\r\n | ECall(at, StaticCall(\"ff:core/SourceLocation.callSite\", _, _), _, _, _, _) => \r\n self.writeMapped(at, \"\\\"\")\r\n self.moduleKey.folders.each {\r\n self.writeMapped(at, _ + \"/\")\r\n }\r\n self.writeMapped(at, self.moduleKey.name)\r\n self.writeMapped(at, \":\" + callAt.line + \":\" + callAt.column)\r\n self.writeMapped(at, \",\" + self.moduleKey.packagePair.group + \",\" + self.moduleKey.packagePair.name)\r\n self.writeMapped(at, \"\\\"\")\r\n | value =>\r\n self.emitTerm(value, async)\r\n }\r\n }\r\n \r\n}\r\n\r\ncapability ProcessedVariantCase(\r\n variantName: String\r\n newtype: Bool\r\n loneVariant: Bool\r\n arguments: List[() => Unit]\r\n)\r\n\r\nrawJs(at: Location, rawIdentifier: String): Term {\r\n let noEffect = TConstructor(at, \"ff:core/Nothing.Nothing\", [])\r\n ECall(at, StaticCall(\"ff:core/Js.rawIdentifier\", False, False), noEffect, [], [\r\n Argument(at, None, EString(at, rawIdentifier))\r\n ], [])\r\n}\r\n\r\ndetectIfElse(term: Term): List[Pair[Term, Term]] {\r\n | ECall(at, StaticCall(\"ff:core/Core.if\", _, _), _, _, [condition, body], _) =>\r\n [Pair(condition.value, invokeImmediately(body.value))]\r\n | ECall(at, StaticCall(\"ff:core/Option.Option_elseIf\", _, _), _, _, [option, condition, body], _) =>\r\n let list = detectIfElse(option.value)\r\n if(list.isEmpty()) {[]} else:\r\n [Pair(invokeImmediately(condition.value), invokeImmediately(body.value)), ...list]\r\n | ECall(at, StaticCall(\"ff:core/Option.Option_else\", _, _), _, _, [option, body], _) =>\r\n let list = detectIfElse(option.value)\r\n if(list.isEmpty()) {[]} else:\r\n [Pair(EVariant(at, \"ff:core/Bool.True\", [], None), invokeImmediately(body.value)), ...list]\r\n | _ =>\r\n []\r\n}\r\n\r\ninvokeImmediately(function: Term): Term {\r\n | ELambda(_, Lambda(_, effect, [MatchCase(_, [], [], body)])) =>\r\n body\r\n | _ =>\r\n let effect = TConstructor(function.at, \"Q$\", []) // Awaits more often than required in async context\r\n ECall(function.at, DynamicCall(function, False), effect, [], [], [])\r\n}\r\n\r\nsafeCommable(term: Term): Bool {\r\n term.{\r\n | EField _ => True\r\n | EVariable _ => True\r\n | EAssign _ => True\r\n | EAssignField _ => True\r\n | ECall _ => True\r\n | ECopy _ => True\r\n | EVariant _ => True\r\n | EString(_, _) => True\r\n | EInt(_, _) => True\r\n | EChar(_, _) => True\r\n | EFloat(_, _) => True\r\n | EList _ => True\r\n | EPipe _ => True\r\n | ERecord _ => True\r\n | EWildcard _ => True \r\n | _ => False\r\n }\r\n}\r\n\r\nextractTypeName(type: Type): String {\r\n | TVariable(at, index) =>\r\n fail(at, \"Unexpected type variable: $\" + index)\r\n | TConstructor t =>\r\n t.name\r\n}\r\n\r\nfirstTypeName(types: List[Type]): String {\r\n types.grabFirst().{\r\n | TConstructor t => t.name\r\n | TVariable t => fail(t.at, \" is still a unification variable\")\r\n }\r\n}\r\n\r\nmakeDictionaryName(traitName: String, typeName: String): String {\r\n traitName.replace(\".\", \"_\").replace(\":\", \"_\").replace(\"/\", \"_\") + \"$\" +\r\n typeName.replace(\".\", \"_\").replace(\":\", \"_\").replace(\"/\", \"_\")\r\n}\r\n\r\ncharLiteralToNumber(charLiteral: String): String {\r\n | \"'\\\\t'\" => \"9\"\r\n | \"'\\\\n'\" => \"10\"\r\n | \"'\\\\r'\" => \"13\"\r\n | \"'\\\\\\\"'\" => \"34\"\r\n | \"'\\\\''\" => \"39\"\r\n | value => \"\" + value.grab(1).codeUnit\r\n}\r\n\r\nescapeResolved(word: String): String {\r\n let parts = word.replace(\":\", \".\").replace(\"/\", \".\").split('.')\r\n let initialParts = parts.dropLast()\r\n if(initialParts.isEmpty()) {\r\n escapeKeyword(parts.grabLast())\r\n } else {\r\n initialParts.join(\"_\") + \".\" + escapeKeyword(parts.grabLast())\r\n }\r\n}\r\n\r\nescapeKeyword(word: String): String {\r\n if(word.grabFirst().isAsciiLower()) {word + \"_\"} else {word}\r\n}\r\n\r\neffectTypeIsAsync(effect: Type): Bool {\r\n | TConstructor(_, \"Q$\", _) => True\r\n | _ => False\r\n}\r\n\r\nsafeBare(quotedString: String): Option[String] {\r\n // TODO: And not a reserved word in JS\r\n quotedString.removeFirst(\"\\\"\").flatMap {_.removeLast(\"\\\"\")}.filter {s => \r\n s.first().any {_.isAsciiLetter()} && s.all {_.isAsciiLetterOrDigit()}\r\n }\r\n}\r\n\r\nnoSideEffects(term: Term): Bool {\r\n term.{\r\n | EField(_, _, e, _) => noSideEffects(e)\r\n | EVariable(_, _) => True\r\n | ECall(_, StaticCall(\"ff:core/BrowserSystem.BrowserSystem_js\", _, _), _, _, [a], _) => noSideEffects(a.value)\r\n | ECall(_, StaticCall(\"ff:core/BuildSystem.BuildSystem_js\", _, _), _, _, [a], _) => noSideEffects(a.value)\r\n | ECall(_, StaticCall(\"ff:core/NodeSystem.NodeSystem_js\", _, _), _, _, [a], _) => noSideEffects(a.value)\r\n | ECall(_, StaticCall(\"ff:core/Js.jsSystem\", _, _), _, _, _, _) => True\r\n | EString(_, _) => True\r\n | EInt(_, _) => True\r\n | EChar(_, _) => True\r\n | EFloat(_, _) => True\r\n | _ => False\r\n }\r\n}\r\n\r\nprimitiveTypes = [\r\n \"ff:core/Bool.Bool\"\r\n \"ff:core/Char.Char\"\r\n \"ff:core/Int.Int\"\r\n \"ff:core/Float.Float\"\r\n \"ff:core/String.String\"\r\n].toSet()\r\n\r\nclass Liner(emitter: JsEmitter, double: Bool, mutable first: Bool = True)\r\n\r\nextend self: Liner {\r\n writeLines() {\r\n if(self.first) {\r\n self.first = False\r\n } else {\r\n self.emitter.writeLine()\r\n if(self.double) {self.emitter.writeLine()}\r\n }\r\n }\r\n}\r\n\r\nclass Comma(emitter: JsEmitter, mutable first: Bool = True, delimiter: String = \", \")\r\n\r\nextend self: Comma {\r\n writeComma() {\r\n if(self.first) {\r\n self.first = False\r\n } else {\r\n self.emitter.writeUnmapped(self.delimiter)\r\n }\r\n }\r\n}\r\n"
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": [
4
- "../../../../../compiler/JsImporter.ff"
4
+ "../../../../compiler/JsImporter.ff"
5
5
  ],
6
6
  "sourcesContent": [
7
7
  "import Syntax\r\n\r\nclass JsImporter(\r\n mutable imports: Map[String, String]\r\n)\r\n\r\nnew(): JsImporter {\r\n JsImporter(Map.new())\r\n}\r\n\r\nfail[T](at: Location, message: String): T {\r\n panic(message + \" \" + at.show())\r\n}\r\n\r\nextend self: JsImporter {\r\n\r\n add(url: String): String {\r\n let importName = self.imports.get(url).{\r\n | None =>\r\n let n = \"import$\" + self.imports.size()\r\n self.imports = self.imports.add(url, n)\r\n n\r\n | Some(n) => n\r\n }\r\n importName\r\n }\r\n\r\n process(at: Location, code: String): String {\r\n let space = code.takeWhile {c => c == ' ' || c == '\\t' || c == '\\r' || c == '\\n' || c == ';'}\r\n let rest = code.dropFirst(space.size())\r\n if(!rest.startsWith(\"import * as \")) {code} else:\r\n let rest2 = rest.dropFirst(\"import * as \".size())\r\n let name = rest2.takeWhile {_.isAsciiLetterOrDigit()}\r\n if(name.size() == 0) {throw(CompileError(at, \"Expected alias after \\\"import * as \\\"\"))}\r\n let rest3 = rest2.dropFirst(name.size())\r\n if(!rest3.startsWith(\" from '\")) {throw(CompileError(at, \"Expected \\\" from '\\\" after \\\"import * as ...\\\"\"))}\r\n let rest4 = rest3.dropFirst(\" from '\".size())\r\n let url = rest4.takeWhile {_ != '\\''}\r\n if(url.size() == 0) {throw(CompileError(at, \"Expected module name after \\\" from '\\\"\"))}\r\n if(url.any {_ == '\\n'}) {throw(CompileError(at, \"Unclosed module name string\"))}\r\n let rest5 = rest4.dropFirst(url.size() + 1)\r\n let importName = self.add(url)\r\n space + \"const \" + name + \" = \" + importName + self.process(at, rest5)\r\n }\r\n\r\n generateImports(ignoreModules: Set[String]): List[String] {\r\n self.imports.pairs().map {| Pair(moduleName, mangledName) =>\r\n if(ignoreModules.contains(moduleName)) {\r\n \"const \" + mangledName + \" = void 0; // Ignored import\"\r\n } else {\r\n \"import * as \" + mangledName + \" from '\" + moduleName + \"';\"\r\n }\r\n }\r\n }\r\n\r\n}\r\n"
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": [
4
- "../../../../../compiler/LspHook.ff"
4
+ "../../../../compiler/LspHook.ff"
5
5
  ],
6
6
  "sourcesContent": [
7
7
  "import Syntax\r\nimport Unification\r\nimport Environment\r\n\r\nclass LspHook(\r\n at: Location\r\n definedAt: Location\r\n insertIdentifier: Bool\r\n trackSymbols: Bool\r\n arrayOfResults: Array[ResultHook]\r\n)\r\n\r\ndisabled(): LspHook {\r\n new(None, None, False, False)\r\n}\r\n\r\nnew(at: Option[Location], definedAt: Option[Location], insertIdentifier: Bool, trackSymbols: Bool): LspHook {\r\n LspHook( // Default dummy values instead of Option[Location] to speed up location hit check\r\n at = at.else {Location(\"^lsp\", -7, -7)}\r\n definedAt = definedAt.else {Location(\"^lsp\", -7, -7)}\r\n insertIdentifier = insertIdentifier\r\n trackSymbols = trackSymbols\r\n arrayOfResults = [].toArray()\r\n )\r\n}\r\n\r\nextend self: LspHook {\r\n isEnabled(): Bool {\r\n self.at.line != -7 || \r\n self.definedAt.line != -7 ||\r\n self.trackSymbols\r\n }\r\n isAt(at: Location): Bool {\r\n self.at.line == at.line &&\r\n self.at.column == at.column &&\r\n self.at.file == at.file\r\n }\r\n isDefinedAt(at: Location): Bool {\r\n self.definedAt.line == at.line &&\r\n self.definedAt.column == at.column &&\r\n self.definedAt.file == at.file\r\n }\r\n emit(result: ResultHook) {\r\n self.arrayOfResults.push(result)\r\n }\r\n results(): List[ResultHook] {\r\n self.arrayOfResults.toList()\r\n }\r\n}\r\n\r\nstrictlyBetween(afterAt: Location, beforeAt: Location, at: Location, extraColumns: Int): Bool {\r\n at.file == afterAt.file && (\r\n (at.line == afterAt.line && at.column > afterAt.column) ||\r\n at.line > afterAt.line\r\n ) && (\r\n (at.line == beforeAt.line && at.column < beforeAt.column + extraColumns) ||\r\n at.line < beforeAt.line\r\n )\r\n}\r\n\r\ndata SymbolHook(\r\n qualifiedName: String\r\n usageAt: Location\r\n definedAt: Location\r\n)\r\n\r\nclass Box[T](mutable value: T)\r\n\r\ndata DocumentSymbolKind {\r\n SLet(mutable: Bool)\r\n SFunction(member: Bool)\r\n SExtend\r\n STraitFunction\r\n STrait\r\n SInstance\r\n SVariant\r\n SType\r\n SParameter\r\n}\r\n\r\nclass ResultHook {\r\n ParseSymbolBegin\r\n ParseSymbolEnd(\r\n name: String\r\n kind: DocumentSymbolKind\r\n selectionStart: Location\r\n selectionEnd: Location\r\n start: Location\r\n end: Location\r\n )\r\n ParseArgumentHook(\r\n callAt: Location\r\n argumentIndex: Int\r\n parameterName: Option[String]\r\n )\r\n ResolveSymbolHook(\r\n symbol: SymbolHook\r\n annotation: Option[Type]\r\n topLevel: Bool\r\n )\r\n ResolveTypeHook(\r\n types: Map[String, String]\r\n typeGenerics: Map[String, List[String]]\r\n symbol: SymbolHook\r\n explicitType: Type\r\n )\r\n ResolveConstraintHook(\r\n symbol: SymbolHook\r\n constrant: Constraint\r\n )\r\n ResolveSignatureHook(\r\n signature: Signature\r\n isInstanceMethod: Bool\r\n topLevel: Bool\r\n )\r\n ResolveVariantFieldHook(\r\n symbol: SymbolHook\r\n type: Type\r\n commonField: Bool\r\n )\r\n InferTermHook(\r\n unification: Unification\r\n environment: Environment\r\n expected: Type\r\n term: Term\r\n recordType: Box[Option[Type]]\r\n missing: StringMap[Pair[Instantiated, Option[List[Argument]]]]\r\n )\r\n InferLambdaStartHook(\r\n unification: Unification\r\n environment: Environment\r\n lambdaType: Type\r\n )\r\n InferSequentialStartHook(\r\n unification: Unification\r\n term: Term\r\n missing: StringMap[Pair[Instantiated, Option[List[Argument]]]]\r\n )\r\n InferFunctionDefinitionHook(\r\n unification: Unification\r\n environment: Environment\r\n definition: DFunction\r\n missing: StringMap[Pair[Instantiated, Option[List[Argument]]]]\r\n )\r\n InferPatternHook(\r\n unification: Unification\r\n environment: Environment\r\n expected: Type\r\n pattern: MatchPattern\r\n )\r\n InferParameterHook(\r\n unification: Unification\r\n environment: Environment\r\n parameter: Parameter\r\n missing: StringMap[Pair[Instantiated, Option[List[Argument]]]]\r\n )\r\n InferArgumentHook(\r\n unification: Unification\r\n environment: Environment\r\n isCopy: Bool\r\n callAt: Location\r\n callName: String\r\n parameters: List[Parameter]\r\n arguments: List[Argument]\r\n argumentIndex: Int\r\n )\r\n InferLookupHook(\r\n unification: Unification\r\n environment: Environment\r\n expected: Type\r\n selfVariable: Option[String]\r\n symbol: Box[SymbolHook]\r\n instantiated: Box[Option[Instantiated]]\r\n )\r\n InferRecordFieldHook(\r\n usageAt: Location\r\n unification: Unification\r\n environment: Environment\r\n expected: Type\r\n recordType: Type\r\n fieldName: String\r\n )\r\n}\r\n\r\nshowHook(hook: ResultHook): String {\r\n | InferArgumentHook(unification, environment, isCopy, callAt, callName, parameters, arguments, argumentIndex) => \"InferArgumentHook(...)\"\r\n | InferFunctionDefinitionHook(unification, environment, definition, missing) => \"InferFunctionDefinitionHook(...)\"\r\n | InferLambdaStartHook(unification, environment, lambdaType) => \"InferLambdaStartHook(...)\"\r\n | InferLookupHook(unification, environment, expected, selfVariable, symbol, instantiated) => \"InferLookupHook(...)\"\r\n | InferParameterHook(unification, environment, parameter, missing) => \"InferParameterHook(...)\"\r\n | InferPatternHook(unification, environment, expected, pattern) => \"InferPatternHook(...)\"\r\n | InferRecordFieldHook(usageAt, unification, environment, expected, recordType, fieldName) => \"InferRecordFieldHook(...)\"\r\n | InferSequentialStartHook(unification, term, missing) => \"InferSequentialStartHook(...)\"\r\n | InferTermHook(unification, environment, expected, term, recordType, missing) => \"InferTermHook(...)\"\r\n | ParseArgumentHook(callAt, argumentIndex, parameterName) => \"ParseArgumentHook(...)\"\r\n | ParseSymbolBegin => \"ParseSymbolBegin(...)\"\r\n | ParseSymbolEnd(name, kind, selectionStart, selectionEnd, start, end) => \"ParseSymbolEnd(...)\"\r\n | ResolveConstraintHook(symbol, constrant) => \"ResolveConstraintHook(...)\"\r\n | ResolveSignatureHook(signature, _, _) => \"ResolveSignatureHook(...)\"\r\n | ResolveSymbolHook(symbol, annotation, _) => \"ResolveSymbolHook(...)\"\r\n | ResolveTypeHook(types, typeGenerics, symbol, explicitType) => \"ResolveTypeHook(...)\"\r\n | ResolveVariantFieldHook(symbol, type, commonField) => \"ResolveVariantFieldHook(...)\"\r\n}"