mirror of
https://github.com/azur1s/bobbylisp.git
synced 2024-10-16 02:37:40 -05:00
simple typechecking
This commit is contained in:
parent
74adfe1f0f
commit
ea90b7f90a
|
@ -63,14 +63,19 @@ fn main() {
|
|||
|
||||
// Typecheck the HIR
|
||||
match check(&ir) {
|
||||
Ok(_) => {},
|
||||
Err(err) => {
|
||||
Ok(_) => {
|
||||
logif!(0, format!("Typechecking took {}ms", start.elapsed().as_millis()));
|
||||
},
|
||||
Err(errs) => {
|
||||
for err in errs {
|
||||
diagnostics.add_typecheck_error(err);
|
||||
}
|
||||
diagnostics.display(src);
|
||||
logif!(0, "Typechecking failed");
|
||||
logif!(2, "Typechecking failed");
|
||||
std::process::exit(1);
|
||||
}
|
||||
}
|
||||
dbg!(check(&ir));
|
||||
|
||||
// Report lowering errors if any
|
||||
if diagnostics.has_error() {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use hir::{IR, IRKind};
|
||||
use hir::{IR, IRKind, Value};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum TypecheckErrorKind {
|
||||
|
@ -29,6 +29,95 @@ pub struct TypecheckError {
|
|||
pub span: std::ops::Range<usize>,
|
||||
}
|
||||
|
||||
pub fn check(ir: &Vec<IR>) -> Result<(), TypecheckError> {
|
||||
todo!();
|
||||
pub fn check(irs: &Vec<IR>) -> Result<(), Vec<TypecheckError>> {
|
||||
let mut errors = Vec::new();
|
||||
for ir in irs {
|
||||
match &ir.kind {
|
||||
ir @ IRKind::Define { .. } => {
|
||||
match check_define(&ir) {
|
||||
Ok(()) => (),
|
||||
Err(e) => errors.push(e),
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
if errors.is_empty() { Ok(()) }
|
||||
else { Err(errors) }
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! return_err {
|
||||
($kind:expr, $span:expr) => {{
|
||||
return Err(TypecheckError {
|
||||
kind: $kind,
|
||||
span: $span.clone()
|
||||
});
|
||||
}};
|
||||
}
|
||||
|
||||
/// Check the types of the definitions.
|
||||
/// This is done by checking the type of the value against the type hint.
|
||||
///
|
||||
/// # Examples
|
||||
/// ```sml
|
||||
/// let x: int = 1; -- Correct
|
||||
///
|
||||
/// let x: string = 1; -- Incorrect
|
||||
/// ```
|
||||
fn check_define(ir: &IRKind) -> Result<(), TypecheckError> {
|
||||
match ir {
|
||||
IRKind::Define {
|
||||
type_hint,
|
||||
value,
|
||||
span,
|
||||
..
|
||||
} => {
|
||||
match &**value {
|
||||
IRKind::Value { value } => {
|
||||
match value {
|
||||
Value::Int(_) => {
|
||||
if type_hint != "number" {
|
||||
return_err!(
|
||||
TypecheckErrorKind::DefinitionTypeMismatch {
|
||||
type_specified: type_hint.to_string(),
|
||||
type_found: "number".to_string(),
|
||||
},
|
||||
span.clone()
|
||||
);
|
||||
}
|
||||
}
|
||||
Value::String(_) => {
|
||||
if type_hint != "string" {
|
||||
return_err!(
|
||||
TypecheckErrorKind::DefinitionTypeMismatch {
|
||||
type_specified: type_hint.to_string(),
|
||||
type_found: "string".to_string(),
|
||||
},
|
||||
span.clone()
|
||||
);
|
||||
}
|
||||
}
|
||||
Value::Boolean(_) => {
|
||||
if type_hint != "boolean" {
|
||||
return_err!(
|
||||
TypecheckErrorKind::DefinitionTypeMismatch {
|
||||
type_specified: type_hint.to_string(),
|
||||
type_found: "boolean".to_string(),
|
||||
},
|
||||
span.clone()
|
||||
);
|
||||
}
|
||||
}
|
||||
// TODO: other types
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
// TODO: other (right-hand side) IRKinds
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
_ => unreachable!()
|
||||
}
|
||||
Ok(())
|
||||
}
|
3
example/err/define_wrong_type.hz
Normal file
3
example/err/define_wrong_type.hz
Normal file
|
@ -0,0 +1,3 @@
|
|||
let foo: int = "123";
|
||||
let bar: string = 69;
|
||||
let baz: bool = "true";
|
Loading…
Reference in a new issue