firefly-compiler 0.4.17 → 0.4.19

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 (115) hide show
  1. package/compiler/Builder.ff +1 -1
  2. package/compiler/Compiler.ff +6 -5
  3. package/compiler/Inference.ff +31 -19
  4. package/compiler/JsEmitter.ff +98 -71
  5. package/compiler/JsImporter.ff +1 -1
  6. package/compiler/LspHook.ff +4 -4
  7. package/compiler/Main.ff +6 -6
  8. package/compiler/Parser.ff +39 -39
  9. package/compiler/Patterns.ff +2 -0
  10. package/compiler/Syntax.ff +1 -1
  11. package/compiler/Tokenizer.ff +2 -2
  12. package/compiler/Workspace.ff +2 -2
  13. package/core/Array.ff +135 -294
  14. package/core/Buffer.ff +3 -3
  15. package/core/BuildSystem.ff +1 -1
  16. package/core/Equal.ff +36 -52
  17. package/core/HttpClient.ff +1 -1
  18. package/core/IntMap.ff +14 -18
  19. package/core/JsSystem.ff +1 -1
  20. package/core/JsValue.ff +6 -12
  21. package/core/Json.ff +19 -28
  22. package/core/List.ff +281 -312
  23. package/core/Map.ff +4 -8
  24. package/core/NodeSystem.ff +2 -2
  25. package/core/Option.ff +0 -4
  26. package/core/Ordering.ff +10 -6
  27. package/core/Pair.ff +0 -4
  28. package/core/Random.ff +12 -26
  29. package/core/RbMap.ff +216 -216
  30. package/core/Serializable.ff +9 -18
  31. package/core/Set.ff +0 -1
  32. package/core/SourceLocation.ff +1 -1
  33. package/core/Stack.ff +32 -45
  34. package/core/Stream.ff +10 -14
  35. package/core/String.ff +24 -6
  36. package/core/StringMap.ff +15 -19
  37. package/guide/Main.ff +20 -2
  38. package/lsp/CompletionHandler.ff +4 -4
  39. package/lsp/Handler.ff +45 -34
  40. package/lsp/HoverHandler.ff +2 -2
  41. package/lsp/LanguageServer.ff +2 -2
  42. package/lsp/SignatureHelpHandler.ff +1 -1
  43. package/lsp/SymbolHandler.ff +1 -1
  44. package/lux/Lux.ff +3 -3
  45. package/output/js/ff/compiler/Builder.mjs +19 -21
  46. package/output/js/ff/compiler/Compiler.mjs +18 -20
  47. package/output/js/ff/compiler/Dependencies.mjs +8 -10
  48. package/output/js/ff/compiler/Deriver.mjs +234 -236
  49. package/output/js/ff/compiler/Dictionaries.mjs +6 -8
  50. package/output/js/ff/compiler/Environment.mjs +42 -44
  51. package/output/js/ff/compiler/Inference.mjs +346 -304
  52. package/output/js/ff/compiler/JsEmitter.mjs +907 -833
  53. package/output/js/ff/compiler/JsImporter.mjs +0 -2
  54. package/output/js/ff/compiler/LspHook.mjs +10 -12
  55. package/output/js/ff/compiler/Main.mjs +109 -111
  56. package/output/js/ff/compiler/Parser.mjs +405 -407
  57. package/output/js/ff/compiler/Patterns.mjs +64 -50
  58. package/output/js/ff/compiler/Resolver.mjs +36 -38
  59. package/output/js/ff/compiler/Substitution.mjs +4 -6
  60. package/output/js/ff/compiler/Syntax.mjs +160 -162
  61. package/output/js/ff/compiler/Token.mjs +52 -54
  62. package/output/js/ff/compiler/Tokenizer.mjs +16 -18
  63. package/output/js/ff/compiler/Unification.mjs +24 -26
  64. package/output/js/ff/compiler/Wildcards.mjs +0 -2
  65. package/output/js/ff/compiler/Workspace.mjs +18 -20
  66. package/output/js/ff/core/Any.mjs +0 -2
  67. package/output/js/ff/core/Array.mjs +216 -613
  68. package/output/js/ff/core/AssetSystem.mjs +2 -4
  69. package/output/js/ff/core/Atomic.mjs +0 -2
  70. package/output/js/ff/core/Bool.mjs +0 -2
  71. package/output/js/ff/core/Box.mjs +0 -2
  72. package/output/js/ff/core/BrowserSystem.mjs +0 -2
  73. package/output/js/ff/core/Buffer.mjs +0 -2
  74. package/output/js/ff/core/BuildSystem.mjs +12 -14
  75. package/output/js/ff/core/Channel.mjs +0 -2
  76. package/output/js/ff/core/Char.mjs +0 -2
  77. package/output/js/ff/core/Core.mjs +0 -2
  78. package/output/js/ff/core/Duration.mjs +0 -2
  79. package/output/js/ff/core/Equal.mjs +0 -22
  80. package/output/js/ff/core/Error.mjs +0 -2
  81. package/output/js/ff/core/FileHandle.mjs +0 -2
  82. package/output/js/ff/core/Float.mjs +0 -2
  83. package/output/js/ff/core/HttpClient.mjs +2 -4
  84. package/output/js/ff/core/Instant.mjs +0 -2
  85. package/output/js/ff/core/Int.mjs +8 -10
  86. package/output/js/ff/core/IntMap.mjs +32 -42
  87. package/output/js/ff/core/JsSystem.mjs +1 -3
  88. package/output/js/ff/core/JsValue.mjs +5 -12
  89. package/output/js/ff/core/Json.mjs +23 -56
  90. package/output/js/ff/core/List.mjs +648 -1989
  91. package/output/js/ff/core/Lock.mjs +0 -2
  92. package/output/js/ff/core/Log.mjs +0 -2
  93. package/output/js/ff/core/Map.mjs +10 -20
  94. package/output/js/ff/core/NodeSystem.mjs +6 -8
  95. package/output/js/ff/core/Nothing.mjs +0 -2
  96. package/output/js/ff/core/Option.mjs +8 -18
  97. package/output/js/ff/core/Ordering.mjs +20 -98
  98. package/output/js/ff/core/Pair.mjs +6 -16
  99. package/output/js/ff/core/Path.mjs +12 -14
  100. package/output/js/ff/core/Random.mjs +24 -54
  101. package/output/js/ff/core/RbMap.mjs +54 -56
  102. package/output/js/ff/core/Serializable.mjs +19 -36
  103. package/output/js/ff/core/Set.mjs +0 -14
  104. package/output/js/ff/core/Show.mjs +0 -2
  105. package/output/js/ff/core/SourceLocation.mjs +0 -2
  106. package/output/js/ff/core/Stream.mjs +34 -44
  107. package/output/js/ff/core/String.mjs +31 -5
  108. package/output/js/ff/core/StringMap.mjs +32 -42
  109. package/output/js/ff/core/Task.mjs +0 -2
  110. package/output/js/ff/core/Try.mjs +0 -2
  111. package/output/js/ff/core/Unit.mjs +0 -2
  112. package/package.json +1 -1
  113. package/vscode/package.json +1 -1
  114. package/webserver/WebServer.ff +8 -8
  115. package/output/js/ff/core/Stack.mjs +0 -603
@@ -213,6 +213,6 @@ internalCallPkg(
213
213
  return await pkg.exec([
214
214
  packageFile_,
215
215
  '--out-path', outputPath_,
216
- '--target', ff_core_List.List_toArray(targets_).join(',')
216
+ '--target', targets_.join(',')
217
217
  ])
218
218
  """
@@ -23,8 +23,8 @@ capability Compiler(
23
23
  mutable derivedModules: Map[String, Module]
24
24
  mutable inferredModules: Map[String, Module]
25
25
  mutable emittedModules: Set[String]
26
- mutable phaseDurations: List[Pair[String, Duration]]
27
26
  mutable phaseDurationDelta: Duration
27
+ phaseDurations: Array[Pair[String, Duration]]
28
28
  )
29
29
 
30
30
  make(
@@ -50,8 +50,8 @@ make(
50
50
  derivedModules = Map.empty()
51
51
  inferredModules = Map.empty()
52
52
  emittedModules = Set.empty()
53
- phaseDurations = []
54
53
  phaseDurationDelta = Duration(0.0)
54
+ phaseDurations = [].toArray()
55
55
  )
56
56
  }
57
57
 
@@ -100,7 +100,6 @@ coreImports: List[DImport] =
100
100
  "Set"
101
101
  "Show"
102
102
  "SourceLocation"
103
- "Stack"
104
103
  "Stream"
105
104
  "String"
106
105
  "StringMap"
@@ -126,12 +125,14 @@ extend self: Compiler {
126
125
  let duration = Duration(stop.seconds - start.seconds)
127
126
  self.phaseDurationDelta = Duration(self.phaseDurationDelta.seconds + duration.seconds)
128
127
  let text = phase + " " + packagePair.groupName() + "/" + moduleName
129
- self.phaseDurations = [Pair(text, duration), ...self.phaseDurations]
128
+ self.phaseDurations.push(Pair(text, duration))
130
129
  result
131
130
  }
132
131
 
133
132
  printMeasurements(): Unit {
134
- let worst = self.phaseDurations.sortBy {(_.second.seconds + 1000000.0) + ""}.takeLast(5).reverse()
133
+ let worst = self.phaseDurations.toList().sortBy {
134
+ (_.second.seconds + 1000000.0) + ""
135
+ }.takeLast(5).reverse()
135
136
  worst.each {| Pair(text, duration) =>
136
137
  Log.debug(text + ":\t" + duration.show())
137
138
  }
@@ -240,7 +240,7 @@ extend self: Inference {
240
240
  }
241
241
  environment.Environment(symbols = environment1.symbols.addAll(symbols))
242
242
  }
243
- mutable guards = []
243
+ let guards = [].toArray()
244
244
  let environment3 = case.guards.foldLeft(environment1) {environment2, g =>
245
245
  let guardType = self.unification.freshUnificationVariable(g.at)
246
246
  let guardTerm = self.inferTerm(environment2, guardType, g.term)
@@ -248,12 +248,12 @@ extend self: Inference {
248
248
  let noEffect = TConstructor(at, "ff:core/Nothing.Nothing", [])
249
249
  Scheme(True, False, False, False, Signature(at, name, False, [], [], [], type, noEffect))
250
250
  }
251
- guards = [g.MatchGuard(term = guardTerm), ...guards]
251
+ guards.push(g.MatchGuard(term = guardTerm))
252
252
  environment2.Environment(symbols = environment2.symbols.addAll(symbols))
253
253
  }
254
254
  case.MatchCase(
255
255
  body = self.inferTerm(environment3, returnType, case.body)
256
- guards = guards.reverse()
256
+ guards = guards.drain()
257
257
  )
258
258
  }
259
259
 
@@ -301,6 +301,18 @@ extend self: Inference {
301
301
  let recordType =
302
302
  TConstructor(at, "Record$" + parameters.map {_.name}.join("$"), parameters.map {_.valueType})
303
303
  variableOption.toList().map {Pair(_, Pair(variableAt, recordType))}.toMap()
304
+ | PVariant(at, "List$Empty", []) =>
305
+ let itemType = self.unification.freshUnificationVariable(at)
306
+ let listType = TConstructor(at, core("List"), [itemType])
307
+ self.unification.unify(at, expected, listType)
308
+ [].toMap()
309
+ | PVariant(at, "List$Link", [head, tail]) =>
310
+ let itemType = self.unification.freshUnificationVariable(at)
311
+ let listType = TConstructor(at, core("List"), [itemType])
312
+ self.unification.unify(at, expected, listType)
313
+ let headVariables = self.inferPattern(environment, itemType, head)
314
+ let tailVariables = self.inferPattern(environment, listType, tail)
315
+ headVariables.addAll(tailVariables)
304
316
  | PVariant(at, name, patterns) =>
305
317
  let instantiated = self.lookup(environment, expected, at, name, [], None).else {
306
318
  throw(CompileError(at, "No such variant: " + name))
@@ -366,7 +378,7 @@ extend self: Inference {
366
378
  InferRecordFieldHook(self.unification, environment, expected, t, e.field)
367
379
  )
368
380
  }
369
- let fieldNames = name.split('$').toList().dropFirst(1)
381
+ let fieldNames = name.split('$').dropFirst(1)
370
382
  fieldNames.pairs().find {_.second == e.field}.map {_.first}.map {index =>
371
383
  let t1 = typeArguments.grab(index)
372
384
  self.unification.unify(e.at, expected, t1)
@@ -943,7 +955,8 @@ extend self: Inference {
943
955
  }
944
956
  }
945
957
  }
946
- mutable remainingArguments = arguments
958
+ mutable remainingArguments = arguments.toArray()
959
+ remainingArguments.reverse()
947
960
  let newArguments = parameters.map {p =>
948
961
  let t = p.valueType
949
962
  function defaultArgument(): Argument {
@@ -958,21 +971,20 @@ extend self: Inference {
958
971
  }
959
972
  }
960
973
  }
961
- remainingArguments.{
962
- | [] =>
963
- defaultArgument()
964
- | [Argument(at, None, e), ...remaining] =>
965
- remainingArguments = remaining
974
+ if(remainingArguments.isEmpty()) {
975
+ defaultArgument()
976
+ } elseIf {remainingArguments.grabLast().name.isEmpty()} {
977
+ let a = remainingArguments.pop().grab()
978
+ let e2 = self.inferTerm(environment, t, a.value)
979
+ Argument(a.at, Some(p.name), e2)
980
+ } else {
981
+ remainingArguments.find {_.name.contains(p.name)}.map {| Argument(at, _, e) =>
982
+ remainingArguments.indexWhere {_.name.contains(p.name)}.each {remainingArguments.delete(_, 1)}
966
983
  let e2 = self.inferTerm(environment, t, e)
967
984
  Argument(at, Some(p.name), e2)
968
- | _ =>
969
- remainingArguments.find {_.name.contains(p.name)}.map {| Argument(at, _, e) =>
970
- remainingArguments = remainingArguments.filter {!_.name.contains(p.name)}
971
- let e2 = self.inferTerm(environment, t, e)
972
- Argument(at, Some(p.name), e2)
973
- }.else {
974
- defaultArgument()
975
- }
985
+ }.else {
986
+ defaultArgument()
987
+ }
976
988
  }
977
989
  }
978
990
  if(!self.lspHook.isEnabled()) {
@@ -982,7 +994,7 @@ extend self: Inference {
982
994
  }
983
995
  newArguments
984
996
  } else {
985
- [...newArguments, ...remainingArguments.map {a => a.Argument(
997
+ [...newArguments, ...remainingArguments.drain().map {a => a.Argument(
986
998
  value = self.inferTerm(environment, self.unification.freshUnificationVariable(a.at), a.value)
987
999
  )}]
988
1000
  }
@@ -77,7 +77,7 @@ extend self: JsEmitter {
77
77
  packagePair.name == "core"
78
78
  ) {["esbuild"]} else {[]}
79
79
  let jsImports = self.jsImporter.generateImports(ignoreJsImports.toSet())
80
- [jsImports, ...parts].map { _.join("\n\n") }.join("\n\n") + "\n"
80
+ [jsImports, ...parts].map {_.join("\n\n")}.join("\n\n") + "\n"
81
81
  }
82
82
 
83
83
  withEmittingAsync[T](body: () => T): T {
@@ -90,14 +90,14 @@ extend self: JsEmitter {
90
90
  }
91
91
 
92
92
  emitRun(functions: List[DFunction], mainPackagePair: PackagePair, bootstrapping: Bool): List[String] {
93
- let buildMainFunction = functions.find { _.signature.name == "buildMain" }.filter {_ =>
93
+ let buildMainFunction = functions.find {_.signature.name == "buildMain"}.filter {_ =>
94
94
  self.emitTarget != EmitBrowser && self.emitTarget != EmitExecutable
95
95
  }
96
96
  let willRunOnNode = self.emitTarget != EmitBrowser
97
- let targetMain = if(willRunOnNode) { "nodeMain" } else { "browserMain" }
97
+ let targetMain = if(willRunOnNode) {"nodeMain"} else {"browserMain"}
98
98
  let mainFunction =
99
- functions.find { _.signature.name == targetMain }.orElse { functions.find { _.signature.name == "main" } }
100
- mainFunction.map {_.signature.name}.map { mainName => [[
99
+ functions.find {_.signature.name == targetMain}.orElse {functions.find {_.signature.name == "main"}}
100
+ mainFunction.map {_.signature.name}.map {mainName => [[
101
101
  "export async function $run$(fireflyPath_, arguments_) {"
102
102
  "Error.stackTraceLimit = 50"
103
103
  "const $task = {controller: new AbortController(), subtasks: new Set(), promise: new Promise(() => {}), started: performance.now() * 0.001}"
@@ -164,31 +164,31 @@ extend self: JsEmitter {
164
164
  }
165
165
 
166
166
  emitExtendsDefinition(definition: DExtend): String {
167
- let typeName = extractTypeName(definition.type).reverse().takeWhile { _ != '.' }.reverse()
168
- let methods = definition.methods.map { method =>
167
+ let typeName = extractTypeName(definition.type).reverse().takeWhile {_ != '.'}.reverse()
168
+ let methods = definition.methods.map {method =>
169
169
  method.DFunction(
170
170
  signature = method.signature.Signature(
171
171
  name = typeName + "_" + method.signature.name
172
172
  )
173
173
  )
174
174
  }
175
- let syncMethods = methods.map { "export " + self.emitFunctionDefinition(_, False) }
176
- let asyncMethods = self.withEmittingAsync {methods.map { "export " + self.emitFunctionDefinition(_, True) }}
175
+ let syncMethods = methods.map {"export " + self.emitFunctionDefinition(_, False)}
176
+ let asyncMethods = self.withEmittingAsync {methods.map {"export " + self.emitFunctionDefinition(_, True)}}
177
177
  [...syncMethods, ...asyncMethods].join("\n\n")
178
178
  }
179
179
 
180
180
  emitInstanceDefinition(definition: DInstance): String {
181
181
  let name = makeDictionaryName(definition.traitName, firstTypeName(definition.typeArguments))
182
- let methods = definition.methods.map {self.emitFunctionDefinition(_, False)}.map { _.dropFirst("function ".size()) } // TODO
182
+ let methods = definition.methods.map {self.emitFunctionDefinition(_, False)}.map {_.dropFirst("function ".size())} // TODO
183
183
  let asyncMethods = self.withEmittingAsync {
184
- definition.methods.map {self.emitFunctionDefinition(_, True)}.map { "async " + _.dropFirst("async function ".size()) } // TODO
184
+ definition.methods.map {self.emitFunctionDefinition(_, True)}.map {"async " + _.dropFirst("async function ".size())} // TODO
185
185
  }
186
186
  let body = "{\n" + [...methods, ...asyncMethods].join(",\n") + "\n}"
187
187
  definition.constraints.{
188
188
  | [] =>
189
189
  "export const " + name + " = " + body + ";"
190
190
  | constraints =>
191
- let dictionaries = constraints.map { c =>
191
+ let dictionaries = constraints.map {c =>
192
192
  makeDictionaryName(c.name, firstTypeName(c.generics))
193
193
  }
194
194
  "export function " + name + "(" + dictionaries.join(", ") + ") { return " + body + "}"
@@ -213,12 +213,12 @@ extend self: JsEmitter {
213
213
  | _ => False
214
214
  }
215
215
  } =>
216
- let body = self.emitTailCall { self.emitStatements(matchCase.body, True, async) }
216
+ let body = self.emitTailCall {self.emitStatements(matchCase.body, True, async)}
217
217
  signature + " {\n" + body + "\n}"
218
218
  | Lambda(_, effect, cases) =>
219
219
  Patterns.convertAndCheck(self.otherModules, cases)
220
- let escapedArguments = definition.signature.parameters.map { _.name + "_a" }
221
- let shadowingWorkaround = definition.signature.parameters.map { p =>
220
+ let escapedArguments = definition.signature.parameters.map {_.name + "_a"}
221
+ let shadowingWorkaround = definition.signature.parameters.map {p =>
222
222
  "const " + p.name + "_a = " + escapeKeyword(p.name) + ";"
223
223
  }.join("\n")
224
224
  let body = self.emitTailCall {
@@ -247,7 +247,7 @@ extend self: JsEmitter {
247
247
 
248
248
  emitSignature(signature: Signature, async: Bool, suffix: String = ""): String {
249
249
  let parameterStrings = signature.parameters.map {self.emitParameter(_, async)}
250
- let dictionaryStrings = signature.constraints.map { c =>
250
+ let dictionaryStrings = signature.constraints.map {c =>
251
251
  makeDictionaryName(c.name, firstTypeName(c.generics))
252
252
  }
253
253
  let controller = if(async) {["$task"]} else {[]}
@@ -258,19 +258,19 @@ extend self: JsEmitter {
258
258
  }
259
259
 
260
260
  emitParameter(parameter: Parameter, async: Bool): String {
261
- let defaultValue = parameter.default.map { " = " + self.emitTerm(_, async) }.else{""}
261
+ let defaultValue = parameter.default.map {" = " + self.emitTerm(_, async) }.else {""}
262
262
  escapeKeyword(parameter.name) + defaultValue
263
263
  }
264
264
 
265
265
  emitTypeDefinition(definition: DType): String {
266
- if(definition.newtype) { "// newtype " + definition.name } else:
266
+ if(definition.newtype) {"// newtype " + definition.name} else:
267
267
  "// type " + definition.name + "\n" +
268
- definition.variants.map { self.emitVariantDefinition(definition, _) }.join("\n")
268
+ definition.variants.map {self.emitVariantDefinition(definition, _)}.join("\n")
269
269
  }
270
270
 
271
271
  emitVariantDefinition(typeDefinition: DType, definition: Variant): String {
272
272
  let allFields = [...typeDefinition.commonFields, ...definition.fields]
273
- let fields = allFields.map { escapeKeyword(_.name) }.join(", ")
273
+ let fields = allFields.map {escapeKeyword(_.name)}.join(", ")
274
274
  if(allFields.isEmpty()) {
275
275
  "const " + definition.name + "$ = {" + definition.name + ": true};\n" +
276
276
  "export function " + definition.name + "(" + fields + ") {\n" +
@@ -287,7 +287,7 @@ extend self: JsEmitter {
287
287
  }
288
288
  }
289
289
 
290
- emitTerm(term: Term, async: Bool): String { term.{
290
+ emitTerm(term: Term, async: Bool): String {term.{
291
291
  | EString(at, value) {value.startsWith("\"\"\"")} =>
292
292
  "`" + value.dropFirst(3).dropLast(3).replace("`", "\\`") + "`" // TODO: Fix escaping
293
293
  | EString(at, value) => value
@@ -306,7 +306,7 @@ extend self: JsEmitter {
306
306
  | EVariant(at, name, _, arguments) =>
307
307
  let argumentsString = arguments.toList().flatten().map {self.emitArgument(at, _, async)}.join(", ")
308
308
  let newtype = self.processVariant(name)
309
- if(newtype) { argumentsString } else:
309
+ if(newtype) {argumentsString} else:
310
310
  escapeResolved(name) + "(" + argumentsString + ")"
311
311
  | EVariantIs(at, "ff:core/Bool.False", _) =>
312
312
  "function(_v) { return !_v ? ff_core_Option.Some(_v) : ff_core_Option.None(); }"
@@ -320,17 +320,17 @@ extend self: JsEmitter {
320
320
  "return _v." + escapeResolved(n) + " ? ff_core_Option.Some(_v) : ff_core_Option.None();" +
321
321
  "})"
322
322
  | ECopy(at, name, record, fields) =>
323
- let fieldCode = fields.map { f => escapeKeyword(f.name) + " = " + self.emitTerm(f.value, async) }.join(", ")
323
+ let fieldCode = fields.map {f => escapeKeyword(f.name) + " = " + self.emitTerm(f.value, async)}.join(", ")
324
324
  "{..." + self.emitTerm(record, async) + ", " + fieldCode + "}"
325
325
  | EField(at, newtype, record, field) =>
326
- if(newtype) { self.emitTerm(record, async) } else:
326
+ if(newtype) {self.emitTerm(record, async)} else:
327
327
  self.emitTerm(record, async) + "." + escapeKeyword(field)
328
328
  | ELambda(at, Lambda(_, effect, [MatchCase(_, patterns, [], body)])) {
329
329
  patterns.all {| PVariable _ => True | _ => False }
330
330
  } =>
331
331
  let newAsync = self.emittingAsync && effectTypeIsAsync(effect)
332
332
  let patternParameters = patterns.map {
333
- | PVariable p => p.name.map(escapeKeyword).else{"_"}
333
+ | PVariable p => p.name.map(escapeKeyword).else {"_"}
334
334
  | _ => panic("!")
335
335
  }
336
336
  let controller = if(newAsync) {["$task"]} else {[]}
@@ -341,9 +341,9 @@ extend self: JsEmitter {
341
341
  let newAsync = self.emittingAsync && effectTypeIsAsync(effect)
342
342
  let controller = if(newAsync) {["$task"]} else {[]}
343
343
  Patterns.convertAndCheck(self.otherModules, cases)
344
- let arguments = cases.grab(0).patterns.pairs().map { "_" + (_.first + 1) }
344
+ let arguments = cases.grab(0).patterns.pairs().map {"_" + (_.first + 1)}
345
345
  let escapedArguments = arguments.map(escapeKeyword) // emitCase arguments must be preescaped
346
- let caseStrings = cases.map { "{\n" + self.emitCase(escapedArguments, _, True, True, newAsync) + "\n}" }
346
+ let caseStrings = cases.map {"{\n" + self.emitCase(escapedArguments, _, True, True, newAsync) + "\n}"}
347
347
  let prefix = if(newAsync) {"async "} else {""}
348
348
  "(" + prefix + "(" + [...escapedArguments, ...controller].join(", ") + ") => " +
349
349
  "{\n" + caseStrings.join("\n") + "\n})"
@@ -389,7 +389,7 @@ extend self: JsEmitter {
389
389
  primitiveTypes.contains(typeName)
390
390
  } =>
391
391
  "(" + self.emitArgument(at, left, async) + " <= " + self.emitArgument(at, right, async) + ")"
392
- | ECall(_, StaticCall("ff:core/Array.fillBy", _, _), effect, _, [size, Argument(_, _, ELambda(at,
392
+ | ECall(_, StaticCall("ff:core/List.fillBy", _, _), effect, _, [size, Argument(_, _, ELambda(at,
393
393
  Lambda(_, _, [MatchCase(_, [PVariable(_, name)], [], body)@c])@l
394
394
  ))], _) {
395
395
  !effectTypeIsAsync(effect)
@@ -411,12 +411,18 @@ extend self: JsEmitter {
411
411
  let ds = dictionaryStrings.dropFirst()
412
412
  let d = dictionaryStrings.grabFirst()
413
413
  let asyncSuffix = if(await) {"$"} else {""}
414
- let n = escapeKeyword(name.reverse().takeWhile { _ != '.' }.reverse()) + asyncSuffix
414
+ let n = escapeKeyword(name.reverse().takeWhile {_ != '.'}.reverse()) + asyncSuffix
415
415
  let emittedArguments = arguments.map {self.emitArgument(at, _, async)}
416
416
  let controller = if(await) {["$task"]} else {[]}
417
417
  let call = d + "." + n + "(" + [...emittedArguments, ...ds, ...controller].join(", ") + ")"
418
418
  if(await) {"(await " + call + ")"} else {call}
419
419
  | ECall(at, StaticCall(name, _, _), effect, typeArguments, arguments, dictionaries) =>
420
+ if(name.contains("bundleForBrowser")) { // TODO: Delete this test (for branch arraysonly)
421
+ if(!arguments.grab(0).name.contains("system")) {
422
+ Log.debug("Wrong arguments for bundleForBrowser: " + Show.show(arguments.map {_.name}))
423
+ throw(GrabException())
424
+ }
425
+ }
420
426
  detectIfElse(term).{
421
427
  | [] =>
422
428
  let await = async && effectTypeIsAsync(effect)
@@ -447,7 +453,7 @@ extend self: JsEmitter {
447
453
  if(await) {"(await " + call + ")"} else {call}
448
454
  | ERecord(at, fields) =>
449
455
  if(fields.isEmpty()) {"{}"} else {
450
- let list = fields.map { f => escapeKeyword(f.name) + ": " + self.emitTerm(f.value, async) }
456
+ let list = fields.map {f => escapeKeyword(f.name) + ": " + self.emitTerm(f.value, async)}
451
457
  "{\n" + list.join(",\n") + "\n}"
452
458
  }
453
459
  | EWildcard(at, index) =>
@@ -459,10 +465,10 @@ extend self: JsEmitter {
459
465
  "(function() {\n" + self.emitStatements(term, True, async) + "\n})()"
460
466
  }}
461
467
 
462
- emitDictionary(d : Dictionary): String {
468
+ emitDictionary(d: Dictionary): String {
463
469
  let m = if(d.moduleName != "") {
464
470
  d.packagePair.groupName("_") + "_" + d.moduleName.replace("/", "_") + "."
465
- } else { "" }
471
+ } else {""}
466
472
  let c = m + makeDictionaryName(d.traitName, d.typeName)
467
473
  if(d.dictionaries.isEmpty()) {
468
474
  c
@@ -474,7 +480,7 @@ extend self: JsEmitter {
474
480
  emitStatements(term: Term, last: Bool, async: Bool): String {
475
481
  term.{
476
482
  | EFunctions(at, functions, body) =>
477
- let functionStrings = functions.map { f =>
483
+ let functionStrings = functions.map {f =>
478
484
  let newAsync = self.emittingAsync && effectTypeIsAsync(f.signature.effect)
479
485
  self.emitFunctionDefinition(f, newAsync)
480
486
  }
@@ -670,37 +676,37 @@ extend self: JsEmitter {
670
676
  self.emitCase([guardName], newCase, jump, last, async)
671
677
  | Pair([], []) =>
672
678
  self.emitStatements(matchCase.body, last, async) +
673
- if(jump && last) { "\nreturn" } elseIf {jump} { "\nbreak" } else {""}
679
+ if(jump && last) {"\nreturn"} elseIf {jump} {"\nbreak"} else {""}
674
680
  }
675
681
  }
676
682
 
677
683
  emitPattern(
678
- argument: String,
679
- pattern: MatchPattern,
680
- arguments: List[String],
681
- matchCase: MatchCase,
682
- jump: Bool,
683
- last: Bool,
684
+ argument: String
685
+ pattern: MatchPattern
686
+ arguments: List[String]
687
+ matchCase: MatchCase
688
+ jump: Bool
689
+ last: Bool
684
690
  async: Bool
685
691
  ): String {
686
692
  pattern.{
687
693
  | PString(_, value) =>
688
- "if(" + argument + " == " + value + ") {\n" +
694
+ "if(" + argument + " === " + value + ") {\n" +
689
695
  self.emitCase(arguments, matchCase, jump, last, async) +
690
696
  "\n}"
691
697
  | PInt(_, value) =>
692
- "if(" + argument + " == " + value + ") {\n" +
698
+ "if(" + argument + " === " + value + ") {\n" +
693
699
  self.emitCase(arguments, matchCase, jump, last, async) +
694
700
  "\n}"
695
701
  | PChar(_, value) =>
696
- "if(" + argument + " == " + charLiteralToNumber(value) + ") {\n" +
702
+ "if(" + argument + " === " + charLiteralToNumber(value) + ") {\n" +
697
703
  self.emitCase(arguments, matchCase, jump, last, async) +
698
704
  "\n}"
699
705
  | PVariable(_, None) =>
700
706
  self.emitCase(arguments, matchCase, jump, last, async)
701
707
  | PVariable(_, Some(name)) =>
702
708
  let escaped = escapeKeyword(name)
703
- if(escaped != argument) { "const " + escaped + " = " + argument + ";\n" } else { "" } +
709
+ if(escaped != argument) {"const " + escaped + " = " + argument + ";\n"} else {""} +
704
710
  self.emitCase(arguments, matchCase, jump, last, async)
705
711
  | PVariant(_, "ff:core/Bool.False", []) =>
706
712
  "if(!" + argument + ") {\n" +
@@ -710,67 +716,88 @@ extend self: JsEmitter {
710
716
  "if(" + argument + ") {\n" +
711
717
  self.emitCase(arguments, matchCase, jump, last, async) +
712
718
  "\n}"
719
+ | PVariant(_, "List$Empty", []) =>
720
+ mutable shortArgument = argument
721
+ mutable shortCount = 0
722
+ while {shortArgument.endsWith(".slice(1)")} {
723
+ shortArgument = shortArgument.dropLast(".slice(1)".size())
724
+ shortCount += 1
725
+ }
726
+ "if(" + shortArgument + ".length === " + shortCount + ") {\n" +
727
+ self.emitCase(arguments, matchCase, jump, last, async) +
728
+ "\n}"
729
+ | PVariant(_, "List$Link", [head, tail]) =>
730
+ mutable shortArgument = argument
731
+ mutable shortCount = 0
732
+ while {shortArgument.endsWith(".slice(1)")} {
733
+ shortArgument = shortArgument.dropLast(".slice(1)".size())
734
+ shortCount += 1
735
+ }
736
+ let newArguments = [shortArgument + "[" + shortCount + "]", argument + ".slice(1)", ...arguments]
737
+ let newMatchCase = matchCase.MatchCase(patterns = [head, tail, ...matchCase.patterns])
738
+ "if(" + shortArgument + ".length > " + shortCount + ") {\n" +
739
+ self.emitCase(newArguments, newMatchCase, jump, last, async) +
740
+ "\n}"
713
741
  | PVariant(_, name, patterns) =>
714
742
  let processed = self.processVariantCase(name, argument)
715
743
  let newMatchCase = matchCase.MatchCase(patterns = [...patterns, ...matchCase.patterns])
716
- if(processed.loneVariant) { "" } else {
744
+ if(processed.loneVariant) {""} else {
717
745
  "if(" + argument + "." + processed.variantName + ") {\n"
718
746
  } +
719
747
  self.emitCase([...processed.arguments, ...arguments], newMatchCase, jump, last, async) +
720
- if(processed.loneVariant) { "" } else { "\n}" }
748
+ if(processed.loneVariant) {""} else {"\n}"}
721
749
  | PVariantAs(at, name, variableAt, variable) =>
722
750
  let processed = self.processVariantCase(name, argument)
723
- if(processed.loneVariant) { "" } else {
751
+ if(processed.loneVariant) {""} else {
724
752
  "if(" + argument + "." + processed.variantName + ") {\n"
725
753
  } +
726
- variable.map(escapeKeyword).filter { _ != argument }.map {
754
+ variable.map(escapeKeyword).filter {_ != argument}.map {
727
755
  "const " + _ + " = " + argument + ";\n"
728
756
  }.else {""} +
729
757
  self.emitCase(arguments, matchCase, jump, last, async) +
730
- if(processed.loneVariant) { "" } else { "\n}" }
758
+ if(processed.loneVariant) {""} else {"\n}"}
731
759
  | PAlias(_, pattern, variable) =>
732
760
  let escaped = escapeKeyword(variable)
733
- if(escaped != argument) { "const " + escaped + " = " + argument + ";\n" } else { "" } +
761
+ if(escaped != argument) {"const " + escaped + " = " + argument + ";\n"} else {""} +
734
762
  self.emitPattern(argument, pattern, arguments, matchCase, jump, last, async)
735
763
  }
736
764
  }
737
765
 
738
- emitList(items: List[Pair[Term, Bool]], async: Bool): String {items.{
739
- | [] =>
740
- "ff_core_List.Empty()"
741
- | [Pair(e, True)] =>
742
- self.emitTerm(e, async)
743
- | [Pair(e, False), ...list] =>
744
- "ff_core_List.Link(" + self.emitTerm(e, async) + ", " + self.emitList(list, async) + ")"
745
- | [Pair(e, True), ...list] =>
746
- "ff_core_List.List_addAll(" + self.emitTerm(e, async) + ", " + self.emitList(list, async) + ")"
747
- }}
766
+ emitList(items: List[Pair[Term, Bool]], async: Bool): String {
767
+ "[" + items.map {
768
+ | Pair(item, False) => self.emitTerm(item, async)
769
+ | Pair(item, True) => "..." + self.emitTerm(item, async)
770
+ }.join(", ") + "]"
771
+ }
748
772
 
749
773
  processVariantCase(name: String, argument: String): ProcessedVariantCase {
750
- let variantNameUnqualified = name.reverse().takeWhile { _ != '.' }.reverse()
774
+ if(name == "List$Empty") {ProcessedVariantCase(name, False, False, [])} else:
775
+ if(name == "List$Link") {ProcessedVariantCase(name, False, False, [argument + "[0]", argument + ".slice(1)"])} else:
776
+ let variantNameUnqualified = name.reverse().takeWhile {_ != '.'}.reverse()
751
777
  let variantName = escapeKeyword(variantNameUnqualified)
752
778
  let moduleName = name.dropLast(variantNameUnqualified.size() + 1)
753
779
  let variantModule = self.otherModules.grab(moduleName)
754
780
  mutable newtype = False
755
781
  mutable loneVariant = False
756
- let newArguments = variantModule.types.collectFirst { definition =>
757
- definition.variants.find { _.name == variantName }.map { variant =>
782
+ let newArguments = variantModule.types.collectFirst {definition =>
783
+ definition.variants.find {_.name == variantName }.map {variant =>
758
784
  newtype = definition.newtype
759
785
  loneVariant = definition.variants.size() == 1
760
- [...definition.commonFields.map { _.name}, ...variant.fields.map {_.name}]
786
+ [...definition.commonFields.map {_.name}, ...variant.fields.map {_.name}]
761
787
  }
762
- }.grab().map { field => if(newtype) { argument } else { argument + "." + escapeKeyword(field) } }
788
+ }.grab().map {field => if(newtype) {argument} else {argument + "." + escapeKeyword(field)}}
763
789
  ProcessedVariantCase(variantName, newtype, loneVariant, newArguments)
764
790
  }
765
791
 
766
792
  processVariant(name: String): Bool {
767
- let variantNameUnqualified = name.reverse().takeWhile { _ != '.' }.reverse()
793
+ if(name.startsWith("List$")) {False} else:
794
+ let variantNameUnqualified = name.reverse().takeWhile {_ != '.'}.reverse()
768
795
  let variantName = escapeKeyword(variantNameUnqualified)
769
796
  let moduleName = name.dropLast(variantNameUnqualified.size() + 1)
770
797
  let variantModule = self.otherModules.grab(moduleName)
771
798
  mutable newtype = False
772
- let newArguments = variantModule.types.collectFirst { definition =>
773
- definition.variants.find { _.name == variantName }.map { variant =>
799
+ let newArguments = variantModule.types.collectFirst {definition =>
800
+ definition.variants.find {_.name == variantName}.map {variant =>
774
801
  newtype = definition.newtype
775
802
  }
776
803
  }.grab()
@@ -801,11 +828,11 @@ detectIfElse(term: Term): List[Pair[Term, Term]] {
801
828
  [Pair(condition.value, invokeImmediately(body.value))]
802
829
  | ECall(at, StaticCall("ff:core/Option.Option_elseIf", _, _), _, _, [option, condition, body], _) =>
803
830
  let list = detectIfElse(option.value)
804
- if(list.isEmpty()) { [] } else:
831
+ if(list.isEmpty()) {[]} else:
805
832
  [Pair(invokeImmediately(condition.value), invokeImmediately(body.value)), ...list]
806
833
  | ECall(at, StaticCall("ff:core/Option.Option_else", _, _), _, _, [option, body], _) =>
807
834
  let list = detectIfElse(option.value)
808
- if(list.isEmpty()) { [] } else:
835
+ if(list.isEmpty()) {[]} else:
809
836
  [Pair(EVariant(at, "ff:core/Bool.True", [], None), invokeImmediately(body.value)), ...list]
810
837
  | _ =>
811
838
  []
@@ -848,7 +875,7 @@ charLiteralToNumber(charLiteral: String): String {
848
875
  }
849
876
 
850
877
  escapeResolved(word: String): String {
851
- let parts = word.replace(":", ".").replace("/", ".").split('.').toList()
878
+ let parts = word.replace(":", ".").replace("/", ".").split('.')
852
879
  let initialParts = parts.dropLast()
853
880
  if(initialParts.isEmpty()) {
854
881
  escapeKeyword(parts.grabLast())
@@ -37,7 +37,7 @@ extend self: JsImporter {
37
37
  let rest4 = rest3.dropFirst(" from '".size())
38
38
  let url = rest4.takeWhile {_ != '\''}
39
39
  if(url.size() == 0) {throw(CompileError(at, "Expected module name after \" from '\""))}
40
- if(url.any{_ == '\n'}) {throw(CompileError(at, "Unclosed module name string"))}
40
+ if(url.any {_ == '\n'}) {throw(CompileError(at, "Unclosed module name string"))}
41
41
  let rest5 = rest4.dropFirst(url.size() + 1)
42
42
  let importName = self.add(url)
43
43
  space + "const " + name + " = " + importName + self.process(at, rest5)
@@ -7,7 +7,7 @@ class LspHook(
7
7
  definedAt: Location
8
8
  insertIdentifier: Bool
9
9
  trackSymbols: Bool
10
- stackOfResults: Stack[ResultHook]
10
+ arrayOfResults: Array[ResultHook]
11
11
  )
12
12
 
13
13
  disabled(): LspHook {
@@ -20,7 +20,7 @@ make(at: Option[Location], definedAt: Option[Location], insertIdentifier: Bool,
20
20
  definedAt = definedAt.else {Location("^lsp", -7, -7)}
21
21
  insertIdentifier = insertIdentifier
22
22
  trackSymbols = trackSymbols
23
- stackOfResults = [].toStack()
23
+ arrayOfResults = [].toArray()
24
24
  )
25
25
  }
26
26
 
@@ -41,10 +41,10 @@ extend self: LspHook {
41
41
  self.definedAt.file == at.file
42
42
  }
43
43
  emit(result: ResultHook) {
44
- self.stackOfResults.push(result)
44
+ self.arrayOfResults.push(result)
45
45
  }
46
46
  results(): List[ResultHook] {
47
- self.stackOfResults.toList()
47
+ self.arrayOfResults.toList()
48
48
  }
49
49
  }
50
50