Standard Library Nodes DSL (#932)

This commit is contained in:
Marcin Kostrzewa 2020-06-24 19:02:42 +02:00 committed by GitHub
parent 5101840dae
commit 0b9558d962
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
66 changed files with 1395 additions and 2615 deletions

451
build.sbt
View File

@ -27,50 +27,50 @@ Global / onChangedBuildSource := ReloadOnSourceChanges
// ============================================================================
javacOptions in ThisBuild ++= Seq(
"-encoding", // Provide explicit encoding (the next line)
"UTF-8", // Specify character encoding used by Java source files.
"-deprecation" // Shows a description of each use or override of a deprecated member or class.
)
"-encoding", // Provide explicit encoding (the next line)
"UTF-8", // Specify character encoding used by Java source files.
"-deprecation" // Shows a description of each use or override of a deprecated member or class.
)
scalacOptions in ThisBuild ++= Seq(
"-deprecation", // Emit warning and location for usages of deprecated APIs.
"-encoding", // Provide explicit encoding (the next line)
"utf-8", // Specify character encoding used by Scala source files.
"-explaintypes", // Explain type errors in more detail.
"-feature", // Emit warning and location for usages of features that should be imported explicitly.
"-language:existentials", // Existential types (besides wildcard types) can be written and inferred
"-language:experimental.macros", // Allow macro definition (besides implementation and application)
"-language:higherKinds", // Allow higher-kinded types
"-language:implicitConversions", // Allow definition of implicit functions called views
"-unchecked", // Enable additional warnings where generated code depends on assumptions.
"-Xcheckinit", // Wrap field accessors to throw an exception on uninitialized access.
"-Xlint:adapted-args", // Warn if an argument list is modified to match the receiver.
"-Xlint:constant", // Evaluation of a constant arithmetic expression results in an error.
"-Xlint:delayedinit-select", // Selecting member of DelayedInit.
"-Xlint:doc-detached", // A Scaladoc comment appears to be detached from its element.
"-Xlint:inaccessible", // Warn about inaccessible types in method signatures.
"-Xlint:infer-any", // Warn when a type argument is inferred to be `Any`.
"-Xlint:missing-interpolator", // A string literal appears to be missing an interpolator id.
"-Xlint:nullary-override", // Warn when non-nullary `def f()' overrides nullary `def f'.
"-Xlint:nullary-unit", // Warn when nullary methods return Unit.
"-Xlint:option-implicit", // Option.apply used implicit view.
"-Xlint:package-object-classes", // Class or object defined in package object.
"-Xlint:poly-implicit-overload", // Parameterized overloaded implicit methods are not visible as view bounds.
"-Xlint:private-shadow", // A private field (or class parameter) shadows a superclass field.
"-Xlint:stars-align", // Pattern sequence wildcard must align with sequence component.
"-Xlint:type-parameter-shadow", // A local type parameter shadows a type already in scope.
"-Xmacro-settings:-logging@org.enso", // Disable the debug logging globally.
"-Ywarn-dead-code", // Warn when dead code is identified.
"-Ywarn-extra-implicit", // Warn when more than one implicit parameter section is defined.
"-Ywarn-numeric-widen", // Warn when numerics are widened.
"-Ywarn-unused:imports", // Warn if an import selector is not referenced.
"-Ywarn-unused:implicits", // Warn if an implicit parameter is unused.
"-Ywarn-unused:locals", // Warn if a local definition is unused.
"-Ywarn-unused:patvars", // Warn if a variable bound in a pattern is unused.
"-Ywarn-unused:privates", // Warn if a private member is unused.
"-Ywarn-unused:params", // Warn if a value parameter is unused.
"-Xfatal-warnings" // Make warnings fatal so they don't make it onto main (use @nowarn for local suppression)
)
"-deprecation", // Emit warning and location for usages of deprecated APIs.
"-encoding", // Provide explicit encoding (the next line)
"utf-8", // Specify character encoding used by Scala source files.
"-explaintypes", // Explain type errors in more detail.
"-feature", // Emit warning and location for usages of features that should be imported explicitly.
"-language:existentials", // Existential types (besides wildcard types) can be written and inferred
"-language:experimental.macros", // Allow macro definition (besides implementation and application)
"-language:higherKinds", // Allow higher-kinded types
"-language:implicitConversions", // Allow definition of implicit functions called views
"-unchecked", // Enable additional warnings where generated code depends on assumptions.
"-Xcheckinit", // Wrap field accessors to throw an exception on uninitialized access.
"-Xlint:adapted-args", // Warn if an argument list is modified to match the receiver.
"-Xlint:constant", // Evaluation of a constant arithmetic expression results in an error.
"-Xlint:delayedinit-select", // Selecting member of DelayedInit.
"-Xlint:doc-detached", // A Scaladoc comment appears to be detached from its element.
"-Xlint:inaccessible", // Warn about inaccessible types in method signatures.
"-Xlint:infer-any", // Warn when a type argument is inferred to be `Any`.
"-Xlint:missing-interpolator", // A string literal appears to be missing an interpolator id.
"-Xlint:nullary-override", // Warn when non-nullary `def f()' overrides nullary `def f'.
"-Xlint:nullary-unit", // Warn when nullary methods return Unit.
"-Xlint:option-implicit", // Option.apply used implicit view.
"-Xlint:package-object-classes", // Class or object defined in package object.
"-Xlint:poly-implicit-overload", // Parameterized overloaded implicit methods are not visible as view bounds.
"-Xlint:private-shadow", // A private field (or class parameter) shadows a superclass field.
"-Xlint:stars-align", // Pattern sequence wildcard must align with sequence component.
"-Xlint:type-parameter-shadow", // A local type parameter shadows a type already in scope.
"-Xmacro-settings:-logging@org.enso", // Disable the debug logging globally.
"-Ywarn-dead-code", // Warn when dead code is identified.
"-Ywarn-extra-implicit", // Warn when more than one implicit parameter section is defined.
"-Ywarn-numeric-widen", // Warn when numerics are widened.
"-Ywarn-unused:imports", // Warn if an import selector is not referenced.
"-Ywarn-unused:implicits", // Warn if an implicit parameter is unused.
"-Ywarn-unused:locals", // Warn if a local definition is unused.
"-Ywarn-unused:patvars", // Warn if a variable bound in a pattern is unused.
"-Ywarn-unused:privates", // Warn if a private member is unused.
"-Ywarn-unused:params", // Warn if a value parameter is unused.
"-Xfatal-warnings" // Make warnings fatal so they don't make it onto main (use @nowarn for local suppression)
)
val jsSettings = Seq(
scalaJSLinkerConfig ~= { _.withModuleKind(ModuleKind.ESModule) }
@ -136,8 +136,8 @@ lazy val enso = (project in file("."))
// === Akka ===================================================================
def akkaPkg(name: String) = akkaURL %% s"akka-$name" % akkaVersion
def akkaHTTPPkg(name: String) = akkaURL %% s"akka-$name" % akkaHTTPVersion
def akkaPkg(name: String) = akkaURL %% s"akka-$name" % akkaVersion
def akkaHTTPPkg(name: String) = akkaURL %% s"akka-$name" % akkaHTTPVersion
val akkaURL = "com.typesafe.akka"
val akkaVersion = "2.6.4"
val akkaHTTPVersion = "10.2.0-M1"
@ -199,7 +199,7 @@ val jacksonVersion = "2.10.3"
val jackson = Seq(
"com.fasterxml.jackson.dataformat" % "jackson-dataformat-cbor" % jacksonVersion,
"com.fasterxml.jackson.core" % "jackson-databind" % jacksonVersion,
"com.fasterxml.jackson.module" %% "jackson-module-scala" % jacksonVersion
"com.fasterxml.jackson.module" %% "jackson-module-scala" % jacksonVersion
)
// === JMH ====================================================================
@ -296,10 +296,10 @@ lazy val flexer = crossProject(JVMPlatform, JSPlatform)
version := "0.1",
resolvers += Resolver.sonatypeRepo("releases"),
libraryDependencies ++= scalaCompiler ++ Seq(
"com.google.guava" % "guava" % guavaVersion,
"org.typelevel" %%% "cats-core" % catsVersion,
"org.typelevel" %%% "kittens" % kittensVersion
)
"com.google.guava" % "guava" % guavaVersion,
"org.typelevel" %%% "cats-core" % catsVersion,
"org.typelevel" %%% "kittens" % kittensVersion
)
)
.jsSettings(jsSettings)
@ -311,13 +311,13 @@ lazy val `syntax-definition` = crossProject(JVMPlatform, JSPlatform)
.settings(
scalacOptions ++= Seq("-Ypatmat-exhaust-depth", "off"),
libraryDependencies ++= monocle ++ scalaCompiler ++ Seq(
"org.typelevel" %%% "cats-core" % catsVersion,
"org.typelevel" %%% "kittens" % kittensVersion,
"com.lihaoyi" %%% "scalatags" % scalatagsVersion,
"io.circe" %%% "circe-core" % circeVersion,
"io.circe" %%% "circe-generic" % circeVersion,
"io.circe" %%% "circe-parser" % circeVersion
)
"org.typelevel" %%% "cats-core" % catsVersion,
"org.typelevel" %%% "kittens" % kittensVersion,
"com.lihaoyi" %%% "scalatags" % scalatagsVersion,
"io.circe" %%% "circe-core" % circeVersion,
"io.circe" %%% "circe-generic" % circeVersion,
"io.circe" %%% "circe-parser" % circeVersion
)
)
.jsSettings(jsSettings)
@ -335,35 +335,35 @@ lazy val syntax = crossProject(JVMPlatform, JSPlatform)
version := "0.1",
logBuffered := false,
libraryDependencies ++= Seq(
"org.scalatest" %%% "scalatest" % scalatestVersion % Test,
"com.lihaoyi" %%% "pprint" % pprintVersion,
"io.circe" %%% "circe-core" % circeVersion,
"io.circe" %%% "circe-generic" % circeVersion,
"io.circe" %%% "circe-parser" % circeVersion
),
"org.scalatest" %%% "scalatest" % scalatestVersion % Test,
"com.lihaoyi" %%% "pprint" % pprintVersion,
"io.circe" %%% "circe-core" % circeVersion,
"io.circe" %%% "circe-generic" % circeVersion,
"io.circe" %%% "circe-parser" % circeVersion
),
compile := (Compile / compile)
.dependsOn(Def.taskDyn {
val parserCompile =
(`syntax-definition`.jvm / Compile / compileIncremental).value
if (parserCompile.hasModified) {
Def.task {
streams.value.log.info("Parser changed, forcing recompilation.")
clean.value
}
} else Def.task {}
})
.value
.dependsOn(Def.taskDyn {
val parserCompile =
(`syntax-definition`.jvm / Compile / compileIncremental).value
if (parserCompile.hasModified) {
Def.task {
streams.value.log.info("Parser changed, forcing recompilation.")
clean.value
}
} else Def.task {}
})
.value
)
.jvmSettings(
inConfig(Benchmark)(Defaults.testSettings),
unmanagedSourceDirectories in Benchmark +=
baseDirectory.value.getParentFile / "shared/src/bench/scala",
baseDirectory.value.getParentFile / "shared/src/bench/scala",
libraryDependencies +=
"com.storm-enroute" %% "scalameter" % scalameterVersion % "bench",
"com.storm-enroute" %% "scalameter" % scalameterVersion % "bench",
testFrameworks := List(
new TestFramework("org.scalatest.tools.Framework"),
new TestFramework("org.scalameter.ScalaMeterFramework")
),
new TestFramework("org.scalatest.tools.Framework"),
new TestFramework("org.scalameter.ScalaMeterFramework")
),
bench := (test in Benchmark).tag(Exclusive).value
)
.jsSettings(
@ -385,10 +385,10 @@ lazy val `text-buffer` = project
.configs(Test)
.settings(
libraryDependencies ++= Seq(
"org.typelevel" %% "cats-core" % catsVersion,
"org.scalatest" %% "scalatest" % scalatestVersion % Test,
"org.scalacheck" %% "scalacheck" % scalacheckVersion % Test
)
"org.typelevel" %% "cats-core" % catsVersion,
"org.scalatest" %% "scalatest" % scalatestVersion % Test,
"org.scalacheck" %% "scalacheck" % scalacheckVersion % Test
)
)
lazy val graph = (project in file("lib/graph/"))
@ -397,18 +397,18 @@ lazy val graph = (project in file("lib/graph/"))
.settings(
version := "0.1",
resolvers ++= Seq(
Resolver.sonatypeRepo("releases"),
Resolver.sonatypeRepo("snapshots")
),
Resolver.sonatypeRepo("releases"),
Resolver.sonatypeRepo("snapshots")
),
scalacOptions += "-Ymacro-annotations",
libraryDependencies ++= scalaCompiler ++ Seq(
"com.chuusai" %% "shapeless" % shapelessVersion,
"io.estatico" %% "newtype" % newtypeVersion,
"org.scalatest" %% "scalatest" % scalatestVersion % Test,
"org.scalacheck" %% "scalacheck" % scalacheckVersion % Test,
"com.github.julien-truffaut" %% "monocle-core" % monocleVersion,
"org.apache.commons" % "commons-lang3" % commonsLangVersion
),
"com.chuusai" %% "shapeless" % shapelessVersion,
"io.estatico" %% "newtype" % newtypeVersion,
"org.scalatest" %% "scalatest" % scalatestVersion % Test,
"org.scalacheck" %% "scalacheck" % scalacheckVersion % Test,
"com.github.julien-truffaut" %% "monocle-core" % monocleVersion,
"org.apache.commons" % "commons-lang3" % commonsLangVersion
),
addCompilerPlugin(
"org.typelevel" %% "kind-projector" % kindProjectorVersion cross CrossVersion.full
),
@ -423,9 +423,9 @@ lazy val pkg = (project in file("lib/pkg"))
mainClass in (Compile, run) := Some("org.enso.pkg.Main"),
version := "0.1",
libraryDependencies ++= circe ++ Seq(
"io.circe" %% "circe-yaml" % circeYamlVersion, // separate from other circe deps because its independent project with its own versioning
"commons-io" % "commons-io" % commonsIoVersion
)
"io.circe" %% "circe-yaml" % circeYamlVersion, // separate from other circe deps because its independent project with its own versioning
"commons-io" % "commons-io" % commonsIoVersion
)
)
lazy val `project-manager` = (project in file("lib/project-manager"))
@ -447,17 +447,17 @@ lazy val `project-manager` = (project in file("lib/project-manager"))
libraryDependencies ++= akka,
libraryDependencies ++= circe,
libraryDependencies ++= Seq(
"com.typesafe" % "config" % typesafeConfigVersion,
"com.github.pureconfig" %% "pureconfig" % pureconfigVersion,
"ch.qos.logback" % "logback-classic" % logbackClassicVersion,
"com.typesafe.scala-logging" %% "scala-logging" % scalaLoggingVersion,
"dev.zio" %% "zio" % zioVersion,
"dev.zio" %% "zio-interop-cats" % zioInteropCatsVersion,
"commons-io" % "commons-io" % commonsIoVersion,
"com.beachape" %% "enumeratum-circe" % enumeratumCirceVersion,
"com.miguno.akka" %% "akka-mock-scheduler" % akkaMockSchedulerVersion % Test,
"org.mockito" %% "mockito-scala" % mockitoScalaVersion % Test
),
"com.typesafe" % "config" % typesafeConfigVersion,
"com.github.pureconfig" %% "pureconfig" % pureconfigVersion,
"ch.qos.logback" % "logback-classic" % logbackClassicVersion,
"com.typesafe.scala-logging" %% "scala-logging" % scalaLoggingVersion,
"dev.zio" %% "zio" % zioVersion,
"dev.zio" %% "zio-interop-cats" % zioInteropCatsVersion,
"commons-io" % "commons-io" % commonsIoVersion,
"com.beachape" %% "enumeratum-circe" % enumeratumCirceVersion,
"com.miguno.akka" %% "akka-mock-scheduler" % akkaMockSchedulerVersion % Test,
"org.mockito" %% "mockito-scala" % mockitoScalaVersion % Test
),
addCompilerPlugin(
"org.typelevel" %% "kind-projector" % kindProjectorVersion cross CrossVersion.full
)
@ -478,17 +478,17 @@ lazy val `project-manager` = (project in file("lib/project-manager"))
case _ => MergeStrategy.first
},
assemblyOption in assembly := (assemblyOption in assembly).value
.copy(
prependShellScript = Some(
defaultUniversalScript(
shebang = false,
javaOpts = Seq("-Dtruffle.class.path.append=runtime.jar")
.copy(
prependShellScript = Some(
defaultUniversalScript(
shebang = false,
javaOpts = Seq("-Dtruffle.class.path.append=runtime.jar")
)
)
)
),
),
assembly := assembly
.dependsOn(runtime / assembly)
.value
.dependsOn(runtime / assembly)
.value
)
.dependsOn(pkg)
.dependsOn(`language-server`)
@ -523,10 +523,10 @@ lazy val `json-rpc-server` = project
libraryDependencies ++= akka,
libraryDependencies ++= circe,
libraryDependencies ++= Seq(
"io.circe" %% "circe-literal" % circeVersion,
akkaTestkit % Test,
"org.scalatest" %% "scalatest" % scalatestVersion % Test
)
"io.circe" %% "circe-literal" % circeVersion,
akkaTestkit % Test,
"org.scalatest" %% "scalatest" % scalatestVersion % Test
)
)
lazy val `json-rpc-server-test` = project
@ -535,10 +535,10 @@ lazy val `json-rpc-server-test` = project
libraryDependencies ++= akka,
libraryDependencies ++= circe,
libraryDependencies ++= Seq(
"io.circe" %% "circe-literal" % circeVersion,
akkaTestkit,
"org.scalatest" %% "scalatest" % scalatestVersion
)
"io.circe" %% "circe-literal" % circeVersion,
akkaTestkit,
"org.scalatest" %% "scalatest" % scalatestVersion
)
)
.dependsOn(`json-rpc-server`)
@ -552,13 +552,13 @@ lazy val `core-definition` = (project in file("lib/core-definition"))
logBuffered in Test := false,
scalacOptions += "-Ymacro-annotations",
libraryDependencies ++= jmh ++ Seq(
"com.chuusai" %% "shapeless" % shapelessVersion,
"org.scalacheck" %% "scalacheck" % scalacheckVersion % Test,
"org.scalactic" %% "scalactic" % scalacticVersion % Test,
"org.scalatest" %% "scalatest" % scalatestVersion % Test,
"org.typelevel" %% "cats-core" % catsVersion,
"com.github.julien-truffaut" %% "monocle-core" % monocleVersion
),
"com.chuusai" %% "shapeless" % shapelessVersion,
"org.scalacheck" %% "scalacheck" % scalacheckVersion % Test,
"org.scalactic" %% "scalactic" % scalacticVersion % Test,
"org.scalatest" %% "scalatest" % scalatestVersion % Test,
"org.typelevel" %% "cats-core" % catsVersion,
"com.github.julien-truffaut" %% "monocle-core" % monocleVersion
),
addCompilerPlugin(
"org.typelevel" %% "kind-projector" % kindProjectorVersion cross CrossVersion.full
),
@ -608,11 +608,11 @@ lazy val `polyglot-api` = project
Seq(s"-Dtruffle.class.path.append=$runtimeClasspath")
},
libraryDependencies ++= Seq(
"org.graalvm.sdk" % "polyglot-tck" % graalVersion % "provided",
"com.google.flatbuffers" % "flatbuffers-java" % flatbuffersVersion,
"org.scalatest" %% "scalatest" % scalatestVersion % Test,
"org.scalacheck" %% "scalacheck" % scalacheckVersion % Test
),
"org.graalvm.sdk" % "polyglot-tck" % graalVersion % "provided",
"com.google.flatbuffers" % "flatbuffers-java" % flatbuffersVersion,
"org.scalatest" %% "scalatest" % scalatestVersion % Test,
"org.scalacheck" %% "scalacheck" % scalacheckVersion % Test
),
libraryDependencies ++= jackson,
addCompilerPlugin(
"org.typelevel" %% "kind-projector" % kindProjectorVersion cross CrossVersion.full
@ -630,23 +630,23 @@ lazy val `polyglot-api` = project
lazy val `language-server` = (project in file("engine/language-server"))
.settings(
libraryDependencies ++= akka ++ circe ++ Seq(
"ch.qos.logback" % "logback-classic" % logbackClassicVersion,
"com.typesafe.scala-logging" %% "scala-logging" % scalaLoggingVersion,
"io.circe" %% "circe-generic-extras" % circeVersion,
"io.circe" %% "circe-literal" % circeVersion,
"org.bouncycastle" % "bcpkix-jdk15on" % bcpkixJdk15Version,
"dev.zio" %% "zio" % zioVersion,
"io.methvin" % "directory-watcher" % directoryWatcherVersion,
"com.beachape" %% "enumeratum-circe" % enumeratumCirceVersion,
"com.google.flatbuffers" % "flatbuffers-java" % flatbuffersVersion,
akkaTestkit % Test,
"commons-io" % "commons-io" % commonsIoVersion,
"org.scalatest" %% "scalatest" % scalatestVersion % Test,
"org.scalacheck" %% "scalacheck" % scalacheckVersion % Test,
"org.graalvm.sdk" % "polyglot-tck" % graalVersion % "provided"
),
"ch.qos.logback" % "logback-classic" % logbackClassicVersion,
"com.typesafe.scala-logging" %% "scala-logging" % scalaLoggingVersion,
"io.circe" %% "circe-generic-extras" % circeVersion,
"io.circe" %% "circe-literal" % circeVersion,
"org.bouncycastle" % "bcpkix-jdk15on" % bcpkixJdk15Version,
"dev.zio" %% "zio" % zioVersion,
"io.methvin" % "directory-watcher" % directoryWatcherVersion,
"com.beachape" %% "enumeratum-circe" % enumeratumCirceVersion,
"com.google.flatbuffers" % "flatbuffers-java" % flatbuffersVersion,
akkaTestkit % Test,
"commons-io" % "commons-io" % commonsIoVersion,
"org.scalatest" %% "scalatest" % scalatestVersion % Test,
"org.scalacheck" %% "scalacheck" % scalacheckVersion % Test,
"org.graalvm.sdk" % "polyglot-tck" % graalVersion % "provided"
),
testOptions in Test += Tests
.Argument(TestFrameworks.ScalaCheck, "-minSuccessfulTests", "1000"),
.Argument(TestFrameworks.ScalaCheck, "-minSuccessfulTests", "1000"),
GenerateFlatbuffers.flatcVersion := flatbuffersVersion,
sourceGenerators in Compile += GenerateFlatbuffers.task
)
@ -656,8 +656,8 @@ lazy val `language-server` = (project in file("engine/language-server"))
bench := (test in Benchmark).value,
libraryDependencies += "com.storm-enroute" %% "scalameter" % scalameterVersion % "bench",
testFrameworks ++= List(
new TestFramework("org.scalameter.ScalaMeterFramework")
)
new TestFramework("org.scalameter.ScalaMeterFramework")
)
)
.dependsOn(`polyglot-api`)
.dependsOn(`json-rpc-server`)
@ -676,40 +676,40 @@ lazy val runtime = (project in file("engine/runtime"))
scalacOptions += "-Ymacro-annotations",
scalacOptions ++= Seq("-Ypatmat-exhaust-depth", "off"),
libraryDependencies ++= circe ++ jmh ++ Seq(
"com.chuusai" %% "shapeless" % shapelessVersion,
"org.apache.commons" % "commons-lang3" % commonsLangVersion,
"org.apache.tika" % "tika-core" % tikaVersion,
"org.graalvm.sdk" % "graal-sdk" % graalVersion % "provided",
"org.graalvm.sdk" % "polyglot-tck" % graalVersion % "provided",
"org.graalvm.truffle" % "truffle-api" % graalVersion % "provided",
"org.graalvm.truffle" % "truffle-dsl-processor" % graalVersion % "provided",
"org.graalvm.truffle" % "truffle-tck" % graalVersion % "provided",
"org.graalvm.truffle" % "truffle-tck-common" % graalVersion % "provided",
"org.scalacheck" %% "scalacheck" % scalacheckVersion % Test,
"org.scalactic" %% "scalactic" % scalacticVersion % Test,
"org.scalatest" %% "scalatest" % scalatestVersion % Test,
"org.graalvm.truffle" % "truffle-api" % graalVersion % Benchmark,
"org.typelevel" %% "cats-core" % catsVersion,
"eu.timepit" %% "refined" % refinedVersion
),
"com.chuusai" %% "shapeless" % shapelessVersion,
"org.apache.commons" % "commons-lang3" % commonsLangVersion,
"org.apache.tika" % "tika-core" % tikaVersion,
"org.graalvm.sdk" % "graal-sdk" % graalVersion % "provided",
"org.graalvm.sdk" % "polyglot-tck" % graalVersion % "provided",
"org.graalvm.truffle" % "truffle-api" % graalVersion % "provided",
"org.graalvm.truffle" % "truffle-dsl-processor" % graalVersion % "provided",
"org.graalvm.truffle" % "truffle-tck" % graalVersion % "provided",
"org.graalvm.truffle" % "truffle-tck-common" % graalVersion % "provided",
"org.scalacheck" %% "scalacheck" % scalacheckVersion % Test,
"org.scalactic" %% "scalactic" % scalacticVersion % Test,
"org.scalatest" %% "scalatest" % scalatestVersion % Test,
"org.graalvm.truffle" % "truffle-api" % graalVersion % Benchmark,
"org.typelevel" %% "cats-core" % catsVersion,
"eu.timepit" %% "refined" % refinedVersion
),
// Note [Unmanaged Classpath]
Compile / unmanagedClasspath += (`core-definition` / Compile / packageBin).value,
Test / unmanagedClasspath += (`core-definition` / Compile / packageBin).value,
Compile / compile := FixInstrumentsGeneration.patchedCompile
.dependsOn(`core-definition` / Compile / packageBin)
.dependsOn(FixInstrumentsGeneration.preCompileTask)
.value,
.dependsOn(`core-definition` / Compile / packageBin)
.dependsOn(FixInstrumentsGeneration.preCompileTask)
.value,
// Note [Classpath Separation]
Test / javaOptions ++= Seq(
"-XX:-UseJVMCIClassLoader",
"-Dgraalvm.locatorDisabled=true"
)
"-XX:-UseJVMCIClassLoader",
"-Dgraalvm.locatorDisabled=true"
)
)
.settings(
(Compile / javacOptions) ++= Seq(
"-s",
(Compile / sourceManaged).value.getAbsolutePath
),
"-s",
(Compile / sourceManaged).value.getAbsolutePath
),
addCompilerPlugin(
"org.typelevel" %% "kind-projector" % kindProjectorVersion cross CrossVersion.full
),
@ -720,22 +720,22 @@ lazy val runtime = (project in file("engine/runtime"))
)
.settings(
(Compile / compile) := (Compile / compile)
.dependsOn(Def.task { (Compile / sourceManaged).value.mkdirs })
.value
.dependsOn(Def.task { (Compile / sourceManaged).value.mkdirs })
.value
)
.settings(
logBuffered := false,
bench := (test in Benchmark).tag(Exclusive).value,
benchOnly := Def.inputTaskDyn {
import complete.Parsers.spaceDelimited
val name = spaceDelimited("<name>").parsed match {
case List(name) => name
case _ => throw new IllegalArgumentException("Expected one argument.")
}
Def.task {
(testOnly in Benchmark).toTask(" -- -z " + name).value
}
}.evaluated,
import complete.Parsers.spaceDelimited
val name = spaceDelimited("<name>").parsed match {
case List(name) => name
case _ => throw new IllegalArgumentException("Expected one argument.")
}
Def.task {
(testOnly in Benchmark).toTask(" -- -z " + name).value
}
}.evaluated,
parallelExecution in Benchmark := false
)
.settings(
@ -753,6 +753,7 @@ lazy val runtime = (project in file("engine/runtime"))
}
)
.dependsOn(pkg)
.dependsOn(`interpreter-dsl`)
.dependsOn(syntax.jvm)
.dependsOn(graph)
.dependsOn(`polyglot-api`)
@ -804,52 +805,58 @@ lazy val runner = project
MergeStrategy.first
},
assemblyOption in assembly := (assemblyOption in assembly).value
.copy(
prependShellScript = Some(
defaultUniversalScript(
shebang = false,
javaOpts = truffleRunOptions ++
Seq("-Dtruffle.class.path.append=runtime.jar")
.copy(
prependShellScript = Some(
defaultUniversalScript(
shebang = false,
javaOpts = truffleRunOptions ++
Seq("-Dtruffle.class.path.append=runtime.jar")
)
)
)
),
),
commands += WithDebugCommand.withDebug,
inConfig(Compile)(truffleRunOptionsSettings),
libraryDependencies ++= Seq(
"org.graalvm.sdk" % "polyglot-tck" % graalVersion % "provided",
"org.graalvm.truffle" % "truffle-api" % graalVersion % "provided",
"commons-cli" % "commons-cli" % commonsCliVersion,
"com.monovore" %% "decline" % declineVersion,
"io.github.spencerpark" % "jupyter-jvm-basekernel" % jupyterJvmBasekernelVersion,
"org.jline" % "jline" % jlineVersion,
"org.typelevel" %% "cats-core" % catsVersion
),
"org.graalvm.sdk" % "polyglot-tck" % graalVersion % "provided",
"org.graalvm.truffle" % "truffle-api" % graalVersion % "provided",
"commons-cli" % "commons-cli" % commonsCliVersion,
"com.monovore" %% "decline" % declineVersion,
"io.github.spencerpark" % "jupyter-jvm-basekernel" % jupyterJvmBasekernelVersion,
"org.jline" % "jline" % jlineVersion,
"org.typelevel" %% "cats-core" % catsVersion
),
connectInput in run := true
)
.settings(
buildNativeImage := Def
.task {
val javaHome = System.getProperty("java.home")
val nativeImagePath = s"$javaHome/bin/native-image"
val classPath = (Runtime / fullClasspath).value.files.mkString(":")
val resourcesGlobOpt = "-H:IncludeResources=.*Main.enso$"
val cmd =
s"$nativeImagePath $resourcesGlobOpt --macro:truffle --no-fallback --initialize-at-build-time -cp $classPath ${(Compile / mainClass).value.get} enso"
cmd !
}
.dependsOn(Compile / compile)
.value
.task {
val javaHome = System.getProperty("java.home")
val nativeImagePath = s"$javaHome/bin/native-image"
val classPath = (Runtime / fullClasspath).value.files.mkString(":")
val resourcesGlobOpt = "-H:IncludeResources=.*Main.enso$"
val cmd =
s"$nativeImagePath $resourcesGlobOpt --macro:truffle --no-fallback --initialize-at-build-time -cp $classPath ${(Compile / mainClass).value.get} enso"
cmd !
}
.dependsOn(Compile / compile)
.value
)
.settings(
Compile / sourceGenerators += Def.task {
val file = (Compile / sourceManaged).value / "buildinfo" / "Info.scala"
BuildInfo
.writeBuildInfoFile(file, ensoVersion, scalacVersion, graalVersion)
}.taskValue,
val file = (Compile / sourceManaged).value / "buildinfo" / "Info.scala"
BuildInfo
.writeBuildInfoFile(file, ensoVersion, scalacVersion, graalVersion)
}.taskValue,
assembly := assembly
.dependsOn(runtime / assembly)
.value
.dependsOn(runtime / assembly)
.value
)
.dependsOn(pkg)
.dependsOn(`language-server`)
.dependsOn(`polyglot-api`)
lazy val `interpreter-dsl` = (project in file("lib/interpreter-dsl"))
.settings(
version := "0.1",
libraryDependencies += "com.google.auto.service" % "auto-service" % "1.0-rc7"
)

View File

@ -0,0 +1,97 @@
---
layout: developer-doc
title: Builtin Base Methods
category: runtime
tags: [runtime, base, standard, library]
order: 7
---
# Builtin Base Methods
While we strive to implement most of the Enso standard library in Enso itself,
it is necessary for certain methods, particularly ones involving operations out
of reach for the standard language semantics, or primitive system calls, to be
implemented in Java.
To facilitate this process, we have created an annotation-based DSL for easier
generation of such methods' boilerplate.
<!-- MarkdownTOC levels="2,3" autolink="true" -->
- [DSL Overview](#dsl-overview)
- [`@BuiltinMethod` Annotation](#builtinmethod-annotation)
- [Structural Requirements](#structural-requirements)
- [`Execute` Method Semantics](#execute-method-semantics)
- [Generated Node](#generated-node)
<!-- /MarkdownTOC -->
## DSL Overview
The Enso Base DSL exposes certain annotations that allow to generate
boilerplate transforming standard Truffle nodes into a shape that can easily
be exported to the Base library. This DSL facilitates automatic parsing
and typechecking of method arguments and wrapping the node in an actual
`Function` object.
## `@BuiltinMethod` Annotation
The `@BuiltinMethod` annotation is applied to a Truffle `Node` subclass that
should be treated as a builtin method. It takes the following arguments:
1. `type` **String** the name of the type the method will be registered on.
2. `name` **String** the method name.
3. `description` **String** a summary of the method's behavior, for
documentation purposes.
4. `alwaysDirect` **Boolean = `true`** describes whether the function can always
be safely called directly. It should be set to `false` for methods that
evaluate user code in a tail position (e.g. `if_then_else`). If the method
does not take functions or thunks as parameters, or it only evaluates these
in a non-tail position, this parameter should be left defaulted.
The annotation will generate a `RootNode` subclass in the same package as the
declaring node, with a name basing on the declaring node's name. The name of
the generated node is the name of the original node, with the `Node` suffix
stripped and the `MethodGen` suffix appended. E.g. `AndOperatorNode` will
generate a `AndOperatorMethodGen` root node.
## Structural Requirements
The DSL places certain structural requirements on the declaring node.
1. **Construction:** The node must be constructible using either
a paremeterless, static `build` method or a parameterless constructor.
If a suitable `build` method is defined, it will be preferred over the
constructor.
2. **Execution:** The node must declare a single, accessible (i.e. at least
package-private), non-void method named `execute`.
## `Execute` Method Semantics
The `execute` method defined by the declaring node has the following semantics.
1. Return type. If the return type is `Stateful`, the method is assumed to
modify the monadic state. For any other return type, the method cannot
modify the monadic state.
2. Arguments. The method may take any number of arguments, though at least
an argument named `self` must be present. The arguments have following
semantics:
1. An `Object` argument may be annotated with `@MonadicState`. This tells
the DSL to substitute it for the current value of monadic state. Note
that this value is read-only. In order to modify state, the method
must return a `Stateful`.
2. Any `VirtualFrame` argument will be passed the current execution frame.
3. Any `CallerInfo` argument will be passed the current `CallerInfo` and
mark the method as requiring the caller info at runtime.
4. All other arguments are treated as positional arguments to the method.
Note that according to the language specification, any method must take
an argument named `this`. Because of a naming conflict with Java, this
argument is called `_this` in the DSL. Please note that it is mandatory
to take an argument called `_this`, even if it is unused.
5. The positional arguments can be of any typed specified by the runtime
type system (see `org.enso.interpreter.runtime.Types`) or `Object`.
Arguments typed as `Thunk` mark the argument as suspended in the
generated function header.
## Generated Node
The DSL generates a single root node per annotated class. This node handles
reading the arguments from the execution frame and typechecking them, before
delegating to the declaring node.
The generated node also defines a static `makeFunction(Language)` method,
wrapping the node in a runtime function object.

View File

@ -3,7 +3,7 @@ layout: developer-doc
title: Searcher
category: runtime
tags: [runtime, search, execution]
order: 7
order: 8
---
# Searcher

View File

@ -1,76 +0,0 @@
package org.enso.interpreter.node.expression.builtin;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.NodeInfo;
import com.oracle.truffle.api.profiles.ConditionProfile;
import org.enso.interpreter.Language;
import org.enso.interpreter.node.callable.thunk.ThunkExecutorNode;
import org.enso.interpreter.runtime.callable.argument.ArgumentDefinition;
import org.enso.interpreter.runtime.callable.argument.Thunk;
import org.enso.interpreter.runtime.callable.function.Function;
import org.enso.interpreter.runtime.callable.function.FunctionSchema;
import org.enso.interpreter.runtime.state.Stateful;
import org.enso.interpreter.runtime.type.TypesGen;
/** The root node for the basic control flow structure of the language. */
@NodeInfo(shortName = "Number.ifZero", description = "Root node of the Number.ifZero method.")
public class IfZeroNode extends BuiltinRootNode {
private @Child ThunkExecutorNode leftThunkExecutorNode = ThunkExecutorNode.build();
private @Child ThunkExecutorNode rightThunkExecutorNode = ThunkExecutorNode.build();
private final ConditionProfile condProfile = ConditionProfile.createCountingProfile();
private IfZeroNode(Language language) {
super(language);
}
/**
* Takes a number and two thunks and executes the first thunk if the number was 0 and second
* otherwise.
*
* <p>Assumes the number is the first argument in the current execution frame, while the first and
* second thunks are respectively the second and third arguments.
*
* @param frame current execution frame
* @return the result of executing the proper thunk
*/
@Override
public Stateful execute(VirtualFrame frame) {
long self =
TypesGen.asLong(Function.ArgumentsHelper.getPositionalArguments(frame.getArguments())[0]);
Thunk ifT =
TypesGen.asThunk(Function.ArgumentsHelper.getPositionalArguments(frame.getArguments())[1]);
Thunk ifF =
TypesGen.asThunk(Function.ArgumentsHelper.getPositionalArguments(frame.getArguments())[2]);
Object state = Function.ArgumentsHelper.getState(frame.getArguments());
if (condProfile.profile(self == 0)) {
return leftThunkExecutorNode.executeThunk(ifT, state, true);
} else {
return rightThunkExecutorNode.executeThunk(ifF, state, true);
}
}
/**
* Creates a three-argument function wrapping this node.
*
* @param language current language instance
* @return a function wrapping this node
*/
public static Function makeFunction(Language language) {
return Function.fromBuiltinRootNode(
new IfZeroNode(language),
FunctionSchema.CallStrategy.DIRECT_WHEN_TAIL,
new ArgumentDefinition(0, "this", ArgumentDefinition.ExecutionMode.EXECUTE),
new ArgumentDefinition(1, "ifTrue", ArgumentDefinition.ExecutionMode.PASS_THUNK),
new ArgumentDefinition(2, "ifFalse", ArgumentDefinition.ExecutionMode.PASS_THUNK));
}
/**
* Gets the source-level name of this node.
*
* @return the source-level name of the node
*/
@Override
public String getName() {
return "Number.ifZero";
}
}

View File

@ -1,72 +1,14 @@
package org.enso.interpreter.node.expression.builtin.bool;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.NodeInfo;
import com.oracle.truffle.api.profiles.BranchProfile;
import org.enso.interpreter.Language;
import org.enso.interpreter.node.expression.builtin.BuiltinRootNode;
import org.enso.interpreter.node.expression.builtin.number.ModNode;
import org.enso.interpreter.runtime.callable.argument.ArgumentDefinition;
import org.enso.interpreter.runtime.callable.function.Function;
import org.enso.interpreter.runtime.callable.function.FunctionSchema;
import org.enso.interpreter.runtime.error.TypeError;
import org.enso.interpreter.runtime.state.Stateful;
import org.enso.interpreter.runtime.type.TypesGen;
import com.oracle.truffle.api.nodes.Node;
import org.enso.interpreter.dsl.BuiltinMethod;
@NodeInfo(shortName = "Boolean.&&", description = "Computes the logical AND of two booleans")
public class AndNode extends BuiltinRootNode {
private final BranchProfile thatOpBadTypeProfile = BranchProfile.create();
private AndNode(Language language) {
super(language);
}
/**
* Creates a two-argument function wrapping this node.
*
* @param language the current language instance
* @return a function wrapping this node
*/
public static Function makeFunction(Language language) {
return Function.fromBuiltinRootNode(
new AndNode(language),
FunctionSchema.CallStrategy.ALWAYS_DIRECT,
new ArgumentDefinition(0, "this", ArgumentDefinition.ExecutionMode.EXECUTE),
new ArgumentDefinition(1, "that", ArgumentDefinition.ExecutionMode.EXECUTE));
}
/**
* Executes this node.
*
* @param frame current execution frame
* @return the result of performing `op` on the operands
*/
@Override
public final Stateful execute(VirtualFrame frame) {
boolean thisArg =
TypesGen.asBoolean(
Function.ArgumentsHelper.getPositionalArguments(frame.getArguments())[0]);
Object thatArg = Function.ArgumentsHelper.getPositionalArguments(frame.getArguments())[1];
if (TypesGen.isBoolean(thatArg)) {
boolean thatArgBool = TypesGen.asBoolean(thatArg);
Object state = Function.ArgumentsHelper.getState(frame.getArguments());
return new Stateful(state, thisArg && thatArgBool);
} else {
thatOpBadTypeProfile.enter();
throw new TypeError("Unexpected type for `that` operand in " + getName(), this);
}
}
/**
* Returns a language-specific name for this node.
*
* @return the name of this node
*/
@Override
public String getName() {
return "Boolean.||";
@BuiltinMethod(
type = "Boolean",
name = "&&",
description = "Computes the logical conjunction of two booleans")
public class AndNode extends Node {
boolean execute(boolean _this, boolean that) {
return _this && that;
}
}

View File

@ -1,80 +1,28 @@
package org.enso.interpreter.node.expression.builtin.bool;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.NodeInfo;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.profiles.ConditionProfile;
import org.enso.interpreter.Language;
import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.dsl.MonadicState;
import org.enso.interpreter.node.callable.thunk.ThunkExecutorNode;
import org.enso.interpreter.node.expression.builtin.BuiltinRootNode;
import org.enso.interpreter.runtime.callable.argument.ArgumentDefinition;
import org.enso.interpreter.runtime.callable.argument.Thunk;
import org.enso.interpreter.runtime.callable.function.Function;
import org.enso.interpreter.runtime.callable.function.FunctionSchema;
import org.enso.interpreter.runtime.state.Stateful;
import org.enso.interpreter.runtime.type.TypesGen;
/** The root node for the basic control flow structure of the language. */
@NodeInfo(
shortName = "Boolean.if_then_else",
@BuiltinMethod(
type = "Boolean",
name = "if_then_else",
alwaysDirect = false,
description = "Performs the standard if-then-else control flow operation.")
public class IfThenElseNode extends BuiltinRootNode {
public class IfThenElseNode extends Node {
private @Child ThunkExecutorNode leftThunkExecutorNode = ThunkExecutorNode.build();
private @Child ThunkExecutorNode rightThunkExecutorNode = ThunkExecutorNode.build();
private final ConditionProfile condProfile = ConditionProfile.createCountingProfile();
private IfThenElseNode(Language language) {
super(language);
}
/**
* Takes a number and two thunks and executes the first thunk if the number was 0 and second
* otherwise.
*
* <p>Assumes the number is the first argument in the current execution frame, while the first and
* second thunks are respectively the second and third arguments.
*
* @param frame current execution frame
* @return the result of executing the proper thunk
*/
@Override
public Stateful execute(VirtualFrame frame) {
boolean self =
TypesGen.asBoolean(
Function.ArgumentsHelper.getPositionalArguments(frame.getArguments())[0]);
Thunk ifT =
TypesGen.asThunk(Function.ArgumentsHelper.getPositionalArguments(frame.getArguments())[1]);
Thunk ifF =
TypesGen.asThunk(Function.ArgumentsHelper.getPositionalArguments(frame.getArguments())[2]);
Object state = Function.ArgumentsHelper.getState(frame.getArguments());
if (condProfile.profile(self)) {
return leftThunkExecutorNode.executeThunk(ifT, state, true);
Stateful execute(@MonadicState Object state, boolean _this, Thunk if_true, Thunk if_false) {
if (condProfile.profile(_this)) {
return leftThunkExecutorNode.executeThunk(if_true, state, true);
} else {
return rightThunkExecutorNode.executeThunk(ifF, state, true);
return rightThunkExecutorNode.executeThunk(if_false, state, true);
}
}
/**
* Creates a three-argument function wrapping this node.
*
* @param language current language instance
* @return a function wrapping this node
*/
public static Function makeFunction(Language language) {
return Function.fromBuiltinRootNode(
new IfThenElseNode(language),
FunctionSchema.CallStrategy.DIRECT_WHEN_TAIL,
new ArgumentDefinition(0, "this", ArgumentDefinition.ExecutionMode.EXECUTE),
new ArgumentDefinition(1, "if_true", ArgumentDefinition.ExecutionMode.PASS_THUNK),
new ArgumentDefinition(2, "if_false", ArgumentDefinition.ExecutionMode.PASS_THUNK));
}
/**
* Gets the source-level name of this node.
*
* @return the source-level name of the node
*/
@Override
public String getName() {
return "Boolean.if_then_else";
}
}

View File

@ -1,58 +1,14 @@
package org.enso.interpreter.node.expression.builtin.bool;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.NodeInfo;
import org.enso.interpreter.Language;
import org.enso.interpreter.node.expression.builtin.BuiltinRootNode;
import org.enso.interpreter.runtime.callable.argument.ArgumentDefinition;
import org.enso.interpreter.runtime.callable.function.Function;
import org.enso.interpreter.runtime.callable.function.FunctionSchema.CallStrategy;
import org.enso.interpreter.runtime.state.Stateful;
import org.enso.interpreter.runtime.type.TypesGen;
import com.oracle.truffle.api.nodes.Node;
import org.enso.interpreter.dsl.BuiltinMethod;
@NodeInfo(shortName = "Boolean.not", description = "Logical negation.")
public class NotNode extends BuiltinRootNode {
private NotNode(Language language) {
super(language);
}
/**
* Creates a one-argument function wrapping this node.
*
* @param language the current language instance
* @return a function wrapping this node
*/
public static Function makeFunction(Language language) {
return Function.fromBuiltinRootNode(
new NotNode(language),
CallStrategy.ALWAYS_DIRECT,
new ArgumentDefinition(0, "this", ArgumentDefinition.ExecutionMode.EXECUTE));
}
/**
* Executes this node.
*
* @param frame current execution frame
* @return the result of negating the function argument
*/
@Override
public Stateful execute(VirtualFrame frame) {
boolean thisArg =
TypesGen.asBoolean(
Function.ArgumentsHelper.getPositionalArguments(frame.getArguments())[0]);
Object state = Function.ArgumentsHelper.getState(frame.getArguments());
return new Stateful(state, !thisArg);
}
/**
* Returns a language-specific name for this node.
*
* @return the name of this node
*/
@Override
public String getName() {
return "Boolean.not";
@BuiltinMethod(
type = "Boolean",
name = "not",
description = "Computes the logical negation of a boolean value")
public class NotNode extends Node {
boolean execute(boolean _this) {
return !_this;
}
}

View File

@ -1,71 +1,14 @@
package org.enso.interpreter.node.expression.builtin.bool;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.NodeInfo;
import com.oracle.truffle.api.profiles.BranchProfile;
import org.enso.interpreter.Language;
import org.enso.interpreter.node.expression.builtin.BuiltinRootNode;
import org.enso.interpreter.runtime.callable.argument.ArgumentDefinition;
import org.enso.interpreter.runtime.callable.function.Function;
import org.enso.interpreter.runtime.callable.function.FunctionSchema;
import org.enso.interpreter.runtime.error.TypeError;
import org.enso.interpreter.runtime.state.Stateful;
import org.enso.interpreter.runtime.type.TypesGen;
import com.oracle.truffle.api.nodes.Node;
import org.enso.interpreter.dsl.BuiltinMethod;
@NodeInfo(shortName = "Boolean.||", description = "Computes the logical OR of two booleans")
public class OrNode extends BuiltinRootNode {
private final BranchProfile thatOpBadTypeProfile = BranchProfile.create();
private OrNode(Language language) {
super(language);
}
/**
* Creates a two-argument function wrapping this node.
*
* @param language the current language instance
* @return a function wrapping this node
*/
public static Function makeFunction(Language language) {
return Function.fromBuiltinRootNode(
new OrNode(language),
FunctionSchema.CallStrategy.ALWAYS_DIRECT,
new ArgumentDefinition(0, "this", ArgumentDefinition.ExecutionMode.EXECUTE),
new ArgumentDefinition(1, "that", ArgumentDefinition.ExecutionMode.EXECUTE));
}
/**
* Executes this node.
*
* @param frame current execution frame
* @return the result of performing `op` on the operands
*/
@Override
public final Stateful execute(VirtualFrame frame) {
boolean thisArg =
TypesGen.asBoolean(
Function.ArgumentsHelper.getPositionalArguments(frame.getArguments())[0]);
Object thatArg = Function.ArgumentsHelper.getPositionalArguments(frame.getArguments())[1];
if (TypesGen.isBoolean(thatArg)) {
boolean thatArgBool = TypesGen.asBoolean(thatArg);
Object state = Function.ArgumentsHelper.getState(frame.getArguments());
return new Stateful(state, thisArg || thatArgBool);
} else {
thatOpBadTypeProfile.enter();
throw new TypeError("Unexpected type for `that` operand in " + getName(), this);
}
}
/**
* Returns a language-specific name for this node.
*
* @return the name of this node
*/
@Override
public String getName() {
return "Boolean.||";
@BuiltinMethod(
type = "Boolean",
name = "||",
description = "Computes the logical disjunction of two booleans")
public class OrNode extends Node {
boolean execute(boolean _this, boolean that) {
return _this || that;
}
}

View File

@ -1,57 +1,11 @@
package org.enso.interpreter.node.expression.builtin.bool;
import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.NodeInfo;
import org.enso.interpreter.Language;
import org.enso.interpreter.node.expression.builtin.BuiltinRootNode;
import org.enso.interpreter.runtime.callable.argument.ArgumentDefinition;
import org.enso.interpreter.runtime.callable.function.Function;
import org.enso.interpreter.runtime.callable.function.FunctionSchema.CallStrategy;
import org.enso.interpreter.runtime.state.Stateful;
import org.enso.interpreter.runtime.type.TypesGen;
import com.oracle.truffle.api.nodes.Node;
import org.enso.interpreter.dsl.BuiltinMethod;
@NodeInfo(shortName = "Boolean.to_text", description = "Boolean to text conversion.")
public class ToTextNode extends BuiltinRootNode {
private ToTextNode(Language language) {
super(language);
}
/**
* Creates a function wrapping this node.
*
* @param language the current language instance
* @return a function wrapping this node
*/
public static Function makeFunction(Language language) {
return Function.fromBuiltinRootNode(
new ToTextNode(language),
CallStrategy.ALWAYS_DIRECT,
new ArgumentDefinition(0, "this", ArgumentDefinition.ExecutionMode.EXECUTE));
}
/**
* Executes the node.
*
* @param frame current execution frame.
* @return the result of converting input into a string.
*/
@Override
public Stateful execute(VirtualFrame frame) {
boolean thisArg =
TypesGen.asBoolean(
Function.ArgumentsHelper.getPositionalArguments(frame.getArguments())[0]);
Object state = Function.ArgumentsHelper.getState(frame.getArguments());
return new Stateful(state, thisArg ? "True" : "False");
}
/**
* Returns a language-specific name for this node.
*
* @return the name of this node
*/
@Override
public String getName() {
return "Boolean.to_text";
@BuiltinMethod(type = "Boolean", name = "to_text", description = "Boolean to text conversion.")
public class ToTextNode extends Node {
String execute(boolean _this) {
return _this ? "True" : "False";
}
}

View File

@ -1,60 +1,77 @@
package org.enso.interpreter.node.expression.builtin.debug;
import com.oracle.truffle.api.debug.DebuggerTags;
import com.oracle.truffle.api.dsl.CachedContext;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.NodeInfo;
import org.enso.interpreter.Constants;
import com.oracle.truffle.api.instrumentation.GenerateWrapper;
import com.oracle.truffle.api.instrumentation.InstrumentableNode;
import com.oracle.truffle.api.instrumentation.ProbeNode;
import com.oracle.truffle.api.instrumentation.Tag;
import com.oracle.truffle.api.nodes.Node;
import org.enso.interpreter.Language;
import org.enso.interpreter.node.expression.builtin.BuiltinRootNode;
import org.enso.interpreter.node.expression.debug.BreakpointNode;
import org.enso.interpreter.runtime.callable.argument.ArgumentDefinition;
import org.enso.interpreter.runtime.callable.function.Function;
import org.enso.interpreter.runtime.callable.function.FunctionSchema;
import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.dsl.MonadicState;
import org.enso.interpreter.runtime.Context;
import org.enso.interpreter.runtime.callable.CallerInfo;
import org.enso.interpreter.runtime.state.Stateful;
/** Root of the builtin Debug.breakpoint function. */
@NodeInfo(
shortName = "Debug.breakpoint",
description = "Root of the builtin Debug.breakpoint function.")
public class DebugBreakpointNode extends BuiltinRootNode {
private @Child BreakpointNode instrumentableNode = BreakpointNode.build();
private DebugBreakpointNode(Language language) {
super(language);
@BuiltinMethod(type = "Debug", name = "breakpoint", description = "Instrumentation marker node.")
@GenerateWrapper
public abstract class DebugBreakpointNode extends Node implements InstrumentableNode {
/**
* Creates a new instance of this node.
*
* @return a new instance of this node
*/
public static DebugBreakpointNode build() {
return DebugBreakpointNodeGen.create();
}
/**
* Executes this node by delegating to its instrumentable child.
* Tells Truffle this node is instrumentable.
*
* @param frame current execution frame
* @return the result of running the instrumentable node
* @return {@code true} this node is always instrumentable.
*/
@Override
public Stateful execute(VirtualFrame frame) {
Object state = Function.ArgumentsHelper.getState(frame.getArguments());
return instrumentableNode.execute(frame, state);
public boolean isInstrumentable() {
return true;
}
abstract Stateful execute(
VirtualFrame frame, CallerInfo callerInfo, @MonadicState Object state, Object _this);
@Specialization
Stateful doExecute(
VirtualFrame frame,
CallerInfo callerInfo,
Object state,
Object _this,
@CachedContext(Language.class) Context context) {
return new Stateful(state, context.getUnit().newInstance());
}
/**
* Wraps this node in a 1-argument function.
* Informs Truffle about the provided tags.
*
* @param language current language instance
* @return the function wrapper for this node
*/
public static Function makeFunction(Language language) {
return Function.fromBuiltinRootNodeWithCallerFrameAccess(
new DebugBreakpointNode(language),
FunctionSchema.CallStrategy.ALWAYS_DIRECT,
new ArgumentDefinition(
0, Constants.Names.THIS_ARGUMENT, ArgumentDefinition.ExecutionMode.EXECUTE));
}
/**
* Gets the source-level name of this node.
* <p>This node only provides the {@link DebuggerTags.AlwaysHalt} tag.
*
* @return the source-level name of the node
* @param tag the tag to verify
* @return {@code true} if the tag is {@link DebuggerTags.AlwaysHalt}, {@code false} otherwise
*/
@Override
public String getName() {
return "Debug.breakpoint";
public boolean hasTag(Class<? extends Tag> tag) {
return tag == DebuggerTags.AlwaysHalt.class;
}
/**
* Creates an instrumentable wrapper node for this node.
*
* @param probeNode the probe node to wrap
* @return the wrapper instance wrapping both this and the probe node
*/
@Override
public WrapperNode createWrapper(ProbeNode probeNode) {
return new DebugBreakpointNodeWrapper(this, probeNode);
}
}

View File

@ -1,65 +1,27 @@
package org.enso.interpreter.node.expression.builtin.debug;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.NodeInfo;
import org.enso.interpreter.Language;
import org.enso.interpreter.node.expression.builtin.BuiltinRootNode;
import com.oracle.truffle.api.nodes.Node;
import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.dsl.MonadicState;
import org.enso.interpreter.node.expression.debug.EvalNode;
import org.enso.interpreter.runtime.callable.CallerInfo;
import org.enso.interpreter.runtime.callable.argument.ArgumentDefinition;
import org.enso.interpreter.runtime.callable.function.Function;
import org.enso.interpreter.runtime.callable.function.FunctionSchema;
import org.enso.interpreter.runtime.state.Stateful;
/** Root node for the builtin Debug.eval function. */
@NodeInfo(shortName = "Debug.eval", description = "Root node for the builtin Debug.eval function")
public class DebugEvalNode extends BuiltinRootNode {
@BuiltinMethod(
type = "Debug",
name = "eval",
description = "Evaluates an expression passed as a Text argument, in the caller frame.",
alwaysDirect = false)
public class DebugEvalNode extends Node {
private @Child EvalNode evalNode = EvalNode.build();
private DebugEvalNode(Language language) {
super(language);
DebugEvalNode() {
evalNode.markTail();
}
/**
* Executes the function in the given execution frame.
*
* <p>Requires a non-null {@link CallerInfo} passed to it. The string argument containing code to
* evaluate is this function's second (non-this) argument.
*
* @param frame current execution frame
* @return
*/
@Override
public Stateful execute(VirtualFrame frame) {
CallerInfo callerInfo = Function.ArgumentsHelper.getCallerInfo(frame.getArguments());
Object state = Function.ArgumentsHelper.getState(frame.getArguments());
String code = (String) Function.ArgumentsHelper.getPositionalArguments(frame.getArguments())[1];
return evalNode.execute(callerInfo, state, code);
}
/**
* Returns a two argument function wrapping this node.
*
* @param language current language instance
* @return a function wrapping this node's logic
*/
public static Function makeFunction(Language language) {
return Function.fromBuiltinRootNodeWithCallerFrameAccess(
new DebugEvalNode(language),
FunctionSchema.CallStrategy.DIRECT_WHEN_TAIL,
new ArgumentDefinition(0, "this", ArgumentDefinition.ExecutionMode.EXECUTE),
new ArgumentDefinition(1, "expression", ArgumentDefinition.ExecutionMode.EXECUTE));
}
/**
* Gets the source-level name of this node.
*
* @return the source-level name of the node
*/
@Override
public String getName() {
return "Debug.eval";
Stateful execute(
CallerInfo callerInfo, @MonadicState Object state, Object _this, String expression) {
return evalNode.execute(callerInfo, state, expression);
}
}

View File

@ -1,26 +1,26 @@
package org.enso.interpreter.node.expression.builtin.error;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.NodeInfo;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.profiles.ConditionProfile;
import org.enso.interpreter.Language;
import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.dsl.MonadicState;
import org.enso.interpreter.node.callable.InvokeCallableNode;
import org.enso.interpreter.node.expression.builtin.BuiltinRootNode;
import org.enso.interpreter.runtime.callable.argument.ArgumentDefinition;
import org.enso.interpreter.runtime.callable.argument.CallArgumentInfo;
import org.enso.interpreter.runtime.callable.function.Function;
import org.enso.interpreter.runtime.callable.function.FunctionSchema;
import org.enso.interpreter.runtime.state.Stateful;
import org.enso.interpreter.runtime.type.TypesGen;
/** Root node for the {@code catch} function. */
@NodeInfo(shortName = "Error.catch", description = "Root node for the catch function.")
public class CatchErrorNode extends BuiltinRootNode {
@BuiltinMethod(
type = "Any",
name = "catch",
description =
"If called on an error, executes the provided handler on the error's payload. Otherwise acts as identity.",
alwaysDirect = false)
public class CatchErrorNode extends Node {
private @Child InvokeCallableNode invokeCallableNode;
private final ConditionProfile executionProfile = ConditionProfile.createCountingProfile();
private CatchErrorNode(Language language) {
super(language);
CatchErrorNode() {
this.invokeCallableNode =
InvokeCallableNode.build(
new CallArgumentInfo[] {new CallArgumentInfo()},
@ -29,49 +29,12 @@ public class CatchErrorNode extends BuiltinRootNode {
this.invokeCallableNode.markTail();
}
/**
* Executes the logic. Assumes the scrutinee is the first argument to the enclosing function and
* the handler is the second. If the scrutinee is an error, the function is called with the error
* payload. Otherwise, it's a no-op.
*
* @param frame current execution frame
* @return the result of calling the handler function
*/
@Override
public Stateful execute(VirtualFrame frame) {
Object[] arguments = Function.ArgumentsHelper.getPositionalArguments(frame.getArguments());
Object state = Function.ArgumentsHelper.getState(frame.getArguments());
Object scrutinee = arguments[0];
Object handler = arguments[1];
if (executionProfile.profile(TypesGen.isRuntimeError(scrutinee))) {
Stateful execute(VirtualFrame frame, @MonadicState Object state, Object _this, Object handler) {
if (executionProfile.profile(TypesGen.isRuntimeError(_this))) {
return invokeCallableNode.execute(
handler, frame, state, new Object[] {TypesGen.asRuntimeError(scrutinee).getPayload()});
handler, frame, state, new Object[] {TypesGen.asRuntimeError(_this).getPayload()});
} else {
return new Stateful(state, scrutinee);
return new Stateful(state, _this);
}
}
/**
* Creates a two-argument function wrapping this node.
*
* @param language current language instance
* @return a function wrapping this node
*/
public static Function makeFunction(Language language) {
return Function.fromBuiltinRootNode(
new CatchErrorNode(language),
FunctionSchema.CallStrategy.DIRECT_WHEN_TAIL,
new ArgumentDefinition(0, "this", ArgumentDefinition.ExecutionMode.EXECUTE),
new ArgumentDefinition(1, "handler", ArgumentDefinition.ExecutionMode.EXECUTE));
}
/**
* Gets the source-level name of this node.
*
* @return the source-level name of the node
*/
@Override
public String getName() {
return "Error.catch";
}
}

View File

@ -1,74 +1,26 @@
package org.enso.interpreter.node.expression.builtin.error;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.NodeInfo;
import org.enso.interpreter.Language;
import com.oracle.truffle.api.nodes.Node;
import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.dsl.MonadicState;
import org.enso.interpreter.node.callable.thunk.ThunkExecutorNode;
import org.enso.interpreter.node.expression.builtin.BuiltinRootNode;
import org.enso.interpreter.runtime.callable.argument.ArgumentDefinition;
import org.enso.interpreter.runtime.callable.function.Function;
import org.enso.interpreter.runtime.callable.function.FunctionSchema;
import org.enso.interpreter.runtime.callable.argument.Thunk;
import org.enso.interpreter.runtime.error.PanicException;
import org.enso.interpreter.runtime.error.RuntimeError;
import org.enso.interpreter.runtime.state.Stateful;
import org.enso.interpreter.runtime.type.TypesGen;
/** Root node for the builtin catch panic function. */
@NodeInfo(
shortName = "Panic.catch",
description = "Root node for the builtin catch panic function.")
public class CatchPanicNode extends BuiltinRootNode {
@BuiltinMethod(
type = "Panic",
name = "catch",
description = "Executes an action and converts any Panic thrown by it into an Error")
public class CatchPanicNode extends Node {
private @Child ThunkExecutorNode thunkExecutorNode = ThunkExecutorNode.build();
private CatchPanicNode(Language language) {
super(language);
}
/**
* Executes the node.
*
* <p>Assumes the suspended, possibly-panicking computation is passed as the second argument and
* executes it, catching any {@link PanicException}s.
*
* @param frame current execution frame
* @return the result of the computation if it didn't throw, or a {@link RuntimeError} containing
* the thrown panic's payload.
*/
public Stateful execute(VirtualFrame frame) {
Object maybeThunk = Function.ArgumentsHelper.getPositionalArguments(frame.getArguments())[1];
Object state = Function.ArgumentsHelper.getState(frame.getArguments());
if (TypesGen.isThunk(maybeThunk)) {
try {
return thunkExecutorNode.executeThunk(TypesGen.asThunk(maybeThunk), state, false);
} catch (PanicException e) {
return new Stateful(state, new RuntimeError(e.getExceptionObject()));
}
} else {
return new Stateful(state, maybeThunk);
Stateful execute(@MonadicState Object state, Object _this, Thunk action) {
try {
return thunkExecutorNode.executeThunk(action, state, false);
} catch (PanicException e) {
return new Stateful(state, new RuntimeError(e.getExceptionObject()));
}
}
/**
* Creates a two-argument function wrapping this node.
*
* @param language current language instance
* @return a function wrapping this node
*/
public static Function makeFunction(Language language) {
return Function.fromBuiltinRootNode(
new CatchPanicNode(language),
FunctionSchema.CallStrategy.ALWAYS_DIRECT,
new ArgumentDefinition(0, "this", ArgumentDefinition.ExecutionMode.EXECUTE),
new ArgumentDefinition(1, "value", ArgumentDefinition.ExecutionMode.PASS_THUNK));
}
/**
* Gets the source-level name of this node.
*
* @return the source-level name of the node
*/
@Override
public String getName() {
return "Panic.catch";
}
}

View File

@ -1,57 +0,0 @@
package org.enso.interpreter.node.expression.builtin.error;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.NodeInfo;
import org.enso.interpreter.Language;
import org.enso.interpreter.node.expression.builtin.BuiltinRootNode;
import org.enso.interpreter.runtime.callable.argument.ArgumentDefinition;
import org.enso.interpreter.runtime.callable.function.Function;
import org.enso.interpreter.runtime.callable.function.FunctionSchema;
import org.enso.interpreter.runtime.error.PanicException;
import org.enso.interpreter.runtime.state.Stateful;
/** Root node for the builtin panic function. */
@NodeInfo(shortName = "Panic.throw", description = "Root node for the builtin panic function.")
public class PanicNode extends BuiltinRootNode {
private PanicNode(Language language) {
super(language);
}
/**
* Executes this node.
*
* <p>Assumes the panic payload is passed as the second argument of the enclosing function and
* throws it as an exception.
*
* @param frame current execution frame
* @return never returns, always throws an exception
*/
public Stateful execute(VirtualFrame frame) {
Object payload = Function.ArgumentsHelper.getPositionalArguments(frame.getArguments())[1];
throw new PanicException(payload, this);
}
/**
* Creates a two-argument function wrapping this node.
*
* @param language current language instance
* @return a function wrapping this node
*/
public static Function makeFunction(Language language) {
return Function.fromBuiltinRootNode(
new PanicNode(language),
FunctionSchema.CallStrategy.ALWAYS_DIRECT,
new ArgumentDefinition(0, "this", ArgumentDefinition.ExecutionMode.EXECUTE),
new ArgumentDefinition(1, "value", ArgumentDefinition.ExecutionMode.EXECUTE));
}
/**
* Returns a language specific name of this node.
*
* @return the name of this node
*/
@Override
public String getName() {
return "Panic.throw";
}
}

View File

@ -1,62 +1,15 @@
package org.enso.interpreter.node.expression.builtin.error;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.NodeInfo;
import org.enso.interpreter.Language;
import org.enso.interpreter.node.expression.builtin.BuiltinRootNode;
import org.enso.interpreter.runtime.callable.argument.ArgumentDefinition;
import org.enso.interpreter.runtime.callable.function.Function;
import org.enso.interpreter.runtime.callable.function.FunctionSchema;
import com.oracle.truffle.api.nodes.Node;
import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.runtime.error.RuntimeError;
import org.enso.interpreter.runtime.state.Stateful;
/** Root node for the builtin throw error function. */
@NodeInfo(
shortName = "Error.throw",
description = "Root node for the builtin throw error function.")
public class ThrowErrorNode extends BuiltinRootNode {
private ThrowErrorNode(Language language) {
super(language);
}
/**
* Executes the node.
*
* <p>Assumes the error payload is provided as the second argument of the enclosing function and
* wraps it in a {@link RuntimeError}.
*
* @param frame current execution frame
* @return a runtime error wrapped argument
*/
@Override
public Stateful execute(VirtualFrame frame) {
Object errorPayload = Function.ArgumentsHelper.getPositionalArguments(frame.getArguments())[1];
Object state = Function.ArgumentsHelper.getState(frame.getArguments());
return new Stateful(state, new RuntimeError(errorPayload));
}
/**
* Creates a two-argument function wrapping this node.
*
* @param language current language instance
* @return a function wrapping this node
*/
public static Function makeFunction(Language language) {
return Function.fromBuiltinRootNode(
new ThrowErrorNode(language),
FunctionSchema.CallStrategy.ALWAYS_DIRECT,
new ArgumentDefinition(0, "this", ArgumentDefinition.ExecutionMode.EXECUTE),
new ArgumentDefinition(1, "payload", ArgumentDefinition.ExecutionMode.EXECUTE));
}
/**
* Gets the source-level name of this node.
*
* @return the source-level name of the node
*/
@Override
public String getName() {
return "Error.throw";
@BuiltinMethod(
type = "Error",
name = "throw",
description = "Returns a new value error with given payload.")
public class ThrowErrorNode extends Node {
public Object execute(Object _this, Object payload) {
return new RuntimeError(payload);
}
}

View File

@ -0,0 +1,16 @@
package org.enso.interpreter.node.expression.builtin.error;
import com.oracle.truffle.api.nodes.Node;
import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.runtime.error.PanicException;
import org.enso.interpreter.runtime.state.Stateful;
@BuiltinMethod(
type = "Panic",
name = "throw",
description = "Throws a new Panic with given payload.")
public class ThrowPanicNode extends Node {
Stateful execute(Object _this, Object payload) {
throw new PanicException(payload, this);
}
}

View File

@ -1,76 +1,32 @@
package org.enso.interpreter.node.expression.builtin.function;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.NodeInfo;
import com.oracle.truffle.api.profiles.ConditionProfile;
import org.enso.interpreter.Language;
import com.oracle.truffle.api.nodes.Node;
import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.dsl.MonadicState;
import org.enso.interpreter.node.callable.InvokeCallableNode;
import org.enso.interpreter.node.expression.builtin.BuiltinRootNode;
import org.enso.interpreter.runtime.callable.argument.ArgumentDefinition;
import org.enso.interpreter.runtime.callable.argument.CallArgumentInfo;
import org.enso.interpreter.runtime.callable.function.Function;
import org.enso.interpreter.runtime.callable.function.FunctionSchema;
import org.enso.interpreter.runtime.state.Stateful;
import org.enso.interpreter.runtime.type.TypesGen;
/**
* This node implements the built-in functionality for the explicit {@code call} operator on
* functions.
*
* <p>It is a standard builtin node, and hence conforms to the interface for these.
*/
@NodeInfo(shortName = "Function.call", description = "Allows function calls to be made explicitly")
public class ExplicitCallFunctionNode extends BuiltinRootNode {
@BuiltinMethod(
type = "Function",
name = "call",
description = "Allows function calls to be made explicitly",
alwaysDirect = false)
public class ExplicitCallFunctionNode extends Node {
private @Child InvokeCallableNode invokeCallableNode;
private final ConditionProfile isFunctionProfile = ConditionProfile.createCountingProfile();
private ExplicitCallFunctionNode(Language language) {
super(language);
this.invokeCallableNode =
ExplicitCallFunctionNode() {
invokeCallableNode =
InvokeCallableNode.build(
new CallArgumentInfo[0],
InvokeCallableNode.DefaultsExecutionMode.EXECUTE,
InvokeCallableNode.ArgumentsExecutionMode.PRE_EXECUTED);
this.invokeCallableNode.markTail();
invokeCallableNode.markTail();
}
/**
* Forces execution of a function.
*
* @param frame current execution frame
* @return the value of executing the function.
*/
@Override
public Stateful execute(VirtualFrame frame) {
Object[] arguments = Function.ArgumentsHelper.getPositionalArguments(frame.getArguments());
Object state = Function.ArgumentsHelper.getState(frame.getArguments());
Object thisArg = arguments[0];
if (isFunctionProfile.profile(TypesGen.isFunction(thisArg))) {
return invokeCallableNode.execute(thisArg, frame, state, new Object[0]);
} else {
throw new RuntimeException("Object not callable: " + thisArg);
}
}
/**
* Creates a {@link Function} object that forces the execution of the object it is applied to.
*
* <p>This behaves in a curried manner, so for some function {@code f} you can call it with
* arguments where necessary (e.g. {@code f.call a b}.
*
* @param language the current {@link Language} instance
* @return a {@link Function} object wrapping the behavior of this node
*/
public static Function makeFunction(Language language) {
return Function.fromBuiltinRootNode(
new ExplicitCallFunctionNode(language),
FunctionSchema.CallStrategy.DIRECT_WHEN_TAIL,
new ArgumentDefinition(0, "this", ArgumentDefinition.ExecutionMode.EXECUTE));
}
@Override
public String getName() {
return "Function.call";
Stateful execute(VirtualFrame frame, @MonadicState Object state, Function _this) {
return invokeCallableNode.execute(_this, frame, state, new Object[0]);
}
}

View File

@ -5,77 +5,37 @@ import com.oracle.truffle.api.interop.ArityException;
import com.oracle.truffle.api.interop.InteropLibrary;
import com.oracle.truffle.api.interop.UnsupportedMessageException;
import com.oracle.truffle.api.interop.UnsupportedTypeException;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.nodes.NodeInfo;
import com.oracle.truffle.api.nodes.UnexpectedResultException;
import com.oracle.truffle.api.profiles.BranchProfile;
import org.enso.interpreter.Constants;
import org.enso.interpreter.Language;
import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.node.expression.builtin.BuiltinRootNode;
import org.enso.interpreter.runtime.callable.argument.ArgumentDefinition;
import org.enso.interpreter.runtime.callable.function.Function;
import org.enso.interpreter.runtime.callable.function.FunctionSchema.CallStrategy;
import org.enso.interpreter.runtime.data.Vector;
import org.enso.interpreter.runtime.error.PanicException;
import org.enso.interpreter.runtime.state.Stateful;
import org.enso.interpreter.runtime.type.TypesGen;
@NodeInfo(
shortName = "Polyglot.execute",
@BuiltinMethod(
type = "Polyglot",
name = "execute",
description = "Executes a polyglot function object (e.g. a lambda).")
public class ExecuteNode extends BuiltinRootNode {
private ExecuteNode(Language language) {
super(language);
}
public class ExecuteNode extends Node {
private @Child InteropLibrary library =
InteropLibrary.getFactory().createDispatched(Constants.CacheSizes.BUILTIN_INTEROP_DISPATCH);
private final BranchProfile err = BranchProfile.create();
/**
* Creates a function wrapping this node.
*
* @param language the current language instance
* @return a function wrapping this node
*/
public static Function makeFunction(Language language) {
return Function.fromBuiltinRootNode(
new ExecuteNode(language),
CallStrategy.ALWAYS_DIRECT,
new ArgumentDefinition(0, "this", ArgumentDefinition.ExecutionMode.EXECUTE),
new ArgumentDefinition(1, "callable", ArgumentDefinition.ExecutionMode.EXECUTE),
new ArgumentDefinition(2, "arguments", ArgumentDefinition.ExecutionMode.EXECUTE));
}
/**
* Executes the node.
*
* @param frame current execution frame.
* @return the result of converting input into a string.
*/
@Override
public Stateful execute(VirtualFrame frame) {
Object[] args = Function.ArgumentsHelper.getPositionalArguments(frame.getArguments());
Object callable = args[1];
Object state = Function.ArgumentsHelper.getState(frame.getArguments());
Object execute(Object _this, Object callable, Vector arguments) {
try {
Object[] arguments = TypesGen.expectVector(args[2]).getItems();
Object res = library.execute(callable, arguments);
return new Stateful(state, res);
} catch (UnsupportedMessageException
| ArityException
| UnsupportedTypeException
| UnexpectedResultException e) {
return library.execute(callable, arguments.getItems());
} catch (UnsupportedMessageException | ArityException | UnsupportedTypeException e) {
err.enter();
throw new PanicException(e.getMessage(), this);
}
}
/**
* Returns a language-specific name for this node.
*
* @return the name of this node
*/
@Override
public String getName() {
return "Polyglot.execute";
}
}

View File

@ -1,82 +1,29 @@
package org.enso.interpreter.node.expression.builtin.interop.generic;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.interop.InteropLibrary;
import com.oracle.truffle.api.interop.InvalidArrayIndexException;
import com.oracle.truffle.api.interop.UnsupportedMessageException;
import com.oracle.truffle.api.nodes.NodeInfo;
import com.oracle.truffle.api.nodes.UnexpectedResultException;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.profiles.BranchProfile;
import org.enso.interpreter.Constants;
import org.enso.interpreter.Language;
import org.enso.interpreter.node.expression.builtin.BuiltinRootNode;
import org.enso.interpreter.runtime.callable.argument.ArgumentDefinition;
import org.enso.interpreter.runtime.callable.function.Function;
import org.enso.interpreter.runtime.callable.function.FunctionSchema.CallStrategy;
import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.runtime.error.PanicException;
import org.enso.interpreter.runtime.error.RuntimeError;
import org.enso.interpreter.runtime.state.Stateful;
import org.enso.interpreter.runtime.type.TypesGen;
@NodeInfo(
shortName = "Polyglot.get_array_element",
@BuiltinMethod(
type = "Polyglot",
name = "get_array_element",
description = "Gets an element by index from a polyglot array.")
public class GetArrayElementNode extends BuiltinRootNode {
private GetArrayElementNode(Language language) {
super(language);
}
public class GetArrayElementNode extends Node {
private @Child InteropLibrary library =
InteropLibrary.getFactory().createDispatched(Constants.CacheSizes.BUILTIN_INTEROP_DISPATCH);
private final BranchProfile err = BranchProfile.create();
/**
* Creates a function wrapping this node.
*
* @param language the current language instance
* @return a function wrapping this node
*/
public static Function makeFunction(Language language) {
return Function.fromBuiltinRootNode(
new GetArrayElementNode(language),
CallStrategy.ALWAYS_DIRECT,
new ArgumentDefinition(0, "this", ArgumentDefinition.ExecutionMode.EXECUTE),
new ArgumentDefinition(1, "array", ArgumentDefinition.ExecutionMode.EXECUTE),
new ArgumentDefinition(2, "index", ArgumentDefinition.ExecutionMode.EXECUTE));
}
/**
* Executes the node.
*
* @param frame current execution frame.
* @return the result of converting input into a string.
*/
@Override
public Stateful execute(VirtualFrame frame) {
Object array = Function.ArgumentsHelper.getPositionalArguments(frame.getArguments())[1];
Object state = Function.ArgumentsHelper.getState(frame.getArguments());
Object execute(Object _this, Object array, long index) {
try {
long index =
TypesGen.expectLong(
Function.ArgumentsHelper.getPositionalArguments(frame.getArguments())[2]);
Object res = library.readArrayElement(array, index);
return new Stateful(state, res);
} catch (UnsupportedMessageException
| InvalidArrayIndexException
| UnexpectedResultException e) {
return library.readArrayElement(array, index);
} catch (UnsupportedMessageException | InvalidArrayIndexException e) {
err.enter();
throw new PanicException(e.getMessage(), this);
}
}
/**
* Returns a language-specific name for this node.
*
* @return the name of this node
*/
@Override
public String getName() {
return "Polyglot.get_array_element";
}
}

View File

@ -1,70 +1,28 @@
package org.enso.interpreter.node.expression.builtin.interop.generic;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.interop.InteropLibrary;
import com.oracle.truffle.api.interop.UnsupportedMessageException;
import com.oracle.truffle.api.nodes.NodeInfo;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.profiles.BranchProfile;
import org.enso.interpreter.Constants;
import org.enso.interpreter.Language;
import org.enso.interpreter.node.expression.builtin.BuiltinRootNode;
import org.enso.interpreter.runtime.callable.argument.ArgumentDefinition;
import org.enso.interpreter.runtime.callable.function.Function;
import org.enso.interpreter.runtime.callable.function.FunctionSchema.CallStrategy;
import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.runtime.error.PanicException;
import org.enso.interpreter.runtime.error.RuntimeError;
import org.enso.interpreter.runtime.state.Stateful;
@NodeInfo(shortName = "Polyglot.get_array_size", description = "Gets the size of a polyglot array.")
public class GetArraySizeNode extends BuiltinRootNode {
private GetArraySizeNode(Language language) {
super(language);
}
@BuiltinMethod(
type = "Polyglot",
name = "get_array_size",
description = "Gets the size of a polyglot array.")
public class GetArraySizeNode extends Node {
private @Child InteropLibrary library =
InteropLibrary.getFactory().createDispatched(Constants.CacheSizes.BUILTIN_INTEROP_DISPATCH);
private final BranchProfile err = BranchProfile.create();
/**
* Creates a function wrapping this node.
*
* @param language the current language instance
* @return a function wrapping this node
*/
public static Function makeFunction(Language language) {
return Function.fromBuiltinRootNode(
new GetArraySizeNode(language),
CallStrategy.ALWAYS_DIRECT,
new ArgumentDefinition(0, "this", ArgumentDefinition.ExecutionMode.EXECUTE),
new ArgumentDefinition(1, "array", ArgumentDefinition.ExecutionMode.EXECUTE));
}
/**
* Executes the node.
*
* @param frame current execution frame.
* @return the result of converting input into a string.
*/
@Override
public Stateful execute(VirtualFrame frame) {
Object obj = Function.ArgumentsHelper.getPositionalArguments(frame.getArguments())[1];
Object state = Function.ArgumentsHelper.getState(frame.getArguments());
Object execute(Object _this, Object array) {
try {
long size = library.getArraySize(obj);
return new Stateful(state, size);
return library.getArraySize(array);
} catch (UnsupportedMessageException e) {
err.enter();
throw new PanicException(e.getMessage(), this);
}
}
/**
* Returns a language-specific name for this node.
*
* @return the name of this node
*/
@Override
public String getName() {
return "Polyglot.get_array_size";
}
}

View File

@ -1,80 +1,29 @@
package org.enso.interpreter.node.expression.builtin.interop.generic;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.interop.InteropLibrary;
import com.oracle.truffle.api.interop.UnknownIdentifierException;
import com.oracle.truffle.api.interop.UnsupportedMessageException;
import com.oracle.truffle.api.nodes.NodeInfo;
import com.oracle.truffle.api.nodes.UnexpectedResultException;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.profiles.BranchProfile;
import org.enso.interpreter.Constants;
import org.enso.interpreter.Language;
import org.enso.interpreter.node.expression.builtin.BuiltinRootNode;
import org.enso.interpreter.runtime.callable.argument.ArgumentDefinition;
import org.enso.interpreter.runtime.callable.function.Function;
import org.enso.interpreter.runtime.callable.function.FunctionSchema.CallStrategy;
import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.runtime.error.PanicException;
import org.enso.interpreter.runtime.state.Stateful;
import org.enso.interpreter.runtime.type.TypesGen;
@NodeInfo(
shortName = "Polyglot.get_member",
@BuiltinMethod(
type = "Polyglot",
name = "get_member",
description = "Gets a member by name from a polyglot object.")
public class GetMemberNode extends BuiltinRootNode {
private GetMemberNode(Language language) {
super(language);
}
public class GetMemberNode extends Node {
private @Child InteropLibrary library =
InteropLibrary.getFactory().createDispatched(Constants.CacheSizes.BUILTIN_INTEROP_DISPATCH);
private final BranchProfile err = BranchProfile.create();
/**
* Creates a function wrapping this node.
*
* @param language the current language instance
* @return a function wrapping this node
*/
public static Function makeFunction(Language language) {
return Function.fromBuiltinRootNode(
new GetMemberNode(language),
CallStrategy.ALWAYS_DIRECT,
new ArgumentDefinition(0, "this", ArgumentDefinition.ExecutionMode.EXECUTE),
new ArgumentDefinition(1, "object", ArgumentDefinition.ExecutionMode.EXECUTE),
new ArgumentDefinition(2, "name", ArgumentDefinition.ExecutionMode.EXECUTE));
}
/**
* Executes the node.
*
* @param frame current execution frame.
* @return the result of converting input into a string.
*/
@Override
public Stateful execute(VirtualFrame frame) {
Object obj = Function.ArgumentsHelper.getPositionalArguments(frame.getArguments())[1];
Object state = Function.ArgumentsHelper.getState(frame.getArguments());
Object execute(Object _this, Object object, String member_name) {
try {
String name =
TypesGen.expectString(
Function.ArgumentsHelper.getPositionalArguments(frame.getArguments())[2]);
Object res = library.readMember(obj, name);
return new Stateful(state, res);
} catch (UnsupportedMessageException
| UnknownIdentifierException
| UnexpectedResultException e) {
return library.readMember(object, member_name);
} catch (UnsupportedMessageException | UnknownIdentifierException e) {
err.enter();
throw new PanicException(e.getMessage(), this);
}
}
/**
* Returns a language-specific name for this node.
*
* @return the name of this node
*/
@Override
public String getName() {
return "Polyglot.get_member";
}
}

View File

@ -1,72 +1,28 @@
package org.enso.interpreter.node.expression.builtin.interop.generic;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.interop.InteropLibrary;
import com.oracle.truffle.api.interop.UnsupportedMessageException;
import com.oracle.truffle.api.nodes.NodeInfo;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.profiles.BranchProfile;
import org.enso.interpreter.Constants;
import org.enso.interpreter.Language;
import org.enso.interpreter.node.expression.builtin.BuiltinRootNode;
import org.enso.interpreter.runtime.callable.argument.ArgumentDefinition;
import org.enso.interpreter.runtime.callable.function.Function;
import org.enso.interpreter.runtime.callable.function.FunctionSchema.CallStrategy;
import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.runtime.error.PanicException;
import org.enso.interpreter.runtime.error.RuntimeError;
import org.enso.interpreter.runtime.state.Stateful;
@NodeInfo(
shortName = "Polyglot.get_members",
@BuiltinMethod(
type = "Polyglot",
name = "get_members",
description = "Returns a polyglot array of the object's member names.")
public class GetMembersNode extends BuiltinRootNode {
private GetMembersNode(Language language) {
super(language);
}
public class GetMembersNode extends Node {
private @Child InteropLibrary library =
InteropLibrary.getFactory().createDispatched(Constants.CacheSizes.BUILTIN_INTEROP_DISPATCH);
private final BranchProfile err = BranchProfile.create();
/**
* Creates a function wrapping this node.
*
* @param language the current language instance
* @return a function wrapping this node
*/
public static Function makeFunction(Language language) {
return Function.fromBuiltinRootNode(
new GetMembersNode(language),
CallStrategy.ALWAYS_DIRECT,
new ArgumentDefinition(0, "this", ArgumentDefinition.ExecutionMode.EXECUTE),
new ArgumentDefinition(1, "object", ArgumentDefinition.ExecutionMode.EXECUTE));
}
/**
* Executes the node.
*
* @param frame current execution frame.
* @return the result of converting input into a string.
*/
@Override
public Stateful execute(VirtualFrame frame) {
Object arg = Function.ArgumentsHelper.getPositionalArguments(frame.getArguments())[1];
Object state = Function.ArgumentsHelper.getState(frame.getArguments());
Object execute(Object _this, Object object) {
try {
Object members = library.getMembers(arg);
return new Stateful(state, members);
return library.getMembers(object);
} catch (UnsupportedMessageException e) {
err.enter();
throw new PanicException(e.getMessage(), this);
}
}
/**
* Returns a language-specific name for this node.
*
* @return the name of this node
*/
@Override
public String getName() {
return "Polyglot.get_members";
}
}

View File

@ -1,79 +1,32 @@
package org.enso.interpreter.node.expression.builtin.interop.generic;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.interop.ArityException;
import com.oracle.truffle.api.interop.InteropLibrary;
import com.oracle.truffle.api.interop.UnsupportedMessageException;
import com.oracle.truffle.api.interop.UnsupportedTypeException;
import com.oracle.truffle.api.nodes.NodeInfo;
import com.oracle.truffle.api.nodes.UnexpectedResultException;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.profiles.BranchProfile;
import org.enso.interpreter.Constants;
import org.enso.interpreter.Language;
import org.enso.interpreter.node.expression.builtin.BuiltinRootNode;
import org.enso.interpreter.runtime.callable.argument.ArgumentDefinition;
import org.enso.interpreter.runtime.callable.function.Function;
import org.enso.interpreter.runtime.callable.function.FunctionSchema.CallStrategy;
import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.runtime.data.Vector;
import org.enso.interpreter.runtime.error.PanicException;
import org.enso.interpreter.runtime.state.Stateful;
import org.enso.interpreter.runtime.type.TypesGen;
@NodeInfo(shortName = "Polyglot.new", description = "Instantiates a polyglot constructor.")
public class InstantiateNode extends BuiltinRootNode {
private InstantiateNode(Language language) {
super(language);
}
@BuiltinMethod(
type = "Polyglot",
name = "new",
description = "Instantiates a polyglot constructor.")
public class InstantiateNode extends Node {
private @Child InteropLibrary library =
InteropLibrary.getFactory().createDispatched(Constants.CacheSizes.BUILTIN_INTEROP_DISPATCH);
private final BranchProfile err = BranchProfile.create();
/**
* Creates a function wrapping this node.
*
* @param language the current language instance
* @return a function wrapping this node
*/
public static Function makeFunction(Language language) {
return Function.fromBuiltinRootNode(
new InstantiateNode(language),
CallStrategy.ALWAYS_DIRECT,
new ArgumentDefinition(0, "this", ArgumentDefinition.ExecutionMode.EXECUTE),
new ArgumentDefinition(1, "constructor", ArgumentDefinition.ExecutionMode.EXECUTE),
new ArgumentDefinition(2, "arguments", ArgumentDefinition.ExecutionMode.EXECUTE));
}
/**
* Executes the node.
*
* @param frame current execution frame.
* @return the result of converting input into a string.
*/
@Override
public Stateful execute(VirtualFrame frame) {
Object[] args = Function.ArgumentsHelper.getPositionalArguments(frame.getArguments());
Object cons = args[1];
Object state = Function.ArgumentsHelper.getState(frame.getArguments());
Object execute(Object _this, Object constructor, Vector arguments) {
try {
Object[] arguments = TypesGen.expectVector(args[2]).getItems();
Object res = library.instantiate(cons, arguments);
return new Stateful(state, res);
} catch (UnsupportedMessageException
| ArityException
| UnsupportedTypeException
| UnexpectedResultException e) {
return library.instantiate(constructor, arguments.getItems());
} catch (UnsupportedMessageException | ArityException | UnsupportedTypeException e) {
err.enter();
throw new PanicException(e.getMessage(), this);
}
}
/**
* Returns a language-specific name for this node.
*
* @return the name of this node
*/
@Override
public String getName() {
return "Polyglot.new";
}
}

View File

@ -1,81 +1,31 @@
package org.enso.interpreter.node.expression.builtin.interop.generic;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.interop.*;
import com.oracle.truffle.api.nodes.NodeInfo;
import com.oracle.truffle.api.nodes.UnexpectedResultException;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.profiles.BranchProfile;
import org.enso.interpreter.Constants;
import org.enso.interpreter.Language;
import org.enso.interpreter.node.expression.builtin.BuiltinRootNode;
import org.enso.interpreter.runtime.callable.argument.ArgumentDefinition;
import org.enso.interpreter.runtime.callable.function.Function;
import org.enso.interpreter.runtime.callable.function.FunctionSchema.CallStrategy;
import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.runtime.data.Vector;
import org.enso.interpreter.runtime.error.PanicException;
import org.enso.interpreter.runtime.state.Stateful;
import org.enso.interpreter.runtime.type.TypesGen;
@NodeInfo(
shortName = "Polyglot.invoke",
@BuiltinMethod(
type = "Polyglot",
name = "invoke",
description = "Invokes a polyglot method by name, dispatching by the target argument.")
public class InvokeNode extends BuiltinRootNode {
private InvokeNode(Language language) {
super(language);
}
public class InvokeNode extends Node {
private @Child InteropLibrary library =
InteropLibrary.getFactory().createDispatched(Constants.CacheSizes.BUILTIN_INTEROP_DISPATCH);
private final BranchProfile err = BranchProfile.create();
/**
* Creates a function wrapping this node.
*
* @param language the current language instance
* @return a function wrapping this node
*/
public static Function makeFunction(Language language) {
return Function.fromBuiltinRootNode(
new InvokeNode(language),
CallStrategy.ALWAYS_DIRECT,
new ArgumentDefinition(0, "this", ArgumentDefinition.ExecutionMode.EXECUTE),
new ArgumentDefinition(1, "target", ArgumentDefinition.ExecutionMode.EXECUTE),
new ArgumentDefinition(2, "method_name", ArgumentDefinition.ExecutionMode.EXECUTE),
new ArgumentDefinition(3, "arguments", ArgumentDefinition.ExecutionMode.EXECUTE));
}
/**
* Executes the node.
*
* @param frame current execution frame.
* @return the result of converting input into a string.
*/
@Override
public Stateful execute(VirtualFrame frame) {
Object[] args = Function.ArgumentsHelper.getPositionalArguments(frame.getArguments());
Object callable = args[1];
Object state = Function.ArgumentsHelper.getState(frame.getArguments());
Object execute(Object _this, Object target, String name, Vector arguments) {
try {
String method = TypesGen.expectString(args[2]);
Object[] arguments = TypesGen.expectVector(args[3]).getItems();
Object res = library.invokeMember(callable, method, arguments);
return new Stateful(state, res);
return library.invokeMember(target, name, arguments.getItems());
} catch (UnsupportedMessageException
| ArityException
| UnsupportedTypeException
| UnexpectedResultException
| UnknownIdentifierException e) {
err.enter();
throw new PanicException(e.getMessage(), this);
}
}
/**
* Returns a language-specific name for this node.
*
* @return the name of this node
*/
@Override
public String getName() {
return "Polyglot.invoke";
}
}

View File

@ -2,62 +2,28 @@ package org.enso.interpreter.node.expression.builtin.interop.java;
import com.oracle.truffle.api.dsl.CachedContext;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.NodeInfo;
import com.oracle.truffle.api.nodes.UnexpectedResultException;
import com.oracle.truffle.api.nodes.Node;
import org.enso.interpreter.Language;
import org.enso.interpreter.node.expression.builtin.BuiltinRootNode;
import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.runtime.Context;
import org.enso.interpreter.runtime.callable.argument.ArgumentDefinition;
import org.enso.interpreter.runtime.callable.function.Function;
import org.enso.interpreter.runtime.callable.function.FunctionSchema.CallStrategy;
import org.enso.interpreter.runtime.error.PanicException;
import org.enso.interpreter.runtime.state.Stateful;
import org.enso.interpreter.runtime.type.TypesGen;
import java.io.File;
@NodeInfo(shortName = "Java.add_to_class_path", description = "Adds a path to the host class path.")
public abstract class AddToClassPathNode extends BuiltinRootNode {
AddToClassPathNode(Language language) {
super(language);
}
@BuiltinMethod(
type = "Java",
name = "add_to_class_path",
description = "Adds a path to the host class path.")
public abstract class AddToClassPathNode extends Node {
/**
* Creates a function wrapping this node.
*
* @param language the current language instance
* @return a function wrapping this node
*/
public static Function makeFunction(Language language) {
return Function.fromBuiltinRootNode(
AddToClassPathNodeGen.create(language),
CallStrategy.ALWAYS_DIRECT,
new ArgumentDefinition(0, "this", ArgumentDefinition.ExecutionMode.EXECUTE),
new ArgumentDefinition(1, "path", ArgumentDefinition.ExecutionMode.EXECUTE));
static AddToClassPathNode build() {
return AddToClassPathNodeGen.create();
}
@Specialization
Stateful doExecute(VirtualFrame frame, @CachedContext(Language.class) Context context) {
try {
String arg =
TypesGen.expectString(
Function.ArgumentsHelper.getPositionalArguments(frame.getArguments())[1]);
Object state = Function.ArgumentsHelper.getState(frame.getArguments());
context.getEnvironment().addToHostClassPath(context.getTruffleFile(new File(arg)));
return new Stateful(state, context.getBuiltins().unit());
} catch (UnexpectedResultException e) {
throw new PanicException(e.getMessage(), this);
}
Object doExecute(Object _this, String path, @CachedContext(Language.class) Context context) {
context.getEnvironment().addToHostClassPath(context.getTruffleFile(new File(path)));
return context.getBuiltins().unit();
}
/**
* Returns a language-specific name for this node.
*
* @return the name of this node
*/
@Override
public String getName() {
return "Java.add_to_class_path";
}
abstract Object execute(Object _this, String path);
}

View File

@ -2,60 +2,21 @@ package org.enso.interpreter.node.expression.builtin.interop.java;
import com.oracle.truffle.api.dsl.CachedContext;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.NodeInfo;
import com.oracle.truffle.api.nodes.UnexpectedResultException;
import com.oracle.truffle.api.nodes.Node;
import org.enso.interpreter.Language;
import org.enso.interpreter.node.expression.builtin.BuiltinRootNode;
import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.runtime.Context;
import org.enso.interpreter.runtime.callable.argument.ArgumentDefinition;
import org.enso.interpreter.runtime.callable.function.Function;
import org.enso.interpreter.runtime.callable.function.FunctionSchema.CallStrategy;
import org.enso.interpreter.runtime.error.PanicException;
import org.enso.interpreter.runtime.state.Stateful;
import org.enso.interpreter.runtime.type.TypesGen;
@NodeInfo(shortName = "Java.lookup_class", description = "Looks up a Java symbol.")
public abstract class LookupClassNode extends BuiltinRootNode {
LookupClassNode(Language language) {
super(language);
}
/**
* Creates a function wrapping this node.
*
* @param language the current language instance
* @return a function wrapping this node
*/
public static Function makeFunction(Language language) {
return Function.fromBuiltinRootNode(
LookupClassNodeGen.create(language),
CallStrategy.ALWAYS_DIRECT,
new ArgumentDefinition(0, "this", ArgumentDefinition.ExecutionMode.EXECUTE),
new ArgumentDefinition(1, "name", ArgumentDefinition.ExecutionMode.EXECUTE));
@BuiltinMethod(type = "Java", name = "lookup_class", description = "Looks up a Java symbol.")
public abstract class LookupClassNode extends Node {
static LookupClassNode build() {
return LookupClassNodeGen.create();
}
@Specialization
Stateful doExecute(VirtualFrame frame, @CachedContext(Language.class) Context ctx) {
try {
String arg =
TypesGen.expectString(
Function.ArgumentsHelper.getPositionalArguments(frame.getArguments())[1]);
Object state = Function.ArgumentsHelper.getState(frame.getArguments());
Object res = ctx.getEnvironment().lookupHostSymbol(arg);
return new Stateful(state, res);
} catch (UnexpectedResultException e) {
throw new PanicException(e.getMessage(), this);
}
Object doExecute(Object _this, String name, @CachedContext(Language.class) Context ctx) {
return ctx.getEnvironment().lookupHostSymbol(name);
}
/**
* Returns a language-specific name for this node.
*
* @return the name of this node
*/
@Override
public String getName() {
return "Java.lookup_class";
}
abstract Object execute(Object _this, String name);
}

View File

@ -3,59 +3,27 @@ package org.enso.interpreter.node.expression.builtin.io;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.dsl.CachedContext;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.NodeInfo;
import com.oracle.truffle.api.nodes.Node;
import java.io.PrintStream;
import org.enso.interpreter.Language;
import org.enso.interpreter.node.expression.builtin.BuiltinRootNode;
import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.runtime.Context;
import org.enso.interpreter.runtime.callable.argument.ArgumentDefinition;
import org.enso.interpreter.runtime.callable.argument.ArgumentDefinition.ExecutionMode;
import org.enso.interpreter.runtime.callable.function.Function;
import org.enso.interpreter.runtime.callable.function.FunctionSchema.CallStrategy;
import org.enso.interpreter.runtime.state.Stateful;
@NodeInfo(shortName = "IO.print_err", description = "Prints its argument to standard error.")
public abstract class PrintErrNode extends BuiltinRootNode {
PrintErrNode(Language language) {
super(language);
@BuiltinMethod(
type = "IO",
name = "print_err",
description = "Prints its argument to standard error.")
public abstract class PrintErrNode extends Node {
static PrintErrNode build() {
return PrintErrNodeGen.create();
}
abstract Object execute(Object _this, Object message);
@Specialization
Stateful doPrint(VirtualFrame frame, @CachedContext(Language.class) Context ctx) {
print(ctx.getErr(), Function.ArgumentsHelper.getPositionalArguments(frame.getArguments())[1]);
Object state = Function.ArgumentsHelper.getState(frame.getArguments());
return new Stateful(state, ctx.getUnit().newInstance());
}
@TruffleBoundary
private void print(PrintStream err, Object object) {
err.println(object);
}
/**
* Creates a {@link Function} object ignoring its first argument and printing the second to the
* standard error stream.
*
* @param language the current {@link Language} instance
* @return a {@link Function} object wrapping the behavior of this node
*/
public static Function makeFunction(Language language) {
return Function.fromBuiltinRootNode(
PrintErrNodeGen.create(language),
CallStrategy.ALWAYS_DIRECT,
new ArgumentDefinition(0, "this", ExecutionMode.EXECUTE),
new ArgumentDefinition(1, "value", ExecutionMode.EXECUTE));
}
/**
* Gets the source-level name of this node.
*
* @return the source-level name of this node
*/
@Override
public String getName() {
return "IO.print_err";
Object doPrint(Object self, Object message, @CachedContext(Language.class) Context ctx) {
ctx.getErr().println(message);
return ctx.getUnit().newInstance();
}
}

View File

@ -1,45 +1,42 @@
package org.enso.interpreter.node.expression.builtin.io;
import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.dsl.CachedContext;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.NodeInfo;
import com.oracle.truffle.api.nodes.Node;
import java.io.PrintStream;
import org.enso.interpreter.Language;
import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.dsl.MonadicState;
import org.enso.interpreter.node.callable.InvokeCallableNode;
import org.enso.interpreter.node.expression.builtin.BuiltinRootNode;
import org.enso.interpreter.runtime.Context;
import org.enso.interpreter.runtime.callable.UnresolvedSymbol;
import org.enso.interpreter.runtime.callable.argument.ArgumentDefinition;
import org.enso.interpreter.runtime.callable.argument.CallArgumentInfo;
import org.enso.interpreter.runtime.callable.function.Function;
import org.enso.interpreter.runtime.callable.function.FunctionSchema;
import org.enso.interpreter.runtime.scope.ModuleScope;
import org.enso.interpreter.runtime.state.Stateful;
/** Allows for printing arbitrary values to the standard output. */
@NodeInfo(shortName = "IO.println", description = "Prints its argument to standard out.")
public abstract class PrintlnNode extends BuiltinRootNode {
private final UnresolvedSymbol toTextSym;
@BuiltinMethod(type = "IO", name = "println", description = "Prints its argument to standard out.")
public abstract class PrintlnNode extends Node {
private @Child InvokeCallableNode invokeCallableNode =
InvokeCallableNode.build(
new CallArgumentInfo[] {new CallArgumentInfo()},
InvokeCallableNode.DefaultsExecutionMode.EXECUTE,
InvokeCallableNode.ArgumentsExecutionMode.PRE_EXECUTED);
PrintlnNode(Language language, ModuleScope scope) {
super(language);
toTextSym = UnresolvedSymbol.build("to_text", scope);
}
abstract Stateful execute(
VirtualFrame frame, @MonadicState Object state, Object _this, Object message);
@Specialization
Stateful doPrint(VirtualFrame frame, @CachedContext(Language.class) Context ctx) {
Object in = Function.ArgumentsHelper.getPositionalArguments(frame.getArguments())[1];
Object state = Function.ArgumentsHelper.getState(frame.getArguments());
Stateful str = invokeCallableNode.execute(toTextSym, frame, state, new Object[] {in});
Stateful doPrint(
VirtualFrame frame,
Object state,
Object self,
Object message,
@CachedContext(Language.class) Context ctx,
@Cached("buildSymbol(ctx)") UnresolvedSymbol symbol) {
Stateful str = invokeCallableNode.execute(symbol, frame, state, new Object[] {message});
print(ctx.getOut(), str.getValue());
return new Stateful(str.getState(), ctx.getUnit().newInstance());
}
@ -48,28 +45,11 @@ public abstract class PrintlnNode extends BuiltinRootNode {
out.println(str);
}
/**
* Creates a {@link Function} object ignoring its first argument and printing the second to the
* standard output.
*
* @param language the current {@link Language} instance
* @return a {@link Function} object wrapping the behavior of this node
*/
public static Function makeFunction(Language language, ModuleScope scope) {
return Function.fromBuiltinRootNode(
PrintlnNodeGen.create(language, scope),
FunctionSchema.CallStrategy.ALWAYS_DIRECT,
new ArgumentDefinition(0, "this", ArgumentDefinition.ExecutionMode.EXECUTE),
new ArgumentDefinition(1, "value", ArgumentDefinition.ExecutionMode.EXECUTE));
UnresolvedSymbol buildSymbol(Context ctx) {
return UnresolvedSymbol.build("to_text", ctx.getBuiltins().getScope());
}
/**
* Gets the source-level name of this node.
*
* @return the source-level name of the node
*/
@Override
public String getName() {
return "IO.println";
static PrintlnNode build() {
return PrintlnNodeGen.create();
}
}

View File

@ -3,63 +3,28 @@ package org.enso.interpreter.node.expression.builtin.io;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.dsl.CachedContext;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.NodeInfo;
import java.io.BufferedReader;
import com.oracle.truffle.api.nodes.Node;
import java.io.IOException;
import org.enso.interpreter.Language;
import org.enso.interpreter.node.expression.builtin.BuiltinRootNode;
import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.runtime.Context;
import org.enso.interpreter.runtime.callable.argument.ArgumentDefinition;
import org.enso.interpreter.runtime.callable.argument.ArgumentDefinition.ExecutionMode;
import org.enso.interpreter.runtime.callable.function.Function;
import org.enso.interpreter.runtime.callable.function.FunctionSchema.CallStrategy;
import org.enso.interpreter.runtime.error.RuntimeError;
import org.enso.interpreter.runtime.state.Stateful;
@NodeInfo(shortName = "IO.readln", description = "Reads a line from standard in.")
public abstract class ReadlnNode extends BuiltinRootNode {
public ReadlnNode(Language language) {
super(language);
@BuiltinMethod(type = "IO", name = "readln", description = "Reads a line from standard in.")
public abstract class ReadlnNode extends Node {
static ReadlnNode build() {
return ReadlnNodeGen.create();
}
abstract Object execute(Object _this);
@Specialization
Stateful doRead(VirtualFrame frame, @CachedContext(Language.class) Context ctx) {
return read(ctx.getIn(), Function.ArgumentsHelper.getState(frame.getArguments()));
}
@TruffleBoundary
private Stateful read(BufferedReader in, Object state) {
Object doRead(Object _this, @CachedContext(Language.class) Context ctx) {
try {
String str = in.readLine();
return new Stateful(state, str);
return ctx.getIn().readLine();
} catch (IOException e) {
return new Stateful(state, new RuntimeError("Empty input stream."));
return new RuntimeError("Empty input stream.");
}
}
/**
* Creates a {@link Function} object ignoring its first argument and reading from the standard
* input stream.
*
* @param language the current {@link Language} instance
* @return a {@link Function} object wrapping the behavior of this node
*/
public static Function makeFunction(Language language) {
return Function.fromBuiltinRootNode(
ReadlnNodeGen.create(language),
CallStrategy.ALWAYS_DIRECT,
new ArgumentDefinition(0, "this", ExecutionMode.EXECUTE));
}
/**
* Gets the source-level name of this node.
*
* @return the source-level name of the node
*/
@Override
public String getName() {
return "IO.readln";
}
}

View File

@ -1,51 +1,11 @@
package org.enso.interpreter.node.expression.builtin.number;
import com.oracle.truffle.api.nodes.NodeInfo;
import org.enso.interpreter.Language;
import org.enso.interpreter.runtime.callable.argument.ArgumentDefinition;
import org.enso.interpreter.runtime.callable.function.Function;
import org.enso.interpreter.runtime.callable.function.FunctionSchema.CallStrategy;
import com.oracle.truffle.api.nodes.Node;
import org.enso.interpreter.dsl.BuiltinMethod;
/** An implementation of the operator + for numbers. */
@NodeInfo(shortName = "Number.+", description = "Addition on numbers.")
public class AddNode extends NumberBinaryOpMethod {
private AddNode(Language language) {
super(language);
}
/**
* Creates a two-argument function wrapping this node.
*
* @param language the current language instance
* @return a function wrapping this node
*/
public static Function makeFunction(Language language) {
return Function.fromBuiltinRootNode(
new AddNode(language),
CallStrategy.ALWAYS_DIRECT,
new ArgumentDefinition(0, "this", ArgumentDefinition.ExecutionMode.EXECUTE),
new ArgumentDefinition(1, "that", ArgumentDefinition.ExecutionMode.EXECUTE));
}
/**
* Adds the two operands to this method.
*
* @param thisArg the left operand (this)
* @param thatArg the right operand (that)
* @return the result of adding {@code thisArg} to {@code thatArg}
*/
@Override
protected long op(long thisArg, long thatArg) {
return thisArg + thatArg;
}
/**
* Returns a language-specific name for this node.
*
* @return the name of this node
*/
@Override
public String getName() {
return "Number.+";
@BuiltinMethod(type = "Number", name = "+", description = "Addition on numbers.")
public class AddNode extends Node {
long execute(long _this, long that) {
return _this + that;
}
}

View File

@ -1,50 +1,11 @@
package org.enso.interpreter.node.expression.builtin.number;
import com.oracle.truffle.api.nodes.NodeInfo;
import org.enso.interpreter.Language;
import org.enso.interpreter.runtime.callable.argument.ArgumentDefinition;
import org.enso.interpreter.runtime.callable.function.Function;
import org.enso.interpreter.runtime.callable.function.FunctionSchema.CallStrategy;
import com.oracle.truffle.api.nodes.Node;
import org.enso.interpreter.dsl.BuiltinMethod;
@NodeInfo(shortName = "Number./", description = "Division for numbers.")
public class DivideNode extends NumberBinaryOpMethod {
public DivideNode(Language language) {
super(language);
}
/**
* Creates a two-argument function wrapping this node.
*
* @param language the current language instance
* @return a function wrapping this node
*/
public static Function makeFunction(Language language) {
return Function.fromBuiltinRootNode(
new DivideNode(language),
CallStrategy.ALWAYS_DIRECT,
new ArgumentDefinition(0, "this", ArgumentDefinition.ExecutionMode.EXECUTE),
new ArgumentDefinition(1, "that", ArgumentDefinition.ExecutionMode.EXECUTE));
}
/**
* The result of dividing this node's operands
*
* @param thisArg the left operand (this)
* @param thatArg the right operand (that)
* @return the result of dividing {@code thisArg} by {@code thatArg}
*/
@Override
protected long op(long thisArg, long thatArg) {
return thisArg / thatArg;
}
/**
* Returns a language-specific name for this node.
*
* @return the name of this node
*/
@Override
public String getName() {
return "Number./";
@BuiltinMethod(type = "Number", name = "/", description = "Division for numbers.")
public class DivideNode extends Node {
long execute(long _this, long that) {
return _this / that;
}
}

View File

@ -1,75 +1,11 @@
package org.enso.interpreter.node.expression.builtin.number;
import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.NodeInfo;
import com.oracle.truffle.api.profiles.BranchProfile;
import org.enso.interpreter.Language;
import org.enso.interpreter.node.expression.builtin.BuiltinRootNode;
import org.enso.interpreter.runtime.callable.argument.ArgumentDefinition;
import org.enso.interpreter.runtime.callable.atom.AtomConstructor;
import org.enso.interpreter.runtime.callable.function.Function;
import org.enso.interpreter.runtime.callable.function.FunctionSchema.CallStrategy;
import org.enso.interpreter.runtime.error.TypeError;
import org.enso.interpreter.runtime.scope.ModuleScope;
import org.enso.interpreter.runtime.state.Stateful;
import org.enso.interpreter.runtime.type.TypesGen;
import com.oracle.truffle.api.nodes.Node;
import org.enso.interpreter.dsl.BuiltinMethod;
@NodeInfo(shortName = "Number.==", description = "Equality on numbers.")
public class EqualsNode extends BuiltinRootNode {
private EqualsNode(Language language) {
super(language);
}
private @CompilerDirectives.CompilationFinal AtomConstructor tru;
private @CompilerDirectives.CompilationFinal AtomConstructor fls;
private final BranchProfile thatOpBadTypeProfile = BranchProfile.create();
/**
* Creates a two-argument function wrapping this node.
*
* @param language the current language instance
* @return a function wrapping this node
*/
public static Function makeFunction(Language language) {
return Function.fromBuiltinRootNode(
new EqualsNode(language),
CallStrategy.ALWAYS_DIRECT,
new ArgumentDefinition(0, "this", ArgumentDefinition.ExecutionMode.EXECUTE),
new ArgumentDefinition(1, "that", ArgumentDefinition.ExecutionMode.EXECUTE));
}
/**
* Executes the node.
*
* @param frame current execution frame
* @return whether or not the input arguments are equal
*/
@Override
public Stateful execute(VirtualFrame frame) {
long thisArg =
TypesGen.asLong(Function.ArgumentsHelper.getPositionalArguments(frame.getArguments())[0]);
Object thatArg = Function.ArgumentsHelper.getPositionalArguments(frame.getArguments())[1];
if (TypesGen.isLong(thatArg)) {
long thatArgAsLong = TypesGen.asLong(thatArg);
Object state = Function.ArgumentsHelper.getState(frame.getArguments());
return new Stateful(state, thisArg == thatArgAsLong);
} else {
thatOpBadTypeProfile.enter();
throw new TypeError("Unexpected type for `that` operand in " + getName(), this);
}
}
/**
* Returns a language-specific name for this node.
*
* @return the name of this node
*/
@Override
public String getName() {
return "Number.==";
@BuiltinMethod(type = "Number", name = "==", description = "Equality on numbers.")
public class EqualsNode extends Node {
boolean execute(long _this, long that) {
return _this == that;
}
}

View File

@ -1,50 +1,11 @@
package org.enso.interpreter.node.expression.builtin.number;
import com.oracle.truffle.api.nodes.NodeInfo;
import org.enso.interpreter.Language;
import org.enso.interpreter.runtime.callable.argument.ArgumentDefinition;
import org.enso.interpreter.runtime.callable.function.Function;
import org.enso.interpreter.runtime.callable.function.FunctionSchema.CallStrategy;
import com.oracle.truffle.api.nodes.Node;
import org.enso.interpreter.dsl.BuiltinMethod;
@NodeInfo(shortName = "Number.%", description = "Mod for numbers.")
public class ModNode extends NumberBinaryOpMethod {
private ModNode(Language language) {
super(language);
}
/**
* Creates a two-argument function wrapping this node.
*
* @param language the current language instance
* @return a function wrapping this node
*/
public static Function makeFunction(Language language) {
return Function.fromBuiltinRootNode(
new ModNode(language),
CallStrategy.ALWAYS_DIRECT,
new ArgumentDefinition(0, "this", ArgumentDefinition.ExecutionMode.EXECUTE),
new ArgumentDefinition(1, "that", ArgumentDefinition.ExecutionMode.EXECUTE));
}
/**
* Calculates the remainder from dividing the node's operands.
*
* @param thisArg the left operand (this)
* @param thatArg the right operand (that)
* @return the remainder when dividing {@code thisArg} by {@code thatArg}
*/
@Override
protected long op(long thisArg, long thatArg) {
return thisArg % thatArg;
}
/**
* Returns a language-specific name for this node.
*
* @return the name of this node
*/
@Override
public String getName() {
return "Number.%";
@BuiltinMethod(type = "Number", name = "%", description = "Modulo operation for numbers.")
public class ModNode extends Node {
long execute(long _this, long that) {
return _this % that;
}
}

View File

@ -1,50 +1,11 @@
package org.enso.interpreter.node.expression.builtin.number;
import com.oracle.truffle.api.nodes.NodeInfo;
import org.enso.interpreter.Language;
import org.enso.interpreter.runtime.callable.argument.ArgumentDefinition;
import org.enso.interpreter.runtime.callable.function.Function;
import org.enso.interpreter.runtime.callable.function.FunctionSchema.CallStrategy;
import com.oracle.truffle.api.nodes.Node;
import org.enso.interpreter.dsl.BuiltinMethod;
@NodeInfo(shortName = "Number.*", description = "Multiplication on numbers.")
public class MultiplyNode extends NumberBinaryOpMethod {
private MultiplyNode(Language language) {
super(language);
}
/**
* Creates a two-argument function wrapping this node.
*
* @param language the current language instance
* @return a function wrapping this node
*/
public static Function makeFunction(Language language) {
return Function.fromBuiltinRootNode(
new MultiplyNode(language),
CallStrategy.ALWAYS_DIRECT,
new ArgumentDefinition(0, "this", ArgumentDefinition.ExecutionMode.EXECUTE),
new ArgumentDefinition(1, "that", ArgumentDefinition.ExecutionMode.EXECUTE));
}
/**
* Multiplies this method's two operands.
*
* @param thisArg the left operand (this)
* @param thatArg the right operand (that)
* @return the result of multiplying {@code thisArg} by {@code thatArg}
*/
@Override
protected long op(long thisArg, long thatArg) {
return thisArg * thatArg;
}
/**
* Returns a language-specific name for this node.
*
* @return the name of this node
*/
@Override
public String getName() {
return "Number.*";
@BuiltinMethod(type = "Number", name = "*", description = "Multiplication on numbers.")
public class MultiplyNode extends Node {
long execute(long _this, long that) {
return _this * that;
}
}

View File

@ -1,57 +1,11 @@
package org.enso.interpreter.node.expression.builtin.number;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.NodeInfo;
import org.enso.interpreter.Language;
import org.enso.interpreter.node.expression.builtin.BuiltinRootNode;
import org.enso.interpreter.runtime.callable.argument.ArgumentDefinition;
import org.enso.interpreter.runtime.callable.function.Function;
import org.enso.interpreter.runtime.callable.function.FunctionSchema.CallStrategy;
import org.enso.interpreter.runtime.state.Stateful;
import org.enso.interpreter.runtime.type.TypesGen;
import com.oracle.truffle.api.nodes.Node;
import org.enso.interpreter.dsl.BuiltinMethod;
@NodeInfo(shortName = "Number.negate", description = "Negation for numbers.")
public class NegateNode extends BuiltinRootNode {
private NegateNode(Language language) {
super(language);
}
/**
* Creates a one-argument function wrapping this node.
*
* @param language the current language instance
* @return a function wrapping this node
*/
public static Function makeFunction(Language language) {
return Function.fromBuiltinRootNode(
new NegateNode(language),
CallStrategy.ALWAYS_DIRECT,
new ArgumentDefinition(0, "this", ArgumentDefinition.ExecutionMode.EXECUTE));
}
/**
* Executes this node.
*
* @param frame current execution frame
* @return the result of negating the function argument
*/
@Override
public Stateful execute(VirtualFrame frame) {
long thisArg =
TypesGen.asLong(Function.ArgumentsHelper.getPositionalArguments(frame.getArguments())[0]);
Object state = Function.ArgumentsHelper.getState(frame.getArguments());
return new Stateful(state, -thisArg);
}
/**
* Returns a language-specific name for this node.
*
* @return the name of this node
*/
@Override
public String getName() {
return "Number.negate";
@BuiltinMethod(type = "Number", name = "negate", description = "Negation for numbers.")
public class NegateNode extends Node {
long execute(long _this) {
return -_this;
}
}

View File

@ -1,78 +0,0 @@
package org.enso.interpreter.node.expression.builtin.number;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.NodeInfo;
import com.oracle.truffle.api.profiles.BranchProfile;
import org.enso.interpreter.Language;
import org.enso.interpreter.node.expression.builtin.BuiltinRootNode;
import org.enso.interpreter.runtime.callable.function.Function;
import org.enso.interpreter.runtime.error.TypeError;
import org.enso.interpreter.runtime.state.Stateful;
import org.enso.interpreter.runtime.type.TypesGen;
@NodeInfo(shortName = "Number.BinOp", description = "An abstract class for binary ops on numbers.")
public abstract class NumberBinaryOpMethod extends BuiltinRootNode {
private final BranchProfile thatOpBadTypeProfile = BranchProfile.create();
/**
* Constructs an instance of this node.
*
* @param language the language instance for which the node is being constructed
*/
protected NumberBinaryOpMethod(Language language) {
super(language);
}
/**
* Executes this node.
*
* @param frame current execution frame
* @return the result of performing `op` on the operands
*/
@Override
public final Stateful execute(VirtualFrame frame) {
// Note [Safe Casts in Execute]
long thisArg =
TypesGen.asLong(Function.ArgumentsHelper.getPositionalArguments(frame.getArguments())[0]);
Object thatArg = Function.ArgumentsHelper.getPositionalArguments(frame.getArguments())[1];
if (TypesGen.isLong(thatArg)) {
long thatArgAsLong = TypesGen.asLong(thatArg);
Object state = Function.ArgumentsHelper.getState(frame.getArguments());
return new Stateful(state, op(thisArg, thatArgAsLong));
} else {
thatOpBadTypeProfile.enter();
throw new TypeError("Unexpected type for `that` operand in " + getName(), this);
}
}
/* Note [Safe Casts in Execute]
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* It is safe to perform this cast here as the type of that argument has already been checked by
* the method dispatch mechanism. If this `execute` method is being called, we know that the
* `this` argument must be of the correct type.
*
* This does not hold for any remaining arguments, and as such they must be checked.
*/
/**
* The binary operation embodied by the subclass of this node.
*
* @param thisArg the left operand (this)
* @param thatArg the right operand (that)
* @return the result of {@code this `op` that}
*/
protected abstract long op(long thisArg, long thatArg);
/**
* Returns a language-specific name for this node.
*
* @return the name of this node
*/
@Override
public String getName() {
return "Number.BinOp";
}
}

View File

@ -1,50 +1,11 @@
package org.enso.interpreter.node.expression.builtin.number;
import com.oracle.truffle.api.nodes.NodeInfo;
import org.enso.interpreter.Language;
import org.enso.interpreter.runtime.callable.argument.ArgumentDefinition;
import org.enso.interpreter.runtime.callable.function.Function;
import org.enso.interpreter.runtime.callable.function.FunctionSchema.CallStrategy;
import com.oracle.truffle.api.nodes.Node;
import org.enso.interpreter.dsl.BuiltinMethod;
@NodeInfo(shortName = "Number.-", description = "Subtraction on numbers.")
public class SubtractNode extends NumberBinaryOpMethod {
private SubtractNode(Language language) {
super(language);
}
/**
* Creates a two-argument function wrapping this node.
*
* @param language the current language instance
* @return a function wrapping this node
*/
public static Function makeFunction(Language language) {
return Function.fromBuiltinRootNode(
new SubtractNode(language),
CallStrategy.ALWAYS_DIRECT,
new ArgumentDefinition(0, "this", ArgumentDefinition.ExecutionMode.EXECUTE),
new ArgumentDefinition(1, "that", ArgumentDefinition.ExecutionMode.EXECUTE));
}
/**
* Subtracts this method's two operands.
*
* @param thisArg the left operand (this)
* @param thatArg the right operand (that)
* @return the result of subtracting {@code thatArg} from {@code thisArg}
*/
@Override
protected long op(long thisArg, long thatArg) {
return thisArg - thatArg;
}
/**
* Returns a language-specific name for this node.
*
* @return the name of this node
*/
@Override
public String getName() {
return "Number.-";
@BuiltinMethod(type = "Number", name = "-", description = "Subtraction on numbers.")
public class SubtractNode extends Node {
long execute(long _this, long that) {
return _this - that;
}
}

View File

@ -1,53 +1,15 @@
package org.enso.interpreter.node.expression.builtin.state;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.NodeInfo;
import org.enso.interpreter.Language;
import org.enso.interpreter.node.expression.builtin.BuiltinRootNode;
import org.enso.interpreter.runtime.callable.argument.ArgumentDefinition;
import org.enso.interpreter.runtime.callable.function.Function;
import org.enso.interpreter.runtime.callable.function.FunctionSchema;
import org.enso.interpreter.runtime.state.Stateful;
import com.oracle.truffle.api.nodes.Node;
import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.dsl.MonadicState;
/** Root node for the builtin State.get function. */
@NodeInfo(shortName = "State.get", description = "Root node for the builtin State.get function")
public class GetStateNode extends BuiltinRootNode {
private GetStateNode(Language language) {
super(language);
}
/**
* Executes the function by accessing the state parameter and returning it.
*
* @param frame current execution frame
* @return the current state value without modifying the state
*/
@Override
public Stateful execute(VirtualFrame frame) {
Object state = Function.ArgumentsHelper.getState(frame.getArguments());
return new Stateful(state, state);
}
/**
* Creates a single-argument function wrapping this node.
*
* @param language current language instance
* @return a function wrapping this node
*/
public static Function makeFunction(Language language) {
return Function.fromBuiltinRootNode(
new GetStateNode(language),
FunctionSchema.CallStrategy.ALWAYS_DIRECT,
new ArgumentDefinition(0, "this", ArgumentDefinition.ExecutionMode.EXECUTE));
}
/**
* Gets the source-level name of this node.
*
* @return the source-level name of the node
*/
@Override
public String getName() {
return "State.get";
@BuiltinMethod(
type = "State",
name = "get",
description = "Returns the current value of monadic state.")
public class GetStateNode extends Node {
Object execute(@MonadicState Object state, Object _this) {
return state;
}
}

View File

@ -1,55 +1,13 @@
package org.enso.interpreter.node.expression.builtin.state;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.NodeInfo;
import org.enso.interpreter.Language;
import org.enso.interpreter.node.expression.builtin.BuiltinRootNode;
import org.enso.interpreter.runtime.callable.argument.ArgumentDefinition;
import org.enso.interpreter.runtime.callable.function.Function;
import org.enso.interpreter.runtime.callable.function.FunctionSchema;
import com.oracle.truffle.api.nodes.Node;
import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.dsl.MonadicState;
import org.enso.interpreter.runtime.state.Stateful;
/** Root node for the builtin State.put function. */
@NodeInfo(shortName = "State.put", description = "Root node for the builtin State.put function")
public class PutStateNode extends BuiltinRootNode {
private PutStateNode(Language language) {
super(language);
}
/**
* Executes by taking the desired state value from the second function argument and setting it as
* the new state.
*
* @param frame current execution frame
* @return The new state value and a modification setting the state to the same value
*/
@Override
public Stateful execute(VirtualFrame frame) {
Object newState = Function.ArgumentsHelper.getPositionalArguments(frame.getArguments())[1];
return new Stateful(newState, newState);
}
/**
* Creates a two-argument function wrapping this node.
*
* @param language current language instance
* @return a function wrapping this node
*/
public static Function makeFunction(Language language) {
return Function.fromBuiltinRootNode(
new PutStateNode(language),
FunctionSchema.CallStrategy.ALWAYS_DIRECT,
new ArgumentDefinition(0, "this", ArgumentDefinition.ExecutionMode.EXECUTE),
new ArgumentDefinition(1, "newState", ArgumentDefinition.ExecutionMode.EXECUTE));
}
/**
* Gets the source-level name of this node.
*
* @return the source-level name of the node
*/
@Override
public String getName() {
return "State.put";
@BuiltinMethod(type = "State", name = "put", description = "Updates the value of monadic state.")
public class PutStateNode extends Node {
Stateful execute(@MonadicState Object state, Object _this, Object new_state) {
return new Stateful(new_state, state);
}
}

View File

@ -1,69 +1,18 @@
package org.enso.interpreter.node.expression.builtin.state;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.NodeInfo;
import com.oracle.truffle.api.profiles.ConditionProfile;
import org.enso.interpreter.Language;
import com.oracle.truffle.api.nodes.Node;
import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.node.callable.thunk.ThunkExecutorNode;
import org.enso.interpreter.node.expression.builtin.BuiltinRootNode;
import org.enso.interpreter.runtime.callable.argument.ArgumentDefinition;
import org.enso.interpreter.runtime.callable.function.Function;
import org.enso.interpreter.runtime.callable.function.FunctionSchema;
import org.enso.interpreter.runtime.state.Stateful;
import org.enso.interpreter.runtime.type.TypesGen;
/** Root for the builtin State.run function. */
@NodeInfo(shortName = "State.run", description = "Root for the builtin State.run function")
public class RunStateNode extends BuiltinRootNode {
private RunStateNode(Language language) {
super(language);
}
import org.enso.interpreter.runtime.callable.argument.Thunk;
@BuiltinMethod(
type = "State",
name = "run",
description = "Runs a stateful computation in a local state environment.")
public class RunStateNode extends Node {
private @Child ThunkExecutorNode thunkExecutorNode = ThunkExecutorNode.build();
private final ConditionProfile thunksProfile = ConditionProfile.createCountingProfile();
/**
* Runs a stateful computation ({@link org.enso.interpreter.runtime.callable.argument.Thunk}) with
* a local state value, without modifying the caller state.
*
* <p>Assumes the local state value is the second argument, while the stateful computation is the
* third argument.
*
* @param frame current execution frame
* @return the result of running the stateful computation with the desired initial state
*/
@Override
public Stateful execute(VirtualFrame frame) {
Object localState = Function.ArgumentsHelper.getPositionalArguments(frame.getArguments())[1];
Object maybeThunk = Function.ArgumentsHelper.getPositionalArguments(frame.getArguments())[2];
Object state = Function.ArgumentsHelper.getState(frame.getArguments());
if (thunksProfile.profile(TypesGen.isThunk(maybeThunk))) {
return new Stateful(
state,
thunkExecutorNode.executeThunk(TypesGen.asThunk(maybeThunk), localState, false).getValue());
} else {
return new Stateful(state, maybeThunk);
}
}
/**
* Creates a three-argument function wrapping this node.
*
* @param language current language instance
* @return a function wrapping this node
*/
public static Function makeFunction(Language language) {
return Function.fromBuiltinRootNode(
new RunStateNode(language),
FunctionSchema.CallStrategy.ALWAYS_DIRECT,
new ArgumentDefinition(0, "this", ArgumentDefinition.ExecutionMode.EXECUTE),
new ArgumentDefinition(1, "state", ArgumentDefinition.ExecutionMode.EXECUTE),
new ArgumentDefinition(
2, "statefulComputation", ArgumentDefinition.ExecutionMode.PASS_THUNK));
}
@Override
public String getName() {
return "State.run";
Object execute(Object _this, Object local_state, Thunk computation) {
return thunkExecutorNode.executeThunk(computation, local_state, false).getValue();
}
}

View File

@ -1,52 +1,16 @@
package org.enso.interpreter.node.expression.builtin.system;
import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.NodeInfo;
import org.enso.interpreter.Language;
import org.enso.interpreter.node.expression.builtin.BuiltinRootNode;
import org.enso.interpreter.runtime.callable.argument.ArgumentDefinition;
import org.enso.interpreter.runtime.callable.function.Function;
import org.enso.interpreter.runtime.callable.function.FunctionSchema;
import org.enso.interpreter.runtime.state.Stateful;
@NodeInfo(shortName = "System.nano_time", description = "Gets the nanosecond resolution system time.")
public final class NanoTimeNode extends BuiltinRootNode {
private NanoTimeNode(Language language) {
super(language);
}
/**
* Creates a {@link Function} object wrapping this object.
*
* @param language the current {@link Language} instance
* @return a {@link Function} object wrapping the behavior of this node
*/
public static Function makeFunction(Language language) {
return Function.fromBuiltinRootNode(
new NanoTimeNode(language),
FunctionSchema.CallStrategy.ALWAYS_DIRECT,
new ArgumentDefinition(0, "this", ArgumentDefinition.ExecutionMode.EXECUTE));
}
@Override
public Stateful execute(VirtualFrame frame) {
Object state = Function.ArgumentsHelper.getState(frame.getArguments());
return new Stateful(state, getNanoTime());
}
import com.oracle.truffle.api.nodes.Node;
import org.enso.interpreter.dsl.BuiltinMethod;
@BuiltinMethod(
type = "System",
name = "nano_time",
description = "Gets the nanosecond resolution system time.")
public final class NanoTimeNode extends Node {
@CompilerDirectives.TruffleBoundary
private long getNanoTime() {
long execute(Object _this) {
return System.nanoTime();
}
/**
* Gets the source-level name of this node.
*
* @return the source-level name of the node
*/
@Override
public String getName() {
return "System.nano_time";
}
}

View File

@ -1,63 +1,13 @@
package org.enso.interpreter.node.expression.builtin.text;
import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.NodeInfo;
import com.oracle.truffle.api.profiles.BranchProfile;
import org.enso.interpreter.Language;
import org.enso.interpreter.node.expression.builtin.BuiltinRootNode;
import org.enso.interpreter.runtime.callable.argument.ArgumentDefinition;
import org.enso.interpreter.runtime.callable.function.Function;
import org.enso.interpreter.runtime.callable.function.FunctionSchema.CallStrategy;
import org.enso.interpreter.runtime.error.TypeError;
import org.enso.interpreter.runtime.state.Stateful;
import org.enso.interpreter.runtime.type.TypesGen;
/** An implementation of generic string conversion. */
@NodeInfo(shortName = "Any.to_text", description = "Generic text conversion.")
public class AnyToTextNode extends BuiltinRootNode {
private AnyToTextNode(Language language) {
super(language);
}
/**
* Creates a function wrapping this node.
*
* @param language the current language instance
* @return a function wrapping this node
*/
public static Function makeFunction(Language language) {
return Function.fromBuiltinRootNode(
new AnyToTextNode(language),
CallStrategy.ALWAYS_DIRECT,
new ArgumentDefinition(0, "this", ArgumentDefinition.ExecutionMode.EXECUTE));
}
/**
* Executes the node.
*
* @param frame current execution frame.
* @return the result of converting input into a string.
*/
@Override
public Stateful execute(VirtualFrame frame) {
Object thisArg = Function.ArgumentsHelper.getPositionalArguments(frame.getArguments())[0];
Object state = Function.ArgumentsHelper.getState(frame.getArguments());
return new Stateful(state, toText(thisArg));
}
import com.oracle.truffle.api.nodes.Node;
import org.enso.interpreter.dsl.BuiltinMethod;
@BuiltinMethod(type = "Any", name = "to_text", description = "Generic text conversion.")
public class AnyToTextNode extends Node {
@CompilerDirectives.TruffleBoundary
private String toText(Object txt) {
return txt.toString();
}
/**
* Returns a language-specific name for this node.
*
* @return the name of this node
*/
@Override
public String getName() {
return "Any.to_text";
String execute(Object _this) {
return _this.toString();
}
}

View File

@ -1,69 +1,11 @@
package org.enso.interpreter.node.expression.builtin.text;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.NodeInfo;
import com.oracle.truffle.api.profiles.BranchProfile;
import org.enso.interpreter.Language;
import org.enso.interpreter.node.expression.builtin.BuiltinRootNode;
import org.enso.interpreter.node.expression.builtin.number.NumberBinaryOpMethod;
import org.enso.interpreter.runtime.callable.argument.ArgumentDefinition;
import org.enso.interpreter.runtime.callable.function.Function;
import org.enso.interpreter.runtime.callable.function.FunctionSchema.CallStrategy;
import org.enso.interpreter.runtime.error.TypeError;
import org.enso.interpreter.runtime.state.Stateful;
import org.enso.interpreter.runtime.type.TypesGen;
import com.oracle.truffle.api.nodes.Node;
import org.enso.interpreter.dsl.BuiltinMethod;
/** An implementation of the operator + for strings. */
@NodeInfo(shortName = "Text.+", description = "Text concatenation.")
public class ConcatNode extends BuiltinRootNode {
private final BranchProfile thatOpBadTypeProfile = BranchProfile.create();
private ConcatNode(Language language) {
super(language);
}
/**
* Creates a two-argument function wrapping this node.
*
* @param language the current language instance
* @return a function wrapping this node
*/
public static Function makeFunction(Language language) {
return Function.fromBuiltinRootNode(
new ConcatNode(language),
CallStrategy.ALWAYS_DIRECT,
new ArgumentDefinition(0, "this", ArgumentDefinition.ExecutionMode.EXECUTE),
new ArgumentDefinition(1, "that", ArgumentDefinition.ExecutionMode.EXECUTE));
}
/**
* Executes the node.
*
* @param frame current execution frame.
* @return the result of concatenating the input strings.
*/
@Override
public Stateful execute(VirtualFrame frame) {
String thisArg =
TypesGen.asString(Function.ArgumentsHelper.getPositionalArguments(frame.getArguments())[0]);
Object thatArg = Function.ArgumentsHelper.getPositionalArguments(frame.getArguments())[1];
if (TypesGen.isString(thatArg)) {
Object state = Function.ArgumentsHelper.getState(frame.getArguments());
return new Stateful(state, thisArg + TypesGen.asString(thatArg));
} else {
thatOpBadTypeProfile.enter();
throw new TypeError("Unexpected type for `that` operand in " + getName(), this);
}
}
/**
* Returns a language-specific name for this node.
*
* @return the name of this node
*/
@Override
public String getName() {
return "Text.+";
@BuiltinMethod(type = "Text", name = "+", description = "Text concatenation.")
public class ConcatNode extends Node {
String execute(String _this, String that) {
return _this + that;
}
}

View File

@ -1,61 +1,14 @@
package org.enso.interpreter.node.expression.builtin.text;
import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.NodeInfo;
import org.enso.interpreter.Language;
import org.enso.interpreter.node.expression.builtin.BuiltinRootNode;
import com.oracle.truffle.api.nodes.Node;
import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.runtime.builtin.LanguageEntitySerializer;
import org.enso.interpreter.runtime.callable.argument.ArgumentDefinition;
import org.enso.interpreter.runtime.callable.function.Function;
import org.enso.interpreter.runtime.callable.function.FunctionSchema.CallStrategy;
import org.enso.interpreter.runtime.state.Stateful;
/** An implementation of generic JSON serialization. */
@NodeInfo(shortName = "Any.json_serialize", description = "Generic JSON serialization.")
public class JsonSerializeNode extends BuiltinRootNode {
private JsonSerializeNode(Language language) {
super(language);
}
/**
* Creates a function wrapping this node.
*
* @param language the current language instance
* @return a function wrapping this node
*/
public static Function makeFunction(Language language) {
return Function.fromBuiltinRootNode(
new JsonSerializeNode(language),
CallStrategy.ALWAYS_DIRECT,
new ArgumentDefinition(0, "this", ArgumentDefinition.ExecutionMode.EXECUTE));
}
/**
* Executes the node.
*
* @param frame current execution frame.
* @return the result of converting input into a string.
*/
@Override
public Stateful execute(VirtualFrame frame) {
Object thisArg = Function.ArgumentsHelper.getPositionalArguments(frame.getArguments())[0];
Object state = Function.ArgumentsHelper.getState(frame.getArguments());
return new Stateful(state, serialize(thisArg));
}
@BuiltinMethod(type = "Any", name = "json_serialize", description = "Generic JSON serialization.")
public class JsonSerializeNode extends Node {
@CompilerDirectives.TruffleBoundary
private String serialize(Object obj) {
return LanguageEntitySerializer.serialize(obj);
}
/**
* Returns a language-specific name for this node.
*
* @return the name of this node
*/
@Override
public String getName() {
return "Any.json_serialize";
String execute(Object _this) {
return LanguageEntitySerializer.serialize(_this);
}
}

View File

@ -1,67 +1,27 @@
package org.enso.interpreter.node.expression.builtin.thread;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.NodeInfo;
import com.oracle.truffle.api.profiles.ConditionProfile;
import org.enso.interpreter.Language;
import com.oracle.truffle.api.nodes.Node;
import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.dsl.MonadicState;
import org.enso.interpreter.node.callable.thunk.ThunkExecutorNode;
import org.enso.interpreter.node.expression.builtin.BuiltinRootNode;
import org.enso.interpreter.runtime.callable.argument.ArgumentDefinition;
import org.enso.interpreter.runtime.callable.argument.Thunk;
import org.enso.interpreter.runtime.callable.function.Function;
import org.enso.interpreter.runtime.callable.function.FunctionSchema;
import org.enso.interpreter.runtime.control.ThreadInterruptedException;
import org.enso.interpreter.runtime.state.Stateful;
import org.enso.interpreter.runtime.type.TypesGen;
@NodeInfo(
shortName = "Thread.with_interrupt_handler",
@BuiltinMethod(
type = "Thread",
name = "with_interrupt_handler",
description = "Runs a computation with a handler for thread interrupts.")
public class WithInterruptHandlerNode extends BuiltinRootNode {
private WithInterruptHandlerNode(Language language) {
super(language);
}
public class WithInterruptHandlerNode extends Node {
private @Child ThunkExecutorNode actExecutorNode = ThunkExecutorNode.build();
private @Child ThunkExecutorNode handlerExecutorNode = ThunkExecutorNode.build();
/**
* Executes the function.
*
* @param frame current execution frame.
* @return the result of running the function.
*/
@Override
public Stateful execute(VirtualFrame frame) {
Thunk act = (Thunk) Function.ArgumentsHelper.getPositionalArguments(frame.getArguments())[1];
Thunk handler =
(Thunk) Function.ArgumentsHelper.getPositionalArguments(frame.getArguments())[2];
Object state = Function.ArgumentsHelper.getState(frame.getArguments());
Stateful execute(@MonadicState Object state, Object _this, Thunk action, Thunk interrupt_handler) {
try {
return actExecutorNode.executeThunk(act, state, false);
return actExecutorNode.executeThunk(action, state, false);
} catch (ThreadInterruptedException e) {
handlerExecutorNode.executeThunk(handler, state, false);
handlerExecutorNode.executeThunk(interrupt_handler, state, false);
throw e;
}
}
/**
* Creates a three-argument function wrapping this node.
*
* @param language current language instance
* @return a function wrapping this node
*/
public static Function makeFunction(Language language) {
return Function.fromBuiltinRootNode(
new WithInterruptHandlerNode(language),
FunctionSchema.CallStrategy.ALWAYS_DIRECT,
new ArgumentDefinition(0, "this", ArgumentDefinition.ExecutionMode.EXECUTE),
new ArgumentDefinition(1, "action", ArgumentDefinition.ExecutionMode.PASS_THUNK),
new ArgumentDefinition(2, "handler", ArgumentDefinition.ExecutionMode.PASS_THUNK));
}
@Override
public String getName() {
return "Thread.with_interrupt_handler";
}
}

View File

@ -1,84 +0,0 @@
package org.enso.interpreter.node.expression.debug;
import com.oracle.truffle.api.debug.DebuggerTags;
import com.oracle.truffle.api.dsl.CachedContext;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.instrumentation.GenerateWrapper;
import com.oracle.truffle.api.instrumentation.InstrumentableNode;
import com.oracle.truffle.api.instrumentation.ProbeNode;
import com.oracle.truffle.api.instrumentation.Tag;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.nodes.NodeInfo;
import org.enso.interpreter.Language;
import org.enso.interpreter.runtime.builtin.Builtins;
import org.enso.interpreter.runtime.Context;
import org.enso.interpreter.runtime.state.Stateful;
/** A base node serving as an instrumentable marker. */
@NodeInfo(shortName = "Breakpoint", description = "Instrumentation marker node.")
@GenerateWrapper
public abstract class BreakpointNode extends Node implements InstrumentableNode {
BreakpointNode() {}
/**
* Creates a new instance of this node.
*
* @return a new instance of this node
*/
public static BreakpointNode build() {
return BreakpointNodeGen.create();
}
/**
* Tells Truffle this node is instrumentable.
*
* @return {@code true} this node is always instrumentable.
*/
@Override
public boolean isInstrumentable() {
return true;
}
/**
* Execute this node. Does not do anything interesting, the default implementation returns {@link
* Builtins#unit()}. The behavior and return value of this node are assumed to be injected by
* attached instruments.
*
* @param frame current execution frame
* @param state current value of the monadic state
* @return the result of executing this node
*/
public abstract Stateful execute(VirtualFrame frame, Object state);
@Specialization
Stateful execute(
VirtualFrame frame, Object state, @CachedContext(Language.class) Context context) {
return new Stateful(state, context.getUnit().newInstance());
}
/**
* Informs Truffle about the provided tags.
*
* <p>This node only provides the {@link DebuggerTags.AlwaysHalt} tag.
*
* @param tag the tag to verify
* @return {@code true} if the tag is {@link DebuggerTags.AlwaysHalt}, {@code false} otherwise
*/
@Override
public boolean hasTag(Class<? extends Tag> tag) {
return tag == DebuggerTags.AlwaysHalt.class;
}
/**
* Creates an instrumentable wrapper node for this node.
*
* @param probeNode the probe node to wrap
* @return the wrapper instance wrapping both this and the probe node
*/
@Override
public WrapperNode createWrapper(ProbeNode probeNode) {
return new BreakpointNodeWrapper(this, probeNode);
}
}

View File

@ -20,11 +20,11 @@ public class Bool {
public Bool(Language language, ModuleScope scope) {
bool = new AtomConstructor("Boolean", scope).initializeFields();
scope.registerConstructor(bool);
scope.registerMethod(bool, "if_then_else", IfThenElseNode.makeFunction(language));
scope.registerMethod(bool, "to_text", ToTextNode.makeFunction(language));
scope.registerMethod(bool, "&&", AndNode.makeFunction(language));
scope.registerMethod(bool, "||", OrNode.makeFunction(language));
scope.registerMethod(bool, "not", NotNode.makeFunction(language));
scope.registerMethod(bool, "if_then_else", IfThenElseMethodGen.makeFunction(language));
scope.registerMethod(bool, "to_text", ToTextMethodGen.makeFunction(language));
scope.registerMethod(bool, "&&", AndMethodGen.makeFunction(language));
scope.registerMethod(bool, "||", OrMethodGen.makeFunction(language));
scope.registerMethod(bool, "not", NotMethodGen.makeFunction(language));
tru = new AtomConstructor("True", scope).initializeFields();
scope.registerConstructor(tru);
fls = new AtomConstructor("False", scope).initializeFields();

View File

@ -3,30 +3,20 @@ package org.enso.interpreter.runtime.builtin;
import com.oracle.truffle.api.RootCallTarget;
import com.oracle.truffle.api.Truffle;
import org.enso.interpreter.Language;
import org.enso.interpreter.node.expression.builtin.IfZeroNode;
import org.enso.interpreter.node.expression.builtin.debug.DebugBreakpointNode;
import org.enso.interpreter.node.expression.builtin.debug.DebugEvalNode;
import org.enso.interpreter.node.expression.builtin.error.CatchErrorNode;
import org.enso.interpreter.node.expression.builtin.error.CatchPanicNode;
import org.enso.interpreter.node.expression.builtin.error.PanicNode;
import org.enso.interpreter.node.expression.builtin.error.ThrowErrorNode;
import org.enso.interpreter.node.expression.builtin.function.ExplicitCallFunctionNode;
import org.enso.interpreter.node.expression.builtin.debug.DebugBreakpointMethodGen;
import org.enso.interpreter.node.expression.builtin.debug.DebugEvalMethodGen;
import org.enso.interpreter.node.expression.builtin.error.*;
import org.enso.interpreter.node.expression.builtin.function.ExplicitCallFunctionMethodGen;
import org.enso.interpreter.node.expression.builtin.interop.generic.*;
import org.enso.interpreter.node.expression.builtin.interop.syntax.MethodDispatchNode;
import org.enso.interpreter.node.expression.builtin.interop.syntax.ConstructorDispatchNode;
import org.enso.interpreter.node.expression.builtin.io.PrintErrNode;
import org.enso.interpreter.node.expression.builtin.io.PrintlnNode;
import org.enso.interpreter.node.expression.builtin.io.ReadlnNode;
import org.enso.interpreter.node.expression.builtin.io.*;
import org.enso.interpreter.node.expression.builtin.number.*;
import org.enso.interpreter.node.expression.builtin.system.NanoTimeNode;
import org.enso.interpreter.node.expression.builtin.state.*;
import org.enso.interpreter.node.expression.builtin.system.NanoTimeMethodGen;
import org.enso.interpreter.node.expression.builtin.interop.java.*;
import org.enso.interpreter.node.expression.builtin.state.GetStateNode;
import org.enso.interpreter.node.expression.builtin.state.PutStateNode;
import org.enso.interpreter.node.expression.builtin.state.RunStateNode;
import org.enso.interpreter.node.expression.builtin.text.AnyToTextNode;
import org.enso.interpreter.node.expression.builtin.text.ConcatNode;
import org.enso.interpreter.node.expression.builtin.text.JsonSerializeNode;
import org.enso.interpreter.node.expression.builtin.thread.WithInterruptHandlerNode;
import org.enso.interpreter.node.expression.builtin.text.*;
import org.enso.interpreter.node.expression.builtin.thread.WithInterruptHandlerMethodGen;
import org.enso.interpreter.runtime.Context;
import org.enso.interpreter.runtime.Module;
import org.enso.interpreter.runtime.callable.argument.ArgumentDefinition;
@ -132,44 +122,43 @@ public class Builtins {
createPolyglot(language);
scope.registerMethod(io, "println", PrintlnNode.makeFunction(language, scope));
scope.registerMethod(io, "print_err", PrintErrNode.makeFunction(language));
scope.registerMethod(io, "readln", ReadlnNode.makeFunction(language));
scope.registerMethod(io, "println", PrintlnMethodGen.makeFunction(language));
scope.registerMethod(io, "print_err", PrintErrMethodGen.makeFunction(language));
scope.registerMethod(io, "readln", ReadlnMethodGen.makeFunction(language));
scope.registerMethod(system, "nano_time", NanoTimeNode.makeFunction(language));
scope.registerMethod(system, "nano_time", NanoTimeMethodGen.makeFunction(language));
scope.registerMethod(panic, "throw", PanicNode.makeFunction(language));
scope.registerMethod(panic, "recover", CatchPanicNode.makeFunction(language));
scope.registerMethod(error, "throw", ThrowErrorNode.makeFunction(language));
scope.registerMethod(any, "catch", CatchErrorNode.makeFunction(language));
scope.registerMethod(panic, "throw", ThrowPanicMethodGen.makeFunction(language));
scope.registerMethod(panic, "recover", CatchPanicMethodGen.makeFunction(language));
scope.registerMethod(error, "throw", ThrowErrorMethodGen.makeFunction(language));
scope.registerMethod(any, "catch", CatchErrorMethodGen.makeFunction(language));
scope.registerMethod(number, "ifZero", IfZeroNode.makeFunction(language));
scope.registerMethod(number, "+", AddNode.makeFunction(language));
scope.registerMethod(number, "-", SubtractNode.makeFunction(language));
scope.registerMethod(number, "*", MultiplyNode.makeFunction(language));
scope.registerMethod(number, "/", DivideNode.makeFunction(language));
scope.registerMethod(number, "%", ModNode.makeFunction(language));
scope.registerMethod(number, "negate", NegateNode.makeFunction(language));
scope.registerMethod(number, "==", EqualsNode.makeFunction(language));
scope.registerMethod(number, "+", AddMethodGen.makeFunction(language));
scope.registerMethod(number, "-", SubtractMethodGen.makeFunction(language));
scope.registerMethod(number, "*", MultiplyMethodGen.makeFunction(language));
scope.registerMethod(number, "/", DivideMethodGen.makeFunction(language));
scope.registerMethod(number, "%", ModMethodGen.makeFunction(language));
scope.registerMethod(number, "negate", NegateMethodGen.makeFunction(language));
scope.registerMethod(number, "==", EqualsMethodGen.makeFunction(language));
scope.registerMethod(state, "get", GetStateNode.makeFunction(language));
scope.registerMethod(state, "put", PutStateNode.makeFunction(language));
scope.registerMethod(state, "run", RunStateNode.makeFunction(language));
scope.registerMethod(state, "get", GetStateMethodGen.makeFunction(language));
scope.registerMethod(state, "put", PutStateMethodGen.makeFunction(language));
scope.registerMethod(state, "run", RunStateMethodGen.makeFunction(language));
scope.registerMethod(debug, MethodNames.Debug.EVAL, DebugEvalNode.makeFunction(language));
scope.registerMethod(debug, "breakpoint", DebugBreakpointNode.makeFunction(language));
scope.registerMethod(debug, MethodNames.Debug.EVAL, DebugEvalMethodGen.makeFunction(language));
scope.registerMethod(debug, "breakpoint", DebugBreakpointMethodGen.makeFunction(language));
scope.registerMethod(function, "call", ExplicitCallFunctionNode.makeFunction(language));
scope.registerMethod(function, "call", ExplicitCallFunctionMethodGen.makeFunction(language));
scope.registerMethod(text, "+", ConcatNode.makeFunction(language));
scope.registerMethod(any, "to_text", AnyToTextNode.makeFunction(language));
scope.registerMethod(any, "json_serialize", JsonSerializeNode.makeFunction(language));
scope.registerMethod(text, "+", ConcatMethodGen.makeFunction(language));
scope.registerMethod(any, "to_text", AnyToTextMethodGen.makeFunction(language));
scope.registerMethod(any, "json_serialize", JsonSerializeMethodGen.makeFunction(language));
scope.registerMethod(java, "add_to_class_path", AddToClassPathNode.makeFunction(language));
scope.registerMethod(java, "lookup_class", LookupClassNode.makeFunction(language));
scope.registerMethod(java, "add_to_class_path", AddToClassPathMethodGen.makeFunction(language));
scope.registerMethod(java, "lookup_class", LookupClassMethodGen.makeFunction(language));
scope.registerMethod(
thread, "with_interrupt_handler", WithInterruptHandlerNode.makeFunction(language));
thread, "with_interrupt_handler", WithInterruptHandlerMethodGen.makeFunction(language));
interopDispatchRoot = Truffle.getRuntime().createCallTarget(MethodDispatchNode.build(language));
interopDispatchSchema =
@ -189,13 +178,14 @@ public class Builtins {
private void createPolyglot(Language language) {
AtomConstructor polyglot = new AtomConstructor("Polyglot", scope).initializeFields();
scope.registerConstructor(polyglot);
scope.registerMethod(polyglot, "execute", ExecuteNode.makeFunction(language));
scope.registerMethod(polyglot, "invoke", InvokeNode.makeFunction(language));
scope.registerMethod(polyglot, "new", InstantiateNode.makeFunction(language));
scope.registerMethod(polyglot, "get_member", GetMemberNode.makeFunction(language));
scope.registerMethod(polyglot, "get_members", GetMembersNode.makeFunction(language));
scope.registerMethod(polyglot, "get_array_size", GetArraySizeNode.makeFunction(language));
scope.registerMethod(polyglot, "get_array_element", GetArrayElementNode.makeFunction(language));
scope.registerMethod(polyglot, "execute", ExecuteMethodGen.makeFunction(language));
scope.registerMethod(polyglot, "invoke", InvokeMethodGen.makeFunction(language));
scope.registerMethod(polyglot, "new", InstantiateMethodGen.makeFunction(language));
scope.registerMethod(polyglot, "get_member", GetMemberMethodGen.makeFunction(language));
scope.registerMethod(polyglot, "get_members", GetMembersMethodGen.makeFunction(language));
scope.registerMethod(polyglot, "get_array_size", GetArraySizeMethodGen.makeFunction(language));
scope.registerMethod(
polyglot, "get_array_element", GetArrayElementMethodGen.makeFunction(language));
}
/**

View File

@ -221,7 +221,7 @@ class ReplTest extends InterpreterTest with BeforeAndAfter with EitherValues {
}
eval(code)
val errorMsg =
"Unexpected type for `that` operand in Number.+"
"Unexpected type provided for argument `that` in Number.+"
evalResult.left.value.getMessage shouldEqual errorMsg
}

View File

@ -53,9 +53,9 @@ class CodeLocationsTest extends InterpreterTest {
"be correct in applications and method calls" in
withLocationsInstrumenter { instrumenter =>
val code = "main = (2 - 2).ifZero (Cons 5 6) 0"
instrumenter.assertNodeExists(7, 27, classOf[ApplicationNode])
instrumenter.assertNodeExists(23, 8, classOf[ApplicationNode])
val code = "main = (2-2 == 0).if_then_else (Cons 5 6) 0"
instrumenter.assertNodeExists(7, 36, classOf[ApplicationNode])
instrumenter.assertNodeExists(32, 8, classOf[ApplicationNode])
eval(code)
()
}

View File

@ -29,7 +29,7 @@ class ConstructorsTest extends InterpreterTest {
val testCode =
"""
|main =
| genList = i -> ifZero i Nil (Cons i (genList (i - 1)))
| genList = i -> if i == 0 then Nil else Cons i (genList (i - 1))
| sumList = list -> case list of
| Cons h t -> h + sumList t
| Nil -> 0
@ -83,7 +83,7 @@ class ConstructorsTest extends InterpreterTest {
"""
|type Cons2 a b
|
|Unit.genList = i -> ifZero i Nil2 (Cons2 i (genList Unit (i - 1)))
|Unit.genList = i -> if i == 0 then Nil2 else Cons2 i (genList Unit (i - 1))
|
|type Nil2
|

View File

@ -65,7 +65,7 @@ class EvalTest extends InterpreterTest {
|main =
| fn = sumTo ->
| summator = acc -> current ->
| Debug.eval "ifZero current acc (summator (acc + current) (current - 1))"
| Debug.eval "if current == 0 then acc else summator (acc + current) (current - 1)"
| summator 0 sumTo
| fn 100
|""".stripMargin
@ -78,7 +78,7 @@ class EvalTest extends InterpreterTest {
|main =
| fn = sumTo ->
| summator = acc -> current ->
| ifZero current acc (Debug.eval "summator (acc + current) (current - 1)")
| if current == 0 then acc else Debug.eval "summator (acc + current) (current - 1)"
|
| summator 0 sumTo
|

View File

@ -41,10 +41,10 @@ class ExpressionIdTest extends InterpreterTest {
"be correct in applications and method calls" in
withIdsInstrumenter { instrumenter =>
val code = "main = (2 - 2).ifZero (Cons 5 6) 0"
val code = "main = (2-2 == 0).if_then_else (Cons 5 6) 0"
val meta = new Metadata
val id1 = meta.addItem(7, 27)
val id2 = meta.addItem(23, 8)
val id1 = meta.addItem(7, 36)
val id2 = meta.addItem(32, 8)
instrumenter.assertNodeExists(id1, "Cons 5 6")
instrumenter.assertNodeExists(id2, "Cons 5 6")

View File

@ -61,7 +61,7 @@ class GlobalScopeTest extends InterpreterTest {
| Unit.fn1 res
|
|Unit.fn1 = number ->
| ifZero (number % 3) number (Unit.decrementCall number)
| if (number % 3) == 0 then number else Unit.decrementCall number
|
|main = Unit.fn1 5
""".stripMargin

View File

@ -33,7 +33,7 @@ class GroupingTest extends InterpreterTest {
val code =
"""
|main =
| ifTest = c -> (~ifT) -> ~ifF -> ifZero c ifT ifF
| ifTest = c -> (~ifT) -> ~ifF -> if c == 0 then ifT else ifF
| sum = c -> acc -> ifTest c acc (sum c-1 acc+c)
| sum 10000 0
|""".stripMargin

View File

@ -12,7 +12,7 @@ class InteropTest extends InterpreterTest {
val code =
"""
|main =
| recurFun = i -> ifZero i 0 (recurFun i-1)
| recurFun = i -> if i == 0 then 0 else recurFun i-1
| recurFun
|""".stripMargin

View File

@ -51,7 +51,7 @@ class LambdaShorthandArgsTest extends InterpreterTest {
"work with mixfix functions" in {
val code =
"""
|Number.if_then_else = ~t -> ~f -> ifZero this t f
|Number.if_then_else = ~t -> ~f -> if this == 0 then t else f
|
|main =
| f = if _ then 10 else 5

View File

@ -44,7 +44,7 @@ class LambdaTest extends InterpreterTest {
val code =
"""
|main =
| sumTo = x -> ifZero x 0 (x + (sumTo (x-1)))
| sumTo = x -> if x == 0 then 0 else x + (sumTo (x-1))
| sumTo 10
""".stripMargin
@ -105,7 +105,7 @@ class LambdaTest extends InterpreterTest {
"""
|main =
| summator = current ->
| ifZero current 0 ((x -> summator (current - 1)) 0)
| if current == 0 then 0 else (x -> summator (current - 1)) 0
| res = summator 0
| res
|""".stripMargin
@ -132,7 +132,7 @@ class LambdaTest extends InterpreterTest {
"call fully saturated lambdas returned with TCO" in {
val code =
"""
|Number.if_then_else = ~t -> ~f -> ifZero this t f
|Number.if_then_else = ~t -> ~f -> if this == 0 then t else f
|
|main =
| lam = (x = 10) -> x

View File

@ -123,7 +123,7 @@ class NamedArgumentsTest extends InterpreterTest {
"""
|Unit.summer = sumTo ->
| summator = (acc = 0) -> current ->
| ifZero current acc (summator (current = current - 1) (acc = acc + current))
| if current == 0 then acc else summator (current = current - 1) (acc = acc + current)
| res = summator (current = sumTo)
| res
|
@ -187,7 +187,7 @@ class NamedArgumentsTest extends InterpreterTest {
|type Nil2
|
|main =
| genList = i -> ifZero i Nil2 (Cons2 (rest = genList i-1) head=i)
| genList = i -> if i == 0 then Nil2 else Cons2 (rest = genList i-1) head=i
|
| sum = list -> case list of
| Cons2 h t -> h + t.sum
@ -206,7 +206,7 @@ class NamedArgumentsTest extends InterpreterTest {
|type Cons2 head (rest = Nil2)
|
|main =
| genList = i -> ifZero i Nil2 (Cons2 (rest = genList i-1) head=i)
| genList = i -> if i == 0 then Nil2 else Cons2 (rest = genList i-1) head=i
|
| sum = list -> case list of
| Cons2 h t -> h + t.sum

View File

@ -66,7 +66,7 @@ class StateTest extends InterpreterTest {
| stateSum = n ->
| acc = State.get
| State.put acc+n
| ifZero n State.get (stateSum n-1)
| if n == 0 then State.get else stateSum n-1
|
| State.run 0 (stateSum 10)
|""".stripMargin

View File

@ -25,7 +25,7 @@ class SuspendedArgumentsTest extends InterpreterTest {
val code =
"""
|main =
| foo = i -> ~x -> ~y -> ifZero i x y
| foo = i -> ~x -> ~y -> if i == 0 then x else y
| foo 1 (IO.println 1) (IO.println 2)
|""".stripMargin
eval(code)
@ -36,7 +36,7 @@ class SuspendedArgumentsTest extends InterpreterTest {
val code =
"""
|main =
| ifTest = c -> ~ifT -> ~ifF -> ifZero c ifT ifF
| ifTest = c -> ~ifT -> ~ifF -> if c == 0 then ifT else ifF
| sum = c -> acc -> ifTest c acc (sum c-1 acc+c)
| sum 10000 0
|""".stripMargin
@ -77,7 +77,7 @@ class SuspendedArgumentsTest extends InterpreterTest {
val code =
"""
|main =
| ifTest = c -> ~ifT -> ~ifF -> ifZero c ifT ifF
| ifTest = c -> ~ifT -> ~ifF -> if c == 0 then ifT else ifF
| foo = c -> ifTest c
|
| foo 0 (IO.println 1) (IO.println 2)

View File

@ -22,7 +22,7 @@ class ThreadInterruptionTest extends InterpreterTest {
val code =
"""
|foo x =
| ifZero x (IO.println "Start.") Unit
| if x == 0 then IO.println "Start." else Unit
| here.foo x+1
|
|main =

View File

@ -0,0 +1,23 @@
package org.enso.interpreter.dsl;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/** An annotation denoting a node that should be wrapped for standard library export. */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.SOURCE)
public @interface BuiltinMethod {
/** @return the language-level type of {@code this} argument. */
String type();
/** @return the language-level name of this method. */
String name();
/** @return a short description of this method. */
String description();
/** @return whether it is safe to always call this function directly. */
boolean alwaysDirect() default true;
}

View File

@ -0,0 +1,264 @@
package org.enso.interpreter.dsl;
import com.google.auto.service.AutoService;
import org.enso.interpreter.dsl.model.MethodDefinition;
import javax.annotation.processing.*;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.Name;
import javax.lang.model.element.TypeElement;
import javax.tools.Diagnostic;
import javax.tools.JavaFileObject;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.*;
/** The processor used to generate code from the {@link BuiltinMethod} annotation. */
@SupportedAnnotationTypes("org.enso.interpreter.dsl.BuiltinMethod")
@SupportedSourceVersion(SourceVersion.RELEASE_8)
@AutoService(Processor.class)
public class MethodProcessor extends AbstractProcessor {
/**
* Processes annotated elements, generating code for each of them.
*
* @param annotations annotation being processed this round.
* @param roundEnv additional round information.
* @return {@code true}
*/
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
for (TypeElement annotation : annotations) {
Set<? extends Element> annotatedElements = roundEnv.getElementsAnnotatedWith(annotation);
for (Element elt : annotatedElements) {
TypeElement element = (TypeElement) elt;
ExecutableElement executeMethod =
element.getEnclosedElements().stream()
.filter(
x -> {
if (!(x instanceof ExecutableElement)) return false;
Name name = x.getSimpleName();
return name.contentEquals("execute");
})
.map(x -> (ExecutableElement) x)
.findFirst()
.orElseGet(
() -> {
processingEnv
.getMessager()
.printMessage(Diagnostic.Kind.ERROR, "No execute method found.", element);
return null;
});
if (executeMethod == null) continue;
String pkgName =
processingEnv.getElementUtils().getPackageOf(element).getQualifiedName().toString();
MethodDefinition def = new MethodDefinition(pkgName, element, executeMethod);
if (!def.validate(processingEnv)) {
continue;
}
try {
generateCode(def);
} catch (IOException e) {
e.printStackTrace();
}
}
}
return true;
}
private final List<String> necessaryImports =
Arrays.asList(
"com.oracle.truffle.api.frame.VirtualFrame",
"com.oracle.truffle.api.nodes.NodeInfo",
"com.oracle.truffle.api.nodes.UnexpectedResultException",
"org.enso.interpreter.Language",
"org.enso.interpreter.node.expression.builtin.BuiltinRootNode",
"org.enso.interpreter.runtime.callable.argument.ArgumentDefinition",
"org.enso.interpreter.runtime.callable.function.Function",
"org.enso.interpreter.runtime.callable.function.FunctionSchema",
"org.enso.interpreter.runtime.error.TypeError",
"org.enso.interpreter.runtime.state.Stateful",
"org.enso.interpreter.runtime.type.TypesGen");
private void generateCode(MethodDefinition methodDefinition) throws IOException {
JavaFileObject gen =
processingEnv.getFiler().createSourceFile(methodDefinition.getQualifiedName());
Set<String> allImports = new HashSet<>(necessaryImports);
allImports.addAll(methodDefinition.getImports());
try (PrintWriter out = new PrintWriter(gen.openWriter())) {
out.println("package " + methodDefinition.getPackageName() + ";");
out.println();
allImports.forEach(pkg -> out.println("import " + pkg + ";"));
out.println();
out.println("@NodeInfo(");
out.println(" shortName = \"" + methodDefinition.getDeclaredName() + "\",");
out.println(" description = \"" + methodDefinition.getDescription() + "\")");
out.println("public class " + methodDefinition.getClassName() + " extends BuiltinRootNode {");
out.println(" private @Child " + methodDefinition.getOriginalClassName() + " bodyNode;");
out.println();
out.println(" private " + methodDefinition.getClassName() + "(Language language) {");
out.println(" super(language);");
out.println(" bodyNode = " + methodDefinition.getConstructorExpression() + ";");
out.println(" }");
out.println();
String functionBuilderMethod =
methodDefinition.needsCallerInfo()
? "fromBuiltinRootNodeWithCallerFrameAccess"
: "fromBuiltinRootNode";
out.println(" public static Function makeFunction(Language language) {");
out.println(" return Function." + functionBuilderMethod + "(");
out.println(" new " + methodDefinition.getClassName() + "(language),");
if (methodDefinition.isAlwaysDirect()) {
out.println(" FunctionSchema.CallStrategy.ALWAYS_DIRECT,");
} else {
out.println(" FunctionSchema.CallStrategy.DIRECT_WHEN_TAIL,");
}
List<String> argumentDefs = new ArrayList<>();
for (MethodDefinition.ArgumentDefinition arg : methodDefinition.getArguments()) {
if (arg.isPositional()) {
String executionMode = arg.isSuspended() ? "PASS_THUNK" : "EXECUTE";
argumentDefs.add(
" new ArgumentDefinition("
+ arg.getPosition()
+ ", \""
+ arg.getName()
+ "\", ArgumentDefinition.ExecutionMode."
+ executionMode
+ ")");
}
}
out.println(String.join(",\n", argumentDefs) + ");");
out.println(" }");
out.println();
out.println(" @Override");
out.println(" public Stateful execute(VirtualFrame frame) {");
out.println(" Object state = Function.ArgumentsHelper.getState(frame.getArguments());");
if (methodDefinition.needsCallerInfo()) {
out.println(
" CallerInfo callerInfo = Function.ArgumentsHelper.getCallerInfo(frame.getArguments());");
}
out.println(
" Object[] arguments = Function.ArgumentsHelper.getPositionalArguments(frame.getArguments());");
List<String> callArgNames = new ArrayList<>();
for (MethodDefinition.ArgumentDefinition argumentDefinition :
methodDefinition.getArguments()) {
if (argumentDefinition.isState()) {
callArgNames.add("state");
} else if (argumentDefinition.isFrame()) {
callArgNames.add("frame");
} else if (argumentDefinition.isCallerInfo()) {
callArgNames.add("callerInfo");
} else {
callArgNames.add("arg" + argumentDefinition.getPosition());
generateArgumentRead(
out, argumentDefinition, methodDefinition.getDeclaredName(), "arguments");
}
}
String executeCall = "bodyNode.execute(" + String.join(", ", callArgNames) + ")";
if (methodDefinition.modifiesState()) {
out.println(" return " + executeCall + ";");
} else {
out.println(" return new Stateful(state, " + executeCall + ");");
}
out.println(" }");
out.println();
out.println(" @Override");
out.println(" public String getName() {");
out.println(" return \"" + methodDefinition.getDeclaredName() + "\";");
out.println(" }");
out.println();
out.println("}");
}
}
private void generateArgumentRead(
PrintWriter out,
MethodDefinition.ArgumentDefinition arg,
String methodName,
String argsArray) {
if (!arg.requiresCast()) {
generateUncastedArgumentRead(out, arg, argsArray);
} else if (arg.getName().equals("this") && arg.getPosition() == 0) {
generateUncheckedArgumentRead(out, arg, argsArray);
} else {
generateCheckedArgumentRead(out, arg, methodName, argsArray);
}
}
private void generateUncastedArgumentRead(
PrintWriter out, MethodDefinition.ArgumentDefinition arg, String argsArray) {
String varName = "arg" + arg.getPosition();
out.println(
" "
+ arg.getTypeName()
+ " "
+ varName
+ " = "
+ argsArray
+ "["
+ arg.getPosition()
+ "];");
}
private void generateUncheckedArgumentRead(
PrintWriter out, MethodDefinition.ArgumentDefinition arg, String argsArray) {
String castName = "TypesGen.as" + capitalize(arg.getTypeName());
String varName = "arg" + arg.getPosition();
out.println(
" "
+ arg.getTypeName()
+ " "
+ varName
+ " = "
+ castName
+ "("
+ argsArray
+ "["
+ arg.getPosition()
+ "]);");
}
private void generateCheckedArgumentRead(
PrintWriter out,
MethodDefinition.ArgumentDefinition arg,
String methodName,
String argsArray) {
String castName = "TypesGen.expect" + capitalize(arg.getTypeName());
String varName = "arg" + arg.getPosition();
out.println(" " + arg.getTypeName() + " " + varName + ";");
out.println(" try {");
out.println(
" " + varName + " = " + castName + "(" + argsArray + "[" + arg.getPosition() + "]);");
out.println(" } catch (UnexpectedResultException e) {");
out.println(
" throw new TypeError(\"Unexpected type provided for argument `"
+ arg.getName()
+ "` in "
+ methodName
+ "\", this);");
out.println(" }");
}
private String capitalize(String name) {
return name.substring(0, 1).toUpperCase() + name.substring(1);
}
}

View File

@ -0,0 +1,11 @@
package org.enso.interpreter.dsl;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/** An interface marking an argument as requiring to be passed the current monadic state. */
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.SOURCE)
public @interface MonadicState {}

View File

@ -0,0 +1,276 @@
package org.enso.interpreter.dsl.model;
import org.enso.interpreter.dsl.BuiltinMethod;
import org.enso.interpreter.dsl.MonadicState;
import javax.annotation.processing.ProcessingEnvironment;
import javax.lang.model.element.*;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import javax.tools.Diagnostic;
import java.util.*;
/** A domain-specific representation of a builtin method. */
public class MethodDefinition {
private static final String STATEFUL = "org.enso.interpreter.runtime.state.Stateful";
private final String packageName;
private final String originalClassName;
private final String className;
private final String qualifiedName;
private final BuiltinMethod annotation;
private final TypeElement element;
private final ExecutableElement executeMethod;
private final List<ArgumentDefinition> arguments;
private final Set<String> imports;
private final boolean modifiesState;
private final boolean needsCallerInfo;
private final String constructorExpression;
/**
* Creates a new instance of this class.
*
* @param packageName the name of the package this method is declared in.
* @param element the element (class) declaring this method.
* @param execute the element (method) containing the logic.
*/
public MethodDefinition(String packageName, TypeElement element, ExecutableElement execute) {
this.annotation = element.getAnnotation(BuiltinMethod.class);
this.element = element;
this.executeMethod = execute;
this.originalClassName = element.getSimpleName().toString();
this.packageName = packageName;
this.className = generateClassName(originalClassName);
this.qualifiedName = packageName + "." + className;
this.arguments = initArguments(execute);
this.imports = initImports();
this.needsCallerInfo = arguments.stream().anyMatch(ArgumentDefinition::isCallerInfo);
this.modifiesState = execute.getReturnType().toString().equals(STATEFUL);
this.constructorExpression = initConstructor(element);
}
private String initConstructor(TypeElement element) {
boolean useBuild =
element.getEnclosedElements().stream()
.anyMatch(
el -> {
if (el.getKind() != ElementKind.METHOD) {
return false;
}
ExecutableElement method = (ExecutableElement) el;
return method.getSimpleName().contentEquals("build")
&& method.getParameters().isEmpty()
&& method.getModifiers().contains(Modifier.STATIC);
});
if (useBuild) {
return originalClassName + ".build()";
} else {
return "new " + originalClassName + "()";
}
}
private Set<String> initImports() {
Set<String> result = new HashSet<>();
for (ArgumentDefinition arg : arguments) {
Optional<String> imp = arg.getImport();
imp.ifPresent(result::add);
}
return result;
}
private String generateClassName(String originalClassName) {
String baseName =
originalClassName.endsWith("Node")
? originalClassName.substring(0, originalClassName.length() - 4)
: originalClassName;
return baseName + "MethodGen";
}
private List<ArgumentDefinition> initArguments(ExecutableElement method) {
List<ArgumentDefinition> args = new ArrayList<>();
List<? extends VariableElement> params = method.getParameters();
int position = 0;
for (VariableElement param : params) {
ArgumentDefinition def = new ArgumentDefinition(param, position);
args.add(def);
if (def.isPositional()) {
position++;
}
}
return args;
}
/**
* Checks the validity of this definition with respect to required properties.
*
* <p>Any invalid elements will be reported as errors.
*
* @param processingEnvironment the current processing environment.
* @return whether the definition is fully valid.
*/
public boolean validate(ProcessingEnvironment processingEnvironment) {
boolean definesThis =
arguments.stream().anyMatch(arg -> arg.getName().equals("this") && arg.isPositional());
if (!definesThis) {
processingEnvironment
.getMessager()
.printMessage(
Diagnostic.Kind.ERROR,
"The execute method does not take `this` argument. At least one positional argument must be named `_this`.",
element);
}
return definesThis;
}
/** @return the package name this method was declared in. */
public String getPackageName() {
return packageName;
}
/** @return the original class name of this method. */
public String getOriginalClassName() {
return originalClassName;
}
/** @return the simple class name of generated method wrapper. */
public String getClassName() {
return className;
}
/** @return full name (with package) of the generated wrapper. */
public String getQualifiedName() {
return qualifiedName;
}
/** @return the language-level name of this method. */
public String getDeclaredName() {
return annotation.type() + "." + annotation.name();
}
/** @return get the description of this method. */
public String getDescription() {
return annotation.description();
}
/** @return the arguments this method declares. */
public List<ArgumentDefinition> getArguments() {
return arguments;
}
/** @return the additional imports this method definition requires. */
public Set<String> getImports() {
return imports;
}
/** @return whether this method modifies the monadic state. */
public boolean modifiesState() {
return modifiesState;
}
/** @return whether this method requires caller info to work properly. */
public boolean needsCallerInfo() {
return needsCallerInfo;
}
/** @return whether this method can be always safely called directly. */
public boolean isAlwaysDirect() {
return annotation.alwaysDirect();
}
public String getConstructorExpression() {
return constructorExpression;
}
/** A domain specific representation of a method argument. */
public static class ArgumentDefinition {
private static final String VIRTUAL_FRAME = "com.oracle.truffle.api.frame.VirtualFrame";
private static final String OBJECT = "java.lang.Object";
private static final String THUNK = "org.enso.interpreter.runtime.callable.argument.Thunk";
private static final String CALLER_INFO = "org.enso.interpreter.runtime.callable.CallerInfo";
private final String typeName;
private final TypeMirror type;
private final String name;
private final boolean isState;
private final boolean isFrame;
private final boolean isCallerInfo;
private final int position;
/**
* Creates a new instance of this class.
*
* @param element the element representing this argument.
* @param position the position (0-indexed) of this argument in the arguments list.
*/
public ArgumentDefinition(VariableElement element, int position) {
type = element.asType();
String[] typeNameSegments = type.toString().split("\\.");
typeName = typeNameSegments[typeNameSegments.length - 1];
String originalName = element.getSimpleName().toString();
name = originalName.equals("_this") ? "this" : originalName;
isState = element.getAnnotation(MonadicState.class) != null && type.toString().equals(OBJECT);
isFrame = type.toString().equals(VIRTUAL_FRAME);
isCallerInfo = type.toString().equals(CALLER_INFO);
this.position = position;
}
/** @return whether this argument should be passed the monadic state. */
public boolean isState() {
return isState;
}
/** @return whether this argument should be passed the execution frame. */
public boolean isFrame() {
return isFrame;
}
/** @return whether this argument should be passed the caller info. */
public boolean isCallerInfo() {
return isCallerInfo;
}
/** @return whether this argument should be passed the next positional function argument. */
public boolean isPositional() {
return !isFrame() && !isState() && !isCallerInfo();
}
/** @return the position of this argument in the positional arguments list. */
public int getPosition() {
return position;
}
/** @return any import this argument requires. */
public Optional<String> getImport() {
if (type.getKind() == TypeKind.DECLARED) {
if (!type.toString().equals(OBJECT)) {
return Optional.of(type.toString());
}
}
return Optional.empty();
}
/** @return whether this argument needs to be type-casted on read. */
public boolean requiresCast() {
return !type.toString().equals(OBJECT);
}
/** @return the name of the type of this argument. */
public String getTypeName() {
return typeName;
}
/** @return the type of this argument. */
public TypeMirror getType() {
return type;
}
/** @return the name of this argument. */
public String getName() {
return name;
}
/** @return whether this argument is expected to be passed suspended. */
public boolean isSuspended() {
return type.toString().equals(THUNK);
}
}
}