wip: anyone know how to write a type checker?

This commit is contained in:
James Harton 2022-08-22 18:53:49 +12:00
parent 9675e7fff5
commit de99800349
4 changed files with 59 additions and 7 deletions

View file

@ -4,7 +4,6 @@ use crate::source::Source;
use crate::span::Span; use crate::span::Span;
use miette::Diagnostic; use miette::Diagnostic;
use std::io::Error as IoError; use std::io::Error as IoError;
use std::num::{ParseFloatError, ParseIntError};
use std::sync::Arc; use std::sync::Arc;
use thiserror::Error; use thiserror::Error;

View file

@ -98,6 +98,39 @@ impl Type {
matches!(self, Type::External { .. }) matches!(self, Type::External { .. })
} }
pub fn is_bound(&self) -> bool {
match self {
Type::Struct { .. } => true,
Type::Protocol { .. } => true,
Type::Impl { .. } => true,
Type::Union { types, .. } => types.iter().all(|t| t.is_bound()),
Type::Atom => true,
Type::Boolean => true,
Type::Integer => true,
Type::Float => true,
Type::String => true,
Type::Array => true,
Type::Map => true,
Type::Function {
associated_type,
arguments,
result,
..
} => {
associated_type.is_bound()
&& result.is_bound()
&& arguments.iter().all(|t| t.is_bound())
}
Type::Variable { r#type, .. } => r#type.borrow().is_bound(),
Type::External { .. } => true,
Type::Alias { target, .. } => target.is_bound(),
}
}
pub fn is_unbound(&self) -> bool {
!self.is_bound()
}
pub fn span(&self) -> Option<Span> { pub fn span(&self) -> Option<Span> {
match self { match self {
Type::Struct { span, .. } => Some(span.clone()), Type::Struct { span, .. } => Some(span.clone()),
@ -190,6 +223,14 @@ impl TypeVariable {
pub fn is_reference(&self) -> bool { pub fn is_reference(&self) -> bool {
matches!(self, TypeVariable::Reference { .. }) matches!(self, TypeVariable::Reference { .. })
} }
pub fn is_bound(&self) -> bool {
match self {
TypeVariable::Unbound { .. } => false,
TypeVariable::Reference { .. } => false,
TypeVariable::Link { target } => target.is_bound(),
}
}
} }
impl ToString for TypeVariable { impl ToString for TypeVariable {

View file

@ -22,6 +22,7 @@ use std::sync::Arc;
pub use error::Error; pub use error::Error;
pub use ir::Context; pub use ir::Context;
pub use ir::Type;
pub use source::Source; pub use source::Source;
pub fn compile(source: Arc<Source>) -> Result<Context, Error> { pub fn compile(source: Arc<Source>) -> Result<Context, Error> {

View file

@ -1,6 +1,4 @@
#[macro_use]
extern crate miette; extern crate miette;
extern crate outrun_compiler; extern crate outrun_compiler;
use outrun_compiler::{Context, Error, Source}; use outrun_compiler::{Context, Error, Source};
@ -17,7 +15,7 @@ pub fn init() -> Result<Vec<Context>, Error> {
let mut results = Vec::new(); let mut results = Vec::new();
for path in files.iter() { for path in files.iter().take(1) {
let source = Source::from_file(path)?; let source = Source::from_file(path)?;
let source = Arc::new(source); let source = Arc::new(source);
let context = outrun_compiler::compile(source)?; let context = outrun_compiler::compile(source)?;
@ -50,13 +48,26 @@ mod test {
use super::*; use super::*;
use miette::Result; use miette::Result;
use outrun_compiler::Type;
#[test] #[test]
fn test_init() -> Result<()> { fn test_init() -> Result<()> {
let result = init()?; let results = init()?;
println!("results: {:#?}", results);
for context in results {
let unbound_types: Vec<Arc<Type>> = context
.types
.iter()
.filter(|t| t.is_unbound())
.cloned()
.collect();
println!("unbound_types: {:#?}", unbound_types);
assert_eq!(unbound_types.len(), 0);
}
println!("result: {:?}", result);
assert!(false);
Ok(()) Ok(())
} }
} }