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::asm::asm_function::AsmFunction;
|
||||||
use crate::ast::assemble_context::AssembleContext;
|
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::constants_table::ConstantsTable;
|
||||||
use crate::diagnostic::Diagnostic;
|
use crate::diagnostic::Diagnostic;
|
||||||
use crate::ir::Ir;
|
|
||||||
use crate::symbol_table::SymbolTable;
|
use crate::symbol_table::SymbolTable;
|
||||||
|
|
||||||
pub struct CompilationUnit {
|
pub struct CompilationUnit {
|
||||||
functions: Vec<Function>,
|
declarations: Vec<ModuleLevelDeclaration>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CompilationUnit {
|
impl CompilationUnit {
|
||||||
pub fn new(functions: Vec<Function>) -> Self {
|
pub fn new(declarations: Vec<ModuleLevelDeclaration>) -> Self {
|
||||||
Self { functions }
|
Self { declarations }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn functions(&self) -> Vec<&Function> {
|
pub fn declarations(&self) -> &[ModuleLevelDeclaration] {
|
||||||
self.functions.iter().collect()
|
&self.declarations
|
||||||
}
|
}
|
||||||
|
|
||||||
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![];
|
||||||
symbol_table.push_scope("compilation_unit_scope");
|
symbol_table.push_scope("compilation_unit_scope");
|
||||||
for function in &mut self.functions {
|
for declaration in &mut self.declarations {
|
||||||
diagnostics.append(&mut function.gather_declared_names(symbol_table));
|
diagnostics.append(&mut declaration.gather_declared_names(symbol_table));
|
||||||
}
|
}
|
||||||
symbol_table.pop_scope();
|
symbol_table.pop_scope();
|
||||||
diagnostics
|
diagnostics
|
||||||
@ -31,36 +30,28 @@ impl CompilationUnit {
|
|||||||
|
|
||||||
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![];
|
||||||
for function in &mut self.functions {
|
for declaration in &mut self.declarations {
|
||||||
diagnostics.append(&mut function.check_name_usages(symbol_table));
|
diagnostics.append(&mut declaration.check_name_usages(symbol_table));
|
||||||
}
|
}
|
||||||
diagnostics
|
diagnostics
|
||||||
}
|
}
|
||||||
|
|
||||||
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![];
|
||||||
for function in &mut self.functions {
|
for declaration in &mut self.declarations {
|
||||||
diagnostics.append(&mut function.type_check(symbol_table));
|
diagnostics.append(&mut declaration.type_check(symbol_table));
|
||||||
}
|
}
|
||||||
diagnostics
|
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(
|
pub fn assemble(
|
||||||
&self,
|
&self,
|
||||||
symbol_table: &SymbolTable,
|
symbol_table: &SymbolTable,
|
||||||
constants_table: &mut ConstantsTable,
|
constants_table: &mut ConstantsTable,
|
||||||
) -> Vec<AsmFunction> {
|
) -> Vec<AsmFunction> {
|
||||||
let mut context = AssembleContext::new();
|
let mut context = AssembleContext::new();
|
||||||
for function in &self.functions {
|
for declaration in &self.declarations {
|
||||||
function.assemble(&mut context, symbol_table, constants_table);
|
declaration.assemble(&mut context, symbol_table, constants_table);
|
||||||
}
|
}
|
||||||
context.take_functions()
|
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(
|
let insert_result = symbol_table.insert_function_symbol(FunctionSymbol::new(
|
||||||
self.declared_name(),
|
self.declared_name(),
|
||||||
&vec![], // todo
|
&vec![], // todo
|
||||||
|
false,
|
||||||
));
|
));
|
||||||
if let Err(symbol_insert_error) = insert_result {
|
if let Err(symbol_insert_error) = insert_result {
|
||||||
match symbol_insert_error {
|
match symbol_insert_error {
|
||||||
|
|||||||
@ -3,19 +3,18 @@ pub mod call;
|
|||||||
pub mod compilation_unit;
|
pub mod compilation_unit;
|
||||||
pub mod expression;
|
pub mod expression;
|
||||||
pub mod expression_statement;
|
pub mod expression_statement;
|
||||||
|
pub mod extern_function;
|
||||||
pub mod fqn;
|
pub mod fqn;
|
||||||
pub mod function;
|
pub mod function;
|
||||||
pub mod identifier;
|
pub mod identifier;
|
||||||
pub mod integer_literal;
|
pub mod integer_literal;
|
||||||
pub mod let_statement;
|
pub mod let_statement;
|
||||||
|
pub mod module_level_declaration;
|
||||||
pub mod statement;
|
pub mod statement;
|
||||||
pub mod string_literal;
|
pub mod string_literal;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod name_tests {
|
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::parser::parse_compilation_unit;
|
||||||
use crate::symbol_table::SymbolTable;
|
use crate::symbol_table::SymbolTable;
|
||||||
|
|
||||||
@ -31,11 +30,6 @@ mod name_tests {
|
|||||||
0
|
0
|
||||||
);
|
);
|
||||||
assert_eq!(compilation_unit.check_name_usages(&symbol_table).len(), 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]
|
#[test]
|
||||||
@ -45,20 +39,6 @@ mod name_tests {
|
|||||||
parse_compilation_unit("fn println() end fn main() println(\"Hello, World!\") end");
|
parse_compilation_unit("fn println() end fn main() println(\"Hello, World!\") end");
|
||||||
compilation_unit.gather_declared_names(&mut symbol_table);
|
compilation_unit.gather_declared_names(&mut symbol_table);
|
||||||
compilation_unit.check_name_usages(&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]
|
#[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::compilation_unit::CompilationUnit;
|
||||||
use crate::ast::expression::Expression;
|
use crate::ast::expression::Expression;
|
||||||
use crate::ast::expression_statement::ExpressionStatement;
|
use crate::ast::expression_statement::ExpressionStatement;
|
||||||
|
use crate::ast::extern_function::ExternFunction;
|
||||||
use crate::ast::function::Function;
|
use crate::ast::function::Function;
|
||||||
use crate::ast::identifier::Identifier;
|
use crate::ast::identifier::Identifier;
|
||||||
use crate::ast::integer_literal::IntegerLiteral;
|
use crate::ast::integer_literal::IntegerLiteral;
|
||||||
use crate::ast::let_statement::LetStatement;
|
use crate::ast::let_statement::LetStatement;
|
||||||
|
use crate::ast::module_level_declaration::ModuleLevelDeclaration;
|
||||||
use crate::ast::statement::Statement;
|
use crate::ast::statement::Statement;
|
||||||
use crate::ast::string_literal::StringLiteral;
|
use crate::ast::string_literal::StringLiteral;
|
||||||
use crate::lexer::Lexer;
|
use crate::lexer::Lexer;
|
||||||
@ -123,12 +125,21 @@ impl<'a> Parser<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn compilation_unit(&mut self) -> CompilationUnit {
|
pub fn compilation_unit(&mut self) -> CompilationUnit {
|
||||||
let mut functions = vec![];
|
let mut declarations = vec![];
|
||||||
self.advance();
|
self.advance();
|
||||||
while self.current.is_some() {
|
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 {
|
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 {
|
fn statement(&mut self) -> Statement {
|
||||||
let current = self.get_current();
|
let current = self.get_current();
|
||||||
match current.kind() {
|
match current.kind() {
|
||||||
@ -241,9 +266,12 @@ mod smoke_tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn hello_world() {
|
fn hello_world() {
|
||||||
let compilation_unit = parse_compilation_unit("fn main() println(\"Hello, World!\") end");
|
let compilation_unit = parse_compilation_unit("fn main() println(\"Hello, World!\") end");
|
||||||
let functions = compilation_unit.functions();
|
let declarations = compilation_unit.declarations();
|
||||||
assert_eq!(functions.len(), 1);
|
assert_eq!(declarations.len(), 1);
|
||||||
let function = functions[0];
|
let function = match &declarations[0] {
|
||||||
|
ModuleLevelDeclaration::Function(function) => function,
|
||||||
|
_ => panic!(),
|
||||||
|
};
|
||||||
assert_eq!(function.declared_name(), "main");
|
assert_eq!(function.declared_name(), "main");
|
||||||
let statements = function.statements();
|
let statements = function.statements();
|
||||||
assert_eq!(statements.len(), 1);
|
assert_eq!(statements.len(), 1);
|
||||||
@ -278,3 +306,20 @@ mod smoke_tests {
|
|||||||
parse_compilation_unit("fn main() getCl()() end");
|
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 {
|
pub struct FunctionSymbol {
|
||||||
name: Rc<str>,
|
name: Rc<str>,
|
||||||
parameters: Vec<Rc<ParameterSymbol>>,
|
parameters: Vec<Rc<ParameterSymbol>>,
|
||||||
|
is_platform: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FunctionSymbol {
|
impl FunctionSymbol {
|
||||||
pub fn new(name: &str, parameters: &[Rc<ParameterSymbol>]) -> Self {
|
pub fn new(name: &str, parameters: &[Rc<ParameterSymbol>], is_platform: bool) -> Self {
|
||||||
Self {
|
Self {
|
||||||
name: name.into(),
|
name: name.into(),
|
||||||
parameters: parameters.into(),
|
parameters: parameters.into(),
|
||||||
|
is_platform,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -35,5 +35,5 @@ pub enum TokenKind {
|
|||||||
IntegerLiteral,
|
IntegerLiteral,
|
||||||
LongLiteral,
|
LongLiteral,
|
||||||
String,
|
String,
|
||||||
Extern
|
Extern,
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user