Skip to content

Commit

Permalink
Also use template strings in Chez backends
Browse files Browse the repository at this point in the history
  • Loading branch information
b-studios committed Jan 18, 2024
1 parent 6d62aa6 commit c29b50c
Show file tree
Hide file tree
Showing 16 changed files with 167 additions and 168 deletions.
4 changes: 0 additions & 4 deletions effekt/jvm/src/test/scala/effekt/ChezSchemeTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,6 @@ abstract class ChezSchemeTests extends EffektTests {
examplesDir / "pos" / "issue319.effekt",
examplesDir / "pos" / "maps.effekt",

// splices not yet supported in Chez backends
examplesDir / "pos" / "capture" / "resources.effekt" ,
examplesDir / "pos" / "capture" / "ffi_blocks.effekt",

// bidirectional effects are not yet supported in our Chez backend
examplesDir / "pos" / "bidirectional",

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package effekt
package generator
package chez

import effekt.util.intercalate
import kiama.output.ParenPrettyPrinter
import kiama.output.PrettyPrinterTypes.Document

Expand All @@ -23,7 +24,7 @@ object PrettyPrinter extends ParenPrettyPrinter {
def toDoc(expr: Expr): Doc = expr match {
case Call(callee, Nil) => parens(toDoc(callee))
case Call(callee, arguments) => parens(toDoc(callee) <+> group(align(hsep(arguments map toDoc, line))))
case RawExpr(raw) => string(raw)
case RawExpr(strings, args) => hcat(intercalate(strings.map(string), args.map(toDoc)))
case RawValue(raw) => string(raw)
case Let(bindings, body) => parens("let" <+> parens(align(vcat(bindings map toDoc))) <> toDoc(body))
case Let_*(bindings, body) => parens("let*" <+> parens(align(vcat(bindings map toDoc))) <> toDoc(body))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,17 +128,15 @@ trait Transformer {
def toChez(decl: core.Extern): chez.Def = decl match {
case Extern.Def(id, tpe, cps, vps, bps, ret, capt, body) =>
chez.Constant(nameDef(id),
chez.Lambda((vps ++ bps) map { p => ChezName(p.id.name.name) },
chez.Lambda((vps ++ bps) map { p => nameDef(p.id) },
toChez(body)))

case Extern.Include(contents) =>
RawDef(contents)
}

def toChez(t: Template[core.Expr]): chez.Expr = t match {
case Template(List(string), Nil) => chez.RawExpr(string)
case _ => sys error "Splices not yet supported in the Chez backend"
}
def toChez(t: Template[core.Expr]): chez.Expr =
chez.RawExpr(t.strings, t.args.map(e => toChez(e)))

def toChez(defn: Definition): Either[chez.Def, Option[chez.Expr]] = defn match {
case Definition.Def(id, block) =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -200,17 +200,15 @@ object TransformerLift {
chez.Constant(nameDef(id),
chez.Lambda( params.flatMap {
case p: Param.EvidenceParam => None
case p => Some(ChezName(p.id.name.name)) },
case p => Some(nameDef(p.id)) },
toChez(body)))

case Extern.Include(contents) =>
RawDef(contents)
}

def toChez(t: Template[lifted.Expr]): chez.Expr = t match {
case Template(List(string), Nil) => chez.RawExpr(string)
case _ => sys error "Splices not yet supported in the Chez Lift backend"
}
def toChez(t: Template[lifted.Expr]): chez.Expr =
chez.RawExpr(t.strings, t.args.map(e => toChez(e)))

def toChez(defn: Definition): Either[chez.Def, Option[chez.Expr]] = defn match {
case Definition.Def(id, block) =>
Expand Down
9 changes: 6 additions & 3 deletions effekt/shared/src/main/scala/effekt/generator/chez/Tree.scala
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,9 @@ enum Expr {
// e.g. (<EXPR> <EXPR>)
case Call(callee: Expr, arguments: List[Expr])

// e.g. (display "foo")
case RawExpr(raw: String)
// e.g. "" <EXPR> " + " <EXPR>
// raw scheme splices, always start with a prefix string, then interleaved with arguments
case RawExpr(raw: List[String], args: List[Expr])

// e.g. 42 (represented as Scala string "42") and inserted verbatim
case RawValue(raw: String)
Expand Down Expand Up @@ -53,6 +54,8 @@ enum Expr {
}
export Expr.*

def RawExpr(str: String): chez.Expr = Expr.RawExpr(List(str), Nil)

enum Def {
// e.g. (define x 42)
case Constant(name: ChezName, value: Expr)
Expand Down Expand Up @@ -83,7 +86,7 @@ def curry(lam: chez.Lambda): chez.Lambda = lam.params.foldRight[chez.Lambda](che
case (p, body) => chez.Lambda(List(p), body)
}

def unit = chez.Expr.RawExpr("'()")
def unit = chez.Expr.RawValue("'()")

implicit def autoVar(n: ChezName): Expr = Variable(n)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package effekt
package generator
package js

import effekt.util.intercalate
import kiama.output.ParenPrettyPrinter
import kiama.output.PrettyPrinterTypes.Document

Expand Down Expand Up @@ -82,11 +83,6 @@ object PrettyPrinter extends ParenPrettyPrinter {

val emptyline: Doc = line <> line

def intercalate[A](a : List[A], b : List[A]): List[A] = a match {
case first :: rest => first :: intercalate(b, rest)
case _ => b
}

def nested(content: Doc): Doc = group(nest(line <> content))

def nested(docs: List[Doc]): Doc = group(nest(line <> vcat(docs)))
Expand Down
7 changes: 7 additions & 0 deletions effekt/shared/src/main/scala/effekt/util/package.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package effekt
package util

def intercalate[A](a : List[A], b : List[A]): List[A] = a match {
case first :: rest => first :: intercalate(b, rest)
case _ => b
}
80 changes: 40 additions & 40 deletions libraries/chez/callcc/effekt.effekt
Original file line number Diff line number Diff line change
Expand Up @@ -14,76 +14,76 @@ def locally[R] { f: => R }: R = f()
// String ops
// ==========
extern pure def infixConcat(s1: String, s2: String): String =
"(string-append s1 s2)"
"(string-append ${s1} ${s2})"

// TODO implement
extern pure def show[R](value: R): String =
"(show_impl value)"
"(show_impl ${value})"

extern io def println[R](r: R): Unit =
"(println_impl r)"
"(println_impl ${r})"

extern io def error[R](msg: String): R =
"(raise msg)"
"(raise ${msg})"

extern io def random(): Double =
"(random 1.0)"

// Math ops
// ========
extern pure def infixAdd(x: Int, y: Int): Int =
"(+ x y)"
"(+ ${x} ${y})"

extern pure def infixMul(x: Int, y: Int): Int =
"(* x y)"
"(* ${x} ${y})"

extern pure def infixDiv(x: Int, y: Int): Int =
"(floor (/ x y))"
"(floor (/ ${x} ${y}))"

extern pure def infixSub(x: Int, y: Int): Int =
"(- x y)"
"(- ${x} ${y})"

extern pure def mod(x: Int, y: Int): Int =
"(modulo x y)"
"(modulo ${x} ${y})"

extern pure def infixAdd(x: Double, y: Double): Double =
"(+ x y)"
"(+ ${x} ${y})"

extern pure def infixMul(x: Double, y: Double): Double =
"(* x y)"
"(* ${x} ${y})"

extern pure def infixDiv(x: Double, y: Double): Double =
"(/ x y)"
"(/ ${x} ${y})"

extern pure def infixSub(x: Double, y: Double): Double =
"(- x y)"
"(- ${x} ${y})"

extern pure def cos(x: Double): Double =
"(cos x)"
"(cos ${x})"

extern pure def sin(x: Double): Double =
"(sin x)"
"(sin ${x})"

extern pure def atan(x: Double): Double =
"(atan x)"
"(atan ${x})"

extern pure def tan(x: Double): Double =
"(tan x)"
"(tan ${x})"

extern pure def sqrt(x: Double): Double =
"(sqrt x)"
"(sqrt ${x})"

extern pure def square(x: Double): Double =
"(* x x)"
"(* ${x} ${x})"

extern pure def log(x: Double): Double =
"(log x)"
"(log ${x})"

extern pure def log1p(x: Double): Double =
"(log (+ x 1))"
"(log (+ ${x} 1))"

extern pure def exp(x: Double): Double =
"(exp x)"
"(exp ${x})"

// since we do not have "extern val", yet
extern pure def _pi(): Double =
Expand All @@ -92,10 +92,10 @@ extern pure def _pi(): Double =
val PI: Double = _pi()

extern pure def toInt(d: Double): Int =
"(round d)"
"(round ${d})"

extern pure def toDouble(d: Int): Double =
"d"
"${d}"

def min(n: Int, m: Int): Int =
if (n < m) n else m
Expand All @@ -106,50 +106,50 @@ def max(n: Int, m: Int): Int =
// Comparison ops
// ==============
extern pure def infixEq[R](x: R, y: R): Boolean =
"(equal_impl x y)"
"(equal_impl ${x} ${y})"

extern pure def infixNeq[R](x: R, y: R): Boolean =
"(not (equal_impl x y))"
"(not (equal_impl ${x} ${y}))"

extern pure def infixLt(x: Int, y: Int): Boolean =
"(< x y)"
"(< ${x} ${y})"

extern pure def infixLte(x: Int, y: Int): Boolean =
"(<= x y)"
"(<= ${x} ${y})"

extern pure def infixGt(x: Int, y: Int): Boolean =
"(> x y)"
"(> ${x} ${y})"

extern pure def infixGte(x: Int, y: Int): Boolean =
"(>= x y)"
"(>= ${x} ${y})"

extern pure def infixLt(x: Double, y: Double): Boolean =
"(< x y)"
"(< ${x} ${y})"

extern pure def infixLte(x: Double, y: Double): Boolean =
"(<= x y)"
"(<= ${x} ${y})"

extern pure def infixGt(x: Double, y: Double): Boolean =
"(> x y)"
"(> ${x} ${y})"

extern pure def infixGte(x: Double, y: Double): Boolean =
"(>= x y)"
"(>= ${x} ${y})"

// Boolean ops
// ===========
// for now those are considered eager
extern pure def not(b: Boolean): Boolean =
"(not b)"
"(not ${b})"

extern pure def infixOr(x: Boolean, y: Boolean): Boolean =
"(or x y)"
"(or ${x} ${y})"

extern pure def infixAnd(x: Boolean, y: Boolean): Boolean =
"(and x y)"
"(and ${x} ${y})"

// Should only be used internally since values in Effekt should not be undefined
extern pure def isUndefined[A](value: A): Boolean =
"(eq? value #f)"
"(eq? ${value} #f)"

// Pairs
// =====
Expand All @@ -163,7 +163,7 @@ record Tuple6[A, B, C, D, E, F](first: A, second: B, third: C, fourth: D, fifth:
// ==========
// a fatal runtime error that cannot be caught
extern io def panic[R](msg: String): R =
"(raise msg)"
"(raise ${msg})"

effect Exception[E] {
def raise[A](exception: E, msg: String): A
Expand Down Expand Up @@ -218,4 +218,4 @@ def repeat(n: Int) { action: () => Unit / Control } = each(0, n) { n => action()
// ============
// should only be used with pure blocks
extern control def measure(warmup: Int, iterations: Int) { block: => Unit }: Unit =
"(display (measure block warmup iterations))"
"(display (measure ${box block} ${warmup} ${iterations}))"
8 changes: 4 additions & 4 deletions libraries/chez/common/immutable/cslist.effekt
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,21 @@ import immutable/list
// a chez scheme cons list
extern type CSList[A]
extern pure def cons[A](el: A, rest: CSList[A]): CSList[A] =
"(cons el rest)"
"(cons ${el} ${rest})"

extern pure def nil[A](): CSList[A] =
"(list)"

extern pure def isEmpty[A](l: CSList[A]): Boolean =
"(null? l)"
"(null? ${l})"

// unsafe!
extern pure def head[A](l: CSList[A]): A =
"(car l)"
"(car ${l})"

// unsafe!
extern pure def tail[A](l: CSList[A]): CSList[A] =
"(cdr l)"
"(cdr ${l})"


def toChez[A](l: List[A]): CSList[A] = l match {
Expand Down
10 changes: 5 additions & 5 deletions libraries/chez/common/mutable/array.effekt
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,21 @@ import immutable/cslist
extern type Array[T]

extern pure def emptyArray[T](size: Int): Array[T] =
"(make-vector size)"
"(make-vector ${size})"

def get[T](arr: Array[T], index: Int): Option[T] =
if (index >= arr.size) None() else Some(arr.unsafeGet(index))

extern pure def size[T](arr: Array[T]): Int =
"(vector-length arr)"
"(vector-length ${arr})"

// raises a scheme exception if out of bounds
extern pure def unsafeGet[T](arr: Array[T], index: Int): T =
"(vector-ref arr index)"
"(vector-ref ${arr} ${index})"

// TODO raises a scheme exception if out of bounds
extern io def put[T](arr: Array[T], index: Int, value: T): Unit =
"(begin (vector-set! arr index value) #f)"
"(begin (vector-set! ${arr} ${index} ${value}) #f)"

extern pure def toArray[A](l: CSList[A]): Array[A] =
"(list->vector l)"
"(list->vector ${l})"
Loading

0 comments on commit c29b50c

Please sign in to comment.