Skip to content
Merged
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
99 changes: 71 additions & 28 deletions engine/baml-compiler/src/builtin.rs
Original file line number Diff line number Diff line change
@@ -1,43 +1,70 @@
use baml_types::ir_type::TypeIR;
use baml_types::ir_type::{TypeIR, UnionConstructor};
use internal_baml_diagnostics::Span;

use crate::hir::{Class, Enum, EnumVariant, Field};

pub mod functions {
pub const FETCH_AS: &str = "baml.fetch_as";
pub const FETCH_VALUE: &str = "baml.fetch_value";
}

pub mod classes {
pub const REQUEST: &str = "std::Request";
pub const REQUEST: &str = "baml.Request";
pub const WATCH_OPTIONS: &str = "baml.WatchOptions";
}

pub mod enums {
pub const HTTP_METHOD: &str = "std::HttpMethod";
pub const HTTP_METHOD: &str = "baml.HttpMethod";
}

pub fn builtin_classes() -> Vec<Class> {
vec![Class {
name: String::from(classes::REQUEST),
methods: vec![],
fields: vec![
Field {
name: String::from("base_url"),
r#type: TypeIR::string(),
span: Span::fake(),
},
Field {
name: String::from("headers"),
r#type: TypeIR::map(TypeIR::string(), TypeIR::string()),
span: Span::fake(),
},
Field {
name: String::from("query_params"),
r#type: TypeIR::map(TypeIR::string(), TypeIR::string()),
span: Span::fake(),
},
],
span: Span::fake(),
}]
vec![
Class {
name: String::from(classes::REQUEST),
methods: vec![],
fields: vec![
Field {
name: String::from("base_url"),
r#type: TypeIR::string(),
span: Span::fake(),
},
Field {
name: String::from("headers"),
r#type: TypeIR::map(TypeIR::string(), TypeIR::string()),
span: Span::fake(),
},
Field {
name: String::from("query_params"),
r#type: TypeIR::map(TypeIR::string(), TypeIR::string()),
span: Span::fake(),
},
],
span: Span::fake(),
},
Class {
name: String::from(classes::WATCH_OPTIONS),
methods: vec![],
fields: vec![
Field {
name: String::from("channel"),
r#type: TypeIR::optional(TypeIR::string()),
span: Span::fake(),
},
Field {
name: String::from("when"),
// "never" | "manual" | (T -> bool)
// We use a generic function type with top type for T
r#type: TypeIR::optional(TypeIR::union(vec![
TypeIR::literal_string("never".to_string()),
TypeIR::literal_string("manual".to_string()),
TypeIR::arrow(vec![TypeIR::top()], TypeIR::bool()),
])),
span: Span::fake(),
},
],
span: Span::fake(),
},
]
}

pub fn builtin_enums() -> Vec<Enum> {
Expand All @@ -51,16 +78,32 @@ pub fn builtin_enums() -> Vec<Enum> {
}]
}

/// Create a type for the std::Request class
/// Create a type for the baml.Request class
pub fn std_request_type() -> TypeIR {
TypeIR::class(classes::REQUEST)
}

/// Create a function signature for std::fetch_value<T>
/// Create a function signature for baml.fetch_as<T>
pub fn baml_fetch_as_signature(return_type: TypeIR) -> TypeIR {
TypeIR::arrow(vec![TypeIR::string()], return_type)
}

/// Create a function signature for baml.fetch_value<T>
pub fn std_fetch_value_signature(return_type: TypeIR) -> TypeIR {
TypeIR::arrow(vec![TypeIR::class(classes::REQUEST)], return_type)
}

pub fn is_builtin_identifier(identifier: &str) -> bool {
identifier.starts_with("std::") || identifier == "true" || identifier == "false"
identifier.starts_with("baml.")
|| identifier == "true"
|| identifier == "false"
|| identifier == "null"
}

pub fn is_builtin_class(class_name: &str) -> bool {
class_name == classes::REQUEST || class_name == classes::WATCH_OPTIONS
}

pub fn is_builtin_enum(enum_name: &str) -> bool {
enum_name == enums::HTTP_METHOD
}
6 changes: 6 additions & 0 deletions engine/baml-compiler/src/codegen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -906,6 +906,12 @@ impl<'g> HirCompiler<'g> {
self.compile_expression(condition);
self.emit(Instruction::Assert);
}
thir::Statement::WatchOptions { .. } => {
// todo!("bytecode codegen update to variable's WatchOptions")
}
thir::Statement::WatchNotify { .. } => {
// todo!("bytecode codegen for manual notification trigger")
}
}
}

Expand Down
23 changes: 19 additions & 4 deletions engine/baml-compiler/src/hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ impl Hir {
Hir {
expr_functions: vec![],
llm_functions: vec![],
classes: vec![],
enums: vec![],
classes: crate::builtin::builtin_classes(),
enums: crate::builtin::builtin_enums(),
global_assignments: baml_types::BamlMap::new(),
}
}
Expand Down Expand Up @@ -186,6 +186,21 @@ pub enum Statement {
condition: Expression,
span: Span,
},

/// Configure watch options for a watched variable.
/// Syntax: `variable.$watch.options( baml.WatchOptions { channel: "channel", when: FilterFunc } )`
WatchOptions {
variable: String,
channel: Option<String>,
when: Option<String>,
span: Span,
},
/// Manually notify watchers of a variable.
/// Syntax: `variable.$watch.notify()`
WatchNotify {
variable: String,
span: Span,
},
}

#[derive(Clone, Debug)]
Expand Down Expand Up @@ -368,8 +383,8 @@ pub enum UnaryOperator {

/// A type argument to a generic function call.
///
/// std.fetch_value<int>(...) == TypeArg::Type(int),
/// std.fetch_value<T>(...) == TypeArg::TypeName("T")
/// baml.fetch_value<int>(...) == TypeArg::Type(int),
/// baml.fetch_value<T>(...) == TypeArg::TypeName("T")
#[derive(Clone, Debug)]
pub enum TypeArg {
Type(TypeIR),
Expand Down
41 changes: 34 additions & 7 deletions engine/baml-compiler/src/hir/dump.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,17 @@ impl Hir {
for func in &self.llm_functions {
docs.push(func.to_doc());
}
// Add classes
// Add classes (excluding builtins)
for class in &self.classes {
docs.push(class.to_doc());
if !crate::builtin::is_builtin_class(&class.name) {
docs.push(class.to_doc());
}
}
// Add enums
// Add enums (excluding builtins)
for enum_def in &self.enums {
docs.push(enum_def.to_doc());
if !crate::builtin::is_builtin_enum(&enum_def.name) {
docs.push(enum_def.to_doc());
}
}
if docs.is_empty() {
RcDoc::nil()
Expand Down Expand Up @@ -270,6 +274,32 @@ impl Statement {
.append(block)
.append(RcDoc::text("}"))
}
Statement::WatchOptions {
variable,
channel,
when,
..
} => {
let mut doc = RcDoc::text(variable.clone()).append(RcDoc::text(".$watch.options("));

let mut parts = vec![];
if let Some(n) = channel {
parts.push(
RcDoc::text("name: \"")
.append(RcDoc::text(n.clone()))
.append(RcDoc::text("\"")),
);
}
if let Some(w) = when {
parts.push(RcDoc::text("when: ").append(RcDoc::text(w.clone())));
}

doc = doc.append(RcDoc::intersperse(parts, RcDoc::text(", ")));
doc.append(RcDoc::text(");"))
}
Statement::WatchNotify { variable, .. } => {
RcDoc::text(variable.clone()).append(RcDoc::text(".$watch.notify();"))
}
}
}
}
Expand Down Expand Up @@ -695,9 +725,6 @@ impl AssignOp {
impl WatchSpec {
pub fn to_doc(&self) -> RcDoc<'static, ()> {
let mut args: Vec<String> = Vec::new();
if self.skip_def {
args.push("skip_def=true".to_string())
}
match &self.when {
WatchWhen::Manual => args.push("when=manual".to_string()),
WatchWhen::True => {}
Expand Down
Loading
Loading