refactor: rename IS_PRIMOP -> PRIMOP_METADATA

This commit is contained in:
2026-01-04 17:32:38 +08:00
parent 45d777a157
commit 89b68d5fe9
6 changed files with 35 additions and 32 deletions

View File

@@ -9,7 +9,7 @@ import { create_thunk } from "../thunk";
* Symbol used to mark functions as primops (primitive operations) * Symbol used to mark functions as primops (primitive operations)
* This is similar to IS_THUNK but for builtin functions * This is similar to IS_THUNK but for builtin functions
*/ */
export const IS_PRIMOP = Symbol("is_primop"); export const PRIMOP_METADATA = Symbol("primop_metadata");
/** /**
* Metadata interface for primop functions * Metadata interface for primop functions
@@ -40,7 +40,7 @@ export const markPrimop = <T extends Function>(
applied: number = 0, applied: number = 0,
): T => { ): T => {
// Mark this function as a primop // Mark this function as a primop
(func as any)[IS_PRIMOP] = { (func as any)[PRIMOP_METADATA] = {
name, name,
arity, arity,
applied, applied,
@@ -59,7 +59,7 @@ export const markPrimop = <T extends Function>(
}) as any; }) as any;
// Copy the primop metadata to the wrapper // Copy the primop metadata to the wrapper
wrappedFunc[IS_PRIMOP] = { wrappedFunc[PRIMOP_METADATA] = {
name, name,
arity, arity,
applied, applied,
@@ -76,12 +76,12 @@ export const markPrimop = <T extends Function>(
* @param value - Value to check * @param value - Value to check
* @returns true if value is marked as a primop * @returns true if value is marked as a primop
*/ */
export const is_primop = (value: unknown): value is Function & { [IS_PRIMOP]: PrimopMetadata } => { export const is_primop = (value: unknown): value is Function & { [PRIMOP_METADATA]: PrimopMetadata } => {
return ( return (
typeof value === "function" && typeof value === "function" &&
IS_PRIMOP in value && PRIMOP_METADATA in value &&
typeof value[IS_PRIMOP] === "object" && typeof value[PRIMOP_METADATA] === "object" &&
value[IS_PRIMOP] !== null value[PRIMOP_METADATA] !== null
); );
}; };
@@ -92,7 +92,7 @@ export const is_primop = (value: unknown): value is Function & { [IS_PRIMOP]: Pr
*/ */
export const get_primop_metadata = (func: unknown): PrimopMetadata | undefined => { export const get_primop_metadata = (func: unknown): PrimopMetadata | undefined => {
if (is_primop(func)) { if (is_primop(func)) {
return func[IS_PRIMOP]; return func[PRIMOP_METADATA];
} }
return undefined; return undefined;
}; };
@@ -117,7 +117,7 @@ import * as misc from "./misc";
* - Single argument functions: (a) => result * - Single argument functions: (a) => result
* - Multi-argument functions: (a) => (b) => result * - Multi-argument functions: (a) => (b) => result
* *
* All primop functions are marked with IS_PRIMOP symbol for runtime introspection * All primop functions are marked with PRIMOP_METADATA symbol for runtime introspection
*/ */
export const builtins: any = { export const builtins: any = {
add: markPrimop(arithmetic.add, "add", 2), add: markPrimop(arithmetic.add, "add", 2),

View File

@@ -7,7 +7,7 @@
import { create_thunk, force, is_thunk, IS_THUNK } from "./thunk"; import { create_thunk, force, is_thunk, IS_THUNK } from "./thunk";
import { select, select_with_default, validate_params, resolve_path } from "./helpers"; import { select, select_with_default, validate_params, resolve_path } from "./helpers";
import { op } from "./operators"; import { op } from "./operators";
import { builtins, IS_PRIMOP } from "./builtins"; import { builtins, PRIMOP_METADATA } from "./builtins";
export type NixRuntime = typeof Nix; export type NixRuntime = typeof Nix;
@@ -27,7 +27,7 @@ export const Nix = {
op, op,
builtins, builtins,
IS_PRIMOP, PRIMOP_METADATA,
}; };
globalThis.Nix = Nix; globalThis.Nix = Nix;

View File

@@ -62,7 +62,7 @@ impl<Ctx: CodegenContext> Compile<Ctx> for Ir {
&Ir::ExprRef(expr_id) => { &Ir::ExprRef(expr_id) => {
format!("expr{}", expr_id.0) format!("expr{}", expr_id.0)
} }
Ir::Builtin(_) => "Nix.builtins".to_string(), Ir::Builtins(_) => "Nix.builtins".to_string(),
Ir::ConcatStrings(x) => x.compile(ctx), Ir::ConcatStrings(x) => x.compile(ctx),
Ir::HasAttr(x) => x.compile(ctx), Ir::HasAttr(x) => x.compile(ctx),
&Ir::Assert(Assert { assertion, expr }) => { &Ir::Assert(Assert { assertion, expr }) => {
@@ -279,7 +279,7 @@ impl<Ctx: CodegenContext> Compile<Ctx> for ConcatStrings {
.iter() .iter()
.map(|part| { .map(|part| {
let compiled = ctx.get_ir(*part).compile(ctx); let compiled = ctx.get_ir(*part).compile(ctx);
// TODO: coercce to string // TODO: coerce to string
format!("String(Nix.force({}))", compiled) format!("String(Nix.force({}))", compiled)
}) })
.collect(); .collect();

View File

@@ -29,13 +29,13 @@ impl Drop for Context {
impl Default for Context { impl Default for Context {
fn default() -> Self { fn default() -> Self {
use crate::ir::{Attr, Builtin, Select, ToIr}; use crate::ir::{Attr, Builtins, Select, ToIr};
let mut symbols = DefaultStringInterner::new(); let mut symbols = DefaultStringInterner::new();
let mut irs = Vec::new(); let mut irs = Vec::new();
let mut global = HashMap::new(); let mut global = HashMap::new();
irs.push(Builtin.to_ir()); irs.push(Builtins.to_ir());
let builtins_expr = ExprId(0); let builtins_expr = ExprId(0);
let builtins_sym = symbols.get_or_intern("builtins"); let builtins_sym = symbols.get_or_intern("builtins");

View File

@@ -60,7 +60,7 @@ ir! {
Arg(ArgId), Arg(ArgId),
ExprRef(ExprId), ExprRef(ExprId),
Thunk(ExprId), Thunk(ExprId),
Builtin, Builtins,
} }
impl AttrSet { impl AttrSet {
@@ -379,6 +379,9 @@ pub struct Path {
} }
/// Represents the special `builtins` global object. /// Represents the special `builtins` global object.
/// This is a unit struct with no fields as it maps directly to the runtime builtins.
#[derive(Debug)] #[derive(Debug)]
pub struct Builtin; pub struct Builtins;
/// Represents an attribute in `builtins`.
#[derive(Debug)]
pub struct Builtin(pub String);

View File

@@ -206,17 +206,17 @@ fn op_resolve_path(#[string] path: String) -> std::result::Result<String, NixErr
struct RuntimeContext<'a, 'b> { struct RuntimeContext<'a, 'b> {
scope: &'a v8::PinnedRef<'a, v8::HandleScope<'b>>, scope: &'a v8::PinnedRef<'a, v8::HandleScope<'b>>,
is_thunk_symbol: Option<v8::Local<'a, v8::Symbol>>, is_thunk_symbol: Option<v8::Local<'a, v8::Symbol>>,
is_primop_symbol: Option<v8::Local<'a, v8::Symbol>>, primop_metadata_symbol: Option<v8::Local<'a, v8::Symbol>>,
} }
impl<'a, 'b> RuntimeContext<'a, 'b> { impl<'a, 'b> RuntimeContext<'a, 'b> {
fn new(scope: &'a v8::PinnedRef<'a, v8::HandleScope<'b>>) -> Self { fn new(scope: &'a v8::PinnedRef<'a, v8::HandleScope<'b>>) -> Self {
let is_thunk_symbol = Self::get_is_thunk_symbol(scope); let is_thunk_symbol = Self::get_is_thunk_symbol(scope);
let is_primop_symbol = Self::get_is_primop_symbol(scope); let primop_metadata_symbol = Self::get_primop_metadata_symbol(scope);
Self { Self {
scope, scope,
is_thunk_symbol, is_thunk_symbol,
is_primop_symbol, primop_metadata_symbol,
} }
} }
@@ -237,18 +237,18 @@ impl<'a, 'b> RuntimeContext<'a, 'b> {
} }
} }
fn get_is_primop_symbol( fn get_primop_metadata_symbol(
scope: &v8::PinnedRef<'a, v8::HandleScope<'b>>, scope: &v8::PinnedRef<'a, v8::HandleScope<'b>>,
) -> Option<v8::Local<'a, v8::Symbol>> { ) -> Option<v8::Local<'a, v8::Symbol>> {
let global = scope.get_current_context().global(scope); let global = scope.get_current_context().global(scope);
let nix_key = v8::String::new(scope, "Nix")?; let nix_key = v8::String::new(scope, "Nix")?;
let nix_obj = global.get(scope, nix_key.into())?.to_object(scope)?; let nix_obj = global.get(scope, nix_key.into())?.to_object(scope)?;
let is_primop_sym_key = v8::String::new(scope, "IS_PRIMOP")?; let primop_metadata_sym_key = v8::String::new(scope, "PRIMOP_METADATA")?;
let is_primop_sym = nix_obj.get(scope, is_primop_sym_key.into())?; let primop_metadata_sym = nix_obj.get(scope, primop_metadata_sym_key.into())?;
if is_primop_sym.is_symbol() { if primop_metadata_sym.is_symbol() {
is_primop_sym.try_cast().ok() primop_metadata_sym.try_cast().ok()
} else { } else {
None None
} }
@@ -382,13 +382,13 @@ fn primop_name<'a, 'b>(
return None; return None;
} }
// Use cached IS_PRIMOP symbol from context // Use cached PRIMOP_METADATA symbol from context
let is_primop_sym = ctx.is_primop_symbol?; let primop_metadata_sym = ctx.primop_metadata_symbol?;
let scope = ctx.scope; let scope = ctx.scope;
let obj = val.to_object(scope).unwrap(); let obj = val.to_object(scope).unwrap();
if let Some(metadata) = obj.get(scope, is_primop_sym.into()) if let Some(metadata) = obj.get(scope, primop_metadata_sym.into())
&& let Some(metadata_obj) = metadata.to_object(scope) && let Some(metadata_obj) = metadata.to_object(scope)
&& let Some(name_key) = v8::String::new(scope, "name") && let Some(name_key) = v8::String::new(scope, "name")
&& let Some(name_val) = metadata_obj.get(scope, name_key.into()) && let Some(name_val) = metadata_obj.get(scope, name_key.into())
@@ -406,13 +406,13 @@ fn primop_app_name<'a, 'b>(
) -> Option<String> { ) -> Option<String> {
let name = primop_name(val, ctx)?; let name = primop_name(val, ctx)?;
// Get cached IS_PRIMOP symbol // Get cached PRIMOP_METADATA symbol
let is_primop_sym = ctx.is_primop_symbol?; let primop_metadata_sym = ctx.primop_metadata_symbol?;
let scope = ctx.scope; let scope = ctx.scope;
let obj = val.to_object(scope).unwrap(); let obj = val.to_object(scope).unwrap();
if let Some(metadata) = obj.get(scope, is_primop_sym.into()) if let Some(metadata) = obj.get(scope, primop_metadata_sym.into())
&& let Some(metadata_obj) = metadata.to_object(scope) && let Some(metadata_obj) = metadata.to_object(scope)
&& let Some(applied_key) = v8::String::new(scope, "applied") && let Some(applied_key) = v8::String::new(scope, "applied")
&& let Some(applied_val) = metadata_obj.get(scope, applied_key.into()) && let Some(applied_val) = metadata_obj.get(scope, applied_key.into())