Files
RustAst/src/ast/nodes.rs
T
Michael Schimmel beb693a068 Refactor: Implement block scoping and statement separation
This commit introduces fundamental changes to Myc's language structure
to enhance type safety and scoping clarity.

Key changes include:
- Introducing local scopes for `do` blocks.
- Separating statements (`def`, `assign`) from expressions, where
  statements now have no return value and are only allowed within
  blocks.
- A block now consists of multiple statements followed by a single final
  expression.
- Stricter validation rules are enforced, such as disallowing
  redefinition of local symbols in the same scope while allowing
  shadowing of outer symbols.
- Compiler errors are generated for statements used in expression
  contexts.

The implementation involved modifications to the AST, parser, binder
(scope-stack), and various compiler passes, along with VM runtime
optimizations.
2026-03-09 16:38:44 +01:00

131 lines
3.5 KiB
Rust

use crate::ast::types::{Identity, Object, Value};
use std::any::Any;
use std::fmt::Debug;
use std::rc::Rc;
/// A name with an optional context for macro hygiene.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Symbol {
pub name: Rc<str>,
/// Points to the identity of the Expansion node if this symbol
/// was created/referenced inside a macro expansion.
pub context: Option<Identity>,
}
impl From<Rc<str>> for Symbol {
fn from(name: Rc<str>) -> Self {
Self {
name,
context: None,
}
}
}
impl From<&str> for Symbol {
fn from(name: &str) -> Self {
Self {
name: Rc::from(name),
context: None,
}
}
}
/// A generic AST Node wrapper to preserve identity and metadata
#[derive(Debug, Clone, PartialEq)]
pub struct Node<K, T = ()> {
pub identity: Identity,
pub kind: K,
pub ty: T,
}
impl Object for Node<UntypedKind> {
fn type_name(&self) -> &'static str {
"ast-node"
}
fn as_any(&self) -> &dyn Any {
self
}
}
/// The base for custom node types (extensions)
pub trait CustomNode: Debug {
fn display_name(&self) -> &'static str;
fn clone_box(&self) -> Box<dyn CustomNode>;
}
impl Clone for Box<dyn CustomNode> {
fn clone(&self) -> Self {
self.clone_box()
}
}
#[derive(Debug, Clone)]
pub enum UntypedKind {
Nop,
Constant(Value),
/// A general identifier (used for both references and declarations in the untyped AST).
Identifier(Symbol),
/// A first-class field accessor (e.g. .name)
FieldAccessor(crate::ast::types::Keyword),
If {
cond: Box<Node<UntypedKind>>,
then_br: Box<Node<UntypedKind>>,
else_br: Option<Box<Node<UntypedKind>>>,
},
Def {
target: Box<Node<UntypedKind>>,
value: Box<Node<UntypedKind>>,
},
Assign {
target: Box<Node<UntypedKind>>,
value: Box<Node<UntypedKind>>,
},
Lambda {
params: Box<Node<UntypedKind>>,
body: Rc<Node<UntypedKind>>,
},
Call {
callee: Box<Node<UntypedKind>>,
args: Box<Node<UntypedKind>>,
},
Again {
args: Box<Node<UntypedKind>>,
},
Pipe {
inputs: Vec<Node<UntypedKind>>,
lambda: Box<Node<UntypedKind>>,
},
Block {
statements: Vec<Node<UntypedKind>>,
result: Box<Node<UntypedKind>>,
},
Tuple {
elements: Vec<Node<UntypedKind>>,
},
Record {
fields: Vec<(Node<UntypedKind>, Node<UntypedKind>)>,
},
/// A macro declaration that can be expanded at compile time.
MacroDecl {
name: Symbol,
params: Box<Node<UntypedKind>>,
body: Box<Node<UntypedKind>>,
},
/// A template for AST nodes, allowing for substitutions. (Quasiquote)
Template(Box<Node<UntypedKind>>),
/// A placeholder inside a template to be replaced by a node or value. (Unquote)
Placeholder(Box<Node<UntypedKind>>),
/// A placeholder that flattens a sequence or merges a record into its surroundings. (Splice)
Splice(Box<Node<UntypedKind>>),
/// Represents an expanded macro call, preserving the original call for debugging.
Expansion {
/// The original call from the source AST.
call: Box<Node<UntypedKind>>,
/// The resulting AST after macro expansion.
expanded: Box<Node<UntypedKind>>,
},
/// A diagnostic poison node, allowing compilation to continue after an error.
Error,
Extension(Box<dyn CustomNode>),
}