firefly-compiler 0.5.7 → 0.5.8
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.
- package/compiler/JsEmitter.ff +285 -114
- package/core/JsValue.ff +21 -22
- package/core/List.ff +1 -1
- package/output/js/ff/compiler/JsEmitter.mjs +1545 -527
- package/output/js/ff/core/Core.mjs +18 -4
- package/output/js/ff/core/JsValue.mjs +34 -34
- package/package.json +1 -1
- package/vscode/package.json +1 -1
package/compiler/JsEmitter.ff
CHANGED
|
@@ -160,7 +160,8 @@ extend self: JsEmitter {
|
|
|
160
160
|
emitLetDefinition(definition: DLet, mutable: Bool, async: Bool): String {
|
|
161
161
|
let mutability = if(mutable) {"let"} else {"const"}
|
|
162
162
|
let valueCode = self.emitTerm(definition.value, async)
|
|
163
|
-
|
|
163
|
+
let assignmentCode = if(valueCode != "(void 0)") {" = " + valueCode} else {""}
|
|
164
|
+
mutability + " " + escapeKeyword(definition.name) + assignmentCode + ";"
|
|
164
165
|
}
|
|
165
166
|
|
|
166
167
|
emitExtendsDefinition(definition: DExtend): String {
|
|
@@ -352,80 +353,10 @@ extend self: JsEmitter {
|
|
|
352
353
|
let c = if(await) {", $task"} else {""}
|
|
353
354
|
let call = "(" + self.emitTerm(function, async) + ")(" + self.emitTerm(value, async) + c + ")"
|
|
354
355
|
if(await) {"(await " + call + ")"} else {call}
|
|
355
|
-
| ECall(at, StaticCall(
|
|
356
|
-
|
|
357
|
-
| ECall(at, StaticCall(operator, _, _), _, [], [left, right], _) {!operator.grabFirst().isAsciiLetter()} =>
|
|
358
|
-
"(" + self.emitArgument(at, left, async) + " " + operator + " " + self.emitArgument(at, right, async) + ")"
|
|
359
|
-
| ECall(at, StaticCall("ff:core/List.List_grab", _, _), _, _, [Argument(_, _, EVariable(_, x1)), Argument(_, _, EVariable(_, x2))], _) =>
|
|
360
|
-
"(" + escapeResolved(x1) + "[" + escapeResolved(x2) + "] ?? " +
|
|
361
|
-
"ff_core_List.internalGrab_(" + escapeResolved(x1) + ", " + escapeResolved(x2) + "))"
|
|
362
|
-
| ECall(at, StaticCall("ff:core/Array.Array_grab", _, _), _, _, [Argument(_, _, EVariable(_, x1)), Argument(_, _, EVariable(_, x2))], _) =>
|
|
363
|
-
"(" + escapeResolved(x1) + ".array[" + escapeResolved(x2) + "] ?? " +
|
|
364
|
-
"ff_core_Array.internalGrab_(" + escapeResolved(x1) + ", " + escapeResolved(x2) + "))"
|
|
365
|
-
| ECall(at, StaticCall("ff:core/UnsafeJs.import", _, _), _, _, [Argument(_, _, EString(_, url))], _) =>
|
|
366
|
-
self.jsImporter.add(url.replace("\"", ""))
|
|
367
|
-
| ECall(at, StaticCall("ff:core/UnsafeJs.await", _, _), _, _, [Argument(_, _, body)], _) =>
|
|
368
|
-
if(async) {
|
|
369
|
-
"(await " + self.emitTerm(body, async) + "($task))"
|
|
370
|
-
} else {
|
|
371
|
-
self.emitTerm(invokeImmediately(body), async)
|
|
372
|
-
}
|
|
373
|
-
| ECall(at, StaticCall("ff:core/UnsafeJs.cancelled", _, _), _, _, [], _) =>
|
|
374
|
-
if(async) {"$task.controller.signal.aborted"} else {"false"}
|
|
375
|
-
| ECall(at, StaticCall("ff:core/UnsafeJs.throwIfCancelled", _, _), _, _, [], _) =>
|
|
376
|
-
if(async) {"((() => ff_core_Task.Task_throwIfAborted($task))())"} else {""}
|
|
377
|
-
| ECall(at, StaticCall("ff:core/UnsafeJs.inAsync", _, _), _, _, [], _) =>
|
|
378
|
-
if(self.emittingAsync) {"true"} else {"false"}
|
|
379
|
-
| ECall(at, StaticCall("ff:core/UnsafeJs.inBrowser", _, _), _, _, [], _) =>
|
|
380
|
-
if(self.emitTarget == EmitBrowser) {"true"} else {"false"}
|
|
381
|
-
| ECall(at, StaticCall("ff:core/UnsafeJs.inNode", _, _), _, _, [], _) =>
|
|
382
|
-
if(self.emitTarget == EmitNode) {"true"} else {"false"}
|
|
383
|
-
| ECall(at, StaticCall("ff:core/UnsafeJs.inBuild", _, _), _, _, [], _) =>
|
|
384
|
-
if(self.emitTarget == EmitBuild) {"true"} else {"false"}
|
|
385
|
-
| ECall(at, StaticCall("ff:core/UnsafeJs.value", _, _), _, _, [Argument(_, _, e)], _) =>
|
|
386
|
-
self.emitTerm(e, async)
|
|
387
|
-
| ECall(at, StaticCall("ff:core/UnsafeJs.fromValue", _, _), _, _, [Argument(_, _, e)], _) =>
|
|
388
|
-
self.emitTerm(e, async)
|
|
389
|
-
| ECall(at, StaticCall("ff:core/Equal.equals", _, _), _, _, [left, right], [Dictionary(_, _, _, typeName, [])]) {
|
|
390
|
-
primitiveTypes.contains(typeName) || typeName == "ff:core/Ordering.Ordering"
|
|
391
|
-
} =>
|
|
392
|
-
"(" + self.emitArgument(at, left, async) + " === " + self.emitArgument(at, right, async) + ")"
|
|
393
|
-
| ECall(at, StaticCall("ff:core/Equal.notEquals", _, _), _, _, [left, right], [Dictionary(_, _, _, typeName, [])]) {
|
|
394
|
-
primitiveTypes.contains(typeName) || typeName == "ff:core/Ordering.Ordering"
|
|
395
|
-
} =>
|
|
396
|
-
"(" + self.emitArgument(at, left, async) + " !== " + self.emitArgument(at, right, async) + ")"
|
|
397
|
-
| ECall(at, StaticCall("ff:core/Ordering.before", _, _), _, _, [left, right], [Dictionary(_, _, _, typeName, [])]) {
|
|
398
|
-
primitiveTypes.contains(typeName)
|
|
399
|
-
} =>
|
|
400
|
-
"(" + self.emitArgument(at, left, async) + " < " + self.emitArgument(at, right, async) + ")"
|
|
401
|
-
| ECall(at, StaticCall("ff:core/Ordering.notBefore", _, _), _, _, [left, right], [Dictionary(_, _, _, typeName, [])]) {
|
|
402
|
-
primitiveTypes.contains(typeName)
|
|
403
|
-
} =>
|
|
404
|
-
"(" + self.emitArgument(at, left, async) + " >= " + self.emitArgument(at, right, async) + ")"
|
|
405
|
-
| ECall(at, StaticCall("ff:core/Ordering.after", _, _), _, _, [left, right], [Dictionary(_, _, _, typeName, [])]) {
|
|
406
|
-
primitiveTypes.contains(typeName)
|
|
407
|
-
} =>
|
|
408
|
-
"(" + self.emitArgument(at, left, async) + " > " + self.emitArgument(at, right, async) + ")"
|
|
409
|
-
| ECall(at, StaticCall("ff:core/Ordering.notAfter", _, _), _, _, [left, right], [Dictionary(_, _, _, typeName, [])]) {
|
|
410
|
-
primitiveTypes.contains(typeName)
|
|
356
|
+
| ECall(at, StaticCall(name, _, _), _, _, arguments, dictionaries) {
|
|
357
|
+
self.emitSpecialCall(term, async, name, arguments.map {_.value}, dictionaries) | Some(code)
|
|
411
358
|
} =>
|
|
412
|
-
|
|
413
|
-
| ECall(_, StaticCall("ff:core/List.fillBy", _, _), effect, _, [size, Argument(_, _, ELambda(at,
|
|
414
|
-
Lambda(_, _, [MatchCase(_, [PVariable(_, name)], [], body)@c])@l
|
|
415
|
-
))], _) {
|
|
416
|
-
!effectTypeIsAsync(effect)
|
|
417
|
-
} =>
|
|
418
|
-
let n = name.map {escapeResolved(_)}.else {"i"}
|
|
419
|
-
let newAsync = self.emittingAsync && effectTypeIsAsync(effect)
|
|
420
|
-
let await = if(newAsync) {"await "} else {""}
|
|
421
|
-
await + "((() => {\n" +
|
|
422
|
-
"const size = " + self.emitArgument(at, size, async) + ";\n" + // Not correct if async and body isn't
|
|
423
|
-
"const result = [];\n" +
|
|
424
|
-
"for(let " + n + " = 0; " + n + " < size; " + n + "++) {\n" +
|
|
425
|
-
"result.push(" + self.emitTerm(body, newAsync) + ");\n" +
|
|
426
|
-
"}\n" +
|
|
427
|
-
"return result;\n" +
|
|
428
|
-
"})())"
|
|
359
|
+
code
|
|
429
360
|
| ECall(at, StaticCall(name, _, True), effect, typeArguments, arguments, dictionaries) =>
|
|
430
361
|
let await = async && effectTypeIsAsync(effect)
|
|
431
362
|
let dictionaryStrings = dictionaries.map {self.emitDictionary(_)}
|
|
@@ -485,6 +416,13 @@ extend self: JsEmitter {
|
|
|
485
416
|
| _ =>
|
|
486
417
|
"(function() {\n" + self.emitStatements(term, True, async) + "\n})()"
|
|
487
418
|
}}
|
|
419
|
+
|
|
420
|
+
emitField(term: Term, async: Bool, dot: String = "."): String {
|
|
421
|
+
term.{
|
|
422
|
+
| EString(_, q) {safeBare(q) | Some(s)} => dot + s
|
|
423
|
+
| _ => "[" + self.emitTerm(term, async) + "]"
|
|
424
|
+
}
|
|
425
|
+
}
|
|
488
426
|
|
|
489
427
|
emitDictionary(d: Dictionary): String {
|
|
490
428
|
let m = if(d.moduleName != "") {
|
|
@@ -522,46 +460,6 @@ extend self: JsEmitter {
|
|
|
522
460
|
| EAssignField(at, operator, record, field, value) =>
|
|
523
461
|
self.emitTerm(record, async) + "." + escapeKeyword(field) + " " + operator + "= " +
|
|
524
462
|
self.emitTerm(value, async)
|
|
525
|
-
| ECall(at, StaticCall("ff:core/Core.while", _, _), _, _, [condition, body], _) =>
|
|
526
|
-
"while(" + self.emitTerm(invokeImmediately(condition.value), async) + ") {\n" +
|
|
527
|
-
self.emitStatements(invokeImmediately(body.value), False, async) + "\n}"
|
|
528
|
-
| ECall(at, StaticCall("ff:core/Core.doWhile", _, _), _, _, [Argument(_, _, doWhileBody)], _) {
|
|
529
|
-
invokeImmediately(doWhileBody) | ESequential(_, body, condition)
|
|
530
|
-
} =>
|
|
531
|
-
"while(true) {\n" +
|
|
532
|
-
self.emitStatements(body, False, async) +
|
|
533
|
-
"\nif(!" + self.emitTerm(condition, async) + ") break" +
|
|
534
|
-
"\n}"
|
|
535
|
-
| ECall(at, StaticCall("ff:core/Core.doWhile", _, _), _, _, [Argument(_, _, doWhileBody)], _) {
|
|
536
|
-
invokeImmediately(doWhileBody) | body
|
|
537
|
-
} =>
|
|
538
|
-
"while(" + self.emitTerm(body, async) + ") {}"
|
|
539
|
-
| ECall(at, StaticCall("ff:core/Core.if", _, _), _, _, [condition, body], _) =>
|
|
540
|
-
"if(" + self.emitTerm(condition.value, async) + ") {\n" +
|
|
541
|
-
if(last) {
|
|
542
|
-
"return ff_core_Option.Some(" + self.emitTerm(invokeImmediately(body.value), async) +
|
|
543
|
-
")\n} else return ff_core_Option.None()"
|
|
544
|
-
} else {
|
|
545
|
-
self.emitStatements(invokeImmediately(body.value), False, async) + "\n}"
|
|
546
|
-
}
|
|
547
|
-
| ECall(at, StaticCall("ff:core/Core.throw", _, _), _, _, [argument], [dictionary]) =>
|
|
548
|
-
let d = self.emitDictionary(dictionary)
|
|
549
|
-
let a = self.emitArgument(at, argument, async)
|
|
550
|
-
"throw Object.assign(new Error(), {ffException: ff_core_Any.toAny_(" + a + ", " + d + ")})"
|
|
551
|
-
| ECall(at, StaticCall("ff:core/Try.Try_catch", _, _), _, _, _, _) {
|
|
552
|
-
self.emitTryCatchFinally(term, last, async) | Some(code)
|
|
553
|
-
} =>
|
|
554
|
-
code
|
|
555
|
-
| ECall(at, StaticCall("ff:core/Try.Try_catchAny", _, _), _, _, _, _) {
|
|
556
|
-
self.emitTryCatchFinally(term, last, async) | Some(code)
|
|
557
|
-
} =>
|
|
558
|
-
code
|
|
559
|
-
| ECall(at, StaticCall("ff:core/Try.Try_finally", _, _), _, _, _, _) {
|
|
560
|
-
self.emitTryCatchFinally(term, last, async) | Some(code)
|
|
561
|
-
} =>
|
|
562
|
-
code
|
|
563
|
-
| ECall(at, StaticCall("ff:core/UnsafeJs.throwIfCancelled", _, _), _, _, [], _) =>
|
|
564
|
-
if(async) {"ff_core_Task.Task_throwIfAborted($task)"} else {""}
|
|
565
463
|
| ECall(at, StaticCall(name, True, instanceCall), effect, _, arguments, _) =>
|
|
566
464
|
if(instanceCall) {throw(CompileError(at, "Not yet implemented: Tail calls on trait methods."))}
|
|
567
465
|
self.tailCallUsed = True
|
|
@@ -572,6 +470,10 @@ extend self: JsEmitter {
|
|
|
572
470
|
))
|
|
573
471
|
}.collect {_}.unzip()
|
|
574
472
|
"{\n" + pair.first.join("\n") + "\n" + pair.second.join("\n") + "\ncontinue _tailcall\n}"
|
|
473
|
+
| ECall(at, StaticCall(name, _, _), _, _, arguments, dictionaries) {
|
|
474
|
+
self.emitSpecialStatement(term, last, async, name, arguments.map {_.value}, dictionaries) | Some(code)
|
|
475
|
+
} =>
|
|
476
|
+
code
|
|
575
477
|
| EPipe(at, value, _, ELambda(_, Lambda(_, _, cases))) =>
|
|
576
478
|
Patterns.convertAndCheck(self.otherModules, cases)
|
|
577
479
|
if(!last) {"do "}.else {""} +
|
|
@@ -601,6 +503,221 @@ extend self: JsEmitter {
|
|
|
601
503
|
}
|
|
602
504
|
}
|
|
603
505
|
}
|
|
506
|
+
|
|
507
|
+
emitSpecialCall(
|
|
508
|
+
term: Term
|
|
509
|
+
async: Bool
|
|
510
|
+
name: String
|
|
511
|
+
arguments: List[Term]
|
|
512
|
+
dictionaries: List[Dictionary]
|
|
513
|
+
): Option[String] {
|
|
514
|
+
name.{
|
|
515
|
+
| operator {!operator.grabFirst().isAsciiLetter()} {arguments | [value]} =>
|
|
516
|
+
Some("(" + operator + self.emitTerm(value, async) + ")")
|
|
517
|
+
| operator {!operator.grabFirst().isAsciiLetter()} {arguments | [left, right]} =>
|
|
518
|
+
Some("(" + self.emitTerm(left, async) + " " + operator + " " + self.emitTerm(right, async) + ")")
|
|
519
|
+
| "ff:core/List.List_grab" {arguments | [EVariable(_, x1), EVariable(_, x2)]} =>
|
|
520
|
+
Some(
|
|
521
|
+
"(" + escapeResolved(x1) + "[" + escapeResolved(x2) + "] ?? " +
|
|
522
|
+
"ff_core_List.internalGrab_(" + escapeResolved(x1) + ", " + escapeResolved(x2) + "))"
|
|
523
|
+
)
|
|
524
|
+
| "ff:core/Array.Array_grab" {arguments | [EVariable(_, x1), EVariable(_, x2)]} =>
|
|
525
|
+
Some(
|
|
526
|
+
"(" + escapeResolved(x1) + ".array[" + escapeResolved(x2) + "] ?? " +
|
|
527
|
+
"ff_core_Array.internalGrab_(" + escapeResolved(x1) + ", " + escapeResolved(x2) + "))"
|
|
528
|
+
)
|
|
529
|
+
| "ff:core/Equal.equals" {arguments | [left, right]} {dictionaries | [Dictionary(_, _, _, typeName, [])]} {
|
|
530
|
+
primitiveTypes.contains(typeName) || typeName == "ff:core/Ordering.Ordering"
|
|
531
|
+
} =>
|
|
532
|
+
Some("(" + self.emitTerm(left, async) + " === " + self.emitTerm(right, async) + ")")
|
|
533
|
+
| "ff:core/Equal.notEquals" {arguments | [left, right]} {dictionaries | [Dictionary(_, _, _, typeName, [])]} {
|
|
534
|
+
primitiveTypes.contains(typeName) || typeName == "ff:core/Ordering.Ordering"
|
|
535
|
+
} =>
|
|
536
|
+
Some("(" + self.emitTerm(left, async) + " !== " + self.emitTerm(right, async) + ")")
|
|
537
|
+
| "ff:core/Ordering.before" {arguments | [left, right]} {dictionaries | [Dictionary(_, _, _, typeName, [])]} {
|
|
538
|
+
primitiveTypes.contains(typeName)
|
|
539
|
+
} =>
|
|
540
|
+
Some("(" + self.emitTerm(left, async) + " < " + self.emitTerm(right, async) + ")")
|
|
541
|
+
| "ff:core/Ordering.notBefore" {arguments | [left, right]} {dictionaries | [Dictionary(_, _, _, typeName, [])]} {
|
|
542
|
+
primitiveTypes.contains(typeName)
|
|
543
|
+
} =>
|
|
544
|
+
Some("(" + self.emitTerm(left, async) + " >= " + self.emitTerm(right, async) + ")")
|
|
545
|
+
| "ff:core/Ordering.after" {arguments | [left, right]} {dictionaries | [Dictionary(_, _, _, typeName, [])]} {
|
|
546
|
+
primitiveTypes.contains(typeName)
|
|
547
|
+
} =>
|
|
548
|
+
Some("(" + self.emitTerm(left, async) + " > " + self.emitTerm(right, async) + ")")
|
|
549
|
+
| "ff:core/Ordering.notAfter" {arguments | [left, right]} {dictionaries | [Dictionary(_, _, _, typeName, [])]} {
|
|
550
|
+
primitiveTypes.contains(typeName)
|
|
551
|
+
} =>
|
|
552
|
+
Some("(" + self.emitTerm(left, async) + " <= " + self.emitTerm(right, async) + ")")
|
|
553
|
+
| "ff:core/List.fillBy" {term | ECall call} {arguments | [size, ELambda(at,
|
|
554
|
+
Lambda(_, _, [MatchCase(_, [PVariable(_, name)], [], body)@c])@l
|
|
555
|
+
)]} {
|
|
556
|
+
!effectTypeIsAsync(call.effect)
|
|
557
|
+
} =>
|
|
558
|
+
let n = name.map {escapeResolved(_)}.else {"i"}
|
|
559
|
+
let newAsync = self.emittingAsync && effectTypeIsAsync(call.effect)
|
|
560
|
+
let await = if(newAsync) {"await "} else {""}
|
|
561
|
+
Some(
|
|
562
|
+
await + "((() => {\n" +
|
|
563
|
+
"const size = " + self.emitTerm(size, async) + ";\n" + // Not correct if async and body isn't
|
|
564
|
+
"const result = [];\n" +
|
|
565
|
+
"for(let " + n + " = 0; " + n + " < size; " + n + "++) {\n" +
|
|
566
|
+
"result.push(" + self.emitTerm(body, newAsync) + ");\n" +
|
|
567
|
+
"}\n" +
|
|
568
|
+
"return result;\n" +
|
|
569
|
+
"})())"
|
|
570
|
+
)
|
|
571
|
+
| "ff:core/UnsafeJs.import" {arguments | [EString(_, url)]} =>
|
|
572
|
+
Some(self.jsImporter.add(url.replace("\"", "")))
|
|
573
|
+
| "ff:core/UnsafeJs.await" {arguments | [body]} =>
|
|
574
|
+
if(async) {
|
|
575
|
+
Some("(await " + self.emitTerm(body, async) + "($task))")
|
|
576
|
+
} else {
|
|
577
|
+
Some(self.emitTerm(invokeImmediately(body), async))
|
|
578
|
+
}
|
|
579
|
+
| "ff:core/UnsafeJs.cancelled" =>
|
|
580
|
+
Some(if(async) {"$task.controller.signal.aborted"} else {"false"})
|
|
581
|
+
| "ff:core/UnsafeJs.throwIfCancelled" =>
|
|
582
|
+
Some(if(async) {"((() => ff_core_Task.Task_throwIfAborted($task))())"} else {""})
|
|
583
|
+
| "ff:core/UnsafeJs.inAsync" =>
|
|
584
|
+
Some(if(self.emittingAsync) {"true"} else {"false"})
|
|
585
|
+
| "ff:core/UnsafeJs.inBrowser" =>
|
|
586
|
+
Some(if(self.emitTarget == EmitBrowser) {"true"} else {"false"})
|
|
587
|
+
| "ff:core/UnsafeJs.inNode" =>
|
|
588
|
+
Some(if(self.emitTarget == EmitNode) {"true"} else {"false"})
|
|
589
|
+
| "ff:core/UnsafeJs.inBuild" =>
|
|
590
|
+
Some(if(self.emitTarget == EmitBuild) {"true"} else {"false"})
|
|
591
|
+
| "ff:core/UnsafeJs.value" {arguments | [e]} =>
|
|
592
|
+
Some(self.emitTerm(e, async))
|
|
593
|
+
| "ff:core/UnsafeJs.fromValue" {arguments | [e]} =>
|
|
594
|
+
Some(self.emitTerm(e, async))
|
|
595
|
+
| "ff:core/JsValue.JsValue_get" {arguments | [e1, e2]} =>
|
|
596
|
+
Some(self.emitTerm(e1, async) + self.emitField(e2, async))
|
|
597
|
+
| name {name.removeFirst("ff:core/JsValue.JsValue_call") | Some(n)} {n.all {_.isAsciiDigit()}} {
|
|
598
|
+
arguments | [e1, e2, ...es]
|
|
599
|
+
} =>
|
|
600
|
+
let argumentCode = es.map {self.emitTerm(_, async)}.join(", ")
|
|
601
|
+
Some(self.emitTerm(e1, async) + self.emitField(e2, async) + "(" + argumentCode + ")")
|
|
602
|
+
| name {name.removeFirst("ff:core/JsValue.JsValue_callValue") | Some(n)} {n.all {_.isAsciiDigit()}} {
|
|
603
|
+
arguments | [e1, ...es]
|
|
604
|
+
} =>
|
|
605
|
+
let argumentCode = es.map {self.emitTerm(_, async)}.join(", ")
|
|
606
|
+
Some(self.emitTerm(e1, async) + "(" + argumentCode + ")")
|
|
607
|
+
| name {name.removeFirst("ff:core/JsValue.JsValue_new") | Some(n)} {n.all {_.isAsciiDigit()}} {
|
|
608
|
+
arguments | [e1, ...es]
|
|
609
|
+
} =>
|
|
610
|
+
let argumentCode = es.map {self.emitTerm(_, async)}.join(", ")
|
|
611
|
+
Some("(new " + self.emitTerm(e1, async) + "(" + argumentCode + ")" + ")")
|
|
612
|
+
| "ff:core/JsValue.JsValue_with" =>
|
|
613
|
+
function go(e: Term, fields: List[Pair[Term, Term]]): String {
|
|
614
|
+
e.{
|
|
615
|
+
| ECall(_, StaticCall("ff:core/JsValue.JsValue_with", _, _), _, _, [a1, a2, a3], _) =>
|
|
616
|
+
go(a1.value, [Pair(a2.value, a3.value), ...fields])
|
|
617
|
+
| ECall(_, StaticCall(name, _, _), _, _, [a], _) {
|
|
618
|
+
name == "ff:core/JsSystem.JsSystem_object" || name == "ff:core/JsSystem.JsSystem_new0"
|
|
619
|
+
} {
|
|
620
|
+
noSideEffects(a.value)
|
|
621
|
+
} =>
|
|
622
|
+
"{" + fields.map {p =>
|
|
623
|
+
self.emitField(p.first, async, dot = "") + ": " + self.emitTerm(p.second, async)
|
|
624
|
+
}.join(", ") + "}"
|
|
625
|
+
| _ =>
|
|
626
|
+
"{..." + self.emitTerm(e, async) + ", " + fields.map {p =>
|
|
627
|
+
self.emitField(p.first, async, dot = "") + ": " + self.emitTerm(p.second, async)
|
|
628
|
+
}.join(", ") + "}"
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
Some(go(term, []))
|
|
632
|
+
| name {name.removeFirst("ff:core/JsSystem.JsSystem_call") | Some(n)} {n.all {_.isAsciiDigit()}} {
|
|
633
|
+
arguments | [e1, EString(_, q)@e2, ...es]
|
|
634
|
+
} {noSideEffects(e1)} =>
|
|
635
|
+
let argumentCode = es.map {self.emitTerm(_, async)}.join(", ")
|
|
636
|
+
Some(safeBare(q).else {"globalThis[" + self.emitTerm(e2, async) + "]"} + "(" + argumentCode + ")")
|
|
637
|
+
| name {name.removeFirst("ff:core/JsSystem.JsSystem_function") | Some(n)} {n.all {_.isAsciiDigit()}} {
|
|
638
|
+
arguments | [e1, e2]
|
|
639
|
+
} {noSideEffects(e1)} {term | ECall call} {!effectTypeIsAsync(call.effect)} =>
|
|
640
|
+
Some(self.emitTerm(e2, async))
|
|
641
|
+
| "ff:core/JsSystem.JsSystem_get" {arguments | [e1, EString(_, q)@e2]} {noSideEffects(e1)} =>
|
|
642
|
+
Some(safeBare(q).else {"globalThis[" + self.emitTerm(e2, async) + "]"})
|
|
643
|
+
| "ff:core/JsSystem.JsSystem_object" {arguments | [e]} {noSideEffects(e)} =>
|
|
644
|
+
Some("{}")
|
|
645
|
+
| "ff:core/JsSystem.JsSystem_new0" {arguments | [e]} {noSideEffects(e)} =>
|
|
646
|
+
Some("{}")
|
|
647
|
+
| "ff:core/JsSystem.JsSystem_null" {arguments | [e]} {noSideEffects(e)} =>
|
|
648
|
+
Some("null")
|
|
649
|
+
| "ff:core/JsSystem.JsSystem_undefined" {arguments | [e]} {noSideEffects(e)} =>
|
|
650
|
+
Some("(void 0)")
|
|
651
|
+
| _ =>
|
|
652
|
+
None
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
emitSpecialStatement(
|
|
657
|
+
term: Term
|
|
658
|
+
last: Bool
|
|
659
|
+
async: Bool
|
|
660
|
+
name: String
|
|
661
|
+
arguments: List[Term]
|
|
662
|
+
dictionaries: List[Dictionary]
|
|
663
|
+
): Option[String] {
|
|
664
|
+
name.{
|
|
665
|
+
| "ff:core/Core.while" {arguments | [condition, body]} =>
|
|
666
|
+
Some(
|
|
667
|
+
"while(" + self.emitComma(invokeImmediately(condition), async) + ") {\n" +
|
|
668
|
+
self.emitStatements(invokeImmediately(body), False, async) + "\n}"
|
|
669
|
+
)
|
|
670
|
+
| "ff:core/Core.doWhile" {arguments | [doWhileBody]} {
|
|
671
|
+
invokeImmediately(doWhileBody) | ESequential(_, body, condition)
|
|
672
|
+
} =>
|
|
673
|
+
Some(
|
|
674
|
+
"while(true) {\n" +
|
|
675
|
+
self.emitStatements(body, False, async) +
|
|
676
|
+
"\nif(!" + self.emitComma(condition, async) + ") break" +
|
|
677
|
+
"\n}"
|
|
678
|
+
)
|
|
679
|
+
| "ff:core/Core.doWhile" {arguments | [doWhileBody]} {
|
|
680
|
+
invokeImmediately(doWhileBody) | body
|
|
681
|
+
} =>
|
|
682
|
+
Some("while(" + self.emitComma(body, async) + ") {}")
|
|
683
|
+
| "ff:core/Core.if" {arguments | [condition, body]} =>
|
|
684
|
+
Some(
|
|
685
|
+
"if(" + self.emitComma(condition, async) + ") {\n" +
|
|
686
|
+
if(last) {
|
|
687
|
+
"return ff_core_Option.Some(" + self.emitTerm(invokeImmediately(body), async) +
|
|
688
|
+
")\n} else return ff_core_Option.None()"
|
|
689
|
+
} else {
|
|
690
|
+
self.emitStatements(invokeImmediately(body), False, async) + "\n}"
|
|
691
|
+
}
|
|
692
|
+
)
|
|
693
|
+
| "ff:core/Core.throw" {term | ECall c} {c.arguments | [argument]} {dictionaries | [dictionary]} =>
|
|
694
|
+
let d = self.emitDictionary(dictionary)
|
|
695
|
+
let a = self.emitArgument(term.at, argument, async)
|
|
696
|
+
Some("throw Object.assign(new Error(), {ffException: ff_core_Any.toAny_(" + a + ", " + d + ")})")
|
|
697
|
+
| "ff:core/Try.Try_catch" {self.emitTryCatchFinally(term, last, async) | Some(code)} =>
|
|
698
|
+
Some(code)
|
|
699
|
+
| "ff:core/Try.Try_catchAny" {self.emitTryCatchFinally(term, last, async) | Some(code)} =>
|
|
700
|
+
Some(code)
|
|
701
|
+
| "ff:core/Try.Try_finally" {self.emitTryCatchFinally(term, last, async) | Some(code)} =>
|
|
702
|
+
Some(code)
|
|
703
|
+
| "ff:core/UnsafeJs.throwIfCancelled" =>
|
|
704
|
+
Some(if(async) {"ff_core_Task.Task_throwIfAborted($task)"} else {""})
|
|
705
|
+
| "ff:core/JsValue.JsValue_set" {arguments | [e1, e2, e3]} =>
|
|
706
|
+
Some(self.emitTerm(e1, async) + self.emitField(e2, async) + " = " + self.emitTerm(e3, async))
|
|
707
|
+
| "ff:core/JsValue.JsValue_increment" {arguments | [e1, e2, e3]} =>
|
|
708
|
+
Some(self.emitTerm(e1, async) + self.emitField(e2, async) + " += " + self.emitTerm(e3, async))
|
|
709
|
+
| "ff:core/JsValue.JsValue_decrement" {arguments | [e1, e2, e3]} =>
|
|
710
|
+
Some(self.emitTerm(e1, async) + self.emitField(e2, async) + " -= " + self.emitTerm(e3, async))
|
|
711
|
+
| "ff:core/JsSystem.JsSystem_set" {arguments | [e1, EString(_, q), e3]} {noSideEffects(e1)} {safeBare(q) | Some(s)} =>
|
|
712
|
+
Some(s + " = " + self.emitTerm(e3, async))
|
|
713
|
+
| "ff:core/JsSystem.JsSystem_increment" {arguments | [e1, EString(_, q), e3]} {noSideEffects(e1)} {safeBare(q) | Some(s)} =>
|
|
714
|
+
Some(s + " += " + self.emitTerm(e3, async))
|
|
715
|
+
| "ff:core/JsSystem.JsSystem_decrement" {arguments | [e1, EString(_, q), e3]} {noSideEffects(e1)} {safeBare(q) | Some(s)} =>
|
|
716
|
+
Some(s + " -= " + self.emitTerm(e3, async))
|
|
717
|
+
| _ =>
|
|
718
|
+
None
|
|
719
|
+
}
|
|
720
|
+
}
|
|
604
721
|
|
|
605
722
|
emitTryCatchFinally(term: Term, last: Bool, async: Bool): Option[String] {
|
|
606
723
|
function emitCatch(catchEffect: Type, cases: List[MatchCase]): String {
|
|
@@ -866,6 +983,22 @@ extend self: JsEmitter {
|
|
|
866
983
|
self.emitTerm(value, async)
|
|
867
984
|
}
|
|
868
985
|
}
|
|
986
|
+
|
|
987
|
+
emitComma(term: Term, async: Bool): String {
|
|
988
|
+
term.{
|
|
989
|
+
| ESequential(_, ESequential(_, before1, before2), after) {
|
|
990
|
+
safeCommable(before1) && safeCommable(before2)
|
|
991
|
+
} =>
|
|
992
|
+
"(" + self.emitStatements(before1, False, async) + ", " +
|
|
993
|
+
self.emitStatements(before2, False, async) + ", " +
|
|
994
|
+
self.emitTerm(after, async) + ")"
|
|
995
|
+
| ESequential(_, before, after) {safeCommable(before)} =>
|
|
996
|
+
"(" + self.emitStatements(before, False, async) + ", " +
|
|
997
|
+
self.emitTerm(after, async) + ")"
|
|
998
|
+
| _ =>
|
|
999
|
+
self.emitTerm(term, async)
|
|
1000
|
+
}
|
|
1001
|
+
}
|
|
869
1002
|
|
|
870
1003
|
}
|
|
871
1004
|
|
|
@@ -899,6 +1032,21 @@ invokeImmediately(function: Term): Term {
|
|
|
899
1032
|
ECall(function.at, DynamicCall(function, False), effect, [], [], [])
|
|
900
1033
|
}
|
|
901
1034
|
|
|
1035
|
+
safeCommable(term: Term): Bool {
|
|
1036
|
+
term.{
|
|
1037
|
+
| EField _ => True
|
|
1038
|
+
| EVariable _ => True
|
|
1039
|
+
| EAssign _ => True
|
|
1040
|
+
| EAssignField _ => True
|
|
1041
|
+
| ECall _ => True
|
|
1042
|
+
| EString(_, _) => True
|
|
1043
|
+
| EInt(_, _) => True
|
|
1044
|
+
| EChar(_, _) => True
|
|
1045
|
+
| EFloat(_, _) => True
|
|
1046
|
+
| _ => False
|
|
1047
|
+
}
|
|
1048
|
+
}
|
|
1049
|
+
|
|
902
1050
|
extractTypeName(type: Type): String {
|
|
903
1051
|
| TVariable(at, index) =>
|
|
904
1052
|
fail(at, "Unexpected type variable: $" + index)
|
|
@@ -946,6 +1094,29 @@ effectTypeIsAsync(effect: Type): Bool {
|
|
|
946
1094
|
| _ => False
|
|
947
1095
|
}
|
|
948
1096
|
|
|
1097
|
+
safeBare(quotedString: String): Option[String] {
|
|
1098
|
+
// TODO: And not a reserved word in JS
|
|
1099
|
+
quotedString.removeFirst("\"").flatMap {_.removeLast("\"")}.filter {s =>
|
|
1100
|
+
s.first().any {_.isAsciiLetter()} && s.all {_.isAsciiLetterOrDigit()}
|
|
1101
|
+
}
|
|
1102
|
+
}
|
|
1103
|
+
|
|
1104
|
+
noSideEffects(term: Term): Bool {
|
|
1105
|
+
term.{
|
|
1106
|
+
| EField(_, _, e, _) => noSideEffects(e)
|
|
1107
|
+
| EVariable(_, _) => True
|
|
1108
|
+
| ECall(_, StaticCall("ff:core/BrowserSystem.BrowserSystem_js", _, _), _, _, [a], _) => noSideEffects(a.value)
|
|
1109
|
+
| ECall(_, StaticCall("ff:core/BuildSystem.BuildSystem_js", _, _), _, _, [a], _) => noSideEffects(a.value)
|
|
1110
|
+
| ECall(_, StaticCall("ff:core/NodeSystem.NodeSystem_js", _, _), _, _, [a], _) => noSideEffects(a.value)
|
|
1111
|
+
| ECall(_, StaticCall("ff:core/UnsafeJs.jsSystem", _, _), _, _, _, _) => True
|
|
1112
|
+
| EString(_, _) => True
|
|
1113
|
+
| EInt(_, _) => True
|
|
1114
|
+
| EChar(_, _) => True
|
|
1115
|
+
| EFloat(_, _) => True
|
|
1116
|
+
| _ => False
|
|
1117
|
+
}
|
|
1118
|
+
}
|
|
1119
|
+
|
|
949
1120
|
primitiveTypes = [
|
|
950
1121
|
"ff:core/Bool.Bool"
|
|
951
1122
|
"ff:core/Char.Char"
|
package/core/JsValue.ff
CHANGED
|
@@ -116,38 +116,37 @@ extend self: JsValue {
|
|
|
116
116
|
target js sync "for(const value of self_) if(!body_(value)) break"
|
|
117
117
|
target js async "for(const value of self_) if(!await body_(value, $task)) break"
|
|
118
118
|
|
|
119
|
-
|
|
120
|
-
call(name: String, arguments: List[JsValue]): JsValue
|
|
119
|
+
call[A0: IsJsValue](name: A0, arguments: List[JsValue]): JsValue
|
|
121
120
|
target js sync "return self_[name_].apply(this_, arguments_)"
|
|
122
121
|
|
|
123
|
-
call0(name:
|
|
122
|
+
call0[A0: IsJsValue](name: A0): JsValue
|
|
124
123
|
target js sync "return self_[name_].call(self_)"
|
|
125
124
|
|
|
126
|
-
call1[A1: IsJsValue](name:
|
|
125
|
+
call1[A0: IsJsValue, A1: IsJsValue](name: A0, a1: A1): JsValue
|
|
127
126
|
target js sync "return self_[name_].call(self_, a1_)"
|
|
128
127
|
|
|
129
|
-
call2[A1: IsJsValue, A2: IsJsValue](name:
|
|
128
|
+
call2[A0: IsJsValue, A1: IsJsValue, A2: IsJsValue](name: A0, a1: A1, a2: A2): JsValue
|
|
130
129
|
target js sync "return self_[name_].call(self_, a1_, a2_)"
|
|
131
130
|
|
|
132
|
-
call3[A1: IsJsValue, A2: IsJsValue, A3: IsJsValue](name:
|
|
131
|
+
call3[A0: IsJsValue, A1: IsJsValue, A2: IsJsValue, A3: IsJsValue](name: A0, a1: A1, a2: A2, a3: A3): JsValue
|
|
133
132
|
target js sync "return self_[name_].call(self_, a1_, a2_, a3_)"
|
|
134
133
|
|
|
135
|
-
call4[A1: IsJsValue, A2: IsJsValue, A3: IsJsValue, A4: IsJsValue](name:
|
|
134
|
+
call4[A0: IsJsValue, A1: IsJsValue, A2: IsJsValue, A3: IsJsValue, A4: IsJsValue](name: A0, a1: A1, a2: A2, a3: A3, a4: A4): JsValue
|
|
136
135
|
target js sync "return self_[name_].call(self_, a1_, a2_, a3_, a4_)"
|
|
137
136
|
|
|
138
|
-
call5[A1: IsJsValue, A2: IsJsValue, A3: IsJsValue, A4: IsJsValue, A5: IsJsValue](name:
|
|
137
|
+
call5[A0: IsJsValue, A1: IsJsValue, A2: IsJsValue, A3: IsJsValue, A4: IsJsValue, A5: IsJsValue](name: A0, a1: A1, a2: A2, a3: A3, a4: A4, a5: A5): JsValue
|
|
139
138
|
target js sync "return self_[name_].call(self_, a1_, a2_, a3_, a4_, a5_)"
|
|
140
139
|
|
|
141
|
-
call6[A1: IsJsValue, A2: IsJsValue, A3: IsJsValue, A4: IsJsValue, A5: IsJsValue, A6: IsJsValue](name:
|
|
140
|
+
call6[A0: IsJsValue, A1: IsJsValue, A2: IsJsValue, A3: IsJsValue, A4: IsJsValue, A5: IsJsValue, A6: IsJsValue](name: A0, a1: A1, a2: A2, a3: A3, a4: A4, a5: A5, a6: A6): JsValue
|
|
142
141
|
target js sync "return self_[name_].call(self_, a1_, a2_, a3_, a4_, a5_, a6_)"
|
|
143
142
|
|
|
144
|
-
call7[A1: IsJsValue, A2: IsJsValue, A3: IsJsValue, A4: IsJsValue, A5: IsJsValue, A6: IsJsValue, A7: IsJsValue](name:
|
|
143
|
+
call7[A0: IsJsValue, A1: IsJsValue, A2: IsJsValue, A3: IsJsValue, A4: IsJsValue, A5: IsJsValue, A6: IsJsValue, A7: IsJsValue](name: A0, a1: A1, a2: A2, a3: A3, a4: A4, a5: A5, a6: A6, a7: A7): JsValue
|
|
145
144
|
target js sync "return self_[name_].call(self_, a1_, a2_, a3_, a4_, a5_, a6_, a7_)"
|
|
146
145
|
|
|
147
|
-
call8[A1: IsJsValue, A2: IsJsValue, A3: IsJsValue, A4: IsJsValue, A5: IsJsValue, A6: IsJsValue, A7: IsJsValue, A8: IsJsValue](name:
|
|
146
|
+
call8[A0: IsJsValue, A1: IsJsValue, A2: IsJsValue, A3: IsJsValue, A4: IsJsValue, A5: IsJsValue, A6: IsJsValue, A7: IsJsValue, A8: IsJsValue](name: A0, a1: A1, a2: A2, a3: A3, a4: A4, a5: A5, a6: A6, a7: A7, a8: A8): JsValue
|
|
148
147
|
target js sync "return self_[name_].call(self_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_)"
|
|
149
148
|
|
|
150
|
-
call9[A1: IsJsValue, A2: IsJsValue, A3: IsJsValue, A4: IsJsValue, A5: IsJsValue, A6: IsJsValue, A7: IsJsValue, A8: IsJsValue, A9: IsJsValue](name:
|
|
149
|
+
call9[A0: IsJsValue, A1: IsJsValue, A2: IsJsValue, A3: IsJsValue, A4: IsJsValue, A5: IsJsValue, A6: IsJsValue, A7: IsJsValue, A8: IsJsValue, A9: IsJsValue](name: A0, a1: A1, a2: A2, a3: A3, a4: A4, a5: A5, a6: A6, a7: A7, a8: A8, a9: A9): JsValue
|
|
151
150
|
target js sync "return self_[name_].call(self_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_)"
|
|
152
151
|
|
|
153
152
|
|
|
@@ -155,34 +154,34 @@ extend self: JsValue {
|
|
|
155
154
|
target js sync "return self_.apply(this_, arguments_)"
|
|
156
155
|
|
|
157
156
|
callValue0(): JsValue
|
|
158
|
-
target js sync "return self_.call(
|
|
157
|
+
target js sync "return self_.call(void 0)"
|
|
159
158
|
|
|
160
159
|
callValue1[A1: IsJsValue](a1: A1): JsValue
|
|
161
|
-
target js sync "return self_.call(
|
|
160
|
+
target js sync "return self_.call(void 0, a1_)"
|
|
162
161
|
|
|
163
162
|
callValue2[A1: IsJsValue, A2: IsJsValue](a1: A1, a2: A2): JsValue
|
|
164
|
-
target js sync "return self_.call(
|
|
163
|
+
target js sync "return self_.call(void 0, a1_, a2_)"
|
|
165
164
|
|
|
166
165
|
callValue3[A1: IsJsValue, A2: IsJsValue, A3: IsJsValue](a1: A1, a2: A2, a3: A3): JsValue
|
|
167
|
-
target js sync "return self_.call(
|
|
166
|
+
target js sync "return self_.call(void 0, a1_, a2_, a3_)"
|
|
168
167
|
|
|
169
168
|
callValue4[A1: IsJsValue, A2: IsJsValue, A3: IsJsValue, A4: IsJsValue](a1: A1, a2: A2, a3: A3, a4: A4): JsValue
|
|
170
|
-
target js sync "return self_.call(
|
|
169
|
+
target js sync "return self_.call(void 0, a1_, a2_, a3_, a4_)"
|
|
171
170
|
|
|
172
171
|
callValue5[A1: IsJsValue, A2: IsJsValue, A3: IsJsValue, A4: IsJsValue, A5: IsJsValue](a1: A1, a2: A2, a3: A3, a4: A4, a5: A5): JsValue
|
|
173
|
-
target js sync "return self_.call(
|
|
172
|
+
target js sync "return self_.call(void 0, a1_, a2_, a3_, a4_, a5_)"
|
|
174
173
|
|
|
175
174
|
callValue6[A1: IsJsValue, A2: IsJsValue, A3: IsJsValue, A4: IsJsValue, A5: IsJsValue, A6: IsJsValue](a1: A1, a2: A2, a3: A3, a4: A4, a5: A5, a6: A6): JsValue
|
|
176
|
-
target js sync "return self_.call(
|
|
175
|
+
target js sync "return self_.call(void 0, a1_, a2_, a3_, a4_, a5_, a6_)"
|
|
177
176
|
|
|
178
177
|
callValue7[A1: IsJsValue, A2: IsJsValue, A3: IsJsValue, A4: IsJsValue, A5: IsJsValue, A6: IsJsValue, A7: IsJsValue](a1: A1, a2: A2, a3: A3, a4: A4, a5: A5, a6: A6, a7: A7): JsValue
|
|
179
|
-
target js sync "return self_.call(
|
|
178
|
+
target js sync "return self_.call(void 0, a1_, a2_, a3_, a4_, a5_, a6_, a7_)"
|
|
180
179
|
|
|
181
180
|
callValue8[A1: IsJsValue, A2: IsJsValue, A3: IsJsValue, A4: IsJsValue, A5: IsJsValue, A6: IsJsValue, A7: IsJsValue, A8: IsJsValue](a1: A1, a2: A2, a3: A3, a4: A4, a5: A5, a6: A6, a7: A7, a8: A8): JsValue
|
|
182
|
-
target js sync "return self_.call(
|
|
181
|
+
target js sync "return self_.call(void 0, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_)"
|
|
183
182
|
|
|
184
183
|
callValue9[A1: IsJsValue, A2: IsJsValue, A3: IsJsValue, A4: IsJsValue, A5: IsJsValue, A6: IsJsValue, A7: IsJsValue, A8: IsJsValue, A9: IsJsValue](a1: A1, a2: A2, a3: A3, a4: A4, a5: A5, a6: A6, a7: A7, a8: A8, a9: A9): JsValue
|
|
185
|
-
target js sync "return self_.call(
|
|
184
|
+
target js sync "return self_.call(void 0, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_)"
|
|
186
185
|
|
|
187
186
|
|
|
188
187
|
new(this: JsValue, arguments: List[JsValue]): JsValue
|
package/core/List.ff
CHANGED
|
@@ -231,7 +231,7 @@ extend self[T]: List[T] {
|
|
|
231
231
|
await body_(self_[i], $task)
|
|
232
232
|
}
|
|
233
233
|
"""
|
|
234
|
-
|
|
234
|
+
|
|
235
235
|
eachWhile(body: T => Bool): Unit
|
|
236
236
|
target js sync "for(const value of self_) if(!body_(value)) break"
|
|
237
237
|
target js async "for(const value of self_) if(!await body_(value, $task)) break"
|