Skip to content

Commit ac13f46

Browse files
committed
first pass
1 parent 8173b0e commit ac13f46

38 files changed

Lines changed: 2941 additions & 599 deletions

File tree

baml_language/crates/baml_builtins2/baml_std/baml/ns_host/host.baml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,13 @@
1010
/// throw rides the VM's normal exception unwinder. A host value left
1111
/// untyped at the boundary erases `E` to `unknown`, which accepts any
1212
/// thrown value — including an opaque `baml.errors.HostCallable`.
13+
///
14+
/// `args` is a two-element pack the VM builds in `host_closure_call_sysop`:
15+
/// `[positional_required_args, { optional_name: value }]`. The VM has already
16+
/// split the call by the callable's declared params (using the captured
17+
/// `Object::HostClosure`), dropping omitted optionals — so each bridge applies
18+
/// its own calling convention (TS `$opts`, Python kwargs) without needing the
19+
/// callee type on the wire.
1320
function call_host_value<T, E>(handle: HostValue, args: unknown[])
1421
-> T throws E {
1522
$rust_io_function

baml_language/crates/baml_cli/src/snapshots/baml_cli__describe_command_tests__render_builtin_package_listing.snap

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,8 +101,8 @@ function future.any <builtin>/baml/ns_future/futur
101101
class glob.ScanOptions <builtin>/baml/ns_glob/glob.baml:2
102102
class glob.Glob <builtin>/baml/ns_glob/glob.baml:18
103103
function glob.new <builtin>/baml/ns_glob/glob.baml:34
104-
function host.call_host_value <builtin>/baml/ns_host/host.baml:13
105-
class host.HostValue <builtin>/baml/ns_host/host.baml:20
104+
function host.call_host_value <builtin>/baml/ns_host/host.baml:20
105+
class host.HostValue <builtin>/baml/ns_host/host.baml:27
106106
class http.Request <builtin>/baml/ns_http/http.baml:8
107107
class http.Response <builtin>/baml/ns_http/http.baml:16
108108
class http.SseStream <builtin>/baml/ns_http/http.baml:94
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// A host-callable parameter whose callable type tries to give one of its own
2+
// arguments a default (`y: int = 10`). A default is a property of a function
3+
// *declaration*, not a function *type*, so the parser rejects it — the same
4+
// `E0010` rule that rejects `type T = (a: int = 1) -> int`, here exercised in
5+
// the host-callback parameter position. This pins that an optional callback
6+
// argument must be written with the `?` marker (`y?: int`), never a default.
7+
function call_with_defaulted_callback(callback: (x: int, y: int = 10) -> string, x: int) -> string {
8+
callback(x)
9+
}

baml_language/crates/baml_tests/snapshots/broken_syntax/optional_parameter_defaults/baml_tests__broken_syntax__optional_parameter_defaults__01_lexer__callback_param_defaults.snap

Lines changed: 157 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

baml_language/crates/baml_tests/snapshots/broken_syntax/optional_parameter_defaults/baml_tests__broken_syntax__optional_parameter_defaults__02_parser__callback_param_defaults.snap

Lines changed: 64 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

baml_language/crates/baml_tests/snapshots/broken_syntax/optional_parameter_defaults/baml_tests__broken_syntax__optional_parameter_defaults__05_diagnostics.snap

Lines changed: 20 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

baml_language/crates/baml_tests/src/compiler2_tir/snapshots/baml_tests__compiler2_tir__phase5__snapshot_baml_package_items.snap

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

baml_language/crates/bex_engine/src/conversion.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -585,6 +585,10 @@ impl BexEngine {
585585
ret_ty: Box::new(ret),
586586
throws_ty: Box::new(normalized_throws),
587587
arity: params.len(),
588+
// Capture the declared params (names + optionality) so the VM
589+
// can split the call args into positional + supplied-optional
590+
// (by name) on dispatch, for the per-bridge argument reshape.
591+
params: Box::new(params.clone()),
588592
};
589593
Value::object(
590594
holder

baml_language/crates/bex_engine/tests/host_value_callable.rs

Lines changed: 23 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@
33
//! through `SysOp::BamlHostCallHostValue` when BAML code invokes it.
44
//!
55
//! The tests stand up a fake host dispatcher that:
6-
//! 1. Decodes the engine-side `BamlOutboundValue` args (a list of typed
7-
//! `BamlOutboundValue`s, per `host_impls::call_host_value`).
6+
//! 1. Decodes the engine-side `BamlToHostArgs` list (the resolved, declared-order
7+
//! supplied args, per `host_impls::call_host_value`) and flattens it back to
8+
//! a positional list.
89
//! 2. Looks up the per-key behaviour registered by the test.
910
//! 3. Calls `sys_native::host_dispatch::complete_with_value` (or
1011
//! `complete_with_error`) directly with a `BexExternalValue`. This
@@ -32,7 +33,7 @@ use bex_engine::{
3233
BexEngine, BexExternalValue, CancellationToken, EngineError, FunctionCallContextBuilder,
3334
};
3435
use bex_resource_types::{HostValueArc, HostValueKind};
35-
use bridge_ctypes::baml_core::cffi::{BamlOutboundValue, baml_outbound_value};
36+
use bridge_ctypes::baml_core::cffi::{BamlOutboundValue, BamlToHostArgs, baml_outbound_value};
3637
use common::compile_for_engine;
3738
use indexmap::IndexMap;
3839
use prost::Message;
@@ -202,25 +203,23 @@ extern "C" fn global_dispatch(host_value_key: u64, call_id: u32, args: *const u8
202203
unsafe { std::slice::from_raw_parts(args, length) }.to_vec()
203204
};
204205

205-
let outbound = match BamlOutboundValue::decode(bytes.as_slice()) {
206+
// The engine sends a `BamlToHostArgs` list it already resolved against the
207+
// callable's declared params (omitted optionals dropped), in declared order.
208+
// Real bridges apply their calling convention (TS `$opts`, Python kwargs);
209+
// these tests invoke positionally, so we take every arg's value in order.
210+
// The callables exercised here have no optional params.
211+
let to_host_args = match BamlToHostArgs::decode(bytes.as_slice()) {
206212
Ok(v) => v,
207213
Err(e) => {
208214
complete_with_test_error(call_id, "DecodeError", &format!("decode failure: {e}"));
209215
return;
210216
}
211217
};
212-
213-
let items: Vec<BamlOutboundValue> = match outbound.value {
214-
Some(baml_outbound_value::Value::ListValue(list)) => list.items,
215-
other => {
216-
complete_with_test_error(
217-
call_id,
218-
"ProtocolError",
219-
&format!("expected ListValue in dispatch args, got {other:?}"),
220-
);
221-
return;
222-
}
223-
};
218+
let items: Vec<BamlOutboundValue> = to_host_args
219+
.args
220+
.into_iter()
221+
.filter_map(|arg| arg.value)
222+
.collect();
224223

225224
// Clone the behaviour out and drop the lock before invoking it; keep the
226225
// entry so the same key can be dispatched again (reusable callable).
@@ -452,9 +451,9 @@ async fn host_callable_invoked_from_native_map_continuation() {
452451

453452
// ============================================================================
454453
// Operand-layout pin: the VM hand-builds the `SysOp::BamlHostCallHostValue`
455-
// args as `[handle, args_array, ret_ty, throws_ty]` to match the
454+
// args as `[handle, args_pack, ret_ty, throws_ty]` to match the
456455
// codegen-generated glue (`sys_ops/.../io_generated.rs` extracts `__arg0`
457-
// as the handle via `as_owned_but_very_slow`, `__arg1` as the args list,
456+
// as the handle via `as_owned_but_very_slow`, `__arg1` as the args pack,
458457
// and `__arg2`/`type_arg_0` + `__arg3`/`type_arg_1` via
459458
// `as_baml_type_owned`). Nothing else pins this contract,
460459
// so a future codegen change to the type-arg operand position (or a swap
@@ -465,13 +464,15 @@ async fn host_callable_invoked_from_native_map_continuation() {
465464
// registered key (the behaviour table lookup by `host_value_key` succeeds);
466465
// if `args[0]` were not the handle, `as_owned_but_very_slow` would not yield
467466
// a `HostValue` and the sys-op would fail with a `TypeError` before dispatch.
468-
// * `args[1]` (args array) — asserted to decode to exactly the user args, in
469-
// order: `[Int(7), Int(8)]`. If `args[1]` carried the ret_ty `Object::Type`
470-
// instead, the glue's `BexExternalValue::Array` extraction would fail.
467+
// * `args[1]` (args pack) — the `[positional_array, optional_map]` pair the VM
468+
// builds; the dispatch decodes the `BamlToHostArgs` list and asserts the
469+
// values are exactly the user args, in order: `[Int(7), Int(8)]`. If
470+
// `args[1]` carried the ret_ty `Object::Type` instead, the glue's
471+
// `BexExternalValue::Array` extraction would fail.
471472
// * `args[2]` (ret_ty) — proven to carry the declared return `RuntimeTy` (`int`):
472473
// the host returns the sum (an `Int`), which only passes return-type
473474
// validation if `type_arg_0` decoded to `int`. If `args[2]` carried the
474-
// args array instead, `as_baml_type_owned` would fail and the call would
475+
// args pack instead, `as_baml_type_owned` would fail and the call would
475476
// error before reaching the host.
476477
// * `args[3]` (throws_ty) — packed by codegen and consumed by the
477478
// engine's host-throw injection site (`lib.rs::execute_sys_op` →

0 commit comments

Comments
 (0)