Structs and comptime reflection stuff

This commit is contained in:
Mia
2026-03-07 01:42:06 +01:00
parent 81d1dfe3d3
commit fb84e09391
18 changed files with 1399 additions and 321 deletions
+6 -1
View File
@@ -14,9 +14,14 @@ pub enum Kind {
SymbolNotFound = 0x0200,
UninitializedSymbol = 0x0201,
NotAType = 0x0202,
NotAFunction = 0x0205,
InvalidIntegerType = 0x0203,
InvalidType = 0x0204,
NotAFunction = 0x0205,
NotAStruct = 0x0208,
FieldNotFound = 0x0206,
InvalidCast = 0x0207,
UninitializedField = 0x0300,
FunctionCompilationFailed = 0x0301,
}
+2 -2
View File
@@ -5,7 +5,7 @@ use leaf_assembly::{
assembly::{Assembly, AssemblyIdentifier, Context},
functions::Function,
types::Type,
values::{AnyConst, Value},
values::{AnyConst, AnyValue},
};
use leaf_parser::{SourceCode, ast};
use std::{collections::VecDeque, ops::Deref, sync::Arc};
@@ -66,7 +66,7 @@ impl<'l> CompilationContext<'l> {
$(
scope.insert(
literal_substr!($id),
Value::Constant(AnyConst::Type($ty.into())),
AnyValue::Constant(AnyConst::Type($ty.into())),
false,
);
)*
+317 -112
View File
@@ -1,17 +1,24 @@
use crate::{FuncQueue, error::*};
use arcstr::Substr;
use arcstr::{Substr, literal_substr};
use leaf_assembly::{
assembly::Assembly,
functions::{
Function,
ir::{Cmp, FunctionBodyBuilder},
},
types::{Type, derivations::PtrT},
values::{AnyConst, Int, Value, ValueFlags},
types::{
Type,
compound::{Field, FieldMap, StructT},
derivations::PtrT,
},
values::{AnyConst, AnyValue, Int, Value, ValueFlags},
};
use leaf_parser::{
SourceCode,
ast::{self, BinaryExpr, BinaryOp, ConstDecl, Expr, Ident, IndexingExpr, NamePattern, While},
ast::{
self, AccessExpr, BinaryExpr, BinaryOp, ConstDecl, Expr, Ident, IndexingExpr, NamePattern,
While,
},
};
use std::{
collections::HashMap,
@@ -26,7 +33,7 @@ struct ExpressionContext<'l, 'r> {
#[derive(Clone)]
struct Variable<'l> {
value: Arc<OnceLock<Value<'l>>>,
value: Arc<OnceLock<AnyValue<'l>>>,
mutable: bool,
}
@@ -46,7 +53,7 @@ impl<'l> Scope<'l> {
}
}
pub fn insert(&mut self, name: Substr, value: Value<'l>, mutable: bool) {
pub fn insert(&mut self, name: Substr, value: AnyValue<'l>, mutable: bool) {
self.values.insert(
name,
Variable {
@@ -122,7 +129,7 @@ impl<'l> Scope<'l> {
Type::Void => builder.ret(None).unwrap(),
_ => {
if let Some(expr) = last_expr.as_mut()
&& expr.flags().contains(ValueFlags::LValue)
&& expr.is_lvalue()
{
*expr = builder.load(*expr).unwrap();
}
@@ -139,7 +146,7 @@ impl<'l> Scope<'l> {
&mut self,
expr: &Expr,
ctx: &mut ExpressionContext<'l, '_>,
) -> Result<Value<'l>, CompilationError> {
) -> Result<AnyValue<'l>, CompilationError> {
match expr {
Expr::Ident(Ident(name)) => match self.values.get(name) {
None => Err(CompilationError {
@@ -167,7 +174,7 @@ impl<'l> Scope<'l> {
Expr::Func(func) => self
.make_function(func, ctx)
.map(|f| Value::Constant(AnyConst::Function(f)))
.map(|f| AnyValue::Constant(AnyConst::Function(f)))
.map_err(|err| CompilationError {
kind: Kind::FunctionCompilationFailed,
message: "Could not compile function.".to_string(),
@@ -189,7 +196,7 @@ impl<'l> Scope<'l> {
Some(("0x", value)) => <$ty>::from_str_radix(value, 16),
_ => n.text.parse::<$ty>(),
}
.map(|v| Value::Constant(AnyConst::Int(Int::$id(v))))
.map(|v| AnyValue::Constant(AnyConst::Int(Int::$id(v))))
.map_err(|_| CompilationError {
kind: Kind::InvalidInteger,
message: format!("`{}` is not a valid integer.", n.text),
@@ -202,19 +209,19 @@ impl<'l> Scope<'l> {
};
}
match n.r#type.as_ref().map(|v| v.as_str()) {
None => parse_number!(i128, ISize),
None => parse_number!(i64, ISize),
Some("i8") => parse_number!(i8, I8),
Some("i16") => parse_number!(i16, I16),
Some("i32") => parse_number!(i32, I32),
Some("i64") => parse_number!(i64, I64),
Some("i128") => parse_number!(i128, I128),
Some("isize") => parse_number!(i128, ISize),
Some("isize") => parse_number!(i64, ISize),
Some("u8") => parse_number!(u8, U8),
Some("u16") => parse_number!(u16, U16),
Some("u32") => parse_number!(u32, U32),
Some("u64") => parse_number!(u64, U64),
Some("u128") => parse_number!(u128, U128),
Some("usize") => parse_number!(u128, USize),
Some("usize") => parse_number!(u64, USize),
Some(ty) => Err(CompilationError {
kind: Kind::InvalidIntegerType,
message: format!("`{ty}` is not a valid integer type."),
@@ -227,6 +234,40 @@ impl<'l> Scope<'l> {
}
}
Expr::Access(expr) => {
let AccessExpr {
value: value_expr,
field,
} = &**expr;
let value = self.compile_expression(value_expr, ctx)?;
if let Some(value) = value.get_associated_value(&field.0) {
return Ok(value);
}
match value.ty() {
Type::Struct(StructT { fields, .. }) => {
if let Some(fields) = fields.get() {
if let Some(field) = fields.get(field.0.as_str()) {
let builder = ctx.builder.as_mut().unwrap();
return Ok(builder
.get_element_value(value, field.name.as_any_value())
.unwrap()
.as_any_value());
}
}
}
_ => {}
};
return Err(CompilationError {
kind: Kind::FieldNotFound,
message: format!("Value does not contain field `{}`.", field.0),
location: Location::Range {
file: self.source.clone(),
range: value_expr.range(),
},
cause: None,
});
}
Expr::Binary(bin_expr) => {
let BinaryExpr {
lhs: lhs_expr,
@@ -235,50 +276,98 @@ impl<'l> Scope<'l> {
} = &**bin_expr;
let mut lhs = self.compile_expression(lhs_expr, ctx)?;
if lhs.flags().contains(ValueFlags::LValue) && !matches!(op, BinaryOp::Assign(_)) {
if lhs.is_lvalue() && !matches!(op, BinaryOp::Assign(_)) {
lhs = ctx.builder.as_mut().unwrap().load(lhs).unwrap();
}
let mut rhs = self.compile_expression(rhs_expr, ctx)?;
if rhs.flags().contains(ValueFlags::LValue) {
if rhs.is_lvalue() {
rhs = ctx.builder.as_mut().unwrap().load(rhs).unwrap();
}
let builder = ctx.builder.as_mut().unwrap();
macro_rules! int_bin_ops {
(
const exact
$([$($ty:ident),*] $op:pat => |$a:ident, $b:ident| $expr:expr,)*
) => {
match op {
$(
$op => match (lhs, rhs) {
$(
(
AnyValue::Constant(AnyConst::Int(Int::$ty($a))),
AnyValue::Constant(AnyConst::Int(Int::$ty($b))),
) => return Ok(AnyValue::Constant(AnyConst::Int(Int::$ty($expr)))),
)*
_ => {}
}
)*
_ => {}
}
};
(
const auto
$([$($ty:ident),*] $op:pat => |$a:ident, $b:ident| $expr:expr,)*
) => {
match op {
$(
$op => match (lhs, rhs) {
$(
(
AnyValue::Constant(AnyConst::Int(Int::$ty($a))),
AnyValue::Constant(AnyConst::Int(Int::$ty($b))),
) => return Ok($expr.as_any_value()),
)*
_ => {}
}
)*
_ => {}
}
};
}
if lhs.is_const() && rhs.is_const() {
int_bin_ops! {
const exact
[I8, I16, I32, I64, I128, U8, U16, U32, U64, U128, ISize, USize] BinaryOp::Add(_) => |a, b| a + b,
[I8, I16, I32, I64, I128, U8, U16, U32, U64, U128, ISize, USize] BinaryOp::Sub(_) => |a, b| a - b,
[I8, I16, I32, I64, I128, U8, U16, U32, U64, U128, ISize, USize] BinaryOp::Mul(_) => |a, b| a - b,
[I8, I16, I32, I64, I128, U8, U16, U32, U64, U128, ISize, USize] BinaryOp::Div(_) => |a, b| a - b,
[I8, I16, I32, I64, I128, U8, U16, U32, U64, U128, ISize, USize] BinaryOp::Mod(_) => |a, b| a - b,
}
int_bin_ops! {
const auto
[I8, I16, I32, I64, I128, U8, U16, U32, U64, U128, ISize, USize] BinaryOp::Eq(_) => |a, b| a == b,
[I8, I16, I32, I64, I128, U8, U16, U32, U64, U128, ISize, USize] BinaryOp::Ne(_) => |a, b| a == b,
[I8, I16, I32, I64, I128, U8, U16, U32, U64, U128, ISize, USize] BinaryOp::Lt(_) => |a, b| a == b,
[I8, I16, I32, I64, I128, U8, U16, U32, U64, U128, ISize, USize] BinaryOp::Gt(_) => |a, b| a == b,
[I8, I16, I32, I64, I128, U8, U16, U32, U64, U128, ISize, USize] BinaryOp::Le(_) => |a, b| a == b,
[I8, I16, I32, I64, I128, U8, U16, U32, U64, U128, ISize, USize] BinaryOp::Ge(_) => |a, b| a == b,
}
}
if match (lhs.ty(), rhs.ty()) {
(Type::Int(a_ty), Type::Int(b_ty)) => a_ty == b_ty,
_ => false,
} {
return Ok(match op {
BinaryOp::Add(_) => builder.add(lhs, rhs).unwrap(),
BinaryOp::Sub(_) => builder.sub(lhs, rhs).unwrap(),
BinaryOp::Mul(_) => builder.mul(lhs, rhs).unwrap(),
BinaryOp::Div(_) => builder.div(lhs, rhs).unwrap(),
BinaryOp::Mod(_) => builder.modulo(lhs, rhs).unwrap(),
BinaryOp::Eq(_) => builder.cmp(lhs, rhs, Cmp::Eq).unwrap(),
BinaryOp::Ne(_) => builder.cmp(lhs, rhs, Cmp::Ne).unwrap(),
BinaryOp::Lt(_) => builder.cmp(lhs, rhs, Cmp::Lt).unwrap(),
BinaryOp::Gt(_) => builder.cmp(lhs, rhs, Cmp::Gt).unwrap(),
BinaryOp::Le(_) => builder.cmp(lhs, rhs, Cmp::Le).unwrap(),
BinaryOp::Ge(_) => builder.cmp(lhs, rhs, Cmp::Ge).unwrap(),
_ => todo!("{lhs:?} {op:?} {rhs:?}"),
});
}
match (lhs.ty(), rhs.ty(), op) {
(Type::Int(a_ty), Type::Int(b_ty), BinaryOp::Add(_)) if a_ty == b_ty => {
Ok(builder.add(lhs, rhs).unwrap())
}
(Type::Int(a_ty), Type::Int(b_ty), BinaryOp::Sub(_)) if a_ty == b_ty => {
Ok(builder.sub(lhs, rhs).unwrap())
}
(Type::Int(a_ty), Type::Int(b_ty), BinaryOp::Mul(_)) if a_ty == b_ty => {
Ok(builder.mul(lhs, rhs).unwrap())
}
(Type::Int(a_ty), Type::Int(b_ty), BinaryOp::Div(_)) if a_ty == b_ty => {
Ok(builder.div(lhs, rhs).unwrap())
}
(Type::Int(a_ty), Type::Int(b_ty), BinaryOp::Mod(_)) if a_ty == b_ty => {
Ok(builder.modulo(lhs, rhs).unwrap())
}
(Type::Int(a_ty), Type::Int(b_ty), BinaryOp::Eq(_)) if a_ty == b_ty => {
Ok(builder.cmp(lhs, rhs, Cmp::Eq).unwrap())
}
(Type::Int(a_ty), Type::Int(b_ty), BinaryOp::Ne(_)) if a_ty == b_ty => {
Ok(builder.cmp(lhs, rhs, Cmp::Ne).unwrap())
}
(Type::Int(a_ty), Type::Int(b_ty), BinaryOp::Lt(_)) if a_ty == b_ty => {
Ok(builder.cmp(lhs, rhs, Cmp::Lt).unwrap())
}
(Type::Int(a_ty), Type::Int(b_ty), BinaryOp::Gt(_)) if a_ty == b_ty => {
Ok(builder.cmp(lhs, rhs, Cmp::Gt).unwrap())
}
(Type::Int(a_ty), Type::Int(b_ty), BinaryOp::Le(_)) if a_ty == b_ty => {
Ok(builder.cmp(lhs, rhs, Cmp::Le).unwrap())
}
(Type::Int(a_ty), Type::Int(b_ty), BinaryOp::Ge(_)) if a_ty == b_ty => {
Ok(builder.cmp(lhs, rhs, Cmp::Ge).unwrap())
}
(Type::Ptr(PtrT { base, .. }), ty, BinaryOp::Assign(_)) => match *base == ty {
true => Ok(builder.store(lhs, rhs).unwrap()),
false => Err(CompilationError {
@@ -294,25 +383,20 @@ impl<'l> Scope<'l> {
}),
},
(src_ty, Type::Type, BinaryOp::Cast(_)) => {
let Value::Constant(AnyConst::Type(dst_ty)) = rhs else {
return Err(CompilationError {
kind: Kind::NotAType,
message: "Cannot perform cast.".to_string(),
location: Location::Range {
file: self.source.clone(),
range: expr.range(),
},
cause: Some(Box::new(CompilationError {
kind: Kind::NotAType,
message: "Cast target is not a type.".to_string(),
let dst_ty =
self.assert_ty(rhs, rhs_expr)
.map_err(|err| CompilationError {
kind: Kind::InvalidCast,
message: "Cannot perform cast.".to_string(),
location: Location::Range {
file: self.source.clone(),
range: rhs_expr.range(),
range: expr.range(),
},
cause: None,
})),
});
};
cause: Some(Box::new(err)),
})?;
if src_ty == dst_ty {
return Ok(lhs);
}
match (src_ty, dst_ty) {
(Type::Int(src_ty), Type::Int(dst_ty)) => {
if dst_ty.precision < src_ty.precision {
@@ -320,6 +404,9 @@ impl<'l> Scope<'l> {
}
todo!("{src_ty} as {dst_ty}");
}
(Type::Int(_), Type::Ptr(dst_ty)) => {
return Ok(builder.int_to_ptr(lhs, dst_ty).unwrap());
}
_ => todo!("{src_ty} as {dst_ty}"),
}
}
@@ -356,7 +443,7 @@ impl<'l> Scope<'l> {
}
builder.jump(cond_block).unwrap();
builder.set_current_block(exit_block);
Ok(last_expr.unwrap_or(Value::Constant(AnyConst::Void)))
Ok(last_expr.unwrap_or(AnyValue::Constant(AnyConst::Void)))
}
Expr::Call {
@@ -364,7 +451,7 @@ impl<'l> Scope<'l> {
args: args_exprs,
} => {
let func = match self.compile_expression(func, ctx)? {
Value::Constant(AnyConst::Function(func)) => func,
AnyValue::Constant(AnyConst::Function(func)) => func,
_ => {
return Err(CompilationError {
kind: Kind::NotAFunction,
@@ -380,7 +467,7 @@ impl<'l> Scope<'l> {
let mut args = Vec::with_capacity(args_exprs.len());
for expr in args_exprs {
let mut arg = self.compile_expression(expr, ctx)?;
if arg.flags().contains(ValueFlags::LValue) {
if arg.is_lvalue() {
arg = ctx.builder.as_mut().unwrap().load(arg).unwrap();
}
args.push(arg);
@@ -390,20 +477,58 @@ impl<'l> Scope<'l> {
}
Expr::Type(ty_expr) => match &**ty_expr {
ast::Type::Ptr { base, mutable } => match self.compile_expression(base, ctx)? {
Value::Constant(AnyConst::Type(ty)) => {
Ok(AnyConst::Type(Type::Ptr(ty.make_ptr(*mutable))).into())
ast::Type::Struct(ast::Struct { fields }) => {
let name = match &ctx.decl_names {
Some(NamePattern::Single(func_name)) => func_name.0.as_str(),
_ => "",
};
let struct_ty = self.assembly.create_struct(name);
let mut scope = self.clone();
let mut expr_ctx = ExpressionContext {
builder: None,
decl_names: None,
fn_queue: ctx.fn_queue,
};
let ctx = self.assembly.ctx();
scope.insert(literal_substr!("Self"), struct_ty.as_any_value(), false);
let mut field_map = FieldMap::default();
for ast::Field {
name,
ty: ty_expr,
public,
mutable,
} in fields
{
let ty = scope.compile_expression(ty_expr, &mut expr_ctx)?;
let name = ctx.intern_str(&name.0);
field_map.insert(
name,
Field {
name,
ty: self.assert_ty(ty, ty_expr)?,
public: public.is_some(),
mutable: mutable.is_some(),
},
);
}
Value::Instruction(inst) if inst.value_flags().contains(ValueFlags::LValue) => {
struct_ty.fields.set(field_map).unwrap();
Ok(struct_ty.as_any_value())
}
ast::Type::Ptr { base, mutable } => match self.compile_expression(base, ctx)? {
AnyValue::Constant(AnyConst::Type(ty)) => {
Ok(AnyConst::Type(Type::Ptr(ty.make_ptr(mutable.is_some()))).into())
}
AnyValue::Instruction(inst) if inst.is_lvalue() => {
let Type::Ptr(PtrT {
base,
mutable: is_mut,
..
}) = inst.value_ty()
}) = inst.ty()
else {
unreachable!()
};
if *mutable && !*is_mut {
if mutable.is_some() && !*is_mut {
return Err(CompilationError {
kind: Kind::NotAFunction,
message: "Cannot obtain a mutable pointer to an immutable value."
@@ -415,27 +540,28 @@ impl<'l> Scope<'l> {
cause: None,
});
}
let mut flags = inst.value_flags();
let mut flags = inst.flags();
let builder = ctx.builder.as_mut().unwrap();
flags.remove(
ValueFlags::Mutable | ValueFlags::Volatile | ValueFlags::LValue,
);
let ptr = Type::Ptr(base.make_ptr(*mutable));
let ptr = Type::Ptr(base.make_ptr(mutable.is_some()));
unsafe {
Ok(builder
.reinterpret(Value::Instruction(inst), ptr, flags)
.reinterpret(AnyValue::Instruction(inst), ptr, flags)
.unwrap())
}
}
v => todo!("{v:?}"),
},
v => todo!("{v:#?}"),
},
Expr::List(expr) => {
let mut expr = expr.iter();
let mut values = Vec::with_capacity(expr.len());
match expr.next() {
None => return Ok(Value::Constant(AnyConst::Array(&[]))),
None => return Ok(AnyValue::Constant(AnyConst::Array(&[]))),
Some(expr) => {
let value = self.compile_expression(expr, ctx)?;
// TODO Check if it matches the ctx type hint
@@ -445,28 +571,14 @@ impl<'l> Scope<'l> {
let element_ty = values[0].ty();
for expr in expr {
let value = self.compile_expression(expr, ctx)?;
if value.ty() != element_ty {
return Err(CompilationError {
kind: Kind::InvalidType,
message: format!(
"Expected type `{}`, found `{}`",
element_ty,
value.ty()
),
location: Location::Range {
file: self.source.clone(),
range: expr.range(),
},
cause: None,
});
}
self.assert_ty_eq(&value, expr, &element_ty)?;
values.push(value);
}
if values.iter().all(|v| matches!(v, Value::Constant(_))) {
if values.iter().all(|v| matches!(v, AnyValue::Constant(_))) {
let alloc = self.assembly.ctx().alloc();
return Ok(Value::Constant(AnyConst::Array(alloc.alloc_slice(
return Ok(AnyValue::Constant(AnyConst::Array(alloc.alloc_slice(
values.into_iter().map(|v| match v {
Value::Constant(c) => c,
AnyValue::Constant(c) => c,
_ => unreachable!(),
}),
))));
@@ -480,7 +592,7 @@ impl<'l> Scope<'l> {
let mut index = self.compile_expression(index, ctx)?;
let builder = ctx.builder.as_mut().unwrap();
if index.flags().contains(ValueFlags::LValue) {
if index.is_lvalue() {
index = builder.load(index).unwrap();
}
@@ -497,48 +609,111 @@ impl<'l> Scope<'l> {
});
}
if value.flags().contains(ValueFlags::LValue) {
let gep = builder.gep(value, index).unwrap();
if value.is_lvalue() {
let gep = builder.get_element_ptr(value, index).unwrap();
return Ok(gep);
}
todo!("{:#?}", value.ty());
}
Expr::Struct(ctor) => {
let ty = self.compile_expression(&ctor.r#type, ctx)?;
let AnyValue::Constant(AnyConst::Type(Type::Struct(
struct_ty @ StructT { name, fields, .. },
))) = ty
else {
return Err(CompilationError {
kind: Kind::NotAStruct,
message: format!("Expected struct type, got value of type `{}`.", ty.ty()),
location: Location::Range {
file: self.source.clone(),
range: ctor.r#type.range(),
},
cause: None,
});
};
let mut non_const = false;
let fields = fields.get().unwrap();
let mut values = Vec::with_capacity(fields.len());
for Field {
name: fld_name, ty, ..
} in fields.values()
{
let Some(name_value_pair) = ctor.values.get(*fld_name) else {
return Err(CompilationError {
kind: Kind::UninitializedField,
message: format!("Uninitialized field `{fld_name}`."),
location: Location::Range {
file: self.source.clone(),
range: expr.range(),
},
cause: None,
});
};
let value = self.compile_expression(&name_value_pair.value, ctx)?;
self.assert_ty_eq(&value, &name_value_pair.value, ty)?;
non_const |= !value.flags().contains(ValueFlags::Const);
values.push(value);
}
Ok(match non_const {
true => {
let builder = ctx.builder.as_mut().unwrap();
let values = self.assembly.ctx().alloc().alloc_slice(values.into_iter());
builder.make_struct(struct_ty, values).unwrap()
}
false => AnyValue::Constant(AnyConst::Struct(
struct_ty,
self.assembly
.ctx()
.alloc()
.alloc_slice(values.into_iter().map(|v| {
let AnyValue::Constant(c) = v else {
unreachable!()
};
c
})),
)),
})
}
_ => todo!("{expr:#?}"),
}
}
fn make_function(
&mut self,
ast: &ast::Function,
ast: &Arc<ast::Function>,
ctx: &mut ExpressionContext<'l, '_>,
) -> Result<&'l Function<'l>, CompilationError> {
let ret_ty = match ast.ret.as_ref() {
None => Value::Constant(AnyConst::Type(Type::Void)),
None => AnyValue::Constant(AnyConst::Type(Type::Void)),
Some(ty) => self.compile_expression(ty, ctx)?,
};
let ret_ty = self.assert_type(ret_ty)?;
let ast_as_expr = Expr::Func(ast.clone());
let ret_ty = self.assert_ty(ret_ty, ast.ret.as_ref().unwrap_or(&ast_as_expr))?;
let mut par_ty = Vec::with_capacity(ast.args.len());
for arg in &ast.args {
let ty = self.compile_expression(&arg.r#type, ctx)?;
let ty = self.assert_type(ty)?;
let ty = self.compile_expression(&arg.value, ctx)?;
let ty = self.assert_ty(ty, &arg.value)?;
par_ty.push(ty);
}
let fn_ty = ret_ty.make_fn(par_ty);
let func = self.assembly.create_function(fn_ty);
if let Some(NamePattern::Single(func_name)) = &ctx.decl_names {
func.name.set(func.ctx().intern_str(&func_name.0)).unwrap();
let name = match &ctx.decl_names {
Some(NamePattern::Single(func_name)) => func_name.0.as_str(),
_ => "",
};
let func = self.assembly.create_function(fn_ty, name);
let Some(block) = &ast.block else {
return Ok(func);
};
let mut scope = self.clone();
for (i, arg) in ast.args.iter().enumerate() {
scope.insert(arg.name.0.clone(), Value::Parameter(i, func), false);
scope.insert(arg.name.0.clone(), AnyValue::Parameter(i, func), false);
}
ctx.fn_queue.push_back((func, block.clone(), scope));
@@ -552,7 +727,7 @@ impl<'l> Scope<'l> {
value: &Expr,
mutable: bool,
ctx: &mut ExpressionContext<'l, '_>,
) -> Result<Value<'l>, CompilationError> {
) -> Result<AnyValue<'l>, CompilationError> {
let mut sub_ctx = ExpressionContext {
decl_names: Some(names),
builder: ctx.builder.as_deref_mut(),
@@ -581,15 +756,45 @@ impl<'l> Scope<'l> {
Ok(AnyConst::Void.into())
}
fn assert_type(&self, val: Value<'l>) -> Result<Type<'l>, CompilationError> {
fn assert_ty(
&self,
val: AnyValue<'l>,
value_expr: &Expr,
) -> Result<Type<'l>, CompilationError> {
match val {
Value::Constant(AnyConst::Type(ty)) => Ok(ty),
AnyValue::Constant(AnyConst::Type(ty)) => Ok(ty),
_ => Err(CompilationError {
kind: Kind::NotAType,
message: "Value is not a type.".to_string(),
location: Location::None,
location: Location::Range {
file: self.source.clone(),
range: value_expr.range(),
},
cause: None,
}),
}
}
pub fn assert_ty_eq(
&self,
value: &AnyValue<'l>,
value_expr: &Expr,
expected: &Type<'l>,
) -> Result<Type<'l>, CompilationError> {
let value_ty = value.ty();
match value_ty == *expected {
true => Ok(value_ty),
false => {
return Err(CompilationError {
kind: Kind::InvalidType,
message: format!("Expected value of type `{expected}`, found `{value_ty}`."),
location: Location::Range {
file: self.source.clone(),
range: value_expr.range(),
},
cause: None,
});
}
}
}
}