Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
213 changes: 208 additions & 5 deletions baml_language/Cargo.lock

Large diffs are not rendered by default.

7 changes: 5 additions & 2 deletions baml_language/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ baml_compiler_lexer = { path = "crates/baml_compiler_lexer" }
baml_compiler_parser = { path = "crates/baml_compiler_parser" }
baml_compiler_syntax = { path = "crates/baml_compiler_syntax" }
bex_project = { path = "crates/bex_project" }
baml_exec = { path = "crates/baml_exec" }
bex_engine = { path = "crates/bex_engine" }
sys_llm = { path = "crates/sys_llm" }
sys_ops = { path = "crates/sys_ops" }
Expand Down Expand Up @@ -139,6 +140,8 @@ quote = { version = "1" }
ratatui = "0.29"
regex = { version = "1.10.2" }
base64 = "0.22"
bitcode = { version = "0.6", features = [ "serde" ] }
libsui = { version = "0.14" }
reqwest = { version = "0.13.1", default-features = false, features = [
"json",
"stream",
Expand All @@ -154,13 +157,13 @@ salsa = { git = "https://github.com/salsa-rs/salsa.git", rev = "cdd0b85516a52c18
serde = { version = "1.0.197", features = [ "derive" ] }
serde_json = { version = "1.0.113", features = [ "preserve_order" ] }
similar = { version = "2.4.0", features = [ "inline" ] }
smol_str = { version = "0.3" }
smol_str = { version = "0.3", features = [ "serde" ] }
strsim = { version = "0.11.1" }
syn = { version = "2", features = [ "full" ] }
taplo = { version = "0.13" }
tempfile = { version = "3" }
time = { version = "0.3", features = [ "formatting", "macros" ] }
text-size = { version = "1.1" }
text-size = { version = "1.1", features = [ "serde" ] }
thiserror = { version = "2.0.0" }
toml = { version = "0.8" }
toml_edit = { version = "0.22" }
Expand Down
1 change: 1 addition & 0 deletions baml_language/crates/baml_base/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ workspace = true
[dependencies]
ariadne = { workspace = true }
salsa = { workspace = true }
serde = { workspace = true }
smol_str = { workspace = true }
text-size = { workspace = true }

10 changes: 7 additions & 3 deletions baml_language/crates/baml_base/src/attr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,17 @@
//! These live in `baml_base` b/c they're shared by `baml_compiler_tir::Ty`
//! (TIR) and `baml_type::Ty` (VIR+).

use serde::{Deserialize, Serialize};

use crate::core_types::Span;

/// Binary present/absent flag for SAP attributes.
///
/// Used instead of `bool` for extensibility — future attributes may
/// need additional states (e.g., `Inherited`, `Explicit`).
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Default)]
#[derive(
Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Default, Serialize, Deserialize,
)]
pub enum TyAttrValue {
#[default]
Unset,
Expand All @@ -34,7 +38,7 @@ impl TyAttrValue {
}

/// A single `@assert` attached to a type expression.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct TyAssert {
/// Index into the program's function table — the assertion body
/// compiled to a `(value) -> bool` function.
Expand Down Expand Up @@ -67,7 +71,7 @@ impl Ord for TyAssert {
///
/// BEP-006 v12 defines three binary (present/absent) SAP attributes
/// that control how the schema-aligned parser handles each streaming state.
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Default)]
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Default, Serialize, Deserialize)]
pub struct TyAttr {
/// `@sap.parse_without_null`: during parsing (both in-progress and done
/// states), exclude `null` from the type's parse candidates.
Expand Down
13 changes: 7 additions & 6 deletions baml_language/crates/baml_base/src/core_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
use std::fmt;

use ariadne;
use serde::{Deserialize, Serialize};
use smol_str::SmolStr;
use text_size::{TextRange, TextSize};

Expand Down Expand Up @@ -32,7 +33,7 @@ use text_size::{TextRange, TextSize};
///
/// - **Roslyn** (C#): synthetic `SyntaxTree`s constructed with a virtual file path.
/// - **Clang**: bit 31 of `SourceLocation` distinguishes file vs macro-expansion locs.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default, Serialize, Deserialize)]
pub struct FileId(u32);

impl FileId {
Expand Down Expand Up @@ -84,7 +85,7 @@ impl fmt::Display for FileId {
}

/// A span in source code, tracking both file and position
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct Span {
pub file_id: FileId,
pub range: TextRange,
Expand Down Expand Up @@ -142,7 +143,7 @@ impl ariadne::Span for Span {
pub type Name = SmolStr;

/// The types of media we support
#[derive(Debug, Clone, PartialEq, Eq, Hash, Copy)]
#[derive(Debug, Clone, PartialEq, Eq, Hash, Copy, Serialize, Deserialize)]
pub enum MediaKind {
Image,
Audio,
Expand All @@ -163,7 +164,7 @@ impl fmt::Display for MediaKind {
}
}

#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
pub enum Literal {
Int(i64),
Float(String),
Expand All @@ -183,7 +184,7 @@ impl fmt::Display for Literal {
}

/// Module identifier (for multi-file support)
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct ModuleId(u32);

impl ModuleId {
Expand All @@ -197,7 +198,7 @@ impl ModuleId {
}

/// Severity level for diagnostics
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum Severity {
Error,
Warning,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,20 @@ class UserPanic {
message string
}

/// A clean process-termination request from `baml.sys.exit(code)`.
///
/// Catchable like any other panic; if left unhandled, the engine
/// terminates the process with this code. Patterned after Python's
/// `SystemExit`.
class Exit {
code int
}

/// Memory allocation failure. This happens when an operation would have caused an unrecoverable
/// Out-Of-Memory error so we panic instead. Note that not all memory allocation failures are
/// guaranteed to panic; some may cause a hard failure.
class AllocFailure {
message string
}

type Panic = DivisionByZero | IndexOutOfBounds | MapKeyNotFound | StackOverflow | AssertionFailed | Unreachable | UserPanic | AllocFailure
type Panic = DivisionByZero | IndexOutOfBounds | MapKeyNotFound | StackOverflow | AssertionFailed | Unreachable | UserPanic | Exit | AllocFailure
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ function panic(message: string) -> never {
$rust_function
}

function exit(code: int) -> never {
$rust_function
}

function now_ms() -> int {
$rust_function
}
Expand Down
1 change: 1 addition & 0 deletions baml_language/crates/baml_builtins2_codegen/src/codegen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ fn is_fallible(path: &str) -> bool {
|| matches!(
path,
"baml.sys.panic"
| "baml.sys.exit"
| "baml.Uint8Array.zeroes"
| "baml.Uint8Array.from_array"
| "baml.Uint8Array.from_hex"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -592,7 +592,7 @@ pub fn generate_sys_op_enum(io_builtins: &[NativeBuiltin]) -> String {
.collect();

let tokens = quote! {
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub enum SysOp {
#(#variant_idents,)*
}
Expand Down
3 changes: 3 additions & 0 deletions baml_language/crates/baml_cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ workspace = true
[dependencies]
baml_codegen_python = { workspace = true }
baml_db = { workspace = true }
baml_exec = { workspace = true }
baml_fmt = { workspace = true }
baml_lsp2_actions = { workspace = true }
baml_lsp_server = { workspace = true }
Expand All @@ -30,9 +31,11 @@ bex_events_native = { workspace = true }
bex_vm_types = { workspace = true }
sys_native = { workspace = true }
anyhow = { workspace = true }
bitcode = { workspace = true }
clap = { workspace = true, features = [ "color", "env" ] }
clap-cargo = { workspace = true }
ctrlc = { workspace = true }
libsui = { workspace = true }
regex = { workspace = true }
serde_json = { workspace = true }
strsim = { workspace = true }
Expand Down
4 changes: 4 additions & 0 deletions baml_language/crates/baml_cli/src/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,9 @@ pub(crate) enum Commands {
#[command(about = "Run a BAML function or script", disable_help_flag = true)]
Run(crate::run_command::RunArgs),

#[command(about = "Package a BAML program into a standalone executable")]
Pack(crate::pack_command::PackArgs),

#[command(about = "Starts a language server", name = "lsp")]
LanguageServer(crate::lsp::LanguageServerArgs),
// #[command(about = "Start an interactive REPL for BAML expressions", hide = true)]
Expand Down Expand Up @@ -140,6 +143,7 @@ impl RuntimeCli {
}
},
Commands::Format(args) => args.run(),
Commands::Pack(args) => args.run(),
}
}
}
Expand Down
25 changes: 6 additions & 19 deletions baml_language/crates/baml_cli/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ pub(crate) mod format;
pub(crate) mod generate;
pub(crate) mod grep_command;
pub(crate) mod lsp;
pub(crate) mod pack_command;
pub(crate) mod project_load;
pub(crate) mod run_command;
pub(crate) mod test_command;
Expand All @@ -39,6 +40,9 @@ pub enum ExitCode {
TestFailure,
TestCancelled,
NoTestsRun,
/// User code requested a specific exit code via `baml.sys.exit(n)`.
/// Already narrowed to i32 (the `std::process::exit` contract).
Exit(i32),
}

impl From<ExitCode> for i32 {
Expand All @@ -56,25 +60,8 @@ impl From<ExitCode> for i32 {
ExitCode::Other | ExitCode::InvalidArgs => 4,
// No tests were found
ExitCode::NoTestsRun => 5,
}
}
}

impl From<ExitCode> for u32 {
fn from(exit_code: ExitCode) -> Self {
match exit_code {
// All tests passed
ExitCode::Success => 0,
// All tests completed, but some required human evaluation
ExitCode::HumanEvalRequired => 1,
// Some tests failed
ExitCode::TestFailure => 2,
// Execution was interrupted
ExitCode::TestCancelled => 3,
// Some internal error occurred
ExitCode::Other | ExitCode::InvalidArgs => 4,
// No tests were found
ExitCode::NoTestsRun => 5,
// `baml.sys.exit(n)` — the user's exact code, already narrowed.
ExitCode::Exit(n) => n,
}
}
}
Expand Down
8 changes: 7 additions & 1 deletion baml_language/crates/baml_cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@ fn main() -> Result<()> {

let argv: Vec<String> = std::env::args().collect();

// `run_cli` returns an `ExitCode` variant describing how the verb
// finished. The real process exit is deferred here so `run_cli` and
// its callees stay testable (no inline `std::process::exit`).
let exit_code = baml_cli::run_cli(argv)?;
std::process::exit(exit_code.into());
match exit_code {
baml_cli::ExitCode::Success => Ok(()),
other => std::process::exit(other.into()),
}
}
Loading
Loading