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
|
// Typecheck the HIR
|
||||||
match check(&ir) {
|
match check(&ir) {
|
||||||
Ok(_) => {},
|
Ok(_) => {
|
||||||
Err(err) => {
|
logif!(0, format!("Typechecking took {}ms", start.elapsed().as_millis()));
|
||||||
diagnostics.add_typecheck_error(err);
|
},
|
||||||
|
Err(errs) => {
|
||||||
|
for err in errs {
|
||||||
|
diagnostics.add_typecheck_error(err);
|
||||||
|
}
|
||||||
diagnostics.display(src);
|
diagnostics.display(src);
|
||||||
logif!(0, "Typechecking failed");
|
logif!(2, "Typechecking failed");
|
||||||
std::process::exit(1);
|
std::process::exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
dbg!(check(&ir));
|
||||||
|
|
||||||
// Report lowering errors if any
|
// Report lowering errors if any
|
||||||
if diagnostics.has_error() {
|
if diagnostics.has_error() {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use hir::{IR, IRKind};
|
use hir::{IR, IRKind, Value};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum TypecheckErrorKind {
|
pub enum TypecheckErrorKind {
|
||||||
|
@ -29,6 +29,95 @@ pub struct TypecheckError {
|
||||||
pub span: std::ops::Range<usize>,
|
pub span: std::ops::Range<usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check(ir: &Vec<IR>) -> Result<(), TypecheckError> {
|
pub fn check(irs: &Vec<IR>) -> Result<(), Vec<TypecheckError>> {
|
||||||
todo!();
|
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