Skip to content

Commit

Permalink
define tuples up to 32 (#1078)
Browse files Browse the repository at this point in the history
* Get core tests compiling

* fix python partiton/rpartition

* Fix TypeTest

* raise test coverage
  • Loading branch information
johnynek authored Dec 8, 2023
1 parent 52d452f commit 695d677
Show file tree
Hide file tree
Showing 12 changed files with 296 additions and 104 deletions.
72 changes: 67 additions & 5 deletions core/src/main/resources/bosatsu/predef.bosatsu
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,38 @@ export (
List(),
String,
Test(),
TupleCons(),
Tuple1(),
Tuple2(),
Tuple3(),
Tuple4(),
Tuple5(),
Tuple6(),
Tuple7(),
Tuple8(),
Tuple9(),
Tuple10(),
Tuple11(),
Tuple12(),
Tuple13(),
Tuple14(),
Tuple15(),
Tuple16(),
Tuple17(),
Tuple18(),
Tuple19(),
Tuple20(),
Tuple21(),
Tuple22(),
Tuple23(),
Tuple24(),
Tuple25(),
Tuple26(),
Tuple27(),
Tuple28(),
Tuple29(),
Tuple30(),
Tuple31(),
Tuple32(),
Order(),
Unit(),
Dict,
Expand Down Expand Up @@ -49,7 +80,38 @@ export (
)

struct Unit
struct TupleCons(first, second)
struct Tuple1[a: +*](item1: a)
struct Tuple2[a: +*, b: +*](item1: a, item2: b)
struct Tuple3[a: +*, b: +*, c: +*](item1: a, item2: b, item3: c)
struct Tuple4[a: +*, b: +*, c: +*, d: +*](item1: a, item2: b, item3: c, item4: d)
struct Tuple5[a: +*, b: +*, c: +*, d: +*, e: +*](item1: a, item2: b, item3: c, item4: d, item5: e)
struct Tuple6[a: +*, b: +*, c: +*, d: +*, e: +*, f: +*](item1: a, item2: b, item3: c, item4: d, item5: e, item6: f)
struct Tuple7[a: +*, b: +*, c: +*, d: +*, e: +*, f: +*, g: +*](item1: a, item2: b, item3: c, item4: d, item5: e, item6: f, item7: g)
struct Tuple8[a: +*, b: +*, c: +*, d: +*, e: +*, f: +*, g: +*, h: +*](item1: a, item2: b, item3: c, item4: d, item5: e, item6: f, item7: g, item8: h)
struct Tuple9[a: +*, b: +*, c: +*, d: +*, e: +*, f: +*, g: +*, h: +*, i: +*](item1: a, item2: b, item3: c, item4: d, item5: e, item6: f, item7: g, item8: h, item9: i)
struct Tuple10[a: +*, b: +*, c: +*, d: +*, e: +*, f: +*, g: +*, h: +*, i: +*, j: +*](item1: a, item2: b, item3: c, item4: d, item5: e, item6: f, item7: g, item8: h, item9: i, item10: j)
struct Tuple11[a: +*, b: +*, c: +*, d: +*, e: +*, f: +*, g: +*, h: +*, i: +*, j: +*, k: +*](item1: a, item2: b, item3: c, item4: d, item5: e, item6: f, item7: g, item8: h, item9: i, item10: j, item11: k)
struct Tuple12[a: +*, b: +*, c: +*, d: +*, e: +*, f: +*, g: +*, h: +*, i: +*, j: +*, k: +*, l: +*](item1: a, item2: b, item3: c, item4: d, item5: e, item6: f, item7: g, item8: h, item9: i, item10: j, item11: k, item12: l)
struct Tuple13[a: +*, b: +*, c: +*, d: +*, e: +*, f: +*, g: +*, h: +*, i: +*, j: +*, k: +*, l: +*, m: +*](item1: a, item2: b, item3: c, item4: d, item5: e, item6: f, item7: g, item8: h, item9: i, item10: j, item11: k, item12: l, item13: m)
struct Tuple14[a: +*, b: +*, c: +*, d: +*, e: +*, f: +*, g: +*, h: +*, i: +*, j: +*, k: +*, l: +*, m: +*, n: +*](item1: a, item2: b, item3: c, item4: d, item5: e, item6: f, item7: g, item8: h, item9: i, item10: j, item11: k, item12: l, item13: m, item14: n)
struct Tuple15[a: +*, b: +*, c: +*, d: +*, e: +*, f: +*, g: +*, h: +*, i: +*, j: +*, k: +*, l: +*, m: +*, n: +*, o: +*](item1: a, item2: b, item3: c, item4: d, item5: e, item6: f, item7: g, item8: h, item9: i, item10: j, item11: k, item12: l, item13: m, item14: n, item15: o)
struct Tuple16[a: +*, b: +*, c: +*, d: +*, e: +*, f: +*, g: +*, h: +*, i: +*, j: +*, k: +*, l: +*, m: +*, n: +*, o: +*, p: +*](item1: a, item2: b, item3: c, item4: d, item5: e, item6: f, item7: g, item8: h, item9: i, item10: j, item11: k, item12: l, item13: m, item14: n, item15: o, item16: p)
struct Tuple17[a: +*, b: +*, c: +*, d: +*, e: +*, f: +*, g: +*, h: +*, i: +*, j: +*, k: +*, l: +*, m: +*, n: +*, o: +*, p: +*, q: +*](item1: a, item2: b, item3: c, item4: d, item5: e, item6: f, item7: g, item8: h, item9: i, item10: j, item11: k, item12: l, item13: m, item14: n, item15: o, item16: p, item17: q)
struct Tuple18[a: +*, b: +*, c: +*, d: +*, e: +*, f: +*, g: +*, h: +*, i: +*, j: +*, k: +*, l: +*, m: +*, n: +*, o: +*, p: +*, q: +*, r: +*](item1: a, item2: b, item3: c, item4: d, item5: e, item6: f, item7: g, item8: h, item9: i, item10: j, item11: k, item12: l, item13: m, item14: n, item15: o, item16: p, item17: q, item18: r)
struct Tuple19[a: +*, b: +*, c: +*, d: +*, e: +*, f: +*, g: +*, h: +*, i: +*, j: +*, k: +*, l: +*, m: +*, n: +*, o: +*, p: +*, q: +*, r: +*, s: +*](item1: a, item2: b, item3: c, item4: d, item5: e, item6: f, item7: g, item8: h, item9: i, item10: j, item11: k, item12: l, item13: m, item14: n, item15: o, item16: p, item17: q, item18: r, item19: s)
struct Tuple20[a: +*, b: +*, c: +*, d: +*, e: +*, f: +*, g: +*, h: +*, i: +*, j: +*, k: +*, l: +*, m: +*, n: +*, o: +*, p: +*, q: +*, r: +*, s: +*, t: +*](item1: a, item2: b, item3: c, item4: d, item5: e, item6: f, item7: g, item8: h, item9: i, item10: j, item11: k, item12: l, item13: m, item14: n, item15: o, item16: p, item17: q, item18: r, item19: s, item20: t)
struct Tuple21[a: +*, b: +*, c: +*, d: +*, e: +*, f: +*, g: +*, h: +*, i: +*, j: +*, k: +*, l: +*, m: +*, n: +*, o: +*, p: +*, q: +*, r: +*, s: +*, t: +*, u: +*](item1: a, item2: b, item3: c, item4: d, item5: e, item6: f, item7: g, item8: h, item9: i, item10: j, item11: k, item12: l, item13: m, item14: n, item15: o, item16: p, item17: q, item18: r, item19: s, item20: t, item21: u)
struct Tuple22[a: +*, b: +*, c: +*, d: +*, e: +*, f: +*, g: +*, h: +*, i: +*, j: +*, k: +*, l: +*, m: +*, n: +*, o: +*, p: +*, q: +*, r: +*, s: +*, t: +*, u: +*, v: +*](item1: a, item2: b, item3: c, item4: d, item5: e, item6: f, item7: g, item8: h, item9: i, item10: j, item11: k, item12: l, item13: m, item14: n, item15: o, item16: p, item17: q, item18: r, item19: s, item20: t, item21: u, item22: v)
struct Tuple23[a: +*, b: +*, c: +*, d: +*, e: +*, f: +*, g: +*, h: +*, i: +*, j: +*, k: +*, l: +*, m: +*, n: +*, o: +*, p: +*, q: +*, r: +*, s: +*, t: +*, u: +*, v: +*, w: +*](item1: a, item2: b, item3: c, item4: d, item5: e, item6: f, item7: g, item8: h, item9: i, item10: j, item11: k, item12: l, item13: m, item14: n, item15: o, item16: p, item17: q, item18: r, item19: s, item20: t, item21: u, item22: v, item23: w)
struct Tuple24[a: +*, b: +*, c: +*, d: +*, e: +*, f: +*, g: +*, h: +*, i: +*, j: +*, k: +*, l: +*, m: +*, n: +*, o: +*, p: +*, q: +*, r: +*, s: +*, t: +*, u: +*, v: +*, w: +*, x: +*](item1: a, item2: b, item3: c, item4: d, item5: e, item6: f, item7: g, item8: h, item9: i, item10: j, item11: k, item12: l, item13: m, item14: n, item15: o, item16: p, item17: q, item18: r, item19: s, item20: t, item21: u, item22: v, item23: w, item24: x)
struct Tuple25[a: +*, b: +*, c: +*, d: +*, e: +*, f: +*, g: +*, h: +*, i: +*, j: +*, k: +*, l: +*, m: +*, n: +*, o: +*, p: +*, q: +*, r: +*, s: +*, t: +*, u: +*, v: +*, w: +*, x: +*, y: +*](item1: a, item2: b, item3: c, item4: d, item5: e, item6: f, item7: g, item8: h, item9: i, item10: j, item11: k, item12: l, item13: m, item14: n, item15: o, item16: p, item17: q, item18: r, item19: s, item20: t, item21: u, item22: v, item23: w, item24: x, item25: y)
struct Tuple26[a: +*, b: +*, c: +*, d: +*, e: +*, f: +*, g: +*, h: +*, i: +*, j: +*, k: +*, l: +*, m: +*, n: +*, o: +*, p: +*, q: +*, r: +*, s: +*, t: +*, u: +*, v: +*, w: +*, x: +*, y: +*, z: +*](item1: a, item2: b, item3: c, item4: d, item5: e, item6: f, item7: g, item8: h, item9: i, item10: j, item11: k, item12: l, item13: m, item14: n, item15: o, item16: p, item17: q, item18: r, item19: s, item20: t, item21: u, item22: v, item23: w, item24: x, item25: y, item26: z)
struct Tuple27[a: +*, b: +*, c: +*, d: +*, e: +*, f: +*, g: +*, h: +*, i: +*, j: +*, k: +*, l: +*, m: +*, n: +*, o: +*, p: +*, q: +*, r: +*, s: +*, t: +*, u: +*, v: +*, w: +*, x: +*, y: +*, z: +*, a0: +*](item1: a, item2: b, item3: c, item4: d, item5: e, item6: f, item7: g, item8: h, item9: i, item10: j, item11: k, item12: l, item13: m, item14: n, item15: o, item16: p, item17: q, item18: r, item19: s, item20: t, item21: u, item22: v, item23: w, item24: x, item25: y, item26: z, item27: a0)
struct Tuple28[a: +*, b: +*, c: +*, d: +*, e: +*, f: +*, g: +*, h: +*, i: +*, j: +*, k: +*, l: +*, m: +*, n: +*, o: +*, p: +*, q: +*, r: +*, s: +*, t: +*, u: +*, v: +*, w: +*, x: +*, y: +*, z: +*, a0: +*, b0: +*](item1: a, item2: b, item3: c, item4: d, item5: e, item6: f, item7: g, item8: h, item9: i, item10: j, item11: k, item12: l, item13: m, item14: n, item15: o, item16: p, item17: q, item18: r, item19: s, item20: t, item21: u, item22: v, item23: w, item24: x, item25: y, item26: z, item27: a0, item28: b0)
struct Tuple29[a: +*, b: +*, c: +*, d: +*, e: +*, f: +*, g: +*, h: +*, i: +*, j: +*, k: +*, l: +*, m: +*, n: +*, o: +*, p: +*, q: +*, r: +*, s: +*, t: +*, u: +*, v: +*, w: +*, x: +*, y: +*, z: +*, a0: +*, b0: +*, c0: +*](item1: a, item2: b, item3: c, item4: d, item5: e, item6: f, item7: g, item8: h, item9: i, item10: j, item11: k, item12: l, item13: m, item14: n, item15: o, item16: p, item17: q, item18: r, item19: s, item20: t, item21: u, item22: v, item23: w, item24: x, item25: y, item26: z, item27: a0, item28: b0, item29: c0)
struct Tuple30[a: +*, b: +*, c: +*, d: +*, e: +*, f: +*, g: +*, h: +*, i: +*, j: +*, k: +*, l: +*, m: +*, n: +*, o: +*, p: +*, q: +*, r: +*, s: +*, t: +*, u: +*, v: +*, w: +*, x: +*, y: +*, z: +*, a0: +*, b0: +*, c0: +*, d0: +*](item1: a, item2: b, item3: c, item4: d, item5: e, item6: f, item7: g, item8: h, item9: i, item10: j, item11: k, item12: l, item13: m, item14: n, item15: o, item16: p, item17: q, item18: r, item19: s, item20: t, item21: u, item22: v, item23: w, item24: x, item25: y, item26: z, item27: a0, item28: b0, item29: c0, item30: d0)
struct Tuple31[a: +*, b: +*, c: +*, d: +*, e: +*, f: +*, g: +*, h: +*, i: +*, j: +*, k: +*, l: +*, m: +*, n: +*, o: +*, p: +*, q: +*, r: +*, s: +*, t: +*, u: +*, v: +*, w: +*, x: +*, y: +*, z: +*, a0: +*, b0: +*, c0: +*, d0: +*, e0: +*](item1: a, item2: b, item3: c, item4: d, item5: e, item6: f, item7: g, item8: h, item9: i, item10: j, item11: k, item12: l, item13: m, item14: n, item15: o, item16: p, item17: q, item18: r, item19: s, item20: t, item21: u, item22: v, item23: w, item24: x, item25: y, item26: z, item27: a0, item28: b0, item29: c0, item30: d0, item31: e0)
struct Tuple32[a: +*, b: +*, c: +*, d: +*, e: +*, f: +*, g: +*, h: +*, i: +*, j: +*, k: +*, l: +*, m: +*, n: +*, o: +*, p: +*, q: +*, r: +*, s: +*, t: +*, u: +*, v: +*, w: +*, x: +*, y: +*, z: +*, a0: +*, b0: +*, c0: +*, d0: +*, e0: +*, f0: +*](item1: a, item2: b, item3: c, item4: d, item5: e, item6: f, item7: g, item8: h, item9: i, item10: j, item11: k, item12: l, item13: m, item14: n, item15: o, item16: p, item17: q, item18: r, item19: s, item20: t, item21: u, item22: v, item23: w, item24: x, item25: y, item26: z, item27: a0, item28: b0, item29: c0, item30: d0, item31: e0, item32: f0)

enum Bool:
False, True
Expand Down Expand Up @@ -138,13 +200,13 @@ external def mod_Int(a: Int, mod: Int) -> Int
external def int_loop(intValue: Int, state: a, fn: (Int, a) -> (Int, a)) -> a

def range(exclusiveUpper: Int) -> List[Int]:
int_loop(exclusiveUpper, [], \i, tail ->
int_loop(exclusiveUpper, [], (i, tail) ->
inext = i.sub(1)
(inext, [inext, *tail]))

def range_fold(inclusiveLower: Int, exclusiveUpper: Int, init: a, fn: (a, Int) -> a) -> a:
diff = exclusiveUpper.sub(inclusiveLower)
int_loop(diff, init, \diff0, a ->
int_loop(diff, init, (diff0, a) ->
idx = exclusiveUpper.sub(diff0)
a1 = fn(a, idx)
(diff0.sub(1), a1))
Expand Down Expand Up @@ -337,7 +399,7 @@ struct Dict[k, v: +*](order: forall a. Order[(k, a)], tree: Tree[(k, v)])

def empty_Dict(comp: Order[k]) -> forall v. Dict[k, v]:
Order(fn) = comp
pair_ord = Order(\(k1, _), (k2, _) -> fn(k1, k2))
pair_ord = Order(((k1, _), (k2, _)) -> fn(k1, k2))
Dict(pair_ord, Empty)

def add_key(dict: Dict[k, v], key: k, value: v) -> Dict[k, v]:
Expand Down
6 changes: 5 additions & 1 deletion core/src/main/scala/org/bykn/bosatsu/PackageMap.scala
Original file line number Diff line number Diff line change
Expand Up @@ -405,7 +405,11 @@ object PackageMap {
case Some(inf) => inf
}
case Validated.Invalid(errs) =>
sys.error(s"expected no errors, found: $errs")
val map = Map(PackageName.PredefName -> (LocationMap(Predef.predefString), "<predef>"))
errs.iterator.foreach { err =>
println(err.message(map, LocationMap.Colorize.None))
}
sys.error("expected no errors")
}
}

Expand Down
4 changes: 2 additions & 2 deletions core/src/main/scala/org/bykn/bosatsu/Predef.scala
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ object PredefImpl {
def gcd_Int(a: Value, b: Value): Value =
VInt(gcdBigInteger(i(a), i(b)))

//def intLoop(intValue: Int, state: a, fn: Int -> a -> TupleCons[Int, TupleCons[a, Unit]]) -> a
//def intLoop(intValue: Int, state: a, fn: Int -> a -> Tuple2[Int, a]) -> a
final def intLoop(intValue: Value, state: Value, fn: Value): Value = {
val fnT = fn.asFn

Expand All @@ -125,7 +125,7 @@ object PredefImpl {
if (bi.compareTo(BigInteger.ZERO) <= 0) state
else {
fnT(NonEmptyList(biValue, state :: Nil)) match {
case ConsValue(nextI, ConsValue(ConsValue(nextA, _), _)) =>
case ConsValue(nextI, ConsValue(nextA, _)) =>
val n = i(nextI)
if (n.compareTo(bi) >= 0) {
// we are done in this case
Expand Down
104 changes: 73 additions & 31 deletions core/src/main/scala/org/bykn/bosatsu/SourceConverter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,71 @@ final class SourceConverter(
}
}


private val unitName = Identifier.Constructor("Unit")
// this is lazy so it isn't initialized before Type
private lazy val tup: Array[Declaration => Expr[Declaration]] =
(Iterator.single(
{ (tc: Declaration) =>
Expr.Global(PackageName.PredefName, unitName, tc)
}
) ++ (1 to Type.FnType.MaxSize)
.iterator
.map { idx =>
val tup = Type.Tuple.Arity(idx)
val defined = tup.tpe.toDefined
val pn = defined.packageName
val cn = defined.name.ident

{ (tc: Declaration) => Expr.Global(pn, cn, tc) }
}).toArray

private def makeTuple(tc: Declaration, args: List[Declaration])(conv: Declaration => Result[Expr[Declaration]]): Result[Expr[Declaration]] =
args.traverse(conv)
.flatMap { exps =>
val size = exps.length
if (size <= Type.FnType.MaxSize) {
val fn = tup(size)(tc)
val res = Expr.buildApp(fn, exps, tc)
success(res)
}
else {
SourceConverter.failure(
SourceConverter.TooManyConstructorArgs(
Type.Tuple.Arity(32).tpe.toDefined.name.ident,
size, 32, tc.region)
)
}
}

private val unitPat =
success(Pattern.PositionalStruct(
(PackageName.PredefName, unitName),
Nil))

def makeTuplePattern[A](args: List[Pattern[(PackageName, Constructor), A]], region: Region): Result[Pattern[(PackageName, Constructor), A]] =
args match {
case Nil => unitPat
case nonEmpty =>
val size = nonEmpty.size
val tupleCons = Type.Tuple.Arity(size)
val defined = tupleCons.tpe.toDefined
val pat = Pattern.PositionalStruct(
(defined.packageName, defined.name.ident),
nonEmpty)
if (size <= Type.FnType.MaxSize) {
success(pat)
}
else {
SourceConverter.partial(
SourceConverter.TooManyConstructorArgs(
Type.Tuple.Arity(32).tpe.toDefined.name.ident,
size, 32, region),
pat
)
}
}

private def fromDecl(decl: Declaration, bound: Set[Bindable], topBound: Set[Bindable]): Result[Expr[Declaration]] = {
implicit val parAp = SourceConverter.parallelIor
def loop(decl: Declaration) = fromDecl(decl, bound, topBound)
Expand Down Expand Up @@ -292,21 +357,7 @@ final class SourceConverter(
val branches = NonEmptyList((p, True), (Pattern.WildCard, False) :: Nil)
Expr.Match(a, branches, m)
}
case tc@TupleCons(its) =>
val tup0: Expr[Declaration] = Expr.Global(PackageName.PredefName, Identifier.Constructor("Unit"), tc)
val tup2: Expr[Declaration] = Expr.Global(PackageName.PredefName, Identifier.Constructor("TupleCons"), tc)
def tup(args: List[Declaration]): Result[Expr[Declaration]] =
args match {
case Nil => success(tup0)
case h :: tail =>
val tailExp = tup(tail)
val headExp = loop(h)
(headExp, tailExp).mapN { (h, t) =>
Expr.buildApp(tup2, h :: t :: Nil, tc)
}
}

tup(its)
case tc@TupleCons(its) => makeTuple(tc, its)(loop)
case s@StringDecl(parts) =>
// a single string item should be converted
// to that thing,
Expand Down Expand Up @@ -773,21 +824,7 @@ final class SourceConverter(
pat.traversePattern[Result, (PackageName, Constructor), rankn.Type]({
case (Pattern.StructKind.Tuple, args) =>
// this is a tuple pattern
def loop[A](args: List[Pattern[(PackageName, Constructor), A]]): Pattern[(PackageName, Constructor), A] =
args match {
case Nil =>
// ()
Pattern.PositionalStruct(
(PackageName.PredefName, Constructor("Unit")),
Nil)
case h :: tail =>
val tailP = loop(tail)
Pattern.PositionalStruct(
(PackageName.PredefName, Constructor("TupleCons")),
h :: tailP :: Nil)
}

args.map(loop(_))
args.flatMap(makeTuplePattern(_, region))
case (Pattern.StructKind.Named(nm, Pattern.StructKind.Style.TupleLike), rargs) =>
rargs.flatMap { args =>
val pc@(p, c) = nameToCons(nm)
Expand Down Expand Up @@ -1542,6 +1579,11 @@ object SourceConverter {

final case class TooManyConstructorArgs(name: Constructor, argCount: Int, max: Int, region: Region) extends Error {
def message =
Doc.text(s"invalid argument count in constructor for ${name.asString} found $argCount maximum allowed $max").render(80)
if (name.asString == "Tuple32") {
Doc.text(s"invalid tuple size. Found $argCount, but maximum allowed ${Type.FnType.MaxSize}").render(80)
}
else {
Doc.text(s"invalid argument count in constructor for ${name.asString} found $argCount maximum allowed $max").render(80)
}
}
}
24 changes: 2 additions & 22 deletions core/src/main/scala/org/bykn/bosatsu/Value.scala
Original file line number Diff line number Diff line change
Expand Up @@ -137,37 +137,17 @@ object Value {
val False: SumValue = SumValue(0, UnitValue)
val True: SumValue = SumValue(1, UnitValue)

object TupleCons {
def unapply(v: Value): Option[(Value, Value)] =
v match {
case ConsValue(a, ConsValue(b, UnitValue)) => Some((a, b))
case _ => None
}

def apply(a: Value, b: Value): ProductValue =
ConsValue(a, ConsValue(b, UnitValue))
}

object Tuple {
/**
* Tuples are encoded as:
* (1, 2, 3) => TupleCons(1, TupleCons(2, TupleCons(3, ())))
* since a Tuple(a, b) is encoded as
* ConsValue(a, ConsValue(b, UnitValue))
* this gives double wrapping
*/
def unapply(v: Value): Option[List[Value]] =
v match {
case TupleCons(a, b) =>
unapply(b).map(a :: _)
case UnitValue => Some(Nil)
case p: ProductValue => Some(p.toList)
case _ => None
}

def fromList(vs: List[Value]): ProductValue =
vs match {
case Nil => UnitValue
case h :: tail => TupleCons(h, fromList(tail))
case h :: tail => ConsValue(h, fromList(tail))
}

def apply(vs: Value*): ProductValue =
Expand Down
Loading

0 comments on commit 695d677

Please sign in to comment.