Skip to content

Commit 4cb4b8b

Browse files
committed
feat: ready to implement auto forward declaration
1 parent ef29625 commit 4cb4b8b

File tree

17 files changed

+533
-115
lines changed

17 files changed

+533
-115
lines changed

Cargo.lock

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/cli/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ clap = { version = "4.5.41", features = ["derive"] }
1414
lexer = { path = "../lexer", version = "*" }
1515
utils = { path = "../utils", version = "*" }
1616
ast = { path = "../ast", version = "*" }
17+
typed_ast = { path = "../typed_ast", version = "*" }
1718
resolver = { path = "../resolver", version = "*" }
1819
colorized = "1.0.0"
1920
toml = "0.8.20"

crates/cli/src/commands.rs

Lines changed: 81 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,93 @@
1+
use crate::CompilerOptions;
12
use ast::token::TokenKind;
3+
use codegen::{context::context::CodeGenContext, options::OutputKind};
4+
use diagcentral::display_single_cusotm_diag;
25
use lexer::Lexer;
6+
use parser::Parser;
7+
use resolver::{Resolver, Visiting, generate_module_id, moduleloader::ModuleLoaderOptions};
8+
use std::{env, mem, process::exit, rc::Rc};
9+
use typed_ast::TypedProgramTree;
10+
11+
fn get_program_trees(options: &CompilerOptions, file_path: String) -> Vec<(String, Rc<TypedProgramTree>)> {
12+
let file_content = utils::fs::read_file(file_path.clone()).0;
13+
let mut lexer = Lexer::new(file_content, file_path.clone());
14+
let mut parser = Parser::new(lexer.tokenize(), file_path.clone());
15+
16+
let node = match parser.parse() {
17+
Ok(node) => node,
18+
Err(errors) => {
19+
parser.display_parser_errors(errors.clone());
20+
exit(1);
21+
}
22+
};
23+
24+
let module_loader_opts = ModuleLoaderOptions {
25+
stdlib_path: options.stdlib.clone(),
26+
source_dirs: options.source_dirs.clone(),
27+
};
28+
29+
let mut resolver = Resolver::new(module_loader_opts, file_path.clone());
30+
let module_id = generate_module_id();
31+
match resolver.resolve_module(module_id, node.as_program(), &mut Visiting::new(), true) {
32+
Some(..) => {}
33+
None => unreachable!(),
34+
};
35+
if resolver.reporter.has_errors() {
36+
resolver.reporter.display();
37+
exit(1);
38+
}
339

4-
use crate::CompilerOptions;
40+
let final_program_trees: Vec<(String, Rc<TypedProgramTree>)>;
41+
let mut program_trees = resolver.program_trees.lock().unwrap();
42+
final_program_trees = mem::take(&mut program_trees);
43+
drop(program_trees);
544

6-
pub(crate) fn command_run(compiler_options: CompilerOptions, file_path: Option<String>) {
7-
// let context = CodeGenContext::new(options, output_kind);
8-
todo!()
45+
final_program_trees
946
}
1047

11-
pub(crate) fn command_emit_llvm(
12-
compiler_options: CompilerOptions,
13-
file_path: Option<String>,
14-
output_path: Option<String>,
15-
) {
16-
// let context = CodeGenContext::new(options, output_kind);
17-
todo!()
48+
pub(crate) fn command_run(options: CompilerOptions, file_path: Option<String>) {
49+
let context = CodeGenContext::new(options.to_compiler_options(), OutputKind::None);
50+
51+
let mut temp = env::temp_dir();
52+
temp.push("path");
53+
let temp_file_path = temp.to_str().unwrap().to_string();
54+
55+
let program_trees = get_program_trees(&options, file_path.unwrap());
56+
context.compile_modules(program_trees);
57+
58+
context.emit_exec(temp_file_path.clone());
59+
if temp.exists() {
60+
std::fs::remove_file(temp_file_path).unwrap();
61+
}
1862
}
1963

20-
pub(crate) fn command_emit_asm(
21-
compiler_options: CompilerOptions,
22-
file_path: Option<String>,
23-
output_path: Option<String>,
24-
) {
64+
pub(crate) fn command_emit_llvm(options: CompilerOptions, file_path: Option<String>, output_path: Option<String>) {
65+
let output_path = output_path.unwrap_or_else(|| {
66+
display_single_cusotm_diag!("Output directory must be specified to generate llvm-ir.".to_string());
67+
});
68+
69+
let context = CodeGenContext::new(options.to_compiler_options(), OutputKind::LlvmIr(output_path));
70+
71+
let program_trees = get_program_trees(&options, file_path.unwrap());
72+
context.compile_modules(program_trees);
73+
}
74+
75+
pub(crate) fn command_emit_asm(options: CompilerOptions, file_path: Option<String>, output_path: Option<String>) {
2576
// let context = CodeGenContext::new(options, output_kind);
2677
todo!()
2778
}
2879

29-
pub(crate) fn command_build(compiler_options: CompilerOptions, file_path: Option<String>, output_path: Option<String>) {
80+
pub(crate) fn command_build(options: CompilerOptions, file_path: Option<String>, output_path: Option<String>) {
3081
// let context = CodeGenContext::new(options, output_kind);
3182
todo!()
3283
}
3384

34-
pub(crate) fn command_object(
35-
compiler_options: CompilerOptions,
36-
file_path: Option<String>,
37-
output_path: Option<String>,
38-
) {
85+
pub(crate) fn command_object(options: CompilerOptions, file_path: Option<String>, output_path: Option<String>) {
3986
// let context = CodeGenContext::new(options, output_kind);
4087
todo!()
4188
}
4289

43-
pub(crate) fn command_dylib(compiler_options: CompilerOptions, file_path: Option<String>, output_path: Option<String>) {
90+
pub(crate) fn command_dylib(options: CompilerOptions, file_path: Option<String>, output_path: Option<String>) {
4491
// let context = CodeGenContext::new(options, output_kind);
4592
todo!()
4693
}
@@ -62,17 +109,17 @@ pub(crate) fn command_lex_only(file_path: String) {
62109
}
63110

64111
pub(crate) fn command_parse_only(file_path: String) {
65-
// let (file_content, file_name) = read_file(file_path.clone());
66-
// let mut lexer = Lexer::new(file_content, file_name);
67-
68-
// match CyrusParser::new(&mut lexer).parse() {
69-
// Ok(result) => println!("{:#?}", result),
70-
// Err(errors) => {
71-
// for err in errors {
72-
// err.print();
73-
// }
74-
// }
75-
// }
112+
let (file_content, file_name) = utils::fs::read_file(file_path.clone());
113+
let mut lexer = Lexer::new(file_content, file_name.clone());
114+
let mut parser = Parser::new(lexer.tokenize(), file_name);
115+
116+
match parser.parse() {
117+
Ok(result) => println!("{:#?}", result),
118+
Err(errors) => {
119+
parser.display_parser_errors(errors.clone());
120+
exit(1);
121+
}
122+
}
76123
}
77124

78125
pub(crate) fn command_syntactic_only(file_path: String) {

crates/cli/src/main.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
use clap::{Parser, ValueEnum};
22
use codegen::options::{BuildDir, CodeGenOptions, CodeModelOptions, RelocModeOptions};
33
use commands::*;
4-
use compiler::project_file_required;
54
use diagcentral::display_single_cusotm_diag;
65
use serde::Deserialize;
6+
use trigger::project_file_required;
77

88
mod commands;
9-
mod compiler;
9+
mod trigger;
1010

1111
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum)]
1212
enum OptimizeLevel {
File renamed without changes.

crates/codegen/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ edition = "2024"
66
[dependencies]
77
utils = { path = "../utils", version = "*" }
88
typed_ast = { path = "../typed_ast", version = "*" }
9+
ast = { path = "../ast", version = "*" }
910
diagcentral = { path = "../diagcentral", version = "*" }
1011
inkwell = { version = "0.5.0", features = ["llvm18-0"] }
1112
serde = { version = "1.0.219", features = ["derive"] }

crates/codegen/src/builder/funcs.rs

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
use super::module::CodeGenBuilder;
2+
use ast::{AccessSpecifier, SelfModifierKind};
3+
use inkwell::{
4+
AddressSpace,
5+
attributes::{Attribute, AttributeLoc},
6+
llvm_sys::{
7+
core::LLVMFunctionType,
8+
prelude::{LLVMBool, LLVMTypeRef},
9+
},
10+
module::Linkage,
11+
types::{AsTypeRef, BasicMetadataTypeEnum, BasicTypeEnum, FunctionType, StructType},
12+
values::FunctionValue,
13+
};
14+
use typed_ast::{TypedFuncParamKind, TypedFuncParams, types::ConcreteType};
15+
16+
impl<'a> CodeGenBuilder<'a> {
17+
pub(crate) fn build_func_decl(
18+
&self,
19+
func_name: String,
20+
params: TypedFuncParams,
21+
return_type: ConcreteType,
22+
vis: AccessSpecifier,
23+
method_struct_type: Option<StructType<'a>>,
24+
) -> FunctionValue<'a> {
25+
let linkage = self.build_func_linkage(vis);
26+
let fn_type = self.build_func_type(params, return_type, method_struct_type);
27+
28+
let llvmmodule = self.llvmmodule.borrow();
29+
let fn_value = llvmmodule.add_function(&func_name, fn_type, Some(linkage));
30+
self.add_func_attrs(fn_value);
31+
drop(llvmmodule);
32+
fn_value
33+
}
34+
35+
pub(crate) fn add_func_attrs(&self, func: FunctionValue) {
36+
let attr_kind_id = |kind: &str| Attribute::get_named_enum_kind_id(kind);
37+
38+
func.add_attribute(
39+
AttributeLoc::Function,
40+
self.llvmctx.create_enum_attribute(attr_kind_id("uwtable"), 2),
41+
);
42+
func.add_attribute(
43+
AttributeLoc::Function,
44+
self.llvmctx.create_enum_attribute(attr_kind_id("ssp"), 0),
45+
);
46+
func.add_attribute(
47+
AttributeLoc::Function,
48+
self.llvmctx.create_enum_attribute(attr_kind_id("nounwind"), 0),
49+
);
50+
51+
func.add_attribute(
52+
AttributeLoc::Function,
53+
self.llvmctx.create_string_attribute("frame-pointer", "all"),
54+
);
55+
func.add_attribute(
56+
AttributeLoc::Function,
57+
self.llvmctx.create_string_attribute("no-trapping-math", "true"),
58+
);
59+
func.add_attribute(
60+
AttributeLoc::Function,
61+
self.llvmctx.create_string_attribute("stack-protector-buffer-size", "8"),
62+
);
63+
}
64+
65+
pub(crate) fn build_func_linkage(&self, vis: AccessSpecifier) -> Linkage {
66+
match vis {
67+
AccessSpecifier::Extern => Linkage::External,
68+
AccessSpecifier::Public => Linkage::External,
69+
AccessSpecifier::Internal => Linkage::Private,
70+
AccessSpecifier::Inline => Linkage::Internal,
71+
AccessSpecifier::PublicInline => Linkage::LinkOnceODR,
72+
AccessSpecifier::PublicExtern => Linkage::External,
73+
}
74+
}
75+
76+
pub(crate) fn build_func_type(
77+
&self,
78+
params: TypedFuncParams,
79+
return_type: ConcreteType,
80+
method_struct_type: Option<StructType<'a>>,
81+
) -> FunctionType<'a> {
82+
let param_types: Vec<BasicMetadataTypeEnum<'a>> = params
83+
.list
84+
.iter()
85+
.map(|param| {
86+
let basic_type_enum: BasicTypeEnum<'a> = match param {
87+
TypedFuncParamKind::FuncParam(typed_func_param) => {
88+
self.build_conrete_type(typed_func_param.ty.clone()).try_into().unwrap()
89+
}
90+
TypedFuncParamKind::SelfModifier(self_modifier) => match self_modifier.kind {
91+
SelfModifierKind::Copied => BasicTypeEnum::StructType(method_struct_type.unwrap()),
92+
SelfModifierKind::Referenced => {
93+
BasicTypeEnum::PointerType(self.llvmctx.ptr_type(AddressSpace::default()))
94+
}
95+
},
96+
};
97+
BasicMetadataTypeEnum::from(basic_type_enum.clone())
98+
})
99+
.collect();
100+
101+
let return_type = self.build_conrete_type(return_type);
102+
103+
let is_var_args = params.variadic.is_some();
104+
let fn_type = unsafe {
105+
let mut param_types = param_types
106+
.iter()
107+
.map(|ty| ty.as_type_ref())
108+
.collect::<Vec<LLVMTypeRef>>();
109+
110+
LLVMFunctionType(
111+
return_type.as_type_ref(),
112+
param_types.as_mut_ptr(),
113+
param_types.len() as u32,
114+
is_var_args as LLVMBool,
115+
)
116+
};
117+
unsafe { FunctionType::new(fn_type) }
118+
}
119+
}

crates/codegen/src/builder/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,4 @@
1+
mod funcs;
12
pub mod module;
3+
mod stmts;
4+
mod types;

0 commit comments

Comments
 (0)