Skip to content

Commit

Permalink
[WIP] feat: precompilers
Browse files Browse the repository at this point in the history
- feat(engine): support for concept of source precompilers
- feat(engine): facility for reporting diagnostics
- feat(graalvm): load precompilers from service loader path
- feat(graalvm): implement native tsx/jsx/ts precompiler via oxc
- feat(graalvm-jvm): implement simple java -> bytecode precompiler

Signed-off-by: Sam Gammon <sam@elide.dev>
  • Loading branch information
sgammon committed Feb 19, 2025
1 parent a90a3ce commit eb83a8b
Show file tree
Hide file tree
Showing 56 changed files with 3,391 additions and 262 deletions.
742 changes: 492 additions & 250 deletions Cargo.lock

Large diffs are not rendered by default.

17 changes: 13 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,15 @@ pubgrub = { git = "https://github.com/elide-tools/pubgrub", rev = "83c0b986493bf
## Local
base = { path = "crates/base" }
builder = { path = "crates/builder" }
diag = { path = "crates/diag" }
deps = { path = "crates/deps" }
entry = { path = "crates/entry" }
model = { path = "crates/model" }
posix = { path = "crates/posix" }
project = { path = "crates/project" }
protocol = { path = "crates/protocol" }
sqlite = { path = "crates/sqlite" }
js = { path = "crates/js" }
substrate = { path = "crates/substrate" }
terminal = { path = "crates/terminal" }
transport = { path = "crates/transport" }
Expand Down Expand Up @@ -179,12 +181,19 @@ biome_suppression = "0.5.7"
biome_unicode_table = "0.5.7"

## Oxc
oxc = { git = "https://github.com/elide-dev/oxc", rev = "fb5b1fa0156e501eea17002178e54296f5964ba8", default-features = false, features = [
#
oxc = { git = "https://github.com/elide-dev/oxc", rev = "328972124b39b6af8525ff090cc112ab5fd4d5ce", default-features = false, features = [
"full",
"codegen",
"isolated_declarations",
"mangler",
"minifier",
"semantic",
"transformer",
] }

## Uv
uv = { git = "https://github.com/elide-dev/uv", rev = "daa5270203156f150c8407e5256827a366656107" }
uv = { git = "https://github.com/elide-dev/uv", rev = "f394f7245377b6368b9412d88575446602f22525" }

## Ruff
ruff = { git = "https://github.com/elide-dev/ruff", rev = "9f065f4a340089406eefbb2dde21f8f9e31f8515" }
ruff = { git = "https://github.com/elide-dev/ruff", rev = "877c1066d3373f9089e71a15123b769d924ff2a6" }

13 changes: 13 additions & 0 deletions PklProject
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
amends "pkl:Project"

package {
name = "elide"
version = "1.0.0-alpha13"
baseUri = "package://pkl.elide.dev/\(name)"
packageZipUrl = "https://github.com/elide-dev/elide/releases/download/\(version)/pkl-\(name)-\(version).zip"
}

dependencies {
["table"] { uri = "package://pkg.pkl-lang.org/pkl-pantry/pkl.table@1.1.0" }
["toml"] { uri = "package://pkg.pkl-lang.org/pkl-pantry/pkl.toml@1.0.2" }
}
19 changes: 19 additions & 0 deletions PklProject.deps.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"schemaVersion": 1,
"resolvedDependencies": {
"package://pkg.pkl-lang.org/pkl-pantry/pkl.toml@1": {
"type": "remote",
"uri": "projectpackage://pkg.pkl-lang.org/pkl-pantry/pkl.toml@1.0.2",
"checksums": {
"sha256": "45fea4cf14e7d776e131b338efe2a7016f86c87b0c0f532409f728033bd82f71"
}
},
"package://pkg.pkl-lang.org/pkl-pantry/pkl.table@1": {
"type": "remote",
"uri": "projectpackage://pkg.pkl-lang.org/pkl-pantry/pkl.table@1.1.0",
"checksums": {
"sha256": "b79cec3bfc84ab197ad331b429d611229cc12b662de5ad10c8aaf59553435fd9"
}
}
}
}
29 changes: 29 additions & 0 deletions crates/diag/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#
# Copyright (c) 2024 Elide Technologies, Inc.
#
# Licensed under the MIT license (the "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# https://opensource.org/license/mit/
#
# Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
# an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under the License.
#

[package]
name = "diag"
edition = "2021"
license = "MIT"
workspace = "../.."
version = "1.0.0-alpha13-SNAPSHOT"

[lib]
crate-type = ["lib", "cdylib", "staticlib"]

[dependencies]
java_native = { workspace = true }
jni = { workspace = true, default-features = false }
jni-sys = { workspace = true }
oxc = { workspace = true }
# miette = { workspace = true }
216 changes: 216 additions & 0 deletions crates/diag/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
/*
* Copyright (c) 2024 Elide Technologies, Inc.
*
* Licensed under the MIT license (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* https://opensource.org/license/mit/
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under the License.
*/

#![forbid(unsafe_op_in_unsafe_fn, unused_unsafe)]

use java_native::jni;
use jni::objects::{JClass, JObject, JValue};
use jni::JNIEnv;

// Class name for the diagnostics reporter.
static CLS_DIAGNOSTICS_REPORTER: &str = "elide/runtime/diag/NativeDiagnostics";

// Method signature which accepts an array of `elide/runtime/diag/DiagnosticInfo` objects.
static METHOD_SIG_REPORT_DIAGNOSTICS: &str = "(Lelide/runtime/diag/DiagnosticInfo;)V";

#[inline]
fn maybe_invoke_string_setter(
env: &mut JNIEnv,
value: &Option<String>,
record: &JObject,
method: &str,
) {
if let Some(advice) = &value {
let jmsg = env
.new_string(advice)
.expect("failed to allocate diagnostic string");
let val = JValue::Object(&jmsg);
let out = env.call_method(
record,
method,
format!("(L{:};)V", "java/lang/String").as_str(),
&[val],
);
out.unwrap_or_else(|_| panic!("failed to call {:} on diagnostic", method));
}
}

/// Diagnostic severity.
///
/// Maps across different types of severity from various tools. Equivalent in JVM is: `elide.runtime.diag.Severity`.
#[derive(Copy, Debug, Clone, Default)]
pub enum Severity {
#[default]
Info = 0,
Warn = 1,
Error = 2,
}

#[derive(Debug)]
pub enum DiagnosticError {
Fail = -1,
}

// Name of the class which hosts a mutable diagnostic record.
static DIAGNOSTIC_CLASS_NAME: &str = "elide/runtime/diag/MutableDiagnostic";

/// Mutable diagnostic record.
///
/// Used for building diagnostic information from native contexts; backed by a Java object.
#[derive(Debug, Default)]
pub struct MutableDiagnostic {
/// Severity for this diagnostic.
severity: Severity,

/// Language which relates to this diagnostic, as applicable.
lang: Option<String>,

/// Tool that reported this diagnostic, if known/applicable.
tool: Option<String>,

/// Message for this diagnostic.
message: Option<String>,

/// Advice for this diagnostic.
advice: Option<String>,
}

/// Describes the structure of a mutable diagnostic builder.
pub trait DiagnosticBuilder {
/// Set the language tag value for this diagnostic.
fn with_lang(&mut self, advice: &str) -> &mut Self;

/// Set the tool tag value for this diagnostic.
fn with_tool(&mut self, advice: &str) -> &mut Self;

/// Set the message for this diagnostic.
fn with_message(&mut self, message: &str) -> &mut Self;

/// Set the advice value for this diagnostic.
fn with_advice(&mut self, advice: &str) -> &mut Self;

/// Set the `Severity` level for this diagnostic.
fn with_severity(&mut self, severity: Severity) -> &mut Self;

/// Build the final diagnostic record.
fn build<'a>(&self, env: &mut JNIEnv<'a>) -> Result<JObject<'a>, DiagnosticError>;
}

impl DiagnosticBuilder for MutableDiagnostic {
fn with_lang(&mut self, lang: &str) -> &mut Self {
self.lang = Some(lang.to_string());
self
}

fn with_tool(&mut self, tool: &str) -> &mut Self {
self.tool = Some(tool.to_string());
self
}

fn with_message(&mut self, message: &str) -> &mut Self {
self.message = Some(message.to_string());
self
}

fn with_advice(&mut self, advice: &str) -> &mut Self {
self.advice = Some(advice.to_string());
self
}

fn with_severity(&mut self, severity: Severity) -> &mut Self {
self.severity = severity;
self
}

fn build<'a>(&self, env: &mut JNIEnv<'a>) -> Result<JObject<'a>, DiagnosticError> {
let cls = env
.find_class(DIAGNOSTIC_CLASS_NAME)
.unwrap_or_else(|_| panic!("failed to locate '{}'", DIAGNOSTIC_CLASS_NAME));
let record = env.new_object(cls, "()V", &[]).unwrap_or_else(|_| {
panic!(
"failed to construct instance of '{}'",
DIAGNOSTIC_CLASS_NAME
)
});
let severity_value = JValue::Int(self.severity as i32);

env
.call_method(
&record,
"setSeverity",
format!("({})L{:};", "I", DIAGNOSTIC_CLASS_NAME).as_str(),
&[severity_value],
)
.expect("failed to call setSeverity on diagnostic");

maybe_invoke_string_setter(env, &self.message, &record, "setMessage");
maybe_invoke_string_setter(env, &self.advice, &record, "setAdvice");
Ok(record)
}
}

/// Diagnostic record.
///
/// Builder for an eventual finalized diagnostic record. Equivalent in JVM is: `elide.runtime.diag.MutableDiagnostic`.
pub fn create_diagnostic() -> MutableDiagnostic {
MutableDiagnostic::default()
}

/// Report an un-built diagnostic record.
pub fn report_diagnostic(
env: &mut JNIEnv,
builder: MutableDiagnostic,
) -> Result<(), DiagnosticError> {
let rec = builder
.build(env)
.expect("failed to build diagnostic record");

let jcls = env
.find_class(CLS_DIAGNOSTICS_REPORTER)
.unwrap_or_else(|_| {
panic!(
"failed to find diagnostics reporter class '{:}'",
CLS_DIAGNOSTICS_REPORTER
)
});
let ret = env
.call_static_method(
jcls,
"reportNativeDiagnostic",
METHOD_SIG_REPORT_DIAGNOSTICS,
&[JValue::Object(&rec)],
)
.or_else(|_| {
env.exception_describe();
Err(DiagnosticError::Fail)
});
match ret {
Ok(_) => Ok(()),
Err(e) => Err(e),
}
}

/// JNI: Create a diagnostic record.
///
/// This method round-trips from JVM to create a mutable diagnostic record natively; mostly used for testing.
#[jni("elide.runtime.diag.NativeDiagnostics")]
pub fn createDiagnostic<'a>(mut env: JNIEnv<'a>, _class: JClass<'a>) -> JObject<'a> {
let mut builder = create_diagnostic();
builder.with_severity(Severity::Warn);
builder.with_message("There was an issue");
let diag = builder
.build(&mut env)
.expect("failed to build diagnostic record");
let _ = report_diagnostic(&mut env, builder);
diag
}
29 changes: 29 additions & 0 deletions crates/js/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#
# Copyright (c) 2024 Elide Technologies, Inc.
#
# Licensed under the MIT license (the "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# https://opensource.org/license/mit/
#
# Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
# an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under the License.
#

[package]
name = "js"
edition = "2021"
license = "MIT"
workspace = "../.."
version = "1.0.0-alpha13-SNAPSHOT"

[lib]
crate-type = ["lib", "cdylib", "staticlib"]

[dependencies]
java_native = { workspace = true }
jni = { workspace = true, default-features = false }
jni-sys = { workspace = true }
oxc = { workspace = true }
diag = { workspace = true }
Loading

0 comments on commit eb83a8b

Please sign in to comment.