mirror of
https://github.com/edg-l/edlang.git
synced 2024-11-22 07:58:24 +00:00
feat: Module file declarations, fixes
This commit is contained in:
parent
7c3bc054e5
commit
f150dd6c61
|
@ -114,7 +114,7 @@ fn main() -> Result<()> {
|
|||
if bin {
|
||||
std::fs::write(
|
||||
path.join("src").join("main.ed"),
|
||||
r#"pub fn main() -> i32 {{
|
||||
r#"pub fn main() -> i32 {
|
||||
return 0;
|
||||
}"#,
|
||||
)?;
|
||||
|
@ -123,7 +123,7 @@ fn main() -> Result<()> {
|
|||
if lib {
|
||||
std::fs::write(
|
||||
path.join("src").join("lib.ed"),
|
||||
r#"pub fn main() -> i32 {{
|
||||
r#"pub fn main() -> i32 {
|
||||
return 0;
|
||||
}"#,
|
||||
)?;
|
||||
|
@ -201,7 +201,6 @@ fn main() -> Result<()> {
|
|||
std::fs::create_dir_all(&target_dir)?;
|
||||
}
|
||||
|
||||
let has_main = src_dir.join("main.ed").exists();
|
||||
let output = target_dir.join(config.package.name);
|
||||
|
||||
let (profile, profile_name) = if let Some(profile) = profile {
|
||||
|
@ -230,27 +229,44 @@ fn main() -> Result<()> {
|
|||
)
|
||||
};
|
||||
|
||||
let lib_ed = src_dir.join("lib.ed");
|
||||
let main_ed = src_dir.join("main.ed");
|
||||
|
||||
let start = Instant::now();
|
||||
|
||||
for file in [main_ed, lib_ed] {
|
||||
if file.exists() {
|
||||
let is_lib = file.file_stem().unwrap() == "lib";
|
||||
|
||||
let compile_args = CompilerArgs {
|
||||
input: src_dir,
|
||||
output: output.clone(),
|
||||
input: file,
|
||||
output: if is_lib {
|
||||
let name = output.file_stem().unwrap().to_string_lossy().to_string();
|
||||
let name = format!("lib{name}");
|
||||
output
|
||||
.with_file_name(name)
|
||||
.with_extension(get_platform_library_ext())
|
||||
} else {
|
||||
output.clone()
|
||||
},
|
||||
release,
|
||||
optlevel: Some(profile.opt_level),
|
||||
debug_info: Some(profile.debug_info),
|
||||
library: !has_main,
|
||||
library: is_lib,
|
||||
ast: false,
|
||||
ir: false,
|
||||
llvm: true,
|
||||
asm: false,
|
||||
object: true,
|
||||
};
|
||||
|
||||
let start = Instant::now();
|
||||
let object = compile(&compile_args)?;
|
||||
|
||||
if !has_main {
|
||||
link_shared_lib(&[object], &output)?;
|
||||
if compile_args.library {
|
||||
link_shared_lib(&[object], &compile_args.output)?;
|
||||
} else {
|
||||
link_binary(&[object], &output)?;
|
||||
link_binary(&[object], &compile_args.output)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let elapsed = start.elapsed();
|
||||
|
@ -280,3 +296,13 @@ fn main() -> Result<()> {
|
|||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn get_platform_library_ext() -> &'static str {
|
||||
if cfg!(target_os = "macos") {
|
||||
"dylib"
|
||||
} else if cfg!(target_os = "windows") {
|
||||
"dll"
|
||||
} else {
|
||||
"so"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ pub use edlang_span::Span;
|
|||
pub struct Module {
|
||||
pub name: Ident,
|
||||
pub imports: Vec<Import>,
|
||||
pub external_modules: Vec<Ident>,
|
||||
pub contents: Vec<ModuleStatement>,
|
||||
pub span: Span,
|
||||
}
|
||||
|
@ -138,6 +139,7 @@ pub struct Function {
|
|||
pub name: Ident,
|
||||
pub is_extern: bool,
|
||||
pub is_public: bool,
|
||||
pub is_exported: bool,
|
||||
pub params: Vec<FnParam>,
|
||||
pub return_type: Option<Type>,
|
||||
pub body: Option<Block>,
|
||||
|
|
|
@ -247,7 +247,7 @@ fn compile_fn_signature(ctx: &ModuleCompileCtx<'_, '_>, fn_id: DefId, is_definit
|
|||
let fn_value = ctx.module.add_function(
|
||||
&body.get_mangled_name(),
|
||||
fn_type,
|
||||
Some(if body.is_pub || body.is_extern {
|
||||
Some(if body.is_extern || body.is_exported {
|
||||
inkwell::module::Linkage::External
|
||||
} else {
|
||||
inkwell::module::Linkage::Private
|
||||
|
@ -272,6 +272,8 @@ fn compile_fn_signature(ctx: &ModuleCompileCtx<'_, '_>, fn_id: DefId, is_definit
|
|||
DIFlagsConstants::PRIVATE
|
||||
},
|
||||
);
|
||||
|
||||
if fn_value.get_subprogram().is_none() {
|
||||
let subprogram = ctx.di_builder.create_function(
|
||||
ctx.di_namespace,
|
||||
&body.name,
|
||||
|
@ -279,13 +281,14 @@ fn compile_fn_signature(ctx: &ModuleCompileCtx<'_, '_>, fn_id: DefId, is_definit
|
|||
ctx.di_unit.get_file(),
|
||||
line as u32 + 1,
|
||||
di_type,
|
||||
!body.is_pub,
|
||||
is_definition,
|
||||
body.is_exported || body.is_extern,
|
||||
is_definition && !body.is_extern,
|
||||
line as u32 + 1,
|
||||
0,
|
||||
false,
|
||||
);
|
||||
fn_value.set_subprogram(subprogram);
|
||||
}
|
||||
}
|
||||
|
||||
fn compile_fn(ctx: &ModuleCompileCtx, fn_id: DefId) -> Result<(), BuilderError> {
|
||||
|
|
|
@ -3,9 +3,9 @@ use std::{path::PathBuf, time::Instant};
|
|||
use anyhow::Result;
|
||||
use ariadne::{sources, Source};
|
||||
use clap::Parser;
|
||||
use edlang_ast::Module;
|
||||
use edlang_lowering::lower_modules;
|
||||
use edlang_session::{DebugInfo, OptLevel, Session};
|
||||
use walkdir::WalkDir;
|
||||
|
||||
use crate::linker::{link_binary, link_shared_lib};
|
||||
|
||||
|
@ -77,26 +77,11 @@ pub fn main() -> Result<()> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn compile(args: &CompilerArgs) -> Result<PathBuf> {
|
||||
let mut files = Vec::new();
|
||||
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") {
|
||||
files.push(entry.path().to_path_buf());
|
||||
}
|
||||
}
|
||||
pub fn parse_file(modules: &mut Vec<(PathBuf, String, Module)>, mut path: PathBuf) -> Result<()> {
|
||||
if path.is_dir() {
|
||||
path = path.join("mod.ed");
|
||||
}
|
||||
|
||||
if files.is_empty() {
|
||||
panic!("files is empty");
|
||||
}
|
||||
|
||||
let start_time = Instant::now();
|
||||
|
||||
let mut modules = Vec::new();
|
||||
|
||||
for path in files {
|
||||
let source = std::fs::read_to_string(&path)?;
|
||||
|
||||
let module_ast = edlang_parser::parse_ast(
|
||||
|
@ -113,9 +98,28 @@ pub fn compile(args: &CompilerArgs) -> Result<PathBuf> {
|
|||
std::process::exit(1)
|
||||
}
|
||||
};
|
||||
modules.push((path, source, module_temp));
|
||||
|
||||
for ident in &module_temp.external_modules {
|
||||
let module_path = path
|
||||
.parent()
|
||||
.unwrap()
|
||||
.join(&ident.name)
|
||||
.with_extension("ed");
|
||||
// todo: fancy error if doesnt exist?
|
||||
parse_file(modules, module_path)?;
|
||||
}
|
||||
|
||||
modules.push((path, source, module_temp));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn compile(args: &CompilerArgs) -> Result<PathBuf> {
|
||||
let start_time = Instant::now();
|
||||
|
||||
let mut modules = Vec::new();
|
||||
parse_file(&mut modules, args.input.clone())?;
|
||||
|
||||
let session = Session {
|
||||
file_paths: modules.iter().map(|x| x.0.clone()).collect(),
|
||||
debug_info: if let Some(debug_info) = args.debug_info {
|
||||
|
@ -181,7 +185,8 @@ pub fn compile(args: &CompilerArgs) -> Result<PathBuf> {
|
|||
)?;
|
||||
}
|
||||
|
||||
let object_path = edlang_codegen_llvm::compile(&session, &program_ir).unwrap();
|
||||
let object_path =
|
||||
edlang_codegen_llvm::compile(&session, &program_ir).expect("failed to compile");
|
||||
|
||||
let elapsed = start_time.elapsed();
|
||||
tracing::debug!("Done in {:?}", elapsed);
|
||||
|
|
|
@ -70,6 +70,8 @@ pub struct Body {
|
|||
pub def_id: DefId,
|
||||
pub is_pub: bool,
|
||||
pub is_extern: bool,
|
||||
// exported means externally available in a shared library or as main
|
||||
pub is_exported: bool,
|
||||
pub name: String,
|
||||
pub locals: SmallVec<[Local; 4]>,
|
||||
pub blocks: SmallVec<[BasicBlock; 8]>,
|
||||
|
@ -94,19 +96,15 @@ impl Body {
|
|||
}
|
||||
|
||||
pub fn get_mangled_name(&self) -> String {
|
||||
if self.is_extern {
|
||||
if self.is_extern || self.is_exported {
|
||||
return self.name.clone();
|
||||
}
|
||||
|
||||
if self.name == "main" {
|
||||
"main".to_string()
|
||||
} else {
|
||||
format!(
|
||||
"{}@{}@{}",
|
||||
self.name, self.def_id.program_id, self.def_id.id
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
|
|
|
@ -149,8 +149,9 @@ fn lower_function(
|
|||
let body = ctx.body.modules.get(&module_id).unwrap();
|
||||
*body.symbols.functions.get(&func.name.name).unwrap()
|
||||
},
|
||||
is_pub: func.is_public || func.name.name == "main",
|
||||
is_pub: func.is_public,
|
||||
is_extern: func.is_extern,
|
||||
is_exported: func.is_exported || func.name.name == "main",
|
||||
fn_span: func.span,
|
||||
},
|
||||
local_module: module_id,
|
||||
|
|
|
@ -28,6 +28,7 @@ extern {
|
|||
"in" => Token::KeywordIn,
|
||||
"extern" => Token::KeywordExtern,
|
||||
"as" => Token::KeywordAs,
|
||||
"exported" => Token::KeywordExported,
|
||||
|
||||
// literals
|
||||
"identifier" => Token::Identifier(<String>),
|
||||
|
@ -426,16 +427,18 @@ pub(crate) Function: ast::Function = {
|
|||
<return_type:("->" <Type>)?> ";" <hi:@R> => ast::Function {
|
||||
is_public: is_public.is_some(),
|
||||
is_extern: true,
|
||||
is_exported: false,
|
||||
name,
|
||||
params,
|
||||
return_type,
|
||||
body: None,
|
||||
span: ast::Span::new(lo, hi),
|
||||
},
|
||||
<lo:@L> <is_public:"pub"?> "fn" <name:Ident> "(" <params:Comma<FnParam>> ")"
|
||||
<lo:@L> <is_public:"pub"?> <is_exported:"exported"?> "fn" <name:Ident> "(" <params:Comma<FnParam>> ")"
|
||||
<return_type:("->" <Type>)?> <body:Block> <hi:@R> => ast::Function {
|
||||
is_public: is_public.is_some(),
|
||||
is_extern: false,
|
||||
is_exported: is_exported.is_some(),
|
||||
name,
|
||||
params,
|
||||
return_type,
|
||||
|
@ -478,13 +481,18 @@ pub(crate) Import: ast::Import = {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) ExternalModule: ast::Ident = {
|
||||
"mod" <name:Ident> ";" => name
|
||||
}
|
||||
|
||||
pub TopLevelModule: ast::Module = {
|
||||
<lo:@L> <imports:List<Import>?> <contents:List<ModuleStatement>> <hi:@R> => ast::Module {
|
||||
<lo:@L> <imports:List<Import>?> <external_modules:List<ExternalModule>?> <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![]),
|
||||
external_modules: external_modules.unwrap_or(vec![]),
|
||||
contents,
|
||||
span: ast::Span::new(lo, hi),
|
||||
}
|
||||
|
@ -494,6 +502,7 @@ pub Module: ast::Module = {
|
|||
<lo:@L> "mod" <name:Ident> "{" <imports:List<Import>?> <contents:List<ModuleStatement>> "}" <hi:@R> => ast::Module {
|
||||
name,
|
||||
imports: imports.unwrap_or(vec![]),
|
||||
external_modules: Vec::new(),
|
||||
contents,
|
||||
span: ast::Span::new(lo, hi),
|
||||
}
|
||||
|
|
|
@ -57,6 +57,8 @@ pub enum Token {
|
|||
KeywordExtern,
|
||||
#[token("as")]
|
||||
KeywordAs,
|
||||
#[token("exported")]
|
||||
KeywordExported,
|
||||
|
||||
// Modern way of allowing identifiers, read: https://unicode.org/reports/tr31/
|
||||
#[regex(r"[\p{XID_Start}_]\p{XID_Continue}*", |lex| lex.slice().to_string())]
|
||||
|
|
Loading…
Reference in a new issue