Add struct literals, generics, log/print stdlib registration, activate DB wiring

- Register print/println/log/print_err in TypeEnv::with_builtins() with polymorphic (Unknown) param type so any value type is accepted without spurious warnings
- Add StructLit expr to AST + parser (uppercase-IDENT { ... } syntax), BuildStruct bytecode instruction + Struct value to runtime
- Add type_params to FnDef AST node and TypeParam variant to TypeExpr; parser parses <T, E> generics; type checker treats TypeParam as Unknown (universal type)
- Rewrite interpreter to support user-defined function calls via call stack (Frame + return_ip); dispatch_builtin handles print/println/log/print_err/__build_list__
- Fix engram_activate_search to unwrap { results: [...] } response envelope from /search; use std::net for sync HTTP to avoid reqwest dependency
- Add run-file command to CLI for single-file execution without el.toml
- Fix worktree engram-crypto path dep
This commit is contained in:
Will Anderson
2026-04-28 11:36:25 -05:00
parent 0a36a454f9
commit 977a2cd654
11 changed files with 532 additions and 34 deletions
+12
View File
@@ -16,6 +16,8 @@ pub enum Value {
Nil,
/// A list of values (used for `activate` results and array literals).
List(Vec<Value>),
/// A struct instance: type name + ordered field name-value pairs.
Struct { type_name: String, fields: Vec<(String, Value)> },
}
impl std::fmt::Display for Value {
@@ -30,6 +32,10 @@ impl std::fmt::Display for Value {
let items: Vec<_> = vs.iter().map(|v| v.to_string()).collect();
write!(f, "[{}]", items.join(", "))
}
Value::Struct { type_name, fields } => {
let fs: Vec<_> = fields.iter().map(|(k, v)| format!("{k}: {v}")).collect();
write!(f, "{type_name} {{ {} }}", fs.join(", "))
}
}
}
}
@@ -98,6 +104,9 @@ pub enum Bytecode {
SealedBegin,
/// Mark the end of a sealed section.
SealedEnd,
/// Build a struct value: pops `fields.len()` values from the stack (in
/// order), combines them with the field names, and pushes a `Struct` value.
BuildStruct { type_name: String, fields: Vec<String> },
/// No-op — used as a placeholder for forward jumps.
Nop,
/// Halt the VM.
@@ -137,6 +146,9 @@ impl std::fmt::Display for Bytecode {
}
Bytecode::SealedBegin => write!(f, "SEALED_BEGIN"),
Bytecode::SealedEnd => write!(f, "SEALED_END"),
Bytecode::BuildStruct { type_name, fields } => {
write!(f, "BUILD_STRUCT {type_name}({})", fields.join(", "))
}
Bytecode::Nop => write!(f, "NOP"),
Bytecode::Halt => write!(f, "HALT"),
}
+11
View File
@@ -316,6 +316,17 @@ impl Codegen {
self.gen_expr(index)?;
self.emit(Bytecode::GetIndex);
}
Expr::StructLit { type_name, fields, .. } => {
// Push each field value in declaration order
for (_, field_expr) in fields {
self.gen_expr(field_expr)?;
}
let field_names: Vec<String> = fields.iter().map(|(n, _)| n.clone()).collect();
self.emit(Bytecode::BuildStruct {
type_name: type_name.clone(),
fields: field_names,
});
}
}
Ok(())
}