Add rudimentary type-use parsing and type-checking parameters.

This commit is contained in:
Jesse Brault 2026-03-02 20:00:16 -06:00
parent 2d601d6115
commit 0a0065a2c1
8 changed files with 61 additions and 5 deletions

View File

@ -13,3 +13,4 @@ pub mod module_level_declaration;
pub mod parameter; pub mod parameter;
pub mod statement; pub mod statement;
pub mod string_literal; pub mod string_literal;
pub mod type_use;

View File

@ -1,3 +1,4 @@
use crate::ast::type_use::TypeUse;
use crate::diagnostic::Diagnostic; use crate::diagnostic::Diagnostic;
use crate::source_range::SourceRange; use crate::source_range::SourceRange;
use crate::symbol::ParameterSymbol; use crate::symbol::ParameterSymbol;
@ -9,13 +10,19 @@ use std::rc::Rc;
pub struct Parameter { pub struct Parameter {
declared_name: String, declared_name: String,
declared_name_source_range: SourceRange, declared_name_source_range: SourceRange,
type_use: TypeUse,
} }
impl Parameter { 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 { Self {
declared_name: declared_name.into(), declared_name: declared_name.into(),
declared_name_source_range, declared_name_source_range,
type_use,
} }
} }
@ -25,7 +32,7 @@ impl Parameter {
) -> Result<Rc<RefCell<ParameterSymbol>>, Vec<Diagnostic>> { ) -> Result<Rc<RefCell<ParameterSymbol>>, Vec<Diagnostic>> {
let insert_result = symbol_table.insert_parameter_symbol(ParameterSymbol::new( let insert_result = symbol_table.insert_parameter_symbol(ParameterSymbol::new(
&self.declared_name, &self.declared_name,
TypeInfo::Any, // todo TypeInfo::from_declared_name(self.type_use.declared_name()),
)); ));
match insert_result { match insert_result {
Ok(parameter_symbol) => Ok(parameter_symbol), Ok(parameter_symbol) => Ok(parameter_symbol),

View File

@ -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
}
}

View File

@ -46,6 +46,8 @@ impl<'a> Lexer<'a> {
Token::new(self.position, self.position + 1, TokenKind::Equals) Token::new(self.position, self.position + 1, TokenKind::Equals)
} else if chunk.starts_with(",") { } else if chunk.starts_with(",") {
Token::new(self.position, self.position + 1, TokenKind::Comma) Token::new(self.position, self.position + 1, TokenKind::Comma)
} else if chunk.starts_with(":") {
Token::new(self.position, self.position + 1, TokenKind::Colon)
} else { } else {
// more than one char token // more than one char token
if chunk.starts_with(|c: char| c.is_ascii_digit()) { if chunk.starts_with(|c: char| c.is_ascii_digit()) {

View File

@ -11,6 +11,7 @@ use crate::ast::module_level_declaration::ModuleLevelDeclaration;
use crate::ast::parameter::Parameter; use crate::ast::parameter::Parameter;
use crate::ast::statement::Statement; use crate::ast::statement::Statement;
use crate::ast::string_literal::StringLiteral; use crate::ast::string_literal::StringLiteral;
use crate::ast::type_use::TypeUse;
use crate::diagnostic::Diagnostic; use crate::diagnostic::Diagnostic;
use crate::lexer::Lexer; use crate::lexer::Lexer;
use crate::source_range::SourceRange; use crate::source_range::SourceRange;
@ -309,14 +310,29 @@ impl<'a> Parser<'a> {
self.advance(); self.advance();
} }
} }
Ok(parameters) if diagnostics.is_empty() {
Ok(parameters)
} else {
Err(diagnostics)
}
} }
fn parameter(&mut self) -> Result<Parameter, Vec<Diagnostic>> { fn parameter(&mut self) -> Result<Parameter, Vec<Diagnostic>> {
let identifier_token = self.expect_advance(TokenKind::Identifier)?; let identifier_token = self.expect_advance(TokenKind::Identifier)?;
self.expect_advance(TokenKind::Colon)?;
let type_use = self.type_use()?;
Ok(Parameter::new( Ok(Parameter::new(
self.token_text(&identifier_token), self.token_text(&identifier_token),
SourceRange::new(identifier_token.start(), identifier_token.end()), SourceRange::new(identifier_token.start(), identifier_token.end()),
type_use,
))
}
fn type_use(&mut self) -> Result<TypeUse, Vec<Diagnostic>> {
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] #[test]
fn extern_fn_with_param() { fn extern_fn_with_param() {
smoke_test("extern fn println(message)") smoke_test("extern fn println(message: Any)")
} }
} }

View File

@ -37,4 +37,5 @@ pub enum TokenKind {
String, String,
Extern, Extern,
Comma, Comma,
Colon,
} }

View File

@ -29,6 +29,16 @@ impl Display for TypeInfo {
} }
impl 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 { pub fn is_assignable_from(&self, other: &TypeInfo) -> bool {
match self { match self {
TypeInfo::Any => true, TypeInfo::Any => true,

View File

@ -1,4 +1,4 @@
extern fn println(message) extern fn println(message: Any)
fn main() fn main()
let x = "Hello, World!" let x = "Hello, World!"