Full AST based syntax highlighting

This commit is contained in:
Mia
2026-03-09 00:52:28 +01:00
parent 45fd421e19
commit 63890e46d9
16 changed files with 1240 additions and 851 deletions
+5 -2
View File
@@ -7,7 +7,10 @@ use leaf_assembly::{
types::Type,
values::{AnyConst, AnyValue},
};
use leaf_parser::{SourceCode, ast};
use leaf_parser::{
SourceCode,
ast::{self, AstNode},
};
use std::{
any::TypeId,
collections::{HashMap, VecDeque},
@@ -22,7 +25,7 @@ mod scope;
pub type SourceFile = Arc<SourceCode>;
type FuncQueue<'l> = VecDeque<(&'l Function<'l>, Arc<ast::Block>, Scope<'l>)>;
type FuncQueue<'l> = VecDeque<(&'l Function<'l>, Arc<AstNode<ast::Block>>, Scope<'l>)>;
pub struct CompilationContext<'l> {
ctx: &'l Context<'l>,
+3 -4
View File
@@ -26,10 +26,9 @@ fn main() {
};
if let Err(err) = context.extend(
ident.clone(),
&[Arc::new(SourceCode {
text: ArcStr::from(std::fs::read_to_string("test.leaf").unwrap()),
file: PathBuf::from("test.leaf"),
})],
&[Arc::new(
SourceCode::from_file_arcstr(&"test.leaf").unwrap(),
)],
) {
println!("{:#?}", err);
return;
+4 -36
View File
@@ -1,4 +1,4 @@
use leaf_parser::{LineCol, SourceCode};
use leaf_parser::{LineCol, Parse, SourceCode};
use std::{
any::Any,
ops::Range,
@@ -26,41 +26,9 @@ impl CodePosition {
pub fn line_col(&self) -> &Range<LineCol> {
self.line_col.get_or_init(|| {
let mut line_col_range = LineCol {
line: 0,
column: 0,
offset: self.range.start,
}..LineCol {
line: 0,
column: 0,
offset: self.range.end,
};
let mut line = 0;
let mut col = 0;
for (byte_idx, ch) in self.file.text.char_indices() {
if byte_idx == self.range.start {
line_col_range.start.line = line;
line_col_range.start.column = col;
}
if byte_idx == self.range.end {
line_col_range.end.line = line;
line_col_range.end.column = col;
}
if ch == '\n' {
line += 1;
col = 0;
} else {
col += 1;
}
}
if self.range.end == self.file.text.len() {
line_col_range.end.line = line;
line_col_range.end.column = col;
}
line_col_range
let start = self.file.position_repr(self.range.start);
let end = self.file.position_repr(self.range.end);
start..end
})
}
}
Regular → Executable
+276 -213
View File
@@ -15,13 +15,12 @@ use leaf_assembly::{
};
use leaf_parser::{
SourceCode,
ast::{
self, AccessExpr, BinaryExpr, BinaryOp, Block, ConstDecl, Else, Expr, Ident, If,
IndexingExpr, NamePattern, While,
},
ast::{self, *},
};
use std::{
borrow::Cow,
collections::HashMap,
ops::Range,
sync::{Arc, OnceLock},
};
@@ -79,11 +78,12 @@ impl<'l> Scope<'l> {
);
}
pub fn declare_constants(&mut self, decl: &[ConstDecl]) {
pub fn declare_constants(&mut self, decl: &[AstNode<ConstDecl>]) {
for val in decl {
for Ident(name) in val.names.as_slice() {
for range in val.names.as_slice() {
let name = self.get_text_arc(range);
self.values.insert(
name.clone(),
name,
Variable {
value: Arc::default(),
},
@@ -94,7 +94,7 @@ impl<'l> Scope<'l> {
pub fn define_constants(
&mut self,
decl: &[ConstDecl],
decl: &[AstNode<ConstDecl>],
fn_queue: &mut FuncQueue<'l>,
) -> Result<(), Diagnostic> {
for val in decl {
@@ -107,10 +107,12 @@ impl<'l> Scope<'l> {
fn_queue,
},
)?;
match &val.names {
match &*val.names {
NamePattern::Single(ident) => {
let name = self.get_text(ident).to_string();
self.values
.get_mut(&ident.0)
.get_mut(&*name)
.unwrap()
.value
.set(expr)
@@ -118,7 +120,7 @@ impl<'l> Scope<'l> {
self.ctx.emit_event(Event::Definition {
value: expr,
position: CodePosition::new(self.source.clone(), ident.range()),
position: CodePosition::new(self.source.clone(), ident.clone()),
});
}
NamePattern::Tuple(_) => todo!(),
@@ -131,7 +133,7 @@ impl<'l> Scope<'l> {
pub fn compile_function(
&mut self,
func: &'l Function<'l>,
block: &Arc<ast::Block>,
block: &Arc<AstNode<ast::Block>>,
fn_queue: &mut FuncQueue<'l>,
) -> Result<(), Diagnostic> {
let mut builder = func.create_body().unwrap();
@@ -154,7 +156,14 @@ impl<'l> Scope<'l> {
if ret.is_lvalue() {
ret = builder.load(ret).unwrap();
}
self.assert_ty_eq(&ret, &Expr::Block(block.clone()), &func.ty.ret_t)?;
self.assert_ty_eq(
&ret,
&AstNode {
range: block.range.clone(),
node: Expr::Block(block.clone()),
},
&func.ty.ret_t,
)?;
builder.ret(Some(ret)).unwrap();
}
};
@@ -166,35 +175,38 @@ impl<'l> Scope<'l> {
fn compile_expression(
&mut self,
expr: &Expr,
expr: &AstNode<Expr>,
ctx: &mut ExpressionContext<'l, '_>,
) -> Result<AnyValue<'l>, Diagnostic> {
match expr {
Expr::Ident(Ident(name)) => match self.values.get(name) {
None => Err(Diagnostic {
kind: Kind::Error,
code: Code::SymbolNotFound,
message: format!("Symbol `{name}` does not exist in the current scope."),
position: CodePosition::new(self.source.clone(), name.range()),
cause: None,
}),
Some(Variable { value, .. }) => match value.get() {
match &**expr {
Expr::Ident(range) => {
let name = self.get_text(range);
match self.values.get(&*name) {
None => Err(Diagnostic {
kind: Kind::Error,
code: Code::UninitializedSymbol,
message: format!("Symbol `{name}` is not initialized at this time."),
position: CodePosition::new(self.source.clone(), name.range()),
code: Code::SymbolNotFound,
message: format!("Symbol `{name}` does not exist in the current scope."),
position: CodePosition::new(self.source.clone(), range.clone()),
cause: None,
}),
Some(value) => {
self.ctx.emit_event(Event::Symbol {
value: *value,
position: CodePosition::new(self.source.clone(), name.range()),
});
Ok(*value)
}
},
},
Some(Variable { value, .. }) => match value.get() {
None => Err(Diagnostic {
kind: Kind::Error,
code: Code::UninitializedSymbol,
message: format!("Symbol `{name}` is not initialized at this time."),
position: CodePosition::new(self.source.clone(), range.clone()),
cause: None,
}),
Some(value) => {
self.ctx.emit_event(Event::Symbol {
value: *value,
position: CodePosition::new(self.source.clone(), range.clone()),
});
Ok(*value)
}
},
}
}
Expr::Func(func) => self
.make_function(func, ctx)
@@ -203,7 +215,7 @@ impl<'l> Scope<'l> {
kind: Kind::Error,
code: Code::FunctionCompilationFailed,
message: "Could not compile function.".to_string(),
position: CodePosition::new(self.source.clone(), func.text.range()),
position: CodePosition::new(self.source.clone(), expr.range.clone()),
cause: Some(Box::new(err)),
}),
@@ -212,23 +224,25 @@ impl<'l> Scope<'l> {
Expr::Number(n) => {
macro_rules! parse_number {
($ty: ty, $id: ident) => {
match n.text.split_at_checked(2) {
($ty: ty, $id: ident) => {{
let text = self.get_text(&n.number);
match text.split_at_checked(2) {
Some(("0b", value)) => <$ty>::from_str_radix(value, 2),
Some(("0x", value)) => <$ty>::from_str_radix(value, 16),
_ => n.text.parse::<$ty>(),
_ => text.parse::<$ty>(),
}
.map(|v| AnyValue::Constant(AnyConst::Int(Int::$id(v))))
.map_err(|_| Diagnostic {
kind: Kind::Error,
code: Code::InvalidInteger,
message: format!("`{}` is not a valid integer.", n.text),
position: CodePosition::new(self.source.clone(), n.text.range()),
message: format!("`{}` is not a valid integer.", text),
position: CodePosition::new(self.source.clone(), n.number.clone()),
cause: None,
})
};
}};
}
let value = match n.r#type.as_ref().map(|v| v.as_str()) {
let ty = n.ty.as_ref().map(|v| self.get_text(v));
let value = match ty.as_ref().map(|ty| &**ty) {
None if ctx.type_hint == Some(Type::I8) => parse_number!(i8, I8),
None if ctx.type_hint == Some(Type::I16) => parse_number!(i16, I16),
None if ctx.type_hint == Some(Type::I32) => parse_number!(i32, I32),
@@ -259,24 +273,25 @@ impl<'l> Scope<'l> {
kind: Kind::Error,
code: Code::InvalidIntegerType,
message: format!("`{ty}` is not a valid integer type."),
position: CodePosition::new(self.source.clone(), n.text.range()),
position: CodePosition::new(self.source.clone(), n.ty.clone().unwrap()),
cause: None,
}),
}?;
self.ctx.emit_event(Event::Symbol {
value: value,
position: CodePosition::new(self.source.clone(), n.text.range()),
position: CodePosition::new(self.source.clone(), n.number.clone()),
});
Ok(value)
}
Expr::Access(expr) => {
let AccessExpr {
value: value_expr,
field,
} = &**expr;
Expr::Access {
value: value_expr,
operator,
field,
} => {
let value = self.compile_expression(value_expr, ctx)?;
if let Some(value) = value.get_associated_value(&field.0) {
let name = self.get_text(field);
if let Some(value) = value.get_associated_value(&*name) {
return Ok(value);
}
@@ -284,7 +299,7 @@ impl<'l> Scope<'l> {
match value.ty() {
Type::Struct(StructT { fields, .. }) => {
if let Some(fields) = fields.get() {
if let Some(field) = fields.get(field.0.as_str()) {
if let Some(field) = fields.get(&*name) {
let builder = ctx.builder.as_mut().unwrap();
break 'value Some(
builder
@@ -301,7 +316,7 @@ impl<'l> Scope<'l> {
..
}) => {
if let Some(fields) = fields.get() {
if let Some(field) = fields.get(field.0.as_str()) {
if let Some(field) = fields.get(&*name) {
let builder = ctx.builder.as_mut().unwrap();
let inst = builder
.get_element_ptr(value, field.name.as_any_value())
@@ -326,7 +341,7 @@ impl<'l> Scope<'l> {
if let Some(value) = value {
self.ctx.emit_event(Event::Symbol {
value: value,
position: CodePosition::new(self.source.clone(), field.range()),
position: CodePosition::new(self.source.clone(), field.clone()),
});
return Ok(value);
}
@@ -334,25 +349,23 @@ impl<'l> Scope<'l> {
return Err(Diagnostic {
kind: Kind::Error,
code: Code::FieldNotFound,
message: format!("Value does not contain field `{}`.", field.0),
position: CodePosition::new(self.source.clone(), field.range()),
message: format!("Value does not contain field `{name}`."),
position: CodePosition::new(self.source.clone(), field.clone()),
cause: None,
});
}
Expr::Binary(bin_expr) => {
let BinaryExpr {
lhs: lhs_expr,
rhs: rhs_expr,
op,
} = &**bin_expr;
Expr::Binary {
lhs: lhs_expr,
rhs: rhs_expr,
operator,
} => {
let mut lhs = self.compile_expression(lhs_expr, ctx)?;
let type_hint = if lhs.is_lvalue() {
let Type::Ptr(PtrT { base, .. }) = lhs.ty() else {
unreachable!();
};
if !matches!(op, BinaryOp::Assign(_)) {
if !matches!(operator.node, BinaryOperator::Assign) {
lhs = ctx.builder.as_mut().unwrap().load(lhs).unwrap();
}
*base
@@ -372,7 +385,7 @@ impl<'l> Scope<'l> {
const exact
$([$($ty:ident),*] $op:pat => |$a:ident, $b:ident| $expr:expr,)*
) => {
match op {
match operator.node {
$(
$op => match (lhs, rhs) {
$(
@@ -391,7 +404,7 @@ impl<'l> Scope<'l> {
const auto
$([$($ty:ident),*] $op:pat => |$a:ident, $b:ident| $expr:expr,)*
) => {
match op {
match operator.node {
$(
$op => match (lhs, rhs) {
$(
@@ -411,20 +424,20 @@ impl<'l> Scope<'l> {
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,
[I8, I16, I32, I64, I128, U8, U16, U32, U64, U128, ISize, USize] BinaryOperator::Add => |a, b| a + b,
[I8, I16, I32, I64, I128, U8, U16, U32, U64, U128, ISize, USize] BinaryOperator::Sub => |a, b| a - b,
[I8, I16, I32, I64, I128, U8, U16, U32, U64, U128, ISize, USize] BinaryOperator::Mul => |a, b| a - b,
[I8, I16, I32, I64, I128, U8, U16, U32, U64, U128, ISize, USize] BinaryOperator::Div => |a, b| a - b,
[I8, I16, I32, I64, I128, U8, U16, U32, U64, U128, ISize, USize] BinaryOperator::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,
[I8, I16, I32, I64, I128, U8, U16, U32, U64, U128, ISize, USize] BinaryOperator::Eq => |a, b| a == b,
[I8, I16, I32, I64, I128, U8, U16, U32, U64, U128, ISize, USize] BinaryOperator::Ne => |a, b| a == b,
[I8, I16, I32, I64, I128, U8, U16, U32, U64, U128, ISize, USize] BinaryOperator::Lt => |a, b| a == b,
[I8, I16, I32, I64, I128, U8, U16, U32, U64, U128, ISize, USize] BinaryOperator::Gt => |a, b| a == b,
[I8, I16, I32, I64, I128, U8, U16, U32, U64, U128, ISize, USize] BinaryOperator::Le => |a, b| a == b,
[I8, I16, I32, I64, I128, U8, U16, U32, U64, U128, ISize, USize] BinaryOperator::Ge => |a, b| a == b,
}
}
@@ -434,19 +447,19 @@ impl<'l> Scope<'l> {
(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:?}"),
return Ok(match operator.node {
BinaryOperator::Add => builder.add(lhs, rhs).unwrap(),
BinaryOperator::Sub => builder.sub(lhs, rhs).unwrap(),
BinaryOperator::Mul => builder.mul(lhs, rhs).unwrap(),
BinaryOperator::Div => builder.div(lhs, rhs).unwrap(),
BinaryOperator::Mod => builder.modulo(lhs, rhs).unwrap(),
BinaryOperator::Eq => builder.cmp(lhs, rhs, Cmp::Eq).unwrap(),
BinaryOperator::Ne => builder.cmp(lhs, rhs, Cmp::Ne).unwrap(),
BinaryOperator::Lt => builder.cmp(lhs, rhs, Cmp::Lt).unwrap(),
BinaryOperator::Gt => builder.cmp(lhs, rhs, Cmp::Gt).unwrap(),
BinaryOperator::Le => builder.cmp(lhs, rhs, Cmp::Le).unwrap(),
BinaryOperator::Ge => builder.cmp(lhs, rhs, Cmp::Ge).unwrap(),
_ => todo!("{lhs:?} {:?} {rhs:?}", operator.node),
});
}
@@ -456,26 +469,27 @@ impl<'l> Scope<'l> {
} {
let lhs = builder.ptr_to_int(lhs, IntT::USIZE).unwrap();
let rhs = builder.ptr_to_int(rhs, IntT::USIZE).unwrap();
return Ok(match op {
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:?}"),
return Ok(match operator.node {
BinaryOperator::Eq => builder.cmp(lhs, rhs, Cmp::Eq).unwrap(),
BinaryOperator::Ne => builder.cmp(lhs, rhs, Cmp::Ne).unwrap(),
BinaryOperator::Lt => builder.cmp(lhs, rhs, Cmp::Lt).unwrap(),
BinaryOperator::Gt => builder.cmp(lhs, rhs, Cmp::Gt).unwrap(),
BinaryOperator::Le => builder.cmp(lhs, rhs, Cmp::Le).unwrap(),
BinaryOperator::Ge => builder.cmp(lhs, rhs, Cmp::Ge).unwrap(),
_ => todo!("{lhs:?} {:?} {rhs:?}", operator.node),
});
}
match (lhs_ty, rhs_ty, op) {
(Type::Ptr(ptr @ PtrT { base, .. }), Type::USIZE, BinaryOp::Add(_)) => {
match (lhs_ty, rhs_ty, operator.node) {
(Type::Ptr(ptr @ PtrT { base, .. }), Type::USIZE, BinaryOperator::Add) => {
let mut value = builder.ptr_to_int(lhs, IntT::USIZE).unwrap();
let add = builder.mul(rhs, AnyConst::SizeOf(*base).into()).unwrap();
value = builder.add(value, add).unwrap();
value = builder.int_to_ptr(value, ptr).unwrap();
Ok(value)
}
(Type::Ptr(PtrT { base, .. }), ty, BinaryOp::Assign(_)) => match *base == ty {
(Type::Ptr(PtrT { base, .. }), ty, BinaryOperator::Assign) => match *base == ty
{
true => Ok(builder.store(lhs, rhs).unwrap()),
false => Err(Diagnostic {
kind: Kind::Error,
@@ -483,16 +497,16 @@ impl<'l> Scope<'l> {
message: format!(
"Cannot assign a value of type `{ty}` to a value of type `{base}`."
),
position: CodePosition::new(self.source.clone(), expr.range()),
position: CodePosition::new(self.source.clone(), expr.range.clone()),
cause: None,
}),
},
(src_ty, Type::Type, BinaryOp::Cast(_)) => {
(src_ty, Type::Type, BinaryOperator::Cast) => {
let dst_ty = self.assert_ty(rhs, rhs_expr).map_err(|err| Diagnostic {
kind: Kind::Error,
code: Code::InvalidCast,
message: "Cannot perform cast.".to_string(),
position: CodePosition::new(self.source.clone(), expr.range()),
position: CodePosition::new(self.source.clone(), expr.range.clone()),
cause: Some(Box::new(err)),
})?;
if src_ty == dst_ty {
@@ -514,14 +528,17 @@ impl<'l> Scope<'l> {
_ => todo!("{src_ty} as {dst_ty}"),
}
}
(a, b, _) => todo!("{a} {op:?} {b} | {lhs:?} {op:?} {rhs:?}"),
(a, b, _) => todo!(
"{a} {op:?} {b} | {lhs:?} {op:?} {rhs:?}",
op = operator.node,
),
}
}
Expr::If(expr) => self.compile_if(expr, ctx),
Expr::While(expr) => {
let While { cond, block } = &**expr;
let While { cond, block, .. } = &**expr;
let mut builder = ctx.builder.as_mut().unwrap();
let cond_block = builder.create_block();
@@ -555,7 +572,7 @@ impl<'l> Scope<'l> {
kind: Kind::Error,
code: Code::NotAFunction,
message: "Value is not a function".into(),
position: CodePosition::new(self.source.clone(), func.range()),
position: CodePosition::new(self.source.clone(), func.range.clone()),
cause: None,
});
}
@@ -573,86 +590,84 @@ impl<'l> Scope<'l> {
let builder = ctx.builder.as_mut().unwrap();
Ok(builder.call(func, args).unwrap())
}
Expr::Type(ty_expr) => match &**ty_expr {
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,
type_hint: Some(Type::Type),
fn_queue: ctx.fn_queue,
};
let ctx = self.assembly.ctx();
scope.insert(literal_substr!("Self"), struct_ty.as_any_value());
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(),
},
);
}
struct_ty.fields.set(field_map).unwrap();
Ok(struct_ty.as_any_value())
Expr::Ptr { mutable, base, .. } => match self.compile_expression(base, ctx)? {
AnyValue::Constant(AnyConst::Type(ty)) => {
Ok(AnyConst::Type(Type::Ptr(ty.make_ptr(mutable.is_some()))).into())
}
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.ty()
else {
unreachable!()
};
if mutable.is_some() && !*is_mut {
return Err(Diagnostic {
kind: Kind::Error,
code: Code::NotAFunction,
message: "Cannot obtain a mutable pointer to an immutable value."
.into(),
position: CodePosition::new(self.source.clone(), expr.range.clone()),
cause: None,
});
}
AnyValue::Instruction(inst) if inst.is_lvalue() => {
let Type::Ptr(PtrT {
base,
mutable: is_mut,
..
}) = inst.ty()
else {
unreachable!()
};
if mutable.is_some() && !*is_mut {
return Err(Diagnostic {
kind: Kind::Error,
code: Code::NotAFunction,
message: "Cannot obtain a mutable pointer to an immutable value."
.into(),
position: CodePosition::new(self.source.clone(), expr.range()),
cause: None,
});
}
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.is_some()));
unsafe {
Ok(builder
.reinterpret(AnyValue::Instruction(inst), ptr, flags)
.unwrap())
}
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.is_some()));
unsafe {
Ok(builder
.reinterpret(AnyValue::Instruction(inst), ptr, flags)
.unwrap())
}
v => todo!("{v:?}"),
},
v => todo!("{v:#?}"),
}
v => todo!("{v:?}"),
},
Expr::Struct { fields, .. } => {
let name = match &ctx.decl_names {
Some(NamePattern::Single(func_name)) => &*self.get_text(func_name),
_ => "",
};
let struct_ty = self.assembly.create_struct(name);
let mut scope = self.clone();
let mut expr_ctx = ExpressionContext {
builder: None,
decl_names: None,
type_hint: Some(Type::Type),
fn_queue: ctx.fn_queue,
};
let ctx = self.assembly.ctx();
scope.insert(literal_substr!("Self"), struct_ty.as_any_value());
let mut field_map = FieldMap::default();
for AstNode {
range,
node:
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(&self.get_text(name));
field_map.insert(
name,
Field {
name,
ty: self.assert_ty(ty, ty_expr)?,
public: public.is_some(),
mutable: mutable.is_some(),
},
);
}
struct_ty.fields.set(field_map).unwrap();
Ok(struct_ty.as_any_value())
}
Expr::List(expr) => {
let mut expr = expr.iter();
@@ -683,7 +698,7 @@ impl<'l> Scope<'l> {
todo!()
}
Expr::Deref(expr) => {
Expr::Deref { value: expr, .. } => {
let value = self.compile_expression(expr, ctx)?;
let builder = ctx.builder.as_mut().unwrap();
let ty = value.ty();
@@ -695,7 +710,10 @@ impl<'l> Scope<'l> {
kind: Kind::Error,
code: Code::CannotDereference,
message: format!("Cannot dereference a value of type `{ty}`."),
position: CodePosition::new(self.source.clone(), expr.range()),
position: CodePosition::new(
self.source.clone(),
expr.range.clone(),
),
cause: None,
});
}
@@ -719,7 +737,10 @@ impl<'l> Scope<'l> {
kind: Kind::Error,
code: Code::CannotDereference,
message: format!("Cannot dereference a value of type `{base}`."),
position: CodePosition::new(self.source.clone(), expr.range()),
position: CodePosition::new(
self.source.clone(),
expr.range.clone(),
),
cause: None,
});
}
@@ -733,10 +754,12 @@ impl<'l> Scope<'l> {
}
}
Expr::Index(expr) => {
let IndexingExpr { value, index } = &**expr;
Expr::Index {
value,
index: index_expr,
} if index_expr.len() == 1 => {
let mut value = self.compile_expression(value, ctx)?;
let mut index = self.compile_expression(index, ctx)?;
let mut index = self.compile_expression(&index_expr[0], ctx)?;
let builder = ctx.builder.as_mut().unwrap();
if index.is_lvalue() {
@@ -749,7 +772,10 @@ impl<'l> Scope<'l> {
kind: Kind::Error,
code: Code::InvalidType,
message: "Value is not of type `usize`".into(),
position: CodePosition::new(self.source.clone(), expr.index.range()),
position: CodePosition::new(
self.source.clone(),
index_expr[0].range.clone(),
),
cause: None,
});
}
@@ -777,8 +803,11 @@ impl<'l> Scope<'l> {
todo!("{:#?}", value.ty());
}
Expr::Struct(ctor) => {
let ty = match &ctor.r#type {
Expr::StructCtor {
ty: ctor_ty,
values: ctor_values,
} => {
let ty = match ctor_ty {
Some(ty) => self.compile_expression(ty, ctx)?,
None => match ctx.type_hint {
Some(ty) => AnyValue::Constant(AnyConst::Type(ty)),
@@ -787,7 +816,10 @@ impl<'l> Scope<'l> {
kind: Kind::Error,
code: Code::CannotInferType,
message: "Type cannot be inferred.".into(),
position: CodePosition::new(self.source.clone(), ctor.range()),
position: CodePosition::new(
self.source.clone(),
expr.range.clone(),
),
cause: None,
});
}
@@ -803,9 +835,9 @@ impl<'l> Scope<'l> {
message: format!("Expected struct type, got value of type `{}`.", ty.ty()),
position: CodePosition::new(
self.source.clone(),
match &ctor.r#type {
None => ctor.range(),
Some(ty) => ty.range(),
match ctor_ty {
None => expr.range.clone(),
Some(ty) => ty.range.clone(),
},
),
cause: None,
@@ -819,12 +851,18 @@ impl<'l> Scope<'l> {
name: fld_name, ty, ..
} in fields.values()
{
let Some(name_value_pair) = ctor.values.get(*fld_name) else {
let Some(name_value_pair) = ctor_values.iter().find_map(|v| {
let name = self.get_text(&v.name);
match name == *fld_name {
true => Some(&v.node),
false => None,
}
}) else {
return Err(Diagnostic {
kind: Kind::Error,
code: Code::UninitializedField,
message: format!("Uninitialized field `{fld_name}`."),
position: CodePosition::new(self.source.clone(), expr.range()),
position: CodePosition::new(self.source.clone(), expr.range.clone()),
cause: None,
});
};
@@ -862,14 +900,17 @@ impl<'l> Scope<'l> {
fn make_function(
&mut self,
ast: &Arc<ast::Function>,
ast: &Arc<AstNode<ast::Function>>,
ctx: &mut ExpressionContext<'l, '_>,
) -> Result<&'l Function<'l>, Diagnostic> {
let ret_ty = match ast.ret.as_ref() {
None => AnyValue::Constant(AnyConst::Type(Type::Void)),
Some(ty) => self.compile_expression(ty, ctx)?,
};
let ast_as_expr = Expr::Func(ast.clone());
let ast_as_expr = AstNode {
range: ast.range.clone(),
node: 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 {
@@ -880,7 +921,7 @@ impl<'l> Scope<'l> {
let fn_ty = ret_ty.make_fn(par_ty);
let name = match &ctx.decl_names {
Some(NamePattern::Single(func_name)) => func_name.0.as_str(),
Some(NamePattern::Single(func_name)) => &*self.get_text(func_name),
_ => "",
};
let func = self.assembly.create_function(fn_ty, name);
@@ -890,7 +931,8 @@ impl<'l> Scope<'l> {
let mut scope = self.clone();
for (i, arg) in ast.args.iter().enumerate() {
scope.insert(arg.name.0.clone(), AnyValue::Parameter(i, func));
let name = self.get_text_arc(&arg.name);
scope.insert(name, AnyValue::Parameter(i, func));
}
ctx.fn_queue.push_back((func, block.clone(), scope));
@@ -901,7 +943,7 @@ impl<'l> Scope<'l> {
fn compile_decl(
&mut self,
names: &NamePattern,
value: &Expr,
value: &AstNode<Expr>,
mutable: bool,
ctx: &mut ExpressionContext<'l, '_>,
) -> Result<AnyValue<'l>, Diagnostic> {
@@ -923,8 +965,9 @@ impl<'l> Scope<'l> {
}
match names {
NamePattern::Single(ident) => {
let name = self.get_text_arc(ident);
self.values.insert(
ident.0.clone(),
name,
Variable {
value: Arc::new(OnceLock::from(value)),
},
@@ -932,7 +975,7 @@ impl<'l> Scope<'l> {
self.ctx.emit_event(Event::Definition {
value: value,
position: CodePosition::new(self.source.clone(), ident.range()),
position: CodePosition::new(self.source.clone(), ident.clone()),
});
}
NamePattern::Tuple(_) => todo!(),
@@ -970,7 +1013,9 @@ impl<'l> Scope<'l> {
expr: &If,
ctx: &mut ExpressionContext<'l, '_>,
) -> Result<AnyValue<'l>, Diagnostic> {
let If { cond, block, else_ } = expr;
let If {
cond, block, else_, ..
} = expr;
let condition = self.compile_expression(cond, ctx)?;
self.assert_ty_eq(&condition, cond, &Type::Bool)?;
@@ -997,8 +1042,8 @@ impl<'l> Scope<'l> {
builder.set_current_block(else_block);
let else_val = match &**else_ {
Else::Block(block) => self.compile_block(block, ctx)?,
Else::If(if_) => self.compile_if(if_, ctx)?,
Else::Block { expr, .. } => self.compile_block(expr, ctx)?,
Else::If { expr, .. } => self.compile_if(expr, ctx)?,
};
let builder = ctx.builder.as_mut().unwrap();
@@ -1027,14 +1072,18 @@ impl<'l> Scope<'l> {
.into())
}
fn assert_ty(&self, val: AnyValue<'l>, value_expr: &Expr) -> Result<Type<'l>, Diagnostic> {
fn assert_ty(
&self,
val: AnyValue<'l>,
value_expr: &AstNode<Expr>,
) -> Result<Type<'l>, Diagnostic> {
match val {
AnyValue::Constant(AnyConst::Type(ty)) => Ok(ty),
_ => Err(Diagnostic {
kind: Kind::Error,
code: Code::NotAType,
message: "Value is not a type.".to_string(),
position: CodePosition::new(self.source.clone(), value_expr.range()),
position: CodePosition::new(self.source.clone(), value_expr.range.clone()),
cause: None,
}),
}
@@ -1043,7 +1092,7 @@ impl<'l> Scope<'l> {
pub fn assert_ty_eq(
&self,
value: &AnyValue<'l>,
value_expr: &Expr,
value_expr: &AstNode<Expr>,
expected: &Type<'l>,
) -> Result<Type<'l>, Diagnostic> {
let value_ty = value.ty();
@@ -1054,10 +1103,24 @@ impl<'l> Scope<'l> {
kind: Kind::Error,
code: Code::InvalidType,
message: format!("Expected value of type `{expected}`, found `{value_ty}`."),
position: CodePosition::new(self.source.clone(), value_expr.range()),
position: CodePosition::new(self.source.clone(), value_expr.range.clone()),
cause: None,
});
}
}
}
fn get_text(&self, range: &Range<usize>) -> Cow<'_, str> {
match &self.source.text {
leaf_parser::Text::ArcStr(arc_str, _) => {
Cow::Borrowed(&arc_str.as_str()[range.clone()])
}
}
}
fn get_text_arc(&self, range: &Range<usize>) -> Substr {
match &self.source.text {
leaf_parser::Text::ArcStr(arc_str, _) => arc_str.substr(range.clone()),
}
}
}