From 0a0065a2c1345c657af041dff43b93484816921c Mon Sep 17 00:00:00 2001 From: Jesse Brault Date: Mon, 2 Mar 2026 20:00:16 -0600 Subject: [PATCH] Add rudimentary type-use parsing and type-checking parameters. --- dmc-lib/src/ast/mod.rs | 1 + dmc-lib/src/ast/parameter.rs | 11 +++++++++-- dmc-lib/src/ast/type_use.rs | 19 +++++++++++++++++++ dmc-lib/src/lexer.rs | 2 ++ dmc-lib/src/parser.rs | 20 ++++++++++++++++++-- dmc-lib/src/token.rs | 1 + dmc-lib/src/type_info.rs | 10 ++++++++++ examples/hello.dm | 2 +- 8 files changed, 61 insertions(+), 5 deletions(-) create mode 100644 dmc-lib/src/ast/type_use.rs diff --git a/dmc-lib/src/ast/mod.rs b/dmc-lib/src/ast/mod.rs index f422696..818a9d9 100644 --- a/dmc-lib/src/ast/mod.rs +++ b/dmc-lib/src/ast/mod.rs @@ -13,3 +13,4 @@ pub mod module_level_declaration; pub mod parameter; pub mod statement; pub mod string_literal; +pub mod type_use; diff --git a/dmc-lib/src/ast/parameter.rs b/dmc-lib/src/ast/parameter.rs index 784cd16..4075d94 100644 --- a/dmc-lib/src/ast/parameter.rs +++ b/dmc-lib/src/ast/parameter.rs @@ -1,3 +1,4 @@ +use crate::ast::type_use::TypeUse; use crate::diagnostic::Diagnostic; use crate::source_range::SourceRange; use crate::symbol::ParameterSymbol; @@ -9,13 +10,19 @@ use std::rc::Rc; pub struct Parameter { declared_name: String, declared_name_source_range: SourceRange, + type_use: TypeUse, } impl Parameter { - pub fn new(declared_name: &str, declared_name_source_range: SourceRange) -> Self { + pub fn new( + declared_name: &str, + declared_name_source_range: SourceRange, + type_use: TypeUse, + ) -> Self { Self { declared_name: declared_name.into(), declared_name_source_range, + type_use, } } @@ -25,7 +32,7 @@ impl Parameter { ) -> Result>, Vec> { let insert_result = symbol_table.insert_parameter_symbol(ParameterSymbol::new( &self.declared_name, - TypeInfo::Any, // todo + TypeInfo::from_declared_name(self.type_use.declared_name()), )); match insert_result { Ok(parameter_symbol) => Ok(parameter_symbol), diff --git a/dmc-lib/src/ast/type_use.rs b/dmc-lib/src/ast/type_use.rs new file mode 100644 index 0000000..f25058e --- /dev/null +++ b/dmc-lib/src/ast/type_use.rs @@ -0,0 +1,19 @@ +use crate::source_range::SourceRange; + +pub struct TypeUse { + declared_name: String, + declared_name_source_range: SourceRange, +} + +impl TypeUse { + pub fn new(declared_name: &str, declared_name_source_range: SourceRange) -> Self { + Self { + declared_name: declared_name.into(), + declared_name_source_range, + } + } + + pub fn declared_name(&self) -> &str { + &self.declared_name + } +} diff --git a/dmc-lib/src/lexer.rs b/dmc-lib/src/lexer.rs index 4a74f94..0254796 100644 --- a/dmc-lib/src/lexer.rs +++ b/dmc-lib/src/lexer.rs @@ -46,6 +46,8 @@ impl<'a> Lexer<'a> { Token::new(self.position, self.position + 1, TokenKind::Equals) } else if chunk.starts_with(",") { Token::new(self.position, self.position + 1, TokenKind::Comma) + } else if chunk.starts_with(":") { + Token::new(self.position, self.position + 1, TokenKind::Colon) } else { // more than one char token if chunk.starts_with(|c: char| c.is_ascii_digit()) { diff --git a/dmc-lib/src/parser.rs b/dmc-lib/src/parser.rs index 4800860..68f70fe 100644 --- a/dmc-lib/src/parser.rs +++ b/dmc-lib/src/parser.rs @@ -11,6 +11,7 @@ use crate::ast::module_level_declaration::ModuleLevelDeclaration; use crate::ast::parameter::Parameter; use crate::ast::statement::Statement; use crate::ast::string_literal::StringLiteral; +use crate::ast::type_use::TypeUse; use crate::diagnostic::Diagnostic; use crate::lexer::Lexer; use crate::source_range::SourceRange; @@ -309,14 +310,29 @@ impl<'a> Parser<'a> { self.advance(); } } - Ok(parameters) + if diagnostics.is_empty() { + Ok(parameters) + } else { + Err(diagnostics) + } } fn parameter(&mut self) -> Result> { let identifier_token = self.expect_advance(TokenKind::Identifier)?; + self.expect_advance(TokenKind::Colon)?; + let type_use = self.type_use()?; Ok(Parameter::new( self.token_text(&identifier_token), SourceRange::new(identifier_token.start(), identifier_token.end()), + type_use, + )) + } + + fn type_use(&mut self) -> Result> { + let identifier_token = self.expect_advance(TokenKind::Identifier)?; + Ok(TypeUse::new( + self.token_text(&identifier_token), + SourceRange::new(identifier_token.start(), identifier_token.end()), )) } @@ -464,7 +480,7 @@ mod smoke_tests { #[test] fn extern_fn_with_param() { - smoke_test("extern fn println(message)") + smoke_test("extern fn println(message: Any)") } } diff --git a/dmc-lib/src/token.rs b/dmc-lib/src/token.rs index e41ab24..29751e3 100644 --- a/dmc-lib/src/token.rs +++ b/dmc-lib/src/token.rs @@ -37,4 +37,5 @@ pub enum TokenKind { String, Extern, Comma, + Colon, } diff --git a/dmc-lib/src/type_info.rs b/dmc-lib/src/type_info.rs index dd1bf5b..8456562 100644 --- a/dmc-lib/src/type_info.rs +++ b/dmc-lib/src/type_info.rs @@ -29,6 +29,16 @@ impl Display for TypeInfo { } impl TypeInfo { + // This is very naive but works for now + pub fn from_declared_name(declared_name: &str) -> Self { + match declared_name { + "Any" => TypeInfo::Any, + "Int" => TypeInfo::Integer, + "String" => TypeInfo::String, + _ => panic!("Unknown type: {}", declared_name), + } + } + pub fn is_assignable_from(&self, other: &TypeInfo) -> bool { match self { TypeInfo::Any => true, diff --git a/examples/hello.dm b/examples/hello.dm index ed2a17f..1871b52 100644 --- a/examples/hello.dm +++ b/examples/hello.dm @@ -1,4 +1,4 @@ -extern fn println(message) +extern fn println(message: Any) fn main() let x = "Hello, World!"