mirror of
https://github.com/edg-l/edlang.git
synced 2024-09-07 19:35:16 +00:00
feat: better cli and add tests
This commit is contained in:
parent
4a83cfd6f9
commit
6fc3e2ba6d
101
Cargo.lock
generated
101
Cargo.lock
generated
|
@ -154,17 +154,14 @@ version = "2.4.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf"
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.85"
|
||||
version = "1.0.83"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b918671670962b48bc23753aef0c51d072dca6f52f01f800854ada6ddb7f7d3"
|
||||
checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
|
@ -325,8 +322,6 @@ dependencies = [
|
|||
name = "edlang_codegen_llvm"
|
||||
version = "0.0.1-alpha.3"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"cc",
|
||||
"edlang_ir",
|
||||
"edlang_parser",
|
||||
"edlang_session",
|
||||
|
@ -350,6 +345,8 @@ dependencies = [
|
|||
"edlang_lowering",
|
||||
"edlang_parser",
|
||||
"edlang_session",
|
||||
"tempfile",
|
||||
"test-case",
|
||||
"tracing",
|
||||
"tracing-subscriber",
|
||||
]
|
||||
|
@ -416,6 +413,16 @@ version = "1.0.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
|
||||
|
||||
[[package]]
|
||||
name = "errno"
|
||||
version = "0.3.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "eyre"
|
||||
version = "0.6.12"
|
||||
|
@ -426,6 +433,12 @@ dependencies = [
|
|||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fastrand"
|
||||
version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5"
|
||||
|
||||
[[package]]
|
||||
name = "fixedbitset"
|
||||
version = "0.4.2"
|
||||
|
@ -469,9 +482,9 @@ checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
|
|||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.3.5"
|
||||
version = "0.3.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d0c62115964e08cb8039170eb33c1d0e2388a256930279edca206fff675f82c3"
|
||||
checksum = "bd5256b483761cd23699d0da46cc6fd2ee3be420bbe6d020ae4a091e70b7e9fd"
|
||||
|
||||
[[package]]
|
||||
name = "indenter"
|
||||
|
@ -596,6 +609,12 @@ dependencies = [
|
|||
"redox_syscall",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.4.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c"
|
||||
|
||||
[[package]]
|
||||
name = "llvm-sys"
|
||||
version = "170.0.1"
|
||||
|
@ -886,6 +905,19 @@ version = "0.1.23"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "0.38.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6ea3e1a662af26cd7a3ba09c0297a31af215563ecf42817c98df621387f4e949"
|
||||
dependencies = [
|
||||
"bitflags 2.4.2",
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustversion"
|
||||
version = "1.0.14"
|
||||
|
@ -955,6 +987,18 @@ dependencies = [
|
|||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tempfile"
|
||||
version = "3.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a365e8cd18e44762ef95d87f284f4b5cd04107fec2ff3052bd6a3e6069669e67"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"fastrand",
|
||||
"rustix",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "term"
|
||||
version = "0.7.0"
|
||||
|
@ -966,6 +1010,39 @@ dependencies = [
|
|||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "test-case"
|
||||
version = "3.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eb2550dd13afcd286853192af8601920d959b14c401fcece38071d53bf0768a8"
|
||||
dependencies = [
|
||||
"test-case-macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "test-case-core"
|
||||
version = "3.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "adcb7fd841cd518e279be3d5a3eb0636409487998a4aff22f3de87b81e88384f"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "test-case-macros"
|
||||
version = "3.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c89e72a01ed4c579669add59014b9a524d609c0c88c6a585ce37485879f6ffb"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"test-case-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.57"
|
||||
|
|
|
@ -13,7 +13,6 @@ repository = "https://github.com/edg-l/edlang"
|
|||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
bumpalo = { version = "3.14.0", features = ["std"] }
|
||||
edlang_ir = { version = "0.0.1-alpha.3", path = "../edlang_ir" }
|
||||
edlang_parser = { version = "0.0.1-alpha.3", path = "../edlang_parser" }
|
||||
edlang_session = { version = "0.0.1-alpha.3", path = "../edlang_session" }
|
||||
|
@ -21,6 +20,3 @@ llvm-sys = "170.0.1"
|
|||
inkwell = { git = "https://github.com/TheDan64/inkwell", rev = "c044e3cd8d92972ca75b374fb6c5a2794f5b53ca", features = ["llvm17-0"] }
|
||||
tracing = { workspace = true }
|
||||
edlang_span = { version = "0.0.1-alpha.3", path = "../edlang_span" }
|
||||
|
||||
[build-dependencies]
|
||||
cc = "1.0.83"
|
||||
|
|
|
@ -17,7 +17,7 @@ use inkwell::{
|
|||
};
|
||||
use ir::{LocalKind, ModuleBody, ProgramBody, TypeInfo, ValueTree};
|
||||
use llvm_sys::debuginfo::LLVMDIFlagPublic;
|
||||
use tracing::info;
|
||||
use tracing::{info, trace};
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
struct CompileCtx<'a> {
|
||||
|
@ -78,8 +78,17 @@ pub fn compile(session: &Session, program: &ProgramBody) -> Result<PathBuf, Box<
|
|||
&triple,
|
||||
cpu_name.to_str()?,
|
||||
cpu_features.to_str()?,
|
||||
inkwell::OptimizationLevel::Aggressive,
|
||||
inkwell::targets::RelocMode::Default,
|
||||
match session.optlevel {
|
||||
edlang_session::OptLevel::None => inkwell::OptimizationLevel::None,
|
||||
edlang_session::OptLevel::Less => inkwell::OptimizationLevel::Less,
|
||||
edlang_session::OptLevel::Default => inkwell::OptimizationLevel::Default,
|
||||
edlang_session::OptLevel::Aggressive => inkwell::OptimizationLevel::Aggressive,
|
||||
},
|
||||
if session.library {
|
||||
inkwell::targets::RelocMode::DynamicNoPic
|
||||
} else {
|
||||
inkwell::targets::RelocMode::Default
|
||||
},
|
||||
inkwell::targets::CodeModel::Default,
|
||||
)
|
||||
.unwrap();
|
||||
|
@ -131,15 +140,20 @@ pub fn compile(session: &Session, program: &ProgramBody) -> Result<PathBuf, Box<
|
|||
module_ctx.di_builder.finalize();
|
||||
module_ctx.module.verify()?;
|
||||
|
||||
module_ctx
|
||||
.module
|
||||
.print_to_file(session.output_file.with_extension("ll"))?;
|
||||
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::Assembly,
|
||||
&session.output_file.with_extension("asm"),
|
||||
)?;
|
||||
machine.write_to_file(
|
||||
&module_ctx.module,
|
||||
inkwell::targets::FileType::Object,
|
||||
|
@ -154,7 +168,7 @@ pub fn compile(session: &Session, program: &ProgramBody) -> Result<PathBuf, Box<
|
|||
|
||||
fn compile_module(ctx: &mut ModuleCompileCtx, module_id: DefId) {
|
||||
let module = ctx.ctx.program.modules.get(&module_id).unwrap();
|
||||
info!("compiling module");
|
||||
trace!("compiling module");
|
||||
for id in module.functions.iter() {
|
||||
compile_fn_signature(ctx, *id);
|
||||
}
|
||||
|
@ -167,7 +181,7 @@ fn compile_module(ctx: &mut ModuleCompileCtx, module_id: DefId) {
|
|||
fn compile_fn_signature(ctx: &ModuleCompileCtx<'_, '_>, fn_id: DefId) {
|
||||
let (arg_types, ret_type) = ctx.ctx.program.function_signatures.get(&fn_id).unwrap();
|
||||
let body = ctx.ctx.program.functions.get(&fn_id).unwrap();
|
||||
info!("compiling fn sig: {}", body.name);
|
||||
trace!("compiling fn sig: {}", body.name);
|
||||
|
||||
let args: Vec<BasicMetadataTypeEnum> = arg_types
|
||||
.iter()
|
||||
|
@ -242,7 +256,7 @@ fn compile_fn_signature(ctx: &ModuleCompileCtx<'_, '_>, fn_id: DefId) {
|
|||
|
||||
fn compile_fn(ctx: &ModuleCompileCtx, fn_id: DefId) -> Result<(), BuilderError> {
|
||||
let body = ctx.ctx.program.functions.get(&fn_id).unwrap();
|
||||
info!("compiling fn body: {}", body.name);
|
||||
trace!("compiling fn body: {}", body.name);
|
||||
|
||||
let fn_value = ctx.module.get_function(&body.name).unwrap();
|
||||
let di_program = fn_value.get_subprogram().unwrap();
|
||||
|
@ -343,14 +357,14 @@ fn compile_fn(ctx: &ModuleCompileCtx, fn_id: DefId) -> Result<(), BuilderError>
|
|||
ctx.builder.build_unconditional_branch(blocks[0])?;
|
||||
|
||||
for (block, llvm_block) in body.blocks.iter().zip(&blocks) {
|
||||
info!("compiling block");
|
||||
trace!("compiling block");
|
||||
ctx.builder.position_at_end(*llvm_block);
|
||||
for stmt in &block.statements {
|
||||
if let Some(span) = stmt.span {
|
||||
debug_loc = ctx.set_debug_loc(debug_loc.get_scope(), span);
|
||||
}
|
||||
|
||||
info!("compiling stmt");
|
||||
trace!("compiling stmt");
|
||||
match &stmt.kind {
|
||||
ir::StatementKind::Assign(place, rvalue) => {
|
||||
let local = &body.locals[place.local];
|
||||
|
@ -409,7 +423,7 @@ fn compile_fn(ctx: &ModuleCompileCtx, fn_id: DefId) -> Result<(), BuilderError>
|
|||
}
|
||||
}
|
||||
|
||||
info!("compiling terminator");
|
||||
trace!("compiling terminator");
|
||||
match &block.terminator {
|
||||
ir::Terminator::Target(id) => {
|
||||
ctx.builder.build_unconditional_branch(blocks[*id])?;
|
||||
|
@ -429,18 +443,14 @@ fn compile_fn(ctx: &ModuleCompileCtx, fn_id: DefId) -> Result<(), BuilderError>
|
|||
discriminator,
|
||||
targets,
|
||||
} => {
|
||||
let (condition, condition_ty) =
|
||||
let (condition, _condition_ty) =
|
||||
compile_load_operand(ctx, fn_id, &locals, discriminator)?;
|
||||
let cond = condition.into_int_value();
|
||||
dbg!(&cond);
|
||||
dbg!(&condition_ty);
|
||||
|
||||
let mut cases = Vec::new();
|
||||
|
||||
for (value, target) in targets.values.iter().zip(targets.targets.iter()) {
|
||||
let target = *target;
|
||||
let ty_kind = value.get_type();
|
||||
dbg!(&ty_kind);
|
||||
let block = blocks[target];
|
||||
let value = compile_value(
|
||||
ctx,
|
||||
|
@ -451,7 +461,6 @@ fn compile_fn(ctx: &ModuleCompileCtx, fn_id: DefId) -> Result<(), BuilderError>
|
|||
},
|
||||
)?
|
||||
.into_int_value();
|
||||
dbg!(&value);
|
||||
cases.push((value, block));
|
||||
}
|
||||
|
||||
|
|
|
@ -25,3 +25,7 @@ edlang_parser = { version = "0.0.1-alpha.3", path = "../edlang_parser" }
|
|||
edlang_session = { version = "0.0.1-alpha.3", path = "../edlang_session" }
|
||||
tracing = { workspace = true }
|
||||
tracing-subscriber = { version = "0.3.18", features = ["env-filter"] }
|
||||
|
||||
[dev-dependencies]
|
||||
tempfile = "3.10.0"
|
||||
test-case = "3.3.1"
|
||||
|
|
|
@ -7,7 +7,7 @@ use edlang_lowering::lower_modules;
|
|||
use edlang_session::{DebugInfo, OptLevel, Session};
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
#[command(author, version, about, long_about = None, bin_name = "edlang")]
|
||||
#[command(author, version, about = "edlang compiler driver", long_about = None, bin_name = "edlang")]
|
||||
pub struct CompilerArgs {
|
||||
/// The input file.
|
||||
input: PathBuf,
|
||||
|
@ -16,18 +16,33 @@ pub struct CompilerArgs {
|
|||
#[arg(short, long, default_value_t = false)]
|
||||
release: bool,
|
||||
|
||||
/// Set the optimization level, 0,1,2,3
|
||||
#[arg(short = 'O', long)]
|
||||
optlevel: Option<u8>,
|
||||
|
||||
/// Always add debug info
|
||||
#[arg(long)]
|
||||
debug_info: Option<bool>,
|
||||
|
||||
/// Build as a library.
|
||||
#[arg(short, long, default_value_t = false)]
|
||||
library: bool,
|
||||
|
||||
#[arg(long, default_value_t = false)]
|
||||
mlir: bool,
|
||||
|
||||
/// Print the edlang AST
|
||||
#[arg(long, default_value_t = false)]
|
||||
ast: bool,
|
||||
|
||||
/// Print the edlang IR
|
||||
#[arg(long, default_value_t = false)]
|
||||
ir: bool,
|
||||
|
||||
/// Output llvm ir
|
||||
#[arg(long, default_value_t = false)]
|
||||
llvm: bool,
|
||||
|
||||
/// Output asm
|
||||
#[arg(long, default_value_t = false)]
|
||||
asm: bool,
|
||||
}
|
||||
|
||||
pub fn main() -> Result<(), Box<dyn Error>> {
|
||||
|
@ -59,19 +74,34 @@ pub fn main() -> Result<(), Box<dyn Error>> {
|
|||
}
|
||||
let output_file = target_dir.join(PathBuf::from(args.input.file_name().unwrap()));
|
||||
let output_file = if args.library {
|
||||
output_file.with_extension("so")
|
||||
output_file.with_extension(Session::get_platform_library_ext())
|
||||
} else if cfg!(target_os = "windows") {
|
||||
output_file.with_extension("exe")
|
||||
} else {
|
||||
output_file.with_extension("")
|
||||
};
|
||||
|
||||
let session = Session {
|
||||
file_path: args.input,
|
||||
debug_info: if args.release {
|
||||
debug_info: if let Some(debug_info) = args.debug_info {
|
||||
if debug_info {
|
||||
DebugInfo::Full
|
||||
} else {
|
||||
DebugInfo::None
|
||||
}
|
||||
} else if args.release {
|
||||
DebugInfo::None
|
||||
} else {
|
||||
DebugInfo::Full
|
||||
},
|
||||
optlevel: if args.release {
|
||||
optlevel: if let Some(optlevel) = args.optlevel {
|
||||
match optlevel {
|
||||
0 => OptLevel::None,
|
||||
1 => OptLevel::Less,
|
||||
2 => OptLevel::Default,
|
||||
_ => OptLevel::Aggressive,
|
||||
}
|
||||
} else if args.release {
|
||||
OptLevel::Aggressive
|
||||
} else {
|
||||
OptLevel::None
|
||||
|
@ -80,8 +110,15 @@ pub fn main() -> Result<(), Box<dyn Error>> {
|
|||
library: args.library,
|
||||
target_dir,
|
||||
output_file,
|
||||
output_asm: args.asm,
|
||||
output_llvm: args.llvm,
|
||||
};
|
||||
tracing::debug!("Compiling with session: {:#?}", session);
|
||||
tracing::debug!("Input file: {:#?}", session.file_path);
|
||||
tracing::debug!("Target dir: {:#?}", session.target_dir);
|
||||
tracing::debug!("Output file: {:#?}", session.output_file);
|
||||
tracing::debug!("Is library: {:#?}", session.library);
|
||||
tracing::debug!("Optlevel: {:#?}", session.optlevel);
|
||||
tracing::debug!("Debug Info: {:#?}", session.debug_info);
|
||||
|
||||
if args.ast {
|
||||
println!("{:#?}", module);
|
||||
|
@ -98,9 +135,9 @@ pub fn main() -> Result<(), Box<dyn Error>> {
|
|||
let object_path = edlang_codegen_llvm::compile(&session, &program_ir)?;
|
||||
|
||||
if session.library {
|
||||
link_shared_lib(&object_path, &session.output_file.with_extension("so"))?;
|
||||
link_shared_lib(&object_path, &session.output_file)?;
|
||||
} else {
|
||||
link_binary(&object_path, &session.output_file.with_extension(""))?;
|
||||
link_binary(&object_path, &session.output_file)?;
|
||||
}
|
||||
|
||||
let elapsed = start_time.elapsed();
|
||||
|
|
88
lib/edlang_driver/tests/common.rs
Normal file
88
lib/edlang_driver/tests/common.rs
Normal file
|
@ -0,0 +1,88 @@
|
|||
use std::{
|
||||
borrow::Cow,
|
||||
fmt,
|
||||
path::{Path, PathBuf},
|
||||
process::Output,
|
||||
};
|
||||
|
||||
use ariadne::Source;
|
||||
use edlang_codegen_llvm::linker::{link_binary, link_shared_lib};
|
||||
use edlang_lowering::lower_modules;
|
||||
use edlang_session::{DebugInfo, OptLevel, Session};
|
||||
use tempfile::TempDir;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct TestError(Cow<'static, str>);
|
||||
|
||||
impl fmt::Display for TestError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.write_str(&self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for TestError {}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct CompileResult {
|
||||
pub folder: TempDir,
|
||||
pub object_file: PathBuf,
|
||||
pub binary_file: PathBuf,
|
||||
}
|
||||
|
||||
pub fn compile_program(
|
||||
source: &str,
|
||||
name: &str,
|
||||
library: bool,
|
||||
) -> Result<CompileResult, Box<dyn std::error::Error>> {
|
||||
let module = edlang_parser::parse_ast(source).unwrap();
|
||||
|
||||
let test_dir = tempfile::tempdir()?;
|
||||
let test_dir_path = test_dir.path();
|
||||
let target_dir = test_dir_path.join("build_artifacts/");
|
||||
if !target_dir.exists() {
|
||||
std::fs::create_dir_all(&target_dir)?;
|
||||
}
|
||||
let output_file = target_dir.join(PathBuf::from(name));
|
||||
let output_file = if library {
|
||||
output_file.with_extension(Session::get_platform_library_ext())
|
||||
} else if cfg!(target_os = "windows") {
|
||||
output_file.with_extension("exe")
|
||||
} else {
|
||||
output_file.with_extension("")
|
||||
};
|
||||
|
||||
let session = Session {
|
||||
file_path: PathBuf::from(name),
|
||||
debug_info: DebugInfo::Full,
|
||||
optlevel: OptLevel::Default,
|
||||
source: Source::from(source.to_string()),
|
||||
library,
|
||||
target_dir,
|
||||
output_file,
|
||||
output_llvm: false,
|
||||
output_asm: false,
|
||||
};
|
||||
|
||||
let program_ir = lower_modules(&[module]);
|
||||
|
||||
let object_path = edlang_codegen_llvm::compile(&session, &program_ir)?;
|
||||
|
||||
if library {
|
||||
link_shared_lib(&object_path, &session.output_file)?;
|
||||
} else {
|
||||
link_binary(&object_path, &session.output_file)?;
|
||||
}
|
||||
|
||||
Ok(CompileResult {
|
||||
folder: test_dir,
|
||||
object_file: object_path,
|
||||
binary_file: session.output_file,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn run_program(program: &Path, args: &[&str]) -> Result<Output, std::io::Error> {
|
||||
std::process::Command::new(program)
|
||||
.args(args)
|
||||
.spawn()?
|
||||
.wait_with_output()
|
||||
}
|
21
lib/edlang_driver/tests/programs.rs
Normal file
21
lib/edlang_driver/tests/programs.rs
Normal file
|
@ -0,0 +1,21 @@
|
|||
use crate::common::{compile_program, run_program};
|
||||
use test_case::test_case;
|
||||
|
||||
mod common;
|
||||
|
||||
#[test_case(include_str!("programs/simple.ed"), "simple", false, 0, &["1"] ; "simple.ed 1")]
|
||||
#[test_case(include_str!("programs/simple.ed"), "simple", false, 1, &["a", "b"] ; "simple.ed 3")]
|
||||
#[test_case(include_str!("programs/basic_ifs.ed"), "basic_ifs", false, 9, &[] ; "basic_ifs")]
|
||||
fn example_tests(source: &str, name: &str, is_library: bool, status_code: i32, args: &[&str]) {
|
||||
let program = compile_program(source, name, is_library).unwrap();
|
||||
|
||||
assert!(program.binary_file.exists(), "program not compiled");
|
||||
|
||||
let result = run_program(&program.binary_file, args).unwrap();
|
||||
assert_eq!(
|
||||
result.status.code().unwrap(),
|
||||
status_code,
|
||||
"Program {} returned a unexpected status code",
|
||||
name
|
||||
);
|
||||
}
|
19
lib/edlang_driver/tests/programs/basic_ifs.ed
Normal file
19
lib/edlang_driver/tests/programs/basic_ifs.ed
Normal file
|
@ -0,0 +1,19 @@
|
|||
mod Main {
|
||||
fn add(a: i32, b: i32) -> i32 {
|
||||
return a + b;
|
||||
}
|
||||
|
||||
fn check(a: i32) -> i32 {
|
||||
if a == 2 {
|
||||
return a;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn main() -> i32 {
|
||||
let x: i32 = 2 + 3;
|
||||
let y: i32 = add(x, 4);
|
||||
return y;
|
||||
}
|
||||
}
|
11
lib/edlang_driver/tests/programs/simple.ed
Normal file
11
lib/edlang_driver/tests/programs/simple.ed
Normal file
|
@ -0,0 +1,11 @@
|
|||
mod Main {
|
||||
pub fn main(argc: i64) -> i64 {
|
||||
let mut a: i64 = 0;
|
||||
|
||||
if argc > 2 {
|
||||
a = 1;
|
||||
}
|
||||
|
||||
return a;
|
||||
}
|
||||
}
|
|
@ -210,12 +210,20 @@ fn lower_if_stmt(builder: &mut BodyBuilder, info: &ast::IfStmt, ret_type: &TypeI
|
|||
}
|
||||
|
||||
// keet idx to change terminator
|
||||
let last_then_block_idx = builder.body.blocks.len();
|
||||
let statements = std::mem::take(&mut builder.statements);
|
||||
builder.body.blocks.push(BasicBlock {
|
||||
statements: statements.into(),
|
||||
terminator: Terminator::Unreachable,
|
||||
});
|
||||
let last_then_block_idx = if !matches!(
|
||||
builder.body.blocks.last().unwrap().terminator,
|
||||
Terminator::Return
|
||||
) {
|
||||
let idx = builder.body.blocks.len();
|
||||
let statements = std::mem::take(&mut builder.statements);
|
||||
builder.body.blocks.push(BasicBlock {
|
||||
statements: statements.into(),
|
||||
terminator: Terminator::Unreachable,
|
||||
});
|
||||
Some(idx)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let first_else_block_idx = builder.body.blocks.len();
|
||||
|
||||
|
@ -225,12 +233,20 @@ fn lower_if_stmt(builder: &mut BodyBuilder, info: &ast::IfStmt, ret_type: &TypeI
|
|||
}
|
||||
}
|
||||
|
||||
let last_else_block_idx = builder.body.blocks.len();
|
||||
let statements = std::mem::take(&mut builder.statements);
|
||||
builder.body.blocks.push(BasicBlock {
|
||||
statements: statements.into(),
|
||||
terminator: Terminator::Unreachable,
|
||||
});
|
||||
let last_else_block_idx = if !matches!(
|
||||
builder.body.blocks.last().unwrap().terminator,
|
||||
Terminator::Return
|
||||
) {
|
||||
let idx = builder.body.blocks.len();
|
||||
let statements = std::mem::take(&mut builder.statements);
|
||||
builder.body.blocks.push(BasicBlock {
|
||||
statements: statements.into(),
|
||||
terminator: Terminator::Unreachable,
|
||||
});
|
||||
Some(idx)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let targets = SwitchTarget {
|
||||
values: vec![TypeKind::Bool.get_falsy_value()],
|
||||
|
@ -244,8 +260,13 @@ fn lower_if_stmt(builder: &mut BodyBuilder, info: &ast::IfStmt, ret_type: &TypeI
|
|||
builder.body.blocks[current_block_idx].terminator = kind;
|
||||
|
||||
let next_block_idx = builder.body.blocks.len();
|
||||
builder.body.blocks[last_then_block_idx].terminator = Terminator::Target(next_block_idx);
|
||||
builder.body.blocks[last_else_block_idx].terminator = Terminator::Target(next_block_idx);
|
||||
if let Some(idx) = last_then_block_idx {
|
||||
builder.body.blocks[idx].terminator = Terminator::Target(next_block_idx);
|
||||
}
|
||||
|
||||
if let Some(idx) = last_else_block_idx {
|
||||
builder.body.blocks[idx].terminator = Terminator::Target(next_block_idx);
|
||||
}
|
||||
}
|
||||
|
||||
fn lower_let(builder: &mut BodyBuilder, info: &ast::LetStmt) {
|
||||
|
|
|
@ -12,6 +12,20 @@ pub struct Session {
|
|||
/// The directory where to store artifacts and intermediate files such as object files.
|
||||
pub target_dir: PathBuf,
|
||||
pub output_file: PathBuf,
|
||||
pub output_llvm: bool,
|
||||
pub output_asm: bool,
|
||||
}
|
||||
|
||||
impl Session {
|
||||
pub fn get_platform_library_ext() -> &'static str {
|
||||
if cfg!(target_os = "macos") {
|
||||
"dylib"
|
||||
} else if cfg!(target_os = "windows") {
|
||||
"dll"
|
||||
} else {
|
||||
"so"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Hash)]
|
||||
|
|
|
@ -11,7 +11,7 @@ mod Main {
|
|||
}
|
||||
}
|
||||
|
||||
fn main() -> i32 {
|
||||
pub fn main(argc: i32) -> i32 {
|
||||
let x: i32 = 2 + 3;
|
||||
let y: i32 = add(x, 4);
|
||||
return y;
|
||||
|
|
Loading…
Reference in a new issue