Skip to content

Commit

Permalink
Merge branch 'master' into refactor/replace-environments-by-substitution
Browse files Browse the repository at this point in the history
  • Loading branch information
b-studios committed Jan 22, 2025
2 parents a9f2583 + 864bd99 commit 19042d4
Show file tree
Hide file tree
Showing 33 changed files with 443 additions and 114 deletions.
8 changes: 3 additions & 5 deletions effekt/js/src/main/scala/effekt/context/VirtualModuleDB.scala
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,9 @@ trait VirtualModuleDB extends ModuleDB { self: Context =>
* used by Namer to resolve FFI includes
*/
override def contentsOf(path: String): Option[String] = {
val f = file(module.source.name).parent / path
if (!f.exists) {
None
} else {
Some(f.read)
val parent = file(module.source.name).parent
(parent :: config.includes().map(file)).collectFirst {
case base if (base / path).exists => (base / path).read
}
}

Expand Down
8 changes: 3 additions & 5 deletions effekt/jvm/src/main/scala/effekt/context/IOModuleDB.scala
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,9 @@ trait IOModuleDB extends ModuleDB { self: Context =>
* used by Namer to resolve FFI includes
*/
override def contentsOf(path: String): Option[String] = {
val includeFile = file(module.source.name).parent / path
if (!includeFile.exists) {
None
} else {
Some(FileSource(includeFile.toString).content)
val parent = file(module.source.name).parent
(parent :: config.includes().map(file)).collectFirst {
case base if (base / path).exists => FileSource((base / path).toString).content
}
}

Expand Down
3 changes: 3 additions & 0 deletions effekt/jvm/src/test/scala/effekt/RecursiveDescentTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,9 @@ class RecursiveDescentTests extends munit.FunSuite {
)
parseExpr("box { (x: Int) => x }")
parseExpr("box new Fresh { def fresh() = \"42\" }")
parseExpr("box foo()")
parseExpr("box bar(1)")
parseExpr("box baz(quux)")

// { f } is parsed as a capture set and not backtracked.
intercept[Throwable] { parseExpr("box { f }") }
Expand Down
3 changes: 0 additions & 3 deletions effekt/jvm/src/test/scala/effekt/StdlibTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,6 @@ class StdlibLLVMTests extends StdlibTests {
override def debug = sys.env.get("EFFEKT_DEBUG").nonEmpty

override def ignored: List[File] = List(
// segfaults
examplesDir / "stdlib" / "stream" / "fuse_newlines.effekt",

// Syscall param write(buf) points to uninitialised byte(s)
examplesDir / "stdlib" / "io" / "filesystem" / "files.effekt",
examplesDir / "stdlib" / "io" / "filesystem" / "async_file_io.effekt",
Expand Down
119 changes: 116 additions & 3 deletions effekt/jvm/src/test/scala/effekt/core/VMTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -674,6 +674,54 @@ class VMTests extends munit.FunSuite {
resumes = 7
)),

examplesDir / "casestudies" / "lexer.effekt.md" -> Some(Summary(
staticDispatches = 245,
dynamicDispatches = 18,
patternMatches = 298,
branches = 405,
pushedFrames = 703,
poppedFrames = 703,
allocations = 202,
closures = 27,
variableReads = 164,
variableWrites = 51,
resets = 31,
shifts = 11,
resumes = 11
)),

examplesDir / "casestudies" / "parser.effekt.md" -> Some(Summary(
staticDispatches = 8845,
dynamicDispatches = 783,
patternMatches = 13502,
branches = 14892,
pushedFrames = 28523,
poppedFrames = 28499,
allocations = 7923,
closures = 521,
variableReads = 6742,
variableWrites = 1901,
resets = 806,
shifts = 855,
resumes = 839
)),

examplesDir / "casestudies" / "anf.effekt.md" -> Some(Summary(
staticDispatches = 4775,
dynamicDispatches = 443,
patternMatches = 7272,
branches = 8110,
pushedFrames = 16275,
poppedFrames = 16260,
allocations = 4317,
closures = 358,
variableReads = 4080,
variableWrites = 1343,
resets = 481,
shifts = 660,
resumes = 644
)),

examplesDir / "casestudies" / "inference.effekt.md" -> Some(Summary(
staticDispatches = 1457444,
dynamicDispatches = 3201452,
Expand All @@ -689,13 +737,80 @@ class VMTests extends munit.FunSuite {
shifts = 297723,
resumes = 9275
)),

examplesDir / "pos" / "raytracer.effekt" -> Some(Summary(
staticDispatches = 79696,
dynamicDispatches = 0,
patternMatches = 1014772,
branches = 71995,
pushedFrames = 223269,
poppedFrames = 223269,
allocations = 127533,
closures = 0,
variableReads = 77886,
variableWrites = 26904,
resets = 0,
shifts = 0,
resumes = 0
)),
)

val other: Seq[(File, Option[Summary])] = Seq(
examplesDir / "benchmarks" / "other" / "emit.effekt" -> Some(Summary(
staticDispatches = 11,
dynamicDispatches = 0,
patternMatches = 0,
branches = 11,
pushedFrames = 102,
poppedFrames = 102,
allocations = 0,
closures = 0,
variableReads = 61,
variableWrites = 30,
resets = 1,
shifts = 10,
resumes = 10
)),

examplesDir / "benchmarks" / "other" / "church_exponentiation.effekt" -> Some(Summary(
staticDispatches = 7,
dynamicDispatches = 1062912,
patternMatches = 0,
branches = 5,
pushedFrames = 531467,
poppedFrames = 531467,
allocations = 0,
closures = 265750,
variableReads = 0,
variableWrites = 0,
resets = 0,
shifts = 0,
resumes = 0
)),

examplesDir / "benchmarks" / "other" / "variadic_combinators.effekt" -> Some(Summary(
staticDispatches = 27057,
dynamicDispatches = 9009,
patternMatches = 30052,
branches = 3003,
pushedFrames = 54105,
poppedFrames = 54105,
allocations = 24060,
closures = 12030,
variableReads = 24048,
variableWrites = 18036,
resets = 0,
shifts = 0,
resumes = 0
)),
)

val testFiles: Seq[(File, Option[Summary])] =
are_we_fast_yet ++
duality_of_compilation ++
effect_handlers_bench ++
casestudies
casestudies ++
other

def runTest(f: File, expectedSummary: Option[Summary]): Unit =
val path = f.getPath
Expand All @@ -711,6 +826,4 @@ class VMTests extends munit.FunSuite {
}

testFiles.foreach(runTest)


}
15 changes: 8 additions & 7 deletions effekt/shared/src/main/scala/effekt/Compiler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,11 @@ trait Compiler[Executable] {
* - Server / Driver to typecheck and report type errors in VSCode
*/
def runFrontend(source: Source)(using C: Context): Option[Module] =
def getStackTrace(e: Throwable): String =
val stringWriter = new java.io.StringWriter()
e.printStackTrace(new java.io.PrintWriter(stringWriter))
stringWriter.toString

try {
val res = Frontend(source).map { res =>
val mod = res.mod
Expand All @@ -128,15 +133,11 @@ trait Compiler[Executable] {
None
case e @ CompilerPanic(msg) =>
C.report(msg)
e.getStackTrace.foreach { line =>
C.info(" at " + line)
}
C.info(getStackTrace(e))
None
case e =>
C.info("Effekt Compiler Crash: " + e.getMessage)
e.getStackTrace.foreach { line =>
C.info(" at " + line)
}
C.info("Effekt Compiler Crash: " + e.toString)
C.info(getStackTrace(e))
None
}

Expand Down
2 changes: 1 addition & 1 deletion effekt/shared/src/main/scala/effekt/RecursiveDescent.scala
Original file line number Diff line number Diff line change
Expand Up @@ -672,7 +672,7 @@ class RecursiveDescent(positions: Positions, tokens: Seq[Token], source: Source)
val captures = `box` ~> backtrack(captureSet())
val expr = if (peek(`{`)) functionArg()
else if (peek(`new`)) newExpr()
else Var(idRef())
else callExpr()
Box(captures, expr)


Expand Down
86 changes: 84 additions & 2 deletions effekt/shared/src/main/scala/effekt/core/vm/Builtin.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package core
package vm

import java.io.PrintStream
import scala.util.matching as regex
import scala.util.matching.Regex

trait Runtime {
def out: PrintStream
Expand Down Expand Up @@ -193,12 +195,56 @@ lazy val strings: Builtins = Map(
},

builtin("effekt::inspect(Any)") {
case any :: Nil => Value.String(inspect(any))
case any :: Nil =>
Runtime.out.println(inspect(any))
Value.Unit()
},

builtin("effekt::infixEq(String, String)") {
case As.String(x) :: As.String(y) :: Nil => Value.Bool(x == y)
},

builtin("effekt::length(String)") {
case As.String(x) :: Nil => Value.Int(x.length)
},

builtin("effekt::substring(String, Int, Int)") {
case As.String(x) :: As.Int(from) :: As.Int(to) :: Nil => Value.String(x.substring(from.toInt, to.toInt))
},

builtin("string::unsafeCharAt(String, Int)") {
case As.String(x) :: As.Int(at) :: Nil => Value.Int(x.charAt(at.toInt).toLong)
},

builtin("string::toInt(Char)") {
case As.Int(n) :: Nil => Value.Int(n)
},

builtin("string::toChar(Int)") {
case As.Int(n) :: Nil => Value.Int(n)
},

builtin("string::infixLte(Char, Char)") {
case As.Int(x) :: As.Int(y) :: Nil => Value.Bool(x <= y)
},

builtin("string::infixLt(Char, Char)") {
case As.Int(x) :: As.Int(y) :: Nil => Value.Bool(x < y)
},

builtin("string::infixGt(Char, Char)") {
case As.Int(x) :: As.Int(y) :: Nil => Value.Bool(x > y)
},

builtin("string::infixGte(Char, Char)") {
case As.Int(x) :: As.Int(y) :: Nil => Value.Bool(x >= y)
},
)

lazy val chars: Builtins = Map(
builtin("effekt::infixEq(Char, Char)") {
case As.Int(x) :: As.Int(y) :: Nil => Value.Bool(x == y)
},
)

lazy val arrays: Builtins = Map(
Expand All @@ -216,6 +262,12 @@ lazy val arrays: Builtins = Map(
},
)

lazy val undefined: Builtins = Map(
builtin("effekt::isUndefined[A](A)") {
case Value.Literal(m) :: Nil => Value.Bool(m == null)
},
)

lazy val refs: Builtins = Map(
builtin("ref::ref[T](T)") {
case init :: Nil => Value.Ref(Reference(init))
Expand All @@ -228,7 +280,22 @@ lazy val refs: Builtins = Map(
},
)

lazy val builtins: Builtins = printing ++ integers ++ doubles ++ booleans ++ strings ++ arrays ++ refs
lazy val regexes: Builtins = Map(
builtin("regex::regex(String)") {
case As.String(str) :: Nil => Value.Literal(new Regex(str))
},
builtin("regex::exec(Regex, String)") {
case As.Regex(r) :: As.String(str) :: Nil => Value.Literal(r.findFirstMatchIn(str).orNull)
},
builtin("regex::matched(RegexMatch)") {
case As.RegexMatch(m) :: Nil => Value.String(m.matched)
},
builtin("regex::index(RegexMatch)") {
case As.RegexMatch(m) :: Nil => Value.Int(m.start)
},
)

lazy val builtins: Builtins = printing ++ integers ++ doubles ++ booleans ++ strings ++ arrays ++ refs ++ chars ++ regexes ++ undefined

protected object As {
object String {
Expand All @@ -240,6 +307,8 @@ protected object As {
object Int {
def unapply(v: Value): Option[scala.Long] = v match {
case Value.Literal(value: scala.Long) => Some(value)
case Value.Literal(value: scala.Int) => Some(value.toLong)
case Value.Literal(value: java.lang.Integer) => Some(value.toLong)
case _ => None
}
}
Expand Down Expand Up @@ -267,4 +336,17 @@ protected object As {
case _ => None
}
}
object Regex {
def unapply(v: Value): Option[regex.Regex] = v match {
case Value.Literal(v: regex.Regex) => Some(v)
case _ => None
}
}
object RegexMatch {
def unapply(v: Value): Option[regex.Regex.Match | Null] = v match {
case Value.Literal(null) => Some(null)
case Value.Literal(v: regex.Regex.Match) => Some(v)
case _ => None
}
}
}
4 changes: 2 additions & 2 deletions effekt/shared/src/main/scala/effekt/core/vm/VM.scala
Original file line number Diff line number Diff line change
Expand Up @@ -491,7 +491,7 @@ class Interpreter(instrumentation: Instrumentation, runtime: Runtime) {
val arguments = vargs.map(a => eval(a, env))
instrumentation.builtin(name)
try { impl(runtime)(arguments) } catch { case e => sys error s"Cannot call ${b} with arguments ${arguments.map {
case Value.Literal(l) => s"${l}: ${l.getClass.getName}"
case Value.Literal(l) => s"${l}: ${l.getClass.getName}\n${e.getMessage}"
case other => other.toString
}.mkString(", ")}" }
}
Expand All @@ -503,7 +503,7 @@ class Interpreter(instrumentation: Instrumentation, runtime: Runtime) {
val arguments = vargs.map(a => eval(a, env))
instrumentation.builtin(name)
try { impl(runtime)(arguments) } catch { case e => sys error s"Cannot call ${x} with arguments ${arguments.map {
case Value.Literal(l) => s"${l}: ${l.getClass.getName}"
case Value.Literal(l) => s"${l}: ${l.getClass.getName}\n${e.getMessage}"
case other => other.toString
}.mkString(", ")}" }
}
Expand Down
Loading

0 comments on commit 19042d4

Please sign in to comment.