Compare commits

...

4 commits

Author SHA1 Message Date
Edgar 7c3bc054e5
allow top level module 2024-03-13 11:12:36 +01:00
Edgar 0ea6ac3085
beter2 2024-03-13 10:31:27 +01:00
Edgar 2debb696ba
fix scope 2024-03-12 17:47:59 +01:00
Edgar 79d0e2ca7e
fix multi file function resolution 2024-03-12 17:46:11 +01:00
9 changed files with 120 additions and 112 deletions

View file

@ -5,18 +5,16 @@ An experimental statically-typed compiled programming language made with LLVM an
Syntax is subject to change any time right now. It has a rusty style for now.
```rust
mod Main {
pub fn main() -> i32 {
let b: i32 = factorial(4);
return b;
}
pub fn main() -> i32 {
let b: i32 = factorial(4);
return b;
}
pub fn factorial(n: i32) -> i32 {
if n == 1 {
return n;
} else {
return n * factorial(n - 1);
}
pub fn factorial(n: i32) -> i32 {
if n == 1 {
return n;
} else {
return n * factorial(n - 1);
}
}
```

View file

@ -34,6 +34,7 @@ enum Commands {
#[arg(long, group = "binary", default_value_t = true)]
bin: bool,
/// Use a library template
#[arg(long, group = "binary")]
lib: bool,
},
@ -105,7 +106,7 @@ fn main() -> Result<()> {
std::fs::write(config_path, toml::to_string_pretty(&config)?)
.context("failed to write Ed.toml")?;
std::fs::write(path.join(".gitignore"), "/target-ed\n")
std::fs::write(path.join(".gitignore"), "/build\n")
.context("failed to write .gitignore")?;
std::fs::write(path.join(".gitattributes"), "*.ed linguist-language=Rust\n")
.context("failed to write .gitattributes")?;
@ -113,30 +114,18 @@ fn main() -> Result<()> {
if bin {
std::fs::write(
path.join("src").join("main.ed"),
format!(
r#"
mod {} {{
pub fn main() -> i32 {{
return 0;
}}
}}"#,
name
),
r#"pub fn main() -> i32 {{
return 0;
}"#,
)?;
}
if lib {
std::fs::write(
path.join("src").join("lib.ed"),
format!(
r#"
mod {} {{
pub fn hello_world() -> i32 {{
return 0;
}}
}}"#,
name
),
r#"pub fn main() -> i32 {{
return 0;
}"#,
)?;
}
@ -206,7 +195,7 @@ mod {} {{
);
let src_dir = base_dir.join("src");
let target_dir = base_dir.join("target-ed");
let target_dir = base_dir.join("build");
if !target_dir.exists() {
std::fs::create_dir_all(&target_dir)?;

View file

@ -1,4 +1,8 @@
use std::{collections::HashMap, error::Error, path::PathBuf};
use std::{
collections::{HashMap, VecDeque},
error::Error,
path::PathBuf,
};
use edlang_ir as ir;
use edlang_ir::DefId;
@ -70,7 +74,7 @@ pub fn compile(session: &Session, program: &ProgramBody) -> Result<PathBuf, Box<
program,
};
let mut llvm_modules = Vec::new();
let mut llvm_modules = VecDeque::new();
Target::initialize_native(&InitializationConfig::default())?;
let triple = TargetMachine::get_default_triple();
@ -96,7 +100,7 @@ pub fn compile(session: &Session, program: &ProgramBody) -> Result<PathBuf, Box<
inkwell::targets::CodeModel::Default,
)
.unwrap();
machine.set_asm_verbosity(true);
// machine.set_asm_verbosity(true);
info!("compiling for: {:?}", target.get_description());
@ -141,7 +145,7 @@ pub fn compile(session: &Session, program: &ProgramBody) -> Result<PathBuf, Box<
);
let di_namespace = di_builder
.create_namespace(di_unit.as_debug_info_scope(), &module.name, true)
.create_namespace(di_unit.get_file().as_debug_info_scope(), &module.name, true)
.as_debug_info_scope();
let mut module_ctx = ModuleCompileCtx {
@ -160,41 +164,45 @@ pub fn compile(session: &Session, program: &ProgramBody) -> Result<PathBuf, Box<
module_ctx.di_builder.finalize();
module_ctx.module.verify()?;
let opt = match session.optlevel {
edlang_session::OptLevel::None => "0",
edlang_session::OptLevel::Less => "1",
edlang_session::OptLevel::Default => "2",
edlang_session::OptLevel::Aggressive => "3",
};
let passopt = PassBuilderOptions::create();
module_ctx
.module
.run_passes(&format!("default<O{}>", opt), &machine, passopt)?;
if session.output_llvm {
module_ctx
.module
.print_to_file(session.output_file.with_extension("ll"))?;
}
if session.output_asm {
machine.write_to_file(
&module_ctx.module,
inkwell::targets::FileType::Assembly,
&session.output_file.with_extension("asm"),
)?;
}
machine.write_to_file(
&module_ctx.module,
inkwell::targets::FileType::Object,
&session.output_file.with_extension("o"),
)?;
// todo link modules together
llvm_modules.push(module_ctx.module);
llvm_modules.push_back(module_ctx.module);
}
let module = llvm_modules.pop_front().unwrap();
for x in llvm_modules.into_iter() {
module.link_in_module(x)?;
}
let opt = match session.optlevel {
edlang_session::OptLevel::None => "0",
edlang_session::OptLevel::Less => "1",
edlang_session::OptLevel::Default => "2",
edlang_session::OptLevel::Aggressive => "3",
};
let passopt = PassBuilderOptions::create();
module.run_passes(&format!("default<O{}>", opt), &machine, passopt)?;
if session.output_llvm {
module.print_to_file(session.output_file.with_extension("ll"))?;
}
if session.output_asm {
machine.write_to_file(
&module,
inkwell::targets::FileType::Assembly,
&session.output_file.with_extension("asm"),
)?;
}
machine.write_to_file(
&module,
inkwell::targets::FileType::Object,
&session.output_file.with_extension("o"),
)?;
Ok(session.output_file.with_extension("o"))
}
@ -202,7 +210,7 @@ fn compile_module(ctx: &mut ModuleCompileCtx, module_id: DefId) {
let module = ctx.ctx.program.modules.get(&module_id).unwrap();
trace!("compiling module: {:?}", module_id);
for id in module.functions.iter() {
compile_fn_signature(ctx, *id);
compile_fn_signature(ctx, *id, true);
}
for id in module.functions.iter() {
@ -210,7 +218,7 @@ fn compile_module(ctx: &mut ModuleCompileCtx, module_id: DefId) {
}
}
fn compile_fn_signature(ctx: &ModuleCompileCtx<'_, '_>, fn_id: DefId) {
fn compile_fn_signature(ctx: &ModuleCompileCtx<'_, '_>, fn_id: DefId, is_definition: bool) {
let (arg_types, ret_type) = ctx.ctx.program.function_signatures.get(&fn_id).unwrap();
let body = ctx.ctx.program.functions.get(&fn_id).unwrap();
trace!("compiling fn sig: {}", body.name);
@ -271,8 +279,8 @@ fn compile_fn_signature(ctx: &ModuleCompileCtx<'_, '_>, fn_id: DefId) {
ctx.di_unit.get_file(),
line as u32 + 1,
di_type,
body.is_pub,
!body.is_extern,
!body.is_pub,
is_definition,
line as u32 + 1,
0,
false,
@ -544,10 +552,16 @@ fn compile_fn(ctx: &ModuleCompileCtx, fn_id: DefId) -> Result<(), BuilderError>
target,
} => {
let target_fn_body = ctx.ctx.program.functions.get(func).unwrap();
let fn_value = ctx
.module
.get_function(&target_fn_body.get_mangled_name())
.unwrap();
// compile_fn_signature(ctx, *id, true);
let fn_value = match ctx.module.get_function(&target_fn_body.get_mangled_name()) {
Some(x) => x,
None => {
compile_fn_signature(ctx, target_fn_body.def_id, false);
ctx.module
.get_function(&target_fn_body.get_mangled_name())
.unwrap()
}
};
let args: Vec<_> = args
.iter()
.map(|x| compile_rvalue(ctx, fn_id, &locals, x).unwrap().0.into())

View file

@ -79,7 +79,7 @@ pub fn main() -> Result<()> {
pub fn compile(args: &CompilerArgs) -> Result<PathBuf> {
let mut files = Vec::new();
for entry in WalkDir::new(&args.input) {
for entry in WalkDir::new(&args.input).sort_by_file_name() {
let entry = entry?;
if let Some(ext) = entry.path().extension() {
if ext.eq_ignore_ascii_case("ed") {
@ -99,10 +99,13 @@ pub fn compile(args: &CompilerArgs) -> Result<PathBuf> {
for path in files {
let source = std::fs::read_to_string(&path)?;
let modules_ast = edlang_parser::parse_ast(&source);
let module_ast = edlang_parser::parse_ast(
&source,
&path.file_stem().expect("no file stem").to_string_lossy(),
);
let modules_temp = match modules_ast {
Ok(modules) => modules,
let module_temp = match module_ast {
Ok(module) => module,
Err(error) => {
let path = path.display().to_string();
let report = edlang_parser::error_to_report(&path, &error)?;
@ -110,7 +113,7 @@ pub fn compile(args: &CompilerArgs) -> Result<PathBuf> {
std::process::exit(1)
}
};
modules.push((path, source, modules_temp));
modules.push((path, source, module_temp));
}
let session = Session {

View file

@ -34,7 +34,7 @@ pub fn compile_program(
name: &str,
library: bool,
) -> Result<CompileResult, Box<dyn std::error::Error>> {
let modules = edlang_parser::parse_ast(source).unwrap();
let module = edlang_parser::parse_ast(source, name).unwrap();
let test_dir = tempfile::tempdir().unwrap();
let test_dir_path = test_dir.path().canonicalize()?;
@ -61,7 +61,7 @@ pub fn compile_program(
output_asm: false,
};
let program_ir = lower_modules(&[modules]).unwrap();
let program_ir = lower_modules(&[module]).unwrap();
let object_path = edlang_codegen_llvm::compile(&session, &program_ir).unwrap();

View file

@ -33,6 +33,7 @@ pub struct ProgramBody {
pub structs: BTreeMap<DefId, AdtBody>,
/// The function signatures.
pub function_signatures: BTreeMap<DefId, (Vec<TypeInfo>, TypeInfo)>,
pub file_names: BTreeMap<usize, String>,
}
#[derive(Debug, Clone)]

View file

@ -15,33 +15,27 @@ mod common;
pub mod errors;
mod prepass;
pub fn lower_modules(modules: &[Vec<ast::Module>]) -> Result<ProgramBody, LoweringError> {
pub fn lower_modules(modules: &[ast::Module]) -> Result<ProgramBody, LoweringError> {
let mut ctx = BuildCtx::default();
// resolve symbols
for (file_id, modules) in modules.iter().enumerate() {
for module in modules {
ctx = prepass::prepass_module(ctx, module, file_id)?;
}
for (file_id, module) in modules.iter().enumerate() {
ctx = prepass::prepass_module(ctx, module, file_id)?;
}
// resolve imports
for (file_id, modules) in modules.iter().enumerate() {
for module in modules {
ctx = prepass::prepass_imports(ctx, module, file_id)?;
}
for (file_id, module) in modules.iter().enumerate() {
ctx = prepass::prepass_imports(ctx, module, file_id)?;
}
for modules in modules {
for mod_def in modules {
let id = *ctx
.body
.top_level_module_names
.get(&mod_def.name.name)
.expect("module should exist");
for mod_def in modules {
let id = *ctx
.body
.top_level_module_names
.get(&mod_def.name.name)
.expect("module should exist");
ctx = lower_module(ctx, mod_def, id)?;
}
ctx = lower_module(ctx, mod_def, id)?;
}
Ok(ctx.body)

View file

@ -3,7 +3,7 @@ use crate::lexer::LexicalError;
use edlang_ast as ast;
use std::str::FromStr;
grammar;
grammar<'module_name>(module_name: &'module_name str);
extern {
type Location = usize;
@ -478,8 +478,16 @@ pub(crate) Import: ast::Import = {
}
}
pub Modules: Vec<ast::Module> = {
<Module+> => <>
pub TopLevelModule: ast::Module = {
<lo:@L> <imports:List<Import>?> <contents:List<ModuleStatement>> <hi:@R> => ast::Module {
name: ast::Ident {
name: module_name.to_string(),
span: ast::Span::new(0, 0),
},
imports: imports.unwrap_or(vec![]),
contents,
span: ast::Span::new(lo, hi),
}
}
pub Module: ast::Module = {

View file

@ -22,10 +22,11 @@ pub mod grammar {
pub fn parse_ast(
source: &str,
) -> Result<Vec<edlang_ast::Module>, ParseError<usize, Token, LexicalError>> {
module_name: &str,
) -> Result<edlang_ast::Module, ParseError<usize, Token, LexicalError>> {
let lexer = Lexer::new(source);
let parser = grammar::ModulesParser::new();
parser.parse(lexer)
let parser = grammar::TopLevelModuleParser::new();
parser.parse(module_name, lexer)
}
pub fn print_report<'a>(
@ -46,7 +47,7 @@ pub fn error_to_report<'a>(
ParseError::InvalidToken { location } => {
let loc = *location;
Report::build(ReportKind::Error, path, loc)
.with_code("P1")
.with_code("InvalidToken")
.with_label(
Label::new((path, loc..(loc + 1)))
.with_color(colors.next())
@ -57,7 +58,7 @@ pub fn error_to_report<'a>(
ParseError::UnrecognizedEof { location, expected } => {
let loc = *location;
Report::build(ReportKind::Error, path, loc)
.with_code("P2")
.with_code("UnrecognizedEof")
.with_label(
Label::new((path, loc..(loc + 1)))
.with_message(format!(
@ -70,7 +71,7 @@ pub fn error_to_report<'a>(
}
ParseError::UnrecognizedToken { token, expected } => {
Report::build(ReportKind::Error, path, token.0)
.with_code(3)
.with_code("UnrecognizedToken")
.with_label(
Label::new((path, token.0..token.2))
.with_message(format!(
@ -83,7 +84,7 @@ pub fn error_to_report<'a>(
.finish()
}
ParseError::ExtraToken { token } => Report::build(ReportKind::Error, path, token.0)
.with_code("P3")
.with_code("ExtraToken")
.with_message("Extra token")
.with_label(
Label::new((path, token.0..token.2))
@ -94,7 +95,7 @@ pub fn error_to_report<'a>(
LexicalError::InvalidToken(err, range) => match err {
tokens::LexingError::NumberParseError => {
Report::build(ReportKind::Error, path, range.start)
.with_code(4)
.with_code("InvalidToken")
.with_message("Error parsing literal number")
.with_label(
Label::new((path, range.start..range.end))
@ -104,7 +105,7 @@ pub fn error_to_report<'a>(
.finish()
}
tokens::LexingError::Other => Report::build(ReportKind::Error, path, range.start)
.with_code(4)
.with_code("Other")
.with_message("Other error")
.with_label(
Label::new((path, range.start..range.end))