Full AST based syntax highlighting
This commit is contained in:
+5
-2
@@ -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>,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
@@ -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()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user