Add parameter-list to regular fns.

This commit is contained in:
Jesse Brault 2026-03-03 12:31:52 -06:00
parent 61d7c66e17
commit 81ceeeadb8
4 changed files with 125 additions and 45 deletions

View File

@ -3,8 +3,6 @@ use crate::diagnostic::Diagnostic;
use crate::source_range::SourceRange; use crate::source_range::SourceRange;
use crate::symbol::FunctionSymbol; use crate::symbol::FunctionSymbol;
use crate::symbol_table::{SymbolInsertError, SymbolTable}; use crate::symbol_table::{SymbolInsertError, SymbolTable};
use std::cell::RefCell;
use std::rc::Rc;
pub struct ExternFunction { pub struct ExternFunction {
declared_name: String, declared_name: String,
@ -35,24 +33,24 @@ impl ExternFunction {
let insert_result = let insert_result =
symbol_table.insert_function_symbol(FunctionSymbol::new(&self.declared_name, true)); symbol_table.insert_function_symbol(FunctionSymbol::new(&self.declared_name, true));
let mut maybe_function_symbol: Option<Rc<RefCell<FunctionSymbol>>> = None; let function_symbol = match insert_result {
match insert_result { Ok(function_symbol) => function_symbol,
Ok(function_symbol) => { Err(symbol_insert_error) => {
maybe_function_symbol = Some(function_symbol); return match symbol_insert_error {
SymbolInsertError::AlreadyDeclared(already_declared) => {
diagnostics.push(Diagnostic::new(
&format!(
"Function {} already declared in current scope.",
already_declared.name()
),
self.declared_name_source_range.start(),
self.declared_name_source_range.end(),
));
diagnostics
}
};
} }
Err(symbol_insert_error) => match symbol_insert_error { };
SymbolInsertError::AlreadyDeclared(already_declared) => {
diagnostics.push(Diagnostic::new(
&format!(
"Function {} already declared in current scope.",
already_declared.name()
),
self.declared_name_source_range.start(),
self.declared_name_source_range.end(),
));
}
},
}
symbol_table.push_scope(&format!("extern_function_scope({})", &self.declared_name)); symbol_table.push_scope(&format!("extern_function_scope({})", &self.declared_name));
@ -68,8 +66,7 @@ impl ExternFunction {
} }
} }
} }
maybe_function_symbol function_symbol
.unwrap()
.borrow_mut() .borrow_mut()
.set_parameters(parameter_symbols); .set_parameters(parameter_symbols);
@ -78,13 +75,21 @@ impl ExternFunction {
diagnostics diagnostics
} }
pub fn check_name_usages(&mut self, _symbol_table: &SymbolTable) -> Vec<Diagnostic> { pub fn check_name_usages(&mut self, symbol_table: &SymbolTable) -> Vec<Diagnostic> {
// no-op (for now) self.parameters
vec![] .iter_mut()
.map(|parameter| parameter.check_name_usages(symbol_table))
.filter_map(Result::err)
.flatten()
.collect()
} }
pub fn type_check(&mut self, _symbol_table: &SymbolTable) -> Vec<Diagnostic> { pub fn type_check(&mut self, symbol_table: &SymbolTable) -> Vec<Diagnostic> {
// no-op (for now) self.parameters
vec![] .iter_mut()
.map(|parameter| parameter.type_check(symbol_table))
.filter_map(Result::err)
.flatten()
.collect()
} }
} }

View File

@ -1,4 +1,5 @@
use crate::ast::assemble_context::AssembleContext; use crate::ast::assemble_context::AssembleContext;
use crate::ast::parameter::Parameter;
use crate::ast::statement::Statement; use crate::ast::statement::Statement;
use crate::constants_table::ConstantsTable; use crate::constants_table::ConstantsTable;
use crate::diagnostic::Diagnostic; use crate::diagnostic::Diagnostic;
@ -9,6 +10,7 @@ use crate::symbol_table::{SymbolInsertError, SymbolTable};
pub struct Function { pub struct Function {
declared_name: String, declared_name: String,
declared_name_source_range: SourceRange, declared_name_source_range: SourceRange,
parameters: Vec<Parameter>,
statements: Vec<Statement>, statements: Vec<Statement>,
} }
@ -16,11 +18,13 @@ impl Function {
pub fn new( pub fn new(
declared_name: &str, declared_name: &str,
declared_name_source_range: SourceRange, declared_name_source_range: SourceRange,
parameters: Vec<Parameter>,
statements: Vec<Statement>, statements: Vec<Statement>,
) -> Self { ) -> Self {
Self { Self {
declared_name: declared_name.to_string(), declared_name: declared_name.to_string(),
declared_name_source_range, declared_name_source_range,
parameters,
statements, statements,
} }
} }
@ -35,36 +39,72 @@ impl Function {
pub fn gather_declared_names(&mut self, symbol_table: &mut SymbolTable) -> Vec<Diagnostic> { pub fn gather_declared_names(&mut self, symbol_table: &mut SymbolTable) -> Vec<Diagnostic> {
let mut diagnostics = vec![]; let mut diagnostics = vec![];
// insert function symbol // insert function symbol
let insert_result = let insert_result =
symbol_table.insert_function_symbol(FunctionSymbol::new(self.declared_name(), false)); symbol_table.insert_function_symbol(FunctionSymbol::new(self.declared_name(), false));
if let Err(symbol_insert_error) = insert_result {
match symbol_insert_error { // get function symbol if successful
SymbolInsertError::AlreadyDeclared(already_declared) => { let function_symbol = match insert_result {
diagnostics.push(Diagnostic::new( Ok(function_symbol) => function_symbol,
&format!( Err(symbol_insert_error) => {
"Function {} already declared in current scope", return match symbol_insert_error {
already_declared.name() SymbolInsertError::AlreadyDeclared(already_declared) => {
), diagnostics.push(Diagnostic::new(
self.declared_name_source_range.start(), &format!(
self.declared_name_source_range.end(), "Function {} already declared in current scope",
)); already_declared.name()
),
self.declared_name_source_range.start(),
self.declared_name_source_range.end(),
));
diagnostics
}
};
}
};
// handle parameters
symbol_table.push_scope(&format!("parameter_scope({})", self.declared_name));
let mut parameter_symbols = vec![];
for parameter in &mut self.parameters {
match parameter.gather_declared_names(symbol_table) {
Ok(parameter_symbol) => {
parameter_symbols.push(parameter_symbol);
}
Err(mut parameter_diagnostics) => {
diagnostics.append(&mut parameter_diagnostics);
} }
} }
} }
function_symbol
.borrow_mut()
.set_parameters(parameter_symbols);
// todo: parameters symbol_table.push_scope(&format!("body_scope({})", self.declared_name));
symbol_table.push_scope(&format!("function_scope({})", self.declared_name()));
for statement in &mut self.statements { for statement in &mut self.statements {
diagnostics.append(&mut statement.gather_declared_names(symbol_table)); diagnostics.append(&mut statement.gather_declared_names(symbol_table));
} }
symbol_table.pop_scope(); symbol_table.pop_scope(); // body
symbol_table.pop_scope(); // params
diagnostics diagnostics
} }
pub fn check_name_usages(&mut self, symbol_table: &SymbolTable) -> Vec<Diagnostic> { pub fn check_name_usages(&mut self, symbol_table: &SymbolTable) -> Vec<Diagnostic> {
let mut diagnostics = vec![]; let mut diagnostics = vec![];
// parameters
diagnostics.append(
&mut self
.parameters
.iter_mut()
.map(|parameter| parameter.check_name_usages(symbol_table))
.filter_map(|result| result.err())
.flatten()
.collect(),
);
// statements
for statement in &mut self.statements { for statement in &mut self.statements {
diagnostics.append(&mut statement.check_name_usages(symbol_table)); diagnostics.append(&mut statement.check_name_usages(symbol_table));
} }
@ -73,9 +113,23 @@ impl Function {
pub fn type_check(&mut self, symbol_table: &SymbolTable) -> Vec<Diagnostic> { pub fn type_check(&mut self, symbol_table: &SymbolTable) -> Vec<Diagnostic> {
let mut diagnostics = vec![]; let mut diagnostics = vec![];
// parameters
diagnostics.append(
&mut self
.parameters
.iter_mut()
.map(|parameter| parameter.type_check(symbol_table))
.filter_map(|result| result.err())
.flatten()
.collect(),
);
// statements
for statement in &mut self.statements { for statement in &mut self.statements {
diagnostics.append(&mut statement.type_check(symbol_table)); diagnostics.append(&mut statement.type_check(symbol_table));
} }
diagnostics diagnostics
} }

View File

@ -45,4 +45,12 @@ impl Parameter {
}, },
} }
} }
pub fn check_name_usages(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
Ok(()) // no-op for now
}
pub fn type_check(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
Ok(()) // no-op for now
}
} }

View File

@ -219,7 +219,9 @@ impl<'a> Parser<'a> {
self.expect_advance(TokenKind::Fn)?; self.expect_advance(TokenKind::Fn)?;
let identifier_token = self.expect_advance(TokenKind::Identifier)?; let identifier_token = self.expect_advance(TokenKind::Identifier)?;
self.expect_advance(TokenKind::LeftParentheses)?; self.expect_advance(TokenKind::LeftParentheses)?;
// add params
let parameters = self.parameter_list()?;
self.expect_advance(TokenKind::RightParentheses)?; self.expect_advance(TokenKind::RightParentheses)?;
let mut statements = vec![]; let mut statements = vec![];
let mut diagnostics = vec![]; let mut diagnostics = vec![];
@ -248,6 +250,7 @@ impl<'a> Parser<'a> {
Ok(Function::new( Ok(Function::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()),
parameters,
statements, statements,
)) ))
} else { } else {
@ -306,7 +309,7 @@ impl<'a> Parser<'a> {
diagnostics.append(&mut parameter_diagnostics); diagnostics.append(&mut parameter_diagnostics);
} }
} }
if self.lookahead.is_some() && self.peek_lookahead(TokenKind::Comma) { if self.current.is_some() && self.peek_current(TokenKind::Comma) {
self.advance(); self.advance();
} }
} }
@ -480,7 +483,17 @@ mod smoke_tests {
#[test] #[test]
fn extern_fn_with_param() { fn extern_fn_with_param() {
smoke_test("extern fn println(message: Any)") smoke_test("extern fn println(message: Any)");
}
#[test]
fn fn_with_param() {
smoke_test("fn foo(bar: Int) end");
}
#[test]
fn fn_with_params() {
smoke_test("fn foo(bar: Int, baz: Int) end");
} }
} }