diff --git a/drimc_rs/src/main.rs b/drimc_rs/src/main.rs index 9ff0951..7563091 100644 --- a/drimc_rs/src/main.rs +++ b/drimc_rs/src/main.rs @@ -2,13 +2,13 @@ use std::{error::Error, fmt::Display, fs::File, io::Write, process::exit, str::FromStr}; +use clap::Parser; use drimc_rs::{ ast2ir::ast2ir, backends, parser::{parser, ParserError, ParserMeta}, typeck::typeck, }; -use clap::Parser; /// Optimization levels. #[derive(Debug)] @@ -256,7 +256,7 @@ fn main() { let source = std::fs::read_to_string(&args.source_file)?; let meta = ParserMeta::default(); let ast = chumsky::Parser::parse(&parser(&meta), source).map_err(ParserError)?; - typeck(&ast)?; + let ast = typeck(ast)?; let ir = ast2ir(ast); diff --git a/drimc_rs/src/syntax.rs b/drimc_rs/src/syntax.rs index f295b05..d834951 100644 --- a/drimc_rs/src/syntax.rs +++ b/drimc_rs/src/syntax.rs @@ -2,6 +2,8 @@ use num_bigint::BigUint; +use crate::typeck; + /// A concrete syntax tree. This represents the full content of a Drim program, including all /// whitespace, comments, and tokens: the source code of the original program can be recovered /// completely using the syntax tree. @@ -68,7 +70,7 @@ pub enum ClassMember { /// The type of the overall function; this is filled in by the typechecker, and is left /// blank by the parser. - typ: Option, + typ: Option, }, /// Declaration of a type that is a literal alias for another type. @@ -98,7 +100,7 @@ pub struct Expr { pub kind: ExprKind, /// An optional type signature, left as `None` by the parser and added by the type checker. - pub typ: Option, + pub typ: Option, } /// The different kinds of expressions. @@ -266,7 +268,7 @@ pub enum Pattern { } /// Namespaced identifiers. -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Hash, PartialEq)] pub struct Identifier { /// The elements of the identifier; there must be at least one of these. pub elems: Vec, diff --git a/drimc_rs/src/typeck.rs b/drimc_rs/src/typeck.rs index 56de735..d12647e 100644 --- a/drimc_rs/src/typeck.rs +++ b/drimc_rs/src/typeck.rs @@ -1,8 +1,10 @@ //! Type checker. -use std::{error::Error, fmt::Display}; +use std::{collections::BTreeMap, error::Error, fmt::Display}; -use crate::syntax::SyntaxTree; +use num_bigint::BigInt; + +use crate::syntax::{Identifier, SyntaxTree}; /// A compile-time type error from the user's source code. #[derive(Debug)] @@ -16,7 +18,39 @@ impl Display for TypeError { impl Error for TypeError {} +/// A type known at compile time. While this resembles the AST `Type` structure, this enum is +/// optimized for unifying types against one another and representing compiler-generated types +/// rather than strictly representing named types. +#[derive(Debug, Clone, PartialEq)] +pub enum Type { + /// `Foo` + Named(Identifier), + + /// `List Int` + Application { + /// The function being applied. This must be a generic type. + function: Box, + + /// The type given as an argument to the type. + expression: Box, + }, + + /// `(a, b)` + Tuple(Vec), + + /// `{ a: x, b: y }` + Record(BTreeMap), + + /// Compiler-internal type representing an arbitrary-precision integer whose value is known at + /// compile time. This is the default type of integer literals. A `CompInt` can be converted to + /// an actual integer type via implicit application of the `fromCompInt` generic function. + CompInt(BigInt), + + /// Compiler-internal type representing a string literal. See `CompInt`. + CompString(String), +} + /// Type-checks the syntax tree. -pub fn typeck(_: &SyntaxTree) -> Result<(), TypeError> { +pub fn typeck(_: SyntaxTree) -> Result { todo!() }