feat: Add StaticType and type checking
This commit introduces `StaticType` and enhances the `Binder` to perform
basic type checking during the binding phase.
Key changes include:
- **`StaticType` enum:** Represents static types such as `Any`, `Void`,
`Bool`, `Int`, `Float`, `Text`, `List`, `Record`, and `Function`.
- **`Node<K, T>`:** The generic `Node` now includes a `ty` field to
store its inferred static type.
- **Binder enhancements:**
- `CompilerScope` now stores `LocalInfo` containing the variable's
slot and `StaticType`.
- `FunctionCompiler` stores upvalues with their associated
`StaticType`.
- `Binder::bind` now returns `Node<BoundKind, StaticType>`,
propagating type information.
- Type checking is added for `If` conditions and `Assign`
operations.
- `Def` nodes now infer and store the type of the defined variable.
- **`Value::static_type()`:** A new method to determine the `StaticType`
of a `Value`.
- **Environment modifications:** `global_names` now stores `(u32,
StaticType)` to associate global variables with their types.
- **Parser modifications:** The `ty` field of nodes is initialized to
`()` by default.
- **VM modifications:** `VM::run` and `VM::eval` now operate on
`Node<BoundKind, StaticType>`.
- **Tests:** Added basic evaluation and type error tests.
feat: Add StaticType and type checking
Introduces `StaticType` enum and integrates it into the AST. The binder
now performs type checking during compilation, ensuring that expressions
conform to expected types, especially for control flow structures like
`if`. This lays the groundwork for static type analysis and error
reporting.
This commit is contained in:
+15
-7
@@ -5,9 +5,10 @@ use crate::ast::types::{Identity, Value};
|
||||
|
||||
/// A generic AST Node wrapper to preserve identity and metadata
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Node<K> {
|
||||
pub struct Node<K, T = ()> {
|
||||
pub identity: Identity,
|
||||
pub kind: K,
|
||||
pub ty: T,
|
||||
}
|
||||
|
||||
/// The base for custom node types (extensions)
|
||||
@@ -63,6 +64,12 @@ pub struct Context {
|
||||
pub scope: Arc<Mutex<Scope>>,
|
||||
}
|
||||
|
||||
impl Default for Context {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl Context {
|
||||
pub fn new() -> Self {
|
||||
let mut root_scope = Scope::new(None);
|
||||
@@ -75,7 +82,7 @@ impl Context {
|
||||
|
||||
fn register_stdlib(scope: &mut Scope) {
|
||||
macro_rules! bin_op {
|
||||
($name:expr, $op:tt) => {
|
||||
($name:expr, $op_name:ident, $op:tt) => {
|
||||
scope.define($name, Value::Function(Arc::new(|args| {
|
||||
if args.len() < 2 { return Value::Void; }
|
||||
let mut acc = match &args[0] {
|
||||
@@ -89,7 +96,7 @@ fn register_stdlib(scope: &mut Scope) {
|
||||
Value::Float(f) => *f,
|
||||
_ => return Value::Void,
|
||||
};
|
||||
acc = acc $op val;
|
||||
acc.$op_name(val);
|
||||
}
|
||||
if acc.fract() == 0.0 {
|
||||
Value::Int(acc as i64)
|
||||
@@ -100,10 +107,11 @@ fn register_stdlib(scope: &mut Scope) {
|
||||
};
|
||||
}
|
||||
|
||||
bin_op!("+", +);
|
||||
bin_op!("-", -);
|
||||
bin_op!("*", *);
|
||||
bin_op!("/", /);
|
||||
use std::ops::{AddAssign, SubAssign, MulAssign, DivAssign};
|
||||
bin_op!("+", add_assign, +=);
|
||||
bin_op!("-", sub_assign, -=);
|
||||
bin_op!("*", mul_assign, *=);
|
||||
bin_op!("/", div_assign, /=);
|
||||
|
||||
scope.define(">", Value::Function(Arc::new(|args| {
|
||||
if args.len() != 2 { return Value::Void; }
|
||||
|
||||
Reference in New Issue
Block a user