feat: stack var (WIP)

This commit is contained in:
2025-08-09 08:12:53 +08:00
parent fd182b6233
commit d8ad7fe904
36 changed files with 1521 additions and 1058 deletions

View File

@@ -39,7 +39,7 @@ pub fn builtins_impl(input: TokenStream) -> TokenStream {
}
};
let mut pub_item_mod: Vec<proc_macro2::TokenStream> = Vec::new();
let mut pub_item_mod = Vec::new();
let mut consts = Vec::new();
let mut global = Vec::new();
let mut scoped = Vec::new();
@@ -110,9 +110,9 @@ pub fn builtins_impl(input: TokenStream) -> TokenStream {
/// Constant values available in the global scope.
pub consts: [(&'static str, ::nixjit_value::Const); #mod_name::CONSTS_LEN],
/// Global functions available in the global scope.
pub global: [(&'static str, usize, fn(&mut Ctx, Vec<::nixjit_eval::Value>) -> ::nixjit_error::Result<::nixjit_eval::Value>); #mod_name::GLOBAL_LEN],
pub global: [(&'static str, usize, fn(&mut Ctx, ::nixjit_eval::Args) -> ::nixjit_error::Result<::nixjit_eval::Value>); #mod_name::GLOBAL_LEN],
/// Scoped functions, typically available under the `builtins` attribute set.
pub scoped: [(&'static str, usize, fn(&mut Ctx, Vec<::nixjit_eval::Value>) -> ::nixjit_error::Result<::nixjit_eval::Value>); #mod_name::SCOPED_LEN],
pub scoped: [(&'static str, usize, fn(&mut Ctx, ::nixjit_eval::Args) -> ::nixjit_error::Result<::nixjit_eval::Value>); #mod_name::SCOPED_LEN],
}
impl<Ctx: BuiltinsContext> Builtins<Ctx> {
@@ -169,7 +169,6 @@ fn generate_primop_wrapper(
let arg_pats: Vec<_> = user_args.rev().collect();
let arg_count = arg_pats.len();
// Generate code to unpack and convert arguments from the `Vec<Value>`.
let arg_unpacks = arg_pats.iter().enumerate().map(|(i, arg)| {
let arg_name = format_ident!("_arg{}", i, span = Span::call_site());
let arg_ty = match &arg {
@@ -178,8 +177,8 @@ fn generate_primop_wrapper(
};
quote! {
let #arg_name: #arg_ty = args.pop().ok_or_else(|| ::nixjit_error::Error::EvalError("Not enough arguments provided".to_string()))?
.try_into().map_err(|e| ::nixjit_error::Error::EvalError(format!("Argument type conversion failed: {}", e)))?;
let #arg_name: #arg_ty = args.pop().ok_or_else(|| ::nixjit_error::Error::eval_error("Not enough arguments provided".to_string()))?
.try_into().map_err(|e| ::nixjit_error::Error::eval_error(format!("Argument type conversion failed: {}", e)))?;
}
});
@@ -222,16 +221,16 @@ fn generate_primop_wrapper(
};
let arity = arg_names.len();
let fn_type = quote! { fn(&mut Ctx, Vec<::nixjit_eval::Value>) -> ::nixjit_error::Result<::nixjit_eval::Value> };
let fn_type = quote! { fn(&mut Ctx, ::nixjit_eval::Args) -> ::nixjit_error::Result<::nixjit_eval::Value> };
// The primop metadata tuple: (name, arity, wrapper_function_pointer)
let primop = quote! { (#name_str, #arity, #mod_name::#wrapper_name as #fn_type) };
// The generated wrapper function.
let wrapper = quote! {
pub fn #wrapper_name<Ctx: BuiltinsContext>(ctx: &mut Ctx, mut args: Vec<::nixjit_eval::Value>) -> ::nixjit_error::Result<::nixjit_eval::Value> {
pub fn #wrapper_name<Ctx: BuiltinsContext>(ctx: &mut Ctx, mut args: ::nixjit_eval::Args) -> ::nixjit_error::Result<::nixjit_eval::Value> {
if args.len() != #arg_count {
return Err(::nixjit_error::Error::EvalError(format!("Function '{}' expects {} arguments, but received {}", #name_str, #arg_count, args.len())));
return Err(::nixjit_error::Error::eval_error(format!("Function '{}' expects {} arguments, but received {}", #name_str, #arg_count, args.len())));
}
#(#arg_unpacks)*