Skip to content

Commit 4334c67

Browse files
committed
Merge remote-tracking branch 'Mark/hkmc2' into feat-llir
2 parents cf7e036 + 7a5cc25 commit 4334c67

29 files changed

+609
-412
lines changed

hkmc2/shared/src/main/scala/hkmc2/codegen/Lowering.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -479,7 +479,7 @@ class Lowering()(using Config, TL, Raise, State, Ctx):
479479
case (param, arg) :: args =>
480480
val (cse, blk) = mkArgs(args)
481481
(cse, Assign(arg, Select(sr, param.id/*FIXME incorrect Ident?*/)(S(param)), blk))
482-
mkMatch(mkArgs(clsParams.zip(args)))
482+
mkMatch(mkArgs(clsParams.iterator.zip(args).collect { case (s1, S(s2)) => (s1, s2) }.toList))
483483
case Pattern.Tuple(len, inf) => mkMatch(Case.Tup(len, inf) -> go(tail, topLevel = false))
484484
case Split.Else(els) =>
485485
if k.isInstanceOf[TailOp] && isIf then term_nonTail(els)(k)

hkmc2/shared/src/main/scala/hkmc2/codegen/js/JSBuilder.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -621,7 +621,7 @@ trait JSBuilderArgNumSanityChecks(using Config, Elaborator.State)
621621
doc"\nlet ${nme} = ${paramsStr}[$i];"}.mkDocument("")
622622
val restAssign = paramRest match
623623
case N => doc""
624-
case S(p) => doc"\nlet $p = globalThis.Predef.tupleSlice($paramsStr, ${params.paramCountLB}, 0);"
624+
case S(p) => doc"\nlet $p = runtime.Tuple.slice($paramsStr, ${params.paramCountLB}, 0);"
625625
(doc"...$paramsStr", doc"$checkArgsNum$paramsAssign$restAssign${this.body(body, endSemi = false)}")
626626
else
627627
super.setupFunction(name, params, body)

hkmc2/shared/src/main/scala/hkmc2/semantics/Pattern.scala

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,22 @@ import ucs.DeBrujinSplit
77

88
/** Flat patterns for pattern matching */
99
enum Pattern extends AutoLocated:
10+
1011
case Lit(literal: Literal)
11-
case ClassLike(sym: ClassSymbol | ModuleSymbol, trm: Term, parameters: Opt[List[BlockLocalSymbol]], var refined: Bool)(val tree: Tree)
12+
13+
/** An individual argument is None when it is not matched, i.e. when an underscore is used there.
14+
* The whole argument list is None when no argument list is being matched at all, as in `x is Some then ...`. */
15+
case ClassLike(
16+
sym: ClassSymbol | ModuleSymbol,
17+
trm: Term,
18+
args: Opt[List[Opt[BlockLocalSymbol]]],
19+
var refined: Bool,
20+
)(val tree: Tree)
21+
1222
case Synonym(symbol: PatternSymbol, patternArguments: Ls[(split: DeBrujinSplit, tree: Tree)])
23+
1324
case Tuple(size: Int, inf: Bool)
25+
1426
case Record(entries: List[(Ident -> BlockLocalSymbol)])
1527

1628
def subTerms: Ls[Term] = this match
@@ -22,15 +34,16 @@ enum Pattern extends AutoLocated:
2234

2335
def children: Ls[Located] = this match
2436
case Lit(literal) => literal :: Nil
25-
case ClassLike(_, t, parameters, _) => t :: parameters.toList.flatten
37+
case ClassLike(_, t, args, _) =>
38+
t :: args.fold(Nil)(_.collect { case S(symbol) => symbol })
2639
case Synonym(_, arguments) => arguments.map(_.tree)
2740
case Tuple(fields, _) => Nil
2841
case Record(entries) => entries.flatMap { case (nme, als) => nme :: als :: Nil }
2942

3043
def showDbg: Str = this match
3144
case Lit(literal) => literal.idStr
3245
case ClassLike(sym, t, ps, rfd) => (if rfd then "refined " else "") +
33-
sym.nme + ps.fold("")(_.mkString("(", ", ", ")"))
46+
sym.nme + ps.fold("")(_.iterator.map(_.fold("_")(_.toString)).mkString("(", ", ", ")"))
3447
case Synonym(symbol, arguments) =>
3548
symbol.nme + arguments.iterator.map(_.tree.showDbg).mkString("(", ", ", ")")
3649
case Tuple(size, inf) => "[]" + (if inf then ">=" else "=") + size

hkmc2/shared/src/main/scala/hkmc2/semantics/ucs/DeBrujinSplit.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -347,7 +347,7 @@ extension (split: DeBrujinSplit)
347347
go(body, ctx2)
348348
val select = scoped("ucs:sel"):
349349
elab.reference(symbol).getOrElse(Term.Error)
350-
val pattern = Pattern.ClassLike(symbol, select, S(subSymbols), false)(Empty())
350+
val pattern = Pattern.ClassLike(symbol, select, S(subSymbols.map(S.apply)), false)(Empty())
351351
semantics.Branch(ctx(scrutinee - 1)(), pattern, consequent2) ~: go(alternative, ctx)
352352
case ClassLike(ConstructorLike.Symbol(symbol: ModuleSymbol)) =>
353353
val select = scoped("ucs:sel"):

hkmc2/shared/src/main/scala/hkmc2/semantics/ucs/Desugarer.scala

Lines changed: 39 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import Keyword.{as, and, `do`, `else`, is, let, `then`}
1111
import collection.mutable.{HashMap, SortedSet}
1212
import Elaborator.{ctx, Ctxl}
1313
import scala.annotation.targetName
14+
import hkmc2.semantics.ClassDef.Parameterized
1415

1516
object Desugarer:
1617
extension (op: Keyword.Infix)
@@ -478,19 +479,27 @@ class Desugarer(val elaborator: Elaborator)
478479
val clsTrm = elaborator.cls(ctor, inAppPrefix = false)
479480
clsTrm.symbol.flatMap(_.asClsLike) match
480481
case S(cls: ClassSymbol) =>
481-
val arity = cls.arity
482-
if arity =/= args.length then
483-
val m = args.length.toString
484-
error:
485-
if arity == 0 then
486-
msg"the constructor does not take any arguments but found $m" -> app.toLoc
487-
else
488-
msg"mismatched arity: expect ${arity.toString}, found $m" -> app.toLoc
489-
val params = scrutSymbol.getSubScrutinees(cls)
482+
val paramSymbols = cls.defn match
483+
case S(Parameterized(params = paramList)) =>
484+
if paramList.params.size =/= args.length then
485+
val n = args.length.toString
486+
val m = paramList.params.size.toString
487+
error:
488+
if paramList.params.isEmpty then
489+
msg"the constructor does not take any arguments but found $n" -> app.toLoc
490+
else
491+
msg"mismatched arity: expect $m, found $n" -> app.toLoc
492+
scrutSymbol.getSubScrutinees(cls).iterator.zip(paramList.params).map:
493+
case (symbol, Param(flags = FldFlags(value = true))) => R(symbol)
494+
case (_, Param(_, paramSymbol, _)) => L(paramSymbol) // to report errors
495+
.toList
496+
case S(_) | N =>
497+
error(msg"class ${cls.name} does not have parameters" -> ctor.toLoc)
498+
Nil
490499
Branch(
491500
ref,
492-
Pattern.ClassLike(cls, clsTrm, S(params), false)(ctor), // TODO: refined?
493-
subMatches(params zip args, sequel)(Split.End)(ctx)
501+
Pattern.ClassLike(cls, clsTrm, S(paramSymbols.map(_.toOption)), false)(ctor), // TODO: refined?
502+
subMatches(paramSymbols.zip(args), sequel)(Split.End)(ctx)
494503
) ~: fallback
495504
case S(pat: PatternSymbol) if compile =>
496505
// When we support extraction parameters, they need to be handled here.
@@ -550,26 +559,26 @@ class Desugarer(val elaborator: Elaborator)
550559
val (wrapRest, restMatches) = rest match
551560
case S((rest, last)) =>
552561
val (wrapLast, reversedLastMatches) = last.reverseIterator.zipWithIndex
553-
.foldLeft[(Split => Split, Ls[(BlockLocalSymbol, Tree)])]((identity, Nil)):
562+
.foldLeft[(Split => Split, Ls[(Right[Nothing, BlockLocalSymbol], Tree)])]((identity, Nil)):
554563
case ((wrapInner, matches), (pat, lastIndex)) =>
555564
val sym = scrutSymbol.getTupleLastSubScrutinee(lastIndex)
556565
val wrap = (split: Split) =>
557566
Split.Let(sym, callTupleGet(ref, -1 - lastIndex, sym), wrapInner(split))
558-
(wrap, (sym, pat) :: matches)
567+
(wrap, (R(sym), pat) :: matches)
559568
val lastMatches = reversedLastMatches.reverse
560569
rest match
561570
case N => (wrapLast, lastMatches)
562571
case S(pat) =>
563572
val sym = TempSymbol(N, "rest")
564573
val wrap = (split: Split) =>
565574
Split.Let(sym, app(tupleSlice, tup(fld(ref), fld(int(lead.length)), fld(int(last.length))), sym), wrapLast(split))
566-
(wrap, (sym, pat) :: lastMatches)
575+
(wrap, (R(sym), pat) :: lastMatches)
567576
case N => (identity: Split => Split, Nil)
568577
val (wrap, matches) = lead.zipWithIndex.foldRight((wrapRest, restMatches)):
569578
case ((pat, i), (wrapInner, matches)) =>
570579
val sym = scrutSymbol.getTupleLeadSubScrutinee(i)
571580
val wrap = (split: Split) => Split.Let(sym, Term.SynthSel(ref, Ident(s"$i"))(N), wrapInner(split))
572-
(wrap, (sym, pat) :: matches)
581+
(wrap, (R(sym), pat) :: matches)
573582
Branch(
574583
ref,
575584
Pattern.Tuple(lead.length + rest.fold(0)(_._2.length), rest.isDefined),
@@ -609,16 +618,29 @@ class Desugarer(val elaborator: Elaborator)
609618
/** Desugar a list of sub-patterns (with their corresponding scrutinees).
610619
* This is called when handling nested patterns. The caller is responsible
611620
* for providing the symbols of scrutinees.
621+
*
622+
* @param matches a list of pairs consisting of a scrutinee and a pattern.
623+
* Each scrutinee is represented by `Either[VarSymbol, BlockLocalSymbol]`.
624+
* If it is not accessible due to the corresponding parameter not being
625+
* declared with `val`, it will be the `Left` of the parameter symbol for
626+
* error reporting.
627+
* @param sequel the innermost split
612628
*/
613-
def subMatches(matches: Ls[(BlockLocalSymbol, Tree)],
629+
def subMatches(matches: Ls[(Either[VarSymbol, BlockLocalSymbol], Tree)],
614630
sequel: Sequel): Split => Sequel = matches match
615631
case Nil => _ => ctx => trace(
616632
pre = s"subMatches (done) <<< Nil",
617633
post = (r: Split) => s"subMatches >>> ${r.showDbg}"
618634
):
619635
sequel(ctx)
620636
case (_, Under()) :: rest => subMatches(rest, sequel)
621-
case (scrutinee, pattern) :: rest => fallback => trace(
637+
case (L(paramSymbol), pattern) :: rest =>
638+
error(msg"This pattern cannot be matched" -> pattern.toLoc,
639+
msg"because the corresponding parameter `${paramSymbol.name}` is not publicly accessible" -> paramSymbol.toLoc,
640+
msg"Suggestion: use a wildcard pattern `_` in this position" -> N,
641+
msg"Suggestion: mark this parameter with `val` so it becomes accessible" -> N)
642+
subMatches(rest, sequel)
643+
case (R(scrutinee), pattern) :: rest => fallback => trace(
622644
pre = s"subMatches (nested) <<< $scrutinee is $pattern",
623645
post = (r: Sequel) => s"subMatches (nested) >>>"
624646
):

hkmc2/shared/src/main/scala/hkmc2/semantics/ucs/DesugaringBase.scala

Lines changed: 20 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import syntax.Tree.*, Elaborator.{Ctxl, ctx}, Elaborator.State
99
trait DesugaringBase(using state: State):
1010
val elaborator: Elaborator
1111

12-
import elaborator.tl.*, state.globalThisSymbol
12+
import elaborator.tl.*
1313

1414
protected final def sel(p: Term, k: Ident): Term.SynthSel = Term.SynthSel(p, k)(N)
1515
protected final def sel(p: Term, k: Ident, s: FieldSymbol): Term.SynthSel = Term.SynthSel(p, k)(S(s))
@@ -22,54 +22,50 @@ trait DesugaringBase(using state: State):
2222
protected final def app(l: Term, r: Term, label: Str): Term.App = app(l, r, FlowSymbol(label))
2323
protected final def app(l: Term, r: Term, s: FlowSymbol): Term.App = Term.App(l, r)(App(Empty(), Empty()), s)
2424

25-
/** Make a term looks like `globalThis.Predef.MatchResult` with its symbol. */
25+
/** Make a term that looks like `runtime.MatchResult` with its symbol. */
2626
protected lazy val matchResultClass: Ctxl[(Term.Sel | Term.SynthSel, ClassSymbol)] =
2727
(State.runtimeSymbol.ref().selNoSym("MatchResult", synth=true), State.matchResultClsSymbol)
2828

29-
/** Make a pattern looks like `globalThis.Predef.MatchResult.class`. */
29+
/** Make a pattern that looks like `runtime.MatchResult.class`. */
3030
protected def matchResultPattern(parameters: Opt[List[BlockLocalSymbol]]): Ctxl[Pattern.ClassLike] =
3131
val (classRef, classSym) = matchResultClass
3232
val classSel = Term.SynthSel(classRef, Ident("class"))(S(classSym))
33-
Pattern.ClassLike(classSym, classSel, parameters, false)(Empty())
33+
Pattern.ClassLike(classSym, classSel, parameters.map(_.map(S.apply)), false)(Empty())
3434

35-
/** Make a term looks like `globalThis.Predef.MatchFailure` with its symbol. */
35+
/** Make a term that looks like `runtime.MatchFailure` with its symbol. */
3636
protected lazy val matchFailureClass: Ctxl[(Term.Sel | Term.SynthSel, ClassSymbol)] =
3737
(State.runtimeSymbol.ref().selNoSym("MatchFailure", synth=true), State.matchFailureClsSymbol)
3838

39-
/** Make a pattern looks like `globalThis.Predef.MatchFailure.class`. */
39+
/** Make a pattern that looks like `runtime.MatchFailure.class`. */
4040
protected def matchFailurePattern(parameters: Opt[List[BlockLocalSymbol]]): Ctxl[Pattern.ClassLike] =
4141
val (classRef, classSym) = matchResultClass
4242
val classSel = Term.SynthSel(classRef, Ident("class"))(S(classSym))
43-
Pattern.ClassLike(classSym, classSel, parameters, false)(Empty())
43+
Pattern.ClassLike(classSym, classSel, parameters.map(_.map(S.apply)), false)(Empty())
4444

45-
/** Create a term that selects a method in the `Predef` module. */
46-
protected final def selectPredefMethod =
47-
sel(sel(globalThisSymbol.ref(), "Predef"), _: Str)
45+
protected lazy val tupleSlice = sel(sel(state.runtimeSymbol.ref(), "Tuple"), "slice")
46+
protected lazy val tupleGet = sel(sel(state.runtimeSymbol.ref(), "Tuple"), "get")
47+
protected lazy val stringStartsWith = sel(sel(state.runtimeSymbol.ref(), "Str"), "startsWith")
48+
protected lazy val stringGet = sel(sel(state.runtimeSymbol.ref(), "Str"), "get")
49+
protected lazy val stringDrop = sel(sel(state.runtimeSymbol.ref(), "Str"), "drop")
4850

49-
protected lazy val tupleSlice = selectPredefMethod("tupleSlice")
50-
protected lazy val tupleGet = selectPredefMethod("tupleGet")
51-
protected lazy val stringStartsWith = selectPredefMethod("stringStartsWith")
52-
protected lazy val stringGet = selectPredefMethod("stringGet")
53-
protected lazy val stringDrop = selectPredefMethod("stringDrop")
54-
55-
/** Make a term that looks like `tupleGet(t, i)`. */
51+
/** Make a term that looks like `runtime.Tuple.get(t, i)`. */
5652
protected final def callTupleGet(t: Term, i: Int, label: Str): Ctxl[Term] =
5753
callTupleGet(t, i, FlowSymbol(label))
5854

59-
/** Make a term that looks like `tupleGet(t, i)`. */
55+
/** Make a term that looks like `runtime.Tuple.slice(t, i)`. */
6056
protected final def callTupleGet(t: Term, i: Int, s: FlowSymbol): Ctxl[Term] =
6157
app(tupleGet, tup(fld(t), fld(int(i))), s)
6258

63-
/** Make a term that looks like `stringStartsWith(t, p)`. */
64-
protected final def callStringStartsWith(t: Term, p: Term, label: Str): Ctxl[Term] =
59+
/** Make a term that looks like `runtime.Str.startsWith(t, p)`. */
60+
protected final def callStringStartsWith(t: Term.Ref, p: Term, label: Str): Ctxl[Term] =
6561
app(stringStartsWith, tup(fld(t), fld(p)), FlowSymbol(label))
6662

67-
/** Make a term that looks like `stringStartsWith(t, i)`. */
68-
protected final def callStringGet(t: Term, i: Int, label: Str): Ctxl[Term] =
63+
/** Make a term that looks like `runtime.Str.get(t, i)`. */
64+
protected final def callStringGet(t: Term.Ref, i: Int, label: Str): Ctxl[Term] =
6965
app(stringGet, tup(fld(t), fld(int(i))), FlowSymbol(label))
7066

71-
/** Make a term that looks like `stringStartsWith(t, n)`. */
72-
protected final def callStringDrop(t: Term, n: Int, label: Str): Ctxl[Term] =
67+
/** Make a term that looks like `runtime.Str.drop(t, n)`. */
68+
protected final def callStringDrop(t: Term.Ref, n: Int, label: Str): Ctxl[Term] =
7369
app(stringDrop, tup(fld(t), fld(int(n))), FlowSymbol(label))
7470

7571
protected final def tempLet(dbgName: Str, term: Term)(inner: TempSymbol => Split): Split =

hkmc2/shared/src/main/scala/hkmc2/semantics/ucs/Normalization.scala

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ class Normalization(elaborator: Elaborator)(using raise: Raise, ctx: Ctx):
4646
def =:=(rhs: Pattern): Bool = (lhs, rhs) match
4747
case (c1: Pattern.ClassLike, c2: Pattern.ClassLike) => c1.sym === c2.sym
4848
case (Pattern.Lit(l1), Pattern.Lit(l2)) => l1 === l2
49-
case (Pattern.Tuple(n1, b1), Pattern.Tuple(n2, b2)) => n1 == n2 && b1 == b2
49+
case (Pattern.Tuple(n1, b1), Pattern.Tuple(n2, b2)) => n1 === n2 && b1 === b2
5050
case (_, _) => false
5151
/** Checks if `lhs` can be subsumed under `rhs`. */
5252
def <:<(rhs: Pattern): Bool = compareCasePattern(lhs, rhs)
@@ -223,8 +223,9 @@ class Normalization(elaborator: Elaborator)(using raise: Raise, ctx: Ctx):
223223
private def aliasBindings(p: Pattern, q: Pattern): Split => Split = (p, q) match
224224
case (Pattern.ClassLike(_, _, S(ps1), _), Pattern.ClassLike(_, _, S(ps2), _)) =>
225225
ps1.iterator.zip(ps2.iterator).foldLeft(identity[Split]):
226-
case (acc, (p1, p2)) if p1 == p2 => acc
227-
case (acc, (p1, p2)) => innermost => Split.Let(p2, p1.ref(), acc(innermost))
226+
case (acc, (S(p1), S(p2))) if p1 === p2 => acc
227+
case (acc, (S(p1), S(p2))) => innermost => Split.Let(p2, p1.ref(), acc(innermost))
228+
case (acc, (_, _)) => acc
228229
case (_, _) => identity
229230
end Normalization
230231

@@ -240,7 +241,7 @@ object Normalization:
240241
case (ClassLike(cs: ClassSymbol, _, _, _), ClassLike(blt.`Object`, _, _, _))
241242
if !ctx.builtins.virtualClasses.contains(cs) => true
242243
case (ClassLike(cs: ModuleSymbol, _, _, _), ClassLike(blt.`Object`, _, _, _)) => true
243-
case (Tuple(n1, false), Tuple(n2, false)) if n1 == n2 => true
244+
case (Tuple(n1, false), Tuple(n2, false)) if n1 === n2 => true
244245
case (Tuple(n1, _), Tuple(n2, true)) if n2 <= n1 => true
245246
case (ClassLike(`Int`, _, _, _), ClassLike(blt.`Num`, _, _, _)) => true
246247
// case (s1: ClassSymbol, s2: ClassSymbol) => s1 <:< s2 // TODO: find a way to check inheritance

hkmc2/shared/src/test/mlscript-compile/Predef.mjs

Lines changed: 9 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -150,32 +150,24 @@ let Predef1;
150150
static tuple(...xs1) {
151151
return xs1
152152
}
153-
static tupleSlice(xs2, i, j) {
154-
let tmp;
155-
tmp = xs2.length - j;
156-
return runtime.safeCall(globalThis.Array.prototype.slice.call(xs2, i, tmp))
157-
}
158-
static tupleGet(xs3, i1) {
159-
return globalThis.Array.prototype.at.call(xs3, i1)
160-
}
161153
static foldr(f9) {
162154
return (first, ...rest) => {
163-
let len, i2, init, scrut, scrut1, tmp, tmp1, tmp2, tmp3, tmp4, tmp5;
155+
let len, i, init, scrut, scrut1, tmp, tmp1, tmp2, tmp3, tmp4, tmp5;
164156
len = rest.length;
165157
scrut1 = len == 0;
166158
if (scrut1 === true) {
167159
return first
168160
} else {
169161
tmp = len - 1;
170-
i2 = tmp;
171-
tmp1 = runtime.safeCall(rest.at(i2));
162+
i = tmp;
163+
tmp1 = runtime.safeCall(rest.at(i));
172164
init = tmp1;
173165
tmp6: while (true) {
174-
scrut = i2 > 0;
166+
scrut = i > 0;
175167
if (scrut === true) {
176-
tmp2 = i2 - 1;
177-
i2 = tmp2;
178-
tmp3 = runtime.safeCall(rest.at(i2));
168+
tmp2 = i - 1;
169+
i = tmp2;
170+
tmp3 = runtime.safeCall(rest.at(i));
179171
tmp4 = runtime.safeCall(f9(tmp3, init));
180172
init = tmp4;
181173
tmp5 = runtime.Unit;
@@ -189,7 +181,7 @@ let Predef1;
189181
}
190182
}
191183
}
192-
static mkStr(...xs4) {
184+
static mkStr(...xs2) {
193185
let tmp, tmp1, lambda;
194186
lambda = (undefined, function (acc, x7) {
195187
let tmp2, tmp3, tmp4;
@@ -204,16 +196,7 @@ let Predef1;
204196
});
205197
tmp = lambda;
206198
tmp1 = runtime.safeCall(Predef.fold(tmp));
207-
return runtime.safeCall(tmp1(...xs4))
208-
}
209-
static stringStartsWith(string, prefix) {
210-
return runtime.safeCall(string.startsWith(prefix))
211-
}
212-
static stringGet(string1, i2) {
213-
return runtime.safeCall(string1.at(i2))
214-
}
215-
static stringDrop(string2, n) {
216-
return runtime.safeCall(string2.slice(n))
199+
return runtime.safeCall(tmp1(...xs2))
217200
}
218201
static get unreachable() {
219202
throw globalThis.Error("unreachable");

hkmc2/shared/src/test/mlscript-compile/Predef.mls

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -50,15 +50,6 @@ fun (???) notImplementedError = throw Error("Not implemented")
5050

5151
fun tuple(...xs) = xs
5252

53-
fun tupleSlice(xs, i, j) =
54-
// * This is more robust than `xs.slice(i, xs.length - j)`
55-
// * as it is not affected by users redefining `slice`
56-
globalThis.Array.prototype.slice.call(xs, i, xs.length - j)
57-
58-
fun tupleGet(xs, i) =
59-
// * Contrary to `xs.[i]`, this supports negative indices (Python-style)
60-
globalThis.Array.prototype.at.call(xs, i)
61-
6253
val foldl = fold
6354

6455
// fun foldr(f)(...rest, init) = // TODO allow this syntax
@@ -78,13 +69,6 @@ fun mkStr(...xs) =
7869
fold((acc, x) => assert(x is Str); acc + x) of ...xs
7970

8071

81-
fun stringStartsWith(string, prefix) = string.startsWith(prefix)
82-
83-
fun stringGet(string, i) = string.at(i)
84-
85-
fun stringDrop(string, n) = string.slice(n)
86-
87-
8872
fun unreachable = throw Error("unreachable")
8973

9074
fun checkArgs(functionName, expected, isUB, got) =

0 commit comments

Comments
 (0)