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