Files
RustAst/src/ast/types.rs
T
Michael Schimmel 7042206ab6 feat: Implement AST binder and VM
Adds a new `Binder` struct that traverses the AST and resolves variable
references to concrete `Address` types (Local, Upvalue, Global). This
information is crucial for the Virtual Machine's execution phase.

Introduces the `BoundKind` enum to represent the AST after binding.

The `VM` is updated to handle `BoundKind` nodes and execute the bound
AST.
It now manages a call stack, local variables, and closures for function
calls and upvalue capturing.

The `Environment` struct is enhanced to manage global variables and
provide
a unified interface for parsing, binding, and executing scripts. It also
includes basic standard library functions.
2026-02-17 02:00:51 +01:00

105 lines
2.9 KiB
Rust

use std::sync::Arc;
use std::collections::HashMap;
use std::fmt;
use std::sync::Mutex;
use lazy_static::lazy_static;
use std::any::Any;
/// Simple source location
#[derive(Debug, Clone, Copy)]
pub struct SourceLocation {
pub line: u32,
pub col: u32,
}
/// Shared identity for nodes (Location, etc.)
#[derive(Debug, Clone)]
pub struct NodeIdentity {
pub location: SourceLocation,
}
pub type Identity = Arc<NodeIdentity>;
/// Interned string identifier
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Keyword(pub u32);
lazy_static! {
static ref KEYWORD_REGISTRY: Mutex<HashMap<String, u32>> = Mutex::new(HashMap::new());
static ref KEYWORD_REVERSE: Mutex<Vec<String>> = Mutex::new(Vec::new());
}
impl Keyword {
pub fn intern(name: &str) -> Self {
let mut reg = KEYWORD_REGISTRY.lock().unwrap();
if let Some(&id) = reg.get(name) {
Keyword(id)
} else {
let mut rev = KEYWORD_REVERSE.lock().unwrap();
let id = rev.len() as u32;
reg.insert(name.to_string(), id);
rev.push(name.to_string());
Keyword(id)
}
}
pub fn name(&self) -> String {
let rev = KEYWORD_REVERSE.lock().unwrap();
rev[self.0 as usize].clone()
}
}
/// Interface for custom objects (Closures, Series, Streams)
pub trait Object: fmt::Debug + Send + Sync {
fn type_name(&self) -> &'static str;
fn as_any(&self) -> &dyn Any;
}
/// Core data value in Myc Script (similar to TDataValue)
#[derive(Clone)]
pub enum Value {
Void,
Bool(bool),
Int(i64),
Float(f64),
Text(Arc<str>),
Keyword(Keyword),
List(Arc<Vec<Value>>),
Record(Arc<HashMap<Keyword, Value>>),
Function(Arc<dyn Fn(Vec<Value>) -> Value + Send + Sync>),
Object(Arc<dyn Object>), // For compiled Closures and other opaque types
}
impl Value {
pub fn is_truthy(&self) -> bool {
match self {
Value::Void => false,
Value::Bool(b) => *b,
_ => true,
}
}
}
impl fmt::Display for Value {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Value::Void => write!(f, "void"),
Value::Bool(b) => write!(f, "{}", b),
Value::Int(i) => write!(f, "{}", i),
Value::Float(fl) => write!(f, "{}", fl),
Value::Text(t) => write!(f, "\"{}\"", t),
Value::Keyword(k) => write!(f, ":{}", k.name()),
Value::List(l) => write!(f, "<list[{}]>", l.len()),
Value::Record(r) => write!(f, "<record[{}]>", r.len()),
Value::Function(_) => write!(f, "<native fn>"),
Value::Object(o) => write!(f, "<{}>", o.type_name()),
}
}
}
impl fmt::Debug for Value {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(self, f)
}
}