Add extern_function AST node.
This commit is contained in:
parent
35a849233c
commit
b7b495178b
@ -1,29 +1,28 @@
|
||||
use crate::asm::asm_function::AsmFunction;
|
||||
use crate::ast::assemble_context::AssembleContext;
|
||||
use crate::ast::function::Function;
|
||||
use crate::ast::module_level_declaration::ModuleLevelDeclaration;
|
||||
use crate::constants_table::ConstantsTable;
|
||||
use crate::diagnostic::Diagnostic;
|
||||
use crate::ir::Ir;
|
||||
use crate::symbol_table::SymbolTable;
|
||||
|
||||
pub struct CompilationUnit {
|
||||
functions: Vec<Function>,
|
||||
declarations: Vec<ModuleLevelDeclaration>,
|
||||
}
|
||||
|
||||
impl CompilationUnit {
|
||||
pub fn new(functions: Vec<Function>) -> Self {
|
||||
Self { functions }
|
||||
pub fn new(declarations: Vec<ModuleLevelDeclaration>) -> Self {
|
||||
Self { declarations }
|
||||
}
|
||||
|
||||
pub fn functions(&self) -> Vec<&Function> {
|
||||
self.functions.iter().collect()
|
||||
pub fn declarations(&self) -> &[ModuleLevelDeclaration] {
|
||||
&self.declarations
|
||||
}
|
||||
|
||||
pub fn gather_declared_names(&mut self, symbol_table: &mut SymbolTable) -> Vec<Diagnostic> {
|
||||
let mut diagnostics = vec![];
|
||||
symbol_table.push_scope("compilation_unit_scope");
|
||||
for function in &mut self.functions {
|
||||
diagnostics.append(&mut function.gather_declared_names(symbol_table));
|
||||
for declaration in &mut self.declarations {
|
||||
diagnostics.append(&mut declaration.gather_declared_names(symbol_table));
|
||||
}
|
||||
symbol_table.pop_scope();
|
||||
diagnostics
|
||||
@ -31,36 +30,28 @@ impl CompilationUnit {
|
||||
|
||||
pub fn check_name_usages(&mut self, symbol_table: &SymbolTable) -> Vec<Diagnostic> {
|
||||
let mut diagnostics = vec![];
|
||||
for function in &mut self.functions {
|
||||
diagnostics.append(&mut function.check_name_usages(symbol_table));
|
||||
for declaration in &mut self.declarations {
|
||||
diagnostics.append(&mut declaration.check_name_usages(symbol_table));
|
||||
}
|
||||
diagnostics
|
||||
}
|
||||
|
||||
pub fn type_check(&mut self, symbol_table: &SymbolTable) -> Vec<Diagnostic> {
|
||||
let mut diagnostics = vec![];
|
||||
for function in &mut self.functions {
|
||||
diagnostics.append(&mut function.type_check(symbol_table));
|
||||
for declaration in &mut self.declarations {
|
||||
diagnostics.append(&mut declaration.type_check(symbol_table));
|
||||
}
|
||||
diagnostics
|
||||
}
|
||||
|
||||
pub fn lower_to_ir(&self) -> Vec<Ir> {
|
||||
let mut irs = vec![];
|
||||
for function in &self.functions {
|
||||
irs.append(&mut function.lower_to_ir());
|
||||
}
|
||||
irs
|
||||
}
|
||||
|
||||
pub fn assemble(
|
||||
&self,
|
||||
symbol_table: &SymbolTable,
|
||||
constants_table: &mut ConstantsTable,
|
||||
) -> Vec<AsmFunction> {
|
||||
let mut context = AssembleContext::new();
|
||||
for function in &self.functions {
|
||||
function.assemble(&mut context, symbol_table, constants_table);
|
||||
for declaration in &self.declarations {
|
||||
declaration.assemble(&mut context, symbol_table, constants_table);
|
||||
}
|
||||
context.take_functions()
|
||||
}
|
||||
|
||||
66
dmc-lib/src/ast/extern_function.rs
Normal file
66
dmc-lib/src/ast/extern_function.rs
Normal file
@ -0,0 +1,66 @@
|
||||
use crate::ast::assemble_context::AssembleContext;
|
||||
use crate::constants_table::ConstantsTable;
|
||||
use crate::diagnostic::Diagnostic;
|
||||
use crate::source_range::SourceRange;
|
||||
use crate::symbol::FunctionSymbol;
|
||||
use crate::symbol_table::{SymbolInsertError, SymbolTable};
|
||||
|
||||
pub struct ExternFunction {
|
||||
declared_name: String,
|
||||
declared_name_source_range: SourceRange,
|
||||
}
|
||||
|
||||
impl ExternFunction {
|
||||
pub fn new(name: &str, declared_name_source_range: SourceRange) -> ExternFunction {
|
||||
ExternFunction {
|
||||
declared_name: name.into(),
|
||||
declared_name_source_range,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn declared_name(&self) -> &str {
|
||||
&self.declared_name
|
||||
}
|
||||
|
||||
pub fn gather_declared_names(&mut self, symbol_table: &mut SymbolTable) -> Vec<Diagnostic> {
|
||||
let insert_result = symbol_table.insert_function_symbol(FunctionSymbol::new(
|
||||
&self.declared_name,
|
||||
&vec![],
|
||||
true,
|
||||
));
|
||||
match insert_result {
|
||||
Ok(_) => vec![],
|
||||
Err(symbol_insert_error) => match symbol_insert_error {
|
||||
SymbolInsertError::AlreadyDeclared(already_declared) => {
|
||||
vec![Diagnostic::new(
|
||||
&format!(
|
||||
"Function {} already declared in current scope.",
|
||||
already_declared.name()
|
||||
),
|
||||
self.declared_name_source_range.start(),
|
||||
self.declared_name_source_range.end(),
|
||||
)]
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn check_name_usages(&mut self, symbol_table: &SymbolTable) -> Vec<Diagnostic> {
|
||||
// no-op (for now)
|
||||
vec![]
|
||||
}
|
||||
|
||||
pub fn type_check(&mut self, symbol_table: &SymbolTable) -> Vec<Diagnostic> {
|
||||
// no-op (for now)
|
||||
vec![]
|
||||
}
|
||||
|
||||
pub fn assemble(
|
||||
&self,
|
||||
context: &mut AssembleContext,
|
||||
symbol_table: &SymbolTable,
|
||||
constants_table: &mut ConstantsTable,
|
||||
) {
|
||||
// no-op
|
||||
}
|
||||
}
|
||||
@ -43,6 +43,7 @@ impl Function {
|
||||
let insert_result = symbol_table.insert_function_symbol(FunctionSymbol::new(
|
||||
self.declared_name(),
|
||||
&vec![], // todo
|
||||
false,
|
||||
));
|
||||
if let Err(symbol_insert_error) = insert_result {
|
||||
match symbol_insert_error {
|
||||
|
||||
@ -3,19 +3,18 @@ pub mod call;
|
||||
pub mod compilation_unit;
|
||||
pub mod expression;
|
||||
pub mod expression_statement;
|
||||
pub mod extern_function;
|
||||
pub mod fqn;
|
||||
pub mod function;
|
||||
pub mod identifier;
|
||||
pub mod integer_literal;
|
||||
pub mod let_statement;
|
||||
pub mod module_level_declaration;
|
||||
pub mod statement;
|
||||
pub mod string_literal;
|
||||
|
||||
#[cfg(test)]
|
||||
mod name_tests {
|
||||
use crate::constants_table::ConstantsTable;
|
||||
use crate::ir::Ir;
|
||||
use crate::ir::assemble_context::AssembleContext;
|
||||
use crate::parser::parse_compilation_unit;
|
||||
use crate::symbol_table::SymbolTable;
|
||||
|
||||
@ -31,11 +30,6 @@ mod name_tests {
|
||||
0
|
||||
);
|
||||
assert_eq!(compilation_unit.check_name_usages(&symbol_table).len(), 0);
|
||||
let mut constants_table = ConstantsTable::new();
|
||||
let asm_functions = compilation_unit.assemble(&symbol_table, &mut constants_table);
|
||||
for asm_function in &asm_functions {
|
||||
println!("{:#?}", asm_function);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -45,20 +39,6 @@ mod name_tests {
|
||||
parse_compilation_unit("fn println() end fn main() println(\"Hello, World!\") end");
|
||||
compilation_unit.gather_declared_names(&mut symbol_table);
|
||||
compilation_unit.check_name_usages(&symbol_table);
|
||||
compilation_unit.type_check(&symbol_table);
|
||||
let irs = compilation_unit.lower_to_ir();
|
||||
for ir in &irs {
|
||||
println!("{:#?}", ir);
|
||||
}
|
||||
for ir in &irs {
|
||||
match ir {
|
||||
Ir::Function(ir_function) => {
|
||||
let asm_function = ir_function.assemble(&mut AssembleContext::new());
|
||||
println!("{:#?}", asm_function);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
58
dmc-lib/src/ast/module_level_declaration.rs
Normal file
58
dmc-lib/src/ast/module_level_declaration.rs
Normal file
@ -0,0 +1,58 @@
|
||||
use crate::ast::assemble_context::AssembleContext;
|
||||
use crate::ast::extern_function::ExternFunction;
|
||||
use crate::ast::function::Function;
|
||||
use crate::constants_table::ConstantsTable;
|
||||
use crate::diagnostic::Diagnostic;
|
||||
use crate::symbol_table::SymbolTable;
|
||||
|
||||
pub enum ModuleLevelDeclaration {
|
||||
Function(Function),
|
||||
ExternFunction(ExternFunction),
|
||||
}
|
||||
|
||||
impl ModuleLevelDeclaration {
|
||||
pub fn gather_declared_names(&mut self, symbol_table: &mut SymbolTable) -> Vec<Diagnostic> {
|
||||
match self {
|
||||
ModuleLevelDeclaration::Function(function) => {
|
||||
function.gather_declared_names(symbol_table)
|
||||
}
|
||||
ModuleLevelDeclaration::ExternFunction(extern_function) => {
|
||||
extern_function.gather_declared_names(symbol_table)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn check_name_usages(&mut self, symbol_table: &SymbolTable) -> Vec<Diagnostic> {
|
||||
match self {
|
||||
ModuleLevelDeclaration::Function(function) => function.check_name_usages(symbol_table),
|
||||
ModuleLevelDeclaration::ExternFunction(extern_function) => {
|
||||
extern_function.check_name_usages(symbol_table)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn type_check(&mut self, symbol_table: &SymbolTable) -> Vec<Diagnostic> {
|
||||
match self {
|
||||
ModuleLevelDeclaration::Function(function) => function.type_check(symbol_table),
|
||||
ModuleLevelDeclaration::ExternFunction(extern_function) => {
|
||||
extern_function.type_check(symbol_table)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn assemble(
|
||||
&self,
|
||||
context: &mut AssembleContext,
|
||||
symbol_table: &SymbolTable,
|
||||
constants_table: &mut ConstantsTable,
|
||||
) {
|
||||
match self {
|
||||
ModuleLevelDeclaration::Function(function) => {
|
||||
function.assemble(context, symbol_table, constants_table)
|
||||
}
|
||||
ModuleLevelDeclaration::ExternFunction(extern_function) => {
|
||||
extern_function.assemble(context, symbol_table, constants_table)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2,10 +2,12 @@ use crate::ast::call::Call;
|
||||
use crate::ast::compilation_unit::CompilationUnit;
|
||||
use crate::ast::expression::Expression;
|
||||
use crate::ast::expression_statement::ExpressionStatement;
|
||||
use crate::ast::extern_function::ExternFunction;
|
||||
use crate::ast::function::Function;
|
||||
use crate::ast::identifier::Identifier;
|
||||
use crate::ast::integer_literal::IntegerLiteral;
|
||||
use crate::ast::let_statement::LetStatement;
|
||||
use crate::ast::module_level_declaration::ModuleLevelDeclaration;
|
||||
use crate::ast::statement::Statement;
|
||||
use crate::ast::string_literal::StringLiteral;
|
||||
use crate::lexer::Lexer;
|
||||
@ -123,12 +125,21 @@ impl<'a> Parser<'a> {
|
||||
}
|
||||
|
||||
pub fn compilation_unit(&mut self) -> CompilationUnit {
|
||||
let mut functions = vec![];
|
||||
let mut declarations = vec![];
|
||||
self.advance();
|
||||
while self.current.is_some() {
|
||||
functions.push(self.function());
|
||||
declarations.push(self.module_level_declaration());
|
||||
}
|
||||
CompilationUnit::new(declarations)
|
||||
}
|
||||
|
||||
fn module_level_declaration(&mut self) -> ModuleLevelDeclaration {
|
||||
let current = self.get_current();
|
||||
match current.kind() {
|
||||
TokenKind::Fn => ModuleLevelDeclaration::Function(self.function()),
|
||||
TokenKind::Extern => ModuleLevelDeclaration::ExternFunction(self.extern_function()),
|
||||
_ => panic!(),
|
||||
}
|
||||
CompilationUnit::new(functions)
|
||||
}
|
||||
|
||||
fn function(&mut self) -> Function {
|
||||
@ -149,6 +160,20 @@ impl<'a> Parser<'a> {
|
||||
)
|
||||
}
|
||||
|
||||
fn extern_function(&mut self) -> ExternFunction {
|
||||
self.expect_advance(TokenKind::Extern);
|
||||
self.expect_advance(TokenKind::Fn);
|
||||
let identifier_token = self.expect_advance(TokenKind::Identifier);
|
||||
self.expect_advance(TokenKind::LeftParentheses);
|
||||
// params
|
||||
self.expect_advance(TokenKind::RightParentheses);
|
||||
// return type
|
||||
ExternFunction::new(
|
||||
self.token_text(&identifier_token),
|
||||
SourceRange::new(identifier_token.start(), identifier_token.end()),
|
||||
)
|
||||
}
|
||||
|
||||
fn statement(&mut self) -> Statement {
|
||||
let current = self.get_current();
|
||||
match current.kind() {
|
||||
@ -241,9 +266,12 @@ mod smoke_tests {
|
||||
#[test]
|
||||
fn hello_world() {
|
||||
let compilation_unit = parse_compilation_unit("fn main() println(\"Hello, World!\") end");
|
||||
let functions = compilation_unit.functions();
|
||||
assert_eq!(functions.len(), 1);
|
||||
let function = functions[0];
|
||||
let declarations = compilation_unit.declarations();
|
||||
assert_eq!(declarations.len(), 1);
|
||||
let function = match &declarations[0] {
|
||||
ModuleLevelDeclaration::Function(function) => function,
|
||||
_ => panic!(),
|
||||
};
|
||||
assert_eq!(function.declared_name(), "main");
|
||||
let statements = function.statements();
|
||||
assert_eq!(statements.len(), 1);
|
||||
@ -278,3 +306,20 @@ mod smoke_tests {
|
||||
parse_compilation_unit("fn main() getCl()() end");
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod concrete_tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn parses_extern_fn() {
|
||||
let cu = parse_compilation_unit("extern fn println()");
|
||||
let declarations = cu.declarations();
|
||||
assert_eq!(declarations.len(), 1);
|
||||
let extern_function = match &declarations[0] {
|
||||
ModuleLevelDeclaration::ExternFunction(extern_function) => extern_function,
|
||||
_ => panic!(),
|
||||
};
|
||||
assert_eq!(extern_function.declared_name(), "println");
|
||||
}
|
||||
}
|
||||
|
||||
@ -5,13 +5,15 @@ use std::rc::Rc;
|
||||
pub struct FunctionSymbol {
|
||||
name: Rc<str>,
|
||||
parameters: Vec<Rc<ParameterSymbol>>,
|
||||
is_platform: bool,
|
||||
}
|
||||
|
||||
impl FunctionSymbol {
|
||||
pub fn new(name: &str, parameters: &[Rc<ParameterSymbol>]) -> Self {
|
||||
pub fn new(name: &str, parameters: &[Rc<ParameterSymbol>], is_platform: bool) -> Self {
|
||||
Self {
|
||||
name: name.into(),
|
||||
parameters: parameters.into(),
|
||||
is_platform,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -35,5 +35,5 @@ pub enum TokenKind {
|
||||
IntegerLiteral,
|
||||
LongLiteral,
|
||||
String,
|
||||
Extern
|
||||
Extern,
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user