From bb96b562e57926b6d54a56c5cda6b72923583578 Mon Sep 17 00:00:00 2001 From: Jonathan Woollett-Light Date: Sun, 24 Dec 2023 00:34:44 +0000 Subject: [PATCH] hello --- Cargo.lock | 113 --------- Cargo.toml | 1 - index.html | 2 +- src/main.rs | 475 +++++++++++++++++++++---------------- src/middle.rs | 4 +- tests/integration_tests.rs | 90 ++----- 6 files changed, 289 insertions(+), 396 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6ec8c43..4ac3289 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,54 +17,6 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" -[[package]] -name = "anstream" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ab91ebe16eb252986481c5b62f6098f3b698a45e34b5b98200cf20dd2484a44" -dependencies = [ - "anstyle", - "anstyle-parse", - "anstyle-query", - "anstyle-wincon", - "colorchoice", - "utf8parse", -] - -[[package]] -name = "anstyle" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87" - -[[package]] -name = "anstyle-parse" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c" -dependencies = [ - "utf8parse", -] - -[[package]] -name = "anstyle-query" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3a318f1f38d2418400f8209655bfd825785afd25aa30bb7ba6cc792e4596748" -dependencies = [ - "windows-sys 0.52.0", -] - -[[package]] -name = "anstyle-wincon" -version = "3.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" -dependencies = [ - "anstyle", - "windows-sys 0.52.0", -] - [[package]] name = "autocfg" version = "1.1.0" @@ -131,52 +83,6 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" -[[package]] -name = "clap" -version = "4.4.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfaff671f6b22ca62406885ece523383b9b64022e341e53e009a62ebc47a45f2" -dependencies = [ - "clap_builder", - "clap_derive", -] - -[[package]] -name = "clap_builder" -version = "4.4.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a216b506622bb1d316cd51328dce24e07bdff4a6128a47c7e7fad11878d5adbb" -dependencies = [ - "anstream", - "anstyle", - "clap_lex", - "strsim", -] - -[[package]] -name = "clap_derive" -version = "4.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "clap_lex" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" - -[[package]] -name = "colorchoice" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" - [[package]] name = "core-foundation" version = "0.9.4" @@ -356,12 +262,6 @@ version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" -[[package]] -name = "heck" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" - [[package]] name = "hermit-abi" version = "0.3.3" @@ -493,7 +393,6 @@ dependencies = [ name = "language" version = "0.1.0" dependencies = [ - "clap", "data-encoding", "itertools", "libc", @@ -926,12 +825,6 @@ version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" -[[package]] -name = "strsim" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" - [[package]] name = "syn" version = "2.0.33" @@ -1150,12 +1043,6 @@ dependencies = [ "percent-encoding", ] -[[package]] -name = "utf8parse" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" - [[package]] name = "uuid" version = "1.4.1" diff --git a/Cargo.toml b/Cargo.toml index 85005de..0960c65 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,7 +9,6 @@ edition = "2021" libc = "0.2.147" reqwest = { version = "0.11.22", features=["blocking"]} num-traits = "0.2.16" -clap = { version = "4.4.11", features=["derive"] } ring = "0.17.7" data-encoding = "2.5.0" itertools = "0.11.0" diff --git a/index.html b/index.html index b8ec27a..cd0cb8c 100644 --- a/index.html +++ b/index.html @@ -42,7 +42,7 @@

Hello, World!

Language

include https://raw.githubusercontent.com/JonathanWoollett-Light/language/master/syscalls.lang
x := "Hello, World!\n"
write 1 &x
exit 0

-

language --path hello-world

+

language --new hello-world
language --build hello-world

.global _start
_start:
mov x8, #64
mov x0, #1
ldr x1, =a
mov x2, #14
svc #0
mov x8, #93
mov x0, #0
svc #0
.data
a: .byte 72,101,108,108,111,44,32,87,111,114,108,100,33,10

diff --git a/src/main.rs b/src/main.rs index bba483f..1ad2021 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,7 +9,6 @@ extern crate test; -use clap::Parser; use data_encoding::HEXUPPER; use ring::digest::{Context, Digest, SHA256}; use std::fs::OpenOptions; @@ -27,14 +26,23 @@ use backend::*; #[cfg(debug_assertions)] const LOOP_LIMIT: usize = 200; -#[derive(Parser, Debug)] -struct Args { - #[arg(long)] - source: Option, - #[arg(long)] - path: Option, - #[arg(long)] - new: Option, +enum Args { + Build(Option), + New(Option), + Run(Option), +} +impl From> for Args { + fn from(args: Vec) -> Self { + match args.as_slice() { + [_, arg] if arg == "--build" => Self::Build(None), + [_, arg] if arg == "--new" => Self::New(None), + [_, arg] if arg == "--run" => Self::Run(None), + [_, arg, path] if arg == "--build" => Self::Build(Some(PathBuf::from(path))), + [_, arg, path] if arg == "--new" => Self::New(Some(PathBuf::from(path))), + [_, arg, path] if arg == "--run" => Self::Run(Some(PathBuf::from(path))), + _ => todo!(), + } + } } fn sha256_digest(mut reader: R) -> std::io::Result { @@ -53,6 +61,7 @@ fn sha256_digest(mut reader: R) -> std::io::Result { } const LANGUAGE_EXTENSION: &str = "abc"; + const BUILD_DIR: &str = "build"; fn write_file(dir: &PathBuf, file: PathBuf, bytes: &[u8], lock_file: &mut std::fs::File) { @@ -70,196 +79,202 @@ fn write_file(dir: &PathBuf, file: PathBuf, bytes: &[u8], lock_file: &mut std::f writeln!(lock_file, "{},{hash}", file_name.to_str().unwrap()).unwrap(); } -#[allow(unreachable_code)] -fn main() { - let args = Args::parse(); - - if let Some(new) = args.new { - if !new.exists() { - std::fs::create_dir(&new).unwrap(); - } - let mut source = OpenOptions::new() - .create(true) - .write(true) - .open(new.join("source")) - .unwrap(); - source.write_all(b"\ - include https://raw.githubusercontent.com/JonathanWoollett-Light/language/master/syscalls.lang\n\ - x := \"Hello, World!\\n\"\n\ - write 1 x\n\ - exit 0\n\ - ").unwrap(); - return; +fn build(path: Option) { + let project_path = path.unwrap_or(PathBuf::from("./")); + let source_path = project_path + .join("source") + .with_extension(LANGUAGE_EXTENSION); + let source = std::fs::read_to_string(source_path).unwrap(); + + // Create build directory + let build_dir = project_path.join(BUILD_DIR); + if !build_dir.exists() { + std::fs::create_dir(build_dir).unwrap(); } - let (source, path_opt) = if let Some(source) = args.source { - (source, None) - } else { - let project_path = args.path.unwrap_or_else(|| PathBuf::from("./")); - let source_path = project_path.join("source"); - ( - std::fs::read_to_string(source_path).unwrap(), - Some(project_path), - ) + // Create lock file + let mut lock_file = OpenOptions::new() + .create(true) + .truncate(true) + .write(true) + .open(project_path.join("lock.csv")) + .unwrap(); + writeln!(&mut lock_file, "file,hash").unwrap(); + + // Includes dependencies + let mut bytes = source.into_bytes(); + get_includes(&mut bytes); + write_file( + &project_path, + PathBuf::from("included").with_extension(LANGUAGE_EXTENSION), + &bytes, + &mut lock_file, + ); + + // Parses AST + let reader = std::io::BufReader::new(bytes.as_slice()); + let mut iter = reader.bytes().peekable(); + let nodes = get_nodes(&mut iter).unwrap(); + + // Inlines functions + let inlined = unsafe { inline_functions(nodes) }; + let inlined_string = display_ast(inlined); + write_file( + &project_path, + PathBuf::from("inlined").with_extension(LANGUAGE_EXTENSION), + inlined_string.as_bytes(), + &mut lock_file, + ); + + // Explores states + let roots = unsafe { roots(inlined) }; + let mut explorer = unsafe { Explorer::new(&roots) }; + let path = loop { + match unsafe { explorer.next() } { + Explore::Current(_) => continue, + Explore::Finished(x) => break x, + } }; - unsafe { - // Includes dependencies - let mut bytes = source.into_bytes(); - get_includes(&mut bytes); - let mut lock = if let Some(path) = &path_opt { - let build_dir = path.join(BUILD_DIR); - if !build_dir.exists() { - std::fs::create_dir(build_dir).unwrap(); - } - let mut lock_file = OpenOptions::new() - .create(true) - .truncate(true) - .write(true) - .open(path.join("lock.csv")) - .unwrap(); - writeln!(&mut lock_file, "file,hash").unwrap(); + // Optimize source + let optimized = unsafe { optimize(path) }; + let optimized_string = display_ast(optimized); + write_file( + &project_path, + PathBuf::from("optimized").with_extension(LANGUAGE_EXTENSION), + optimized_string.as_bytes(), + &mut lock_file, + ); + + // Construct assembly + let assembly = assembly_from_node(optimized); + let assembly_path = PathBuf::from("assembly").with_extension("s"); + write_file( + &project_path, + assembly_path.clone(), + assembly.as_bytes(), + &mut lock_file, + ); + + // Make object file + let object_path = project_path + .join("build") + .join("object") + .with_extension("o"); + let object_output = std::process::Command::new("as") + .args([ + "-o", + &object_path.display().to_string(), + &project_path + .join("build") + .join(assembly_path) + .display() + .to_string(), + ]) + .output() + .unwrap(); + assert_eq!( + object_output.stdout, + [], + "{}", + std::str::from_utf8(&object_output.stdout).unwrap() + ); + assert_eq!( + object_output.stderr, + [], + "{}", + std::str::from_utf8(&object_output.stderr).unwrap() + ); + assert_eq!(object_output.status.code(), Some(0)); + // Write object hash + let mut object_buffer = Vec::new(); + let mut object_file = OpenOptions::new().read(true).open(&object_path).unwrap(); + object_file.read_to_end(&mut object_buffer).unwrap(); + let object_hash = HEXUPPER.encode(sha256_digest(object_buffer.as_slice()).unwrap().as_ref()); + let object_file_name = object_path.file_stem().unwrap(); + writeln!( + &mut lock_file, + "{},{object_hash}", + object_file_name.to_str().unwrap() + ) + .unwrap(); + + // Make binary file + let binary_path = project_path.join("build").join("binary"); + let binary_output = std::process::Command::new("ld") + .args([ + "-s", + "-o", + &binary_path.display().to_string(), + &object_path.display().to_string(), + ]) + .output() + .unwrap(); + assert_eq!( + binary_output.stdout, + [], + "{}", + std::str::from_utf8(&binary_output.stdout).unwrap() + ); + assert_eq!( + binary_output.stderr, + [], + "{}", + std::str::from_utf8(&binary_output.stderr).unwrap() + ); + assert_eq!(binary_output.status.code(), Some(0)); + // Write binary hash + let mut binary_buffer = Vec::new(); + let mut binary_file = OpenOptions::new().read(true).open(&binary_path).unwrap(); + binary_file.read_to_end(&mut binary_buffer).unwrap(); + let binary_hash = HEXUPPER.encode(sha256_digest(binary_buffer.as_slice()).unwrap().as_ref()); + let binary_file_name = binary_path.file_stem().unwrap(); + writeln!( + &mut lock_file, + "{},{binary_hash}", + binary_file_name.to_str().unwrap() + ) + .unwrap(); +} - write_file( - path, - PathBuf::from("included").with_extension(LANGUAGE_EXTENSION), - &bytes, - &mut lock_file, - ); - Some(lock_file) - } else { - None - }; +fn run(path: Option) { + build(path.clone()); + let project_path = path.unwrap_or(PathBuf::from("./")); + std::process::Command::new( + &project_path + .join("build") + .join("binary") + .display() + .to_string(), + ) + .spawn() + .unwrap(); +} - // Parses AST - let reader = std::io::BufReader::new(bytes.as_slice()); - let mut iter = reader.bytes().peekable(); - let nodes = get_nodes(&mut iter).unwrap(); - - // Inlines functions - let inlined = inline_functions(nodes); - if let Some(path) = &path_opt { - let inlined_string = display_ast(inlined); - write_file( - path, - PathBuf::from("inlined").with_extension(LANGUAGE_EXTENSION), - inlined_string.as_bytes(), - lock.as_mut().unwrap(), - ); - } +#[allow(unreachable_code)] +fn main() { + let args = Args::from(std::env::args().collect::>()); - // Explores states - let roots = roots(inlined); - let mut explorer = Explorer::new(&roots); - let path = loop { - match explorer.next() { - Explore::Current(_) => continue, - Explore::Finished(x) => break x, + match args { + Args::New(Some(path)) => { + if !path.exists() { + std::fs::create_dir(&path).unwrap(); } - }; - - // Optimize source - let optimized = optimize(path); - if let Some(path) = &path_opt { - let optimized_string = display_ast(optimized); - write_file( - path, - PathBuf::from("optimized").with_extension(LANGUAGE_EXTENSION), - optimized_string.as_bytes(), - lock.as_mut().unwrap(), - ); - } - - // panic!("does not hit this"); - - // Construct assembly - let assembly = assembly_from_node(optimized); - if let Some(path) = path_opt { - let assembly_path = PathBuf::from("assembly").with_extension("s"); - write_file( - &path, - assembly_path.clone(), - assembly.as_bytes(), - lock.as_mut().unwrap(), - ); - - let object_path = path.join("build").join("object").with_extension("o"); - let object_output = std::process::Command::new("as") - .args([ - "-o", - &object_path.display().to_string(), - &path.join("build").join(assembly_path).display().to_string(), - ]) - .output() - .unwrap(); - assert_eq!( - object_output.stdout, - [], - "{}", - std::str::from_utf8(&object_output.stdout).unwrap() - ); - assert_eq!( - object_output.stderr, - [], - "{}", - std::str::from_utf8(&object_output.stderr).unwrap() - ); - assert_eq!(object_output.status.code(), Some(0)); - - // Write object hash - let mut object_buffer = Vec::new(); - let mut object_file = OpenOptions::new().read(true).open(&object_path).unwrap(); - object_file.read_to_end(&mut object_buffer).unwrap(); - let object_hash = - HEXUPPER.encode(sha256_digest(object_buffer.as_slice()).unwrap().as_ref()); - let object_file_name = object_path.file_stem().unwrap(); - writeln!( - lock.as_mut().unwrap(), - "{},{object_hash}", - object_file_name.to_str().unwrap() - ) - .unwrap(); - - let binary_path = path.join("build").join("binary"); - let binary_output = std::process::Command::new("ld") - .args([ - "-s", - "-o", - &binary_path.display().to_string(), - &object_path.display().to_string(), - ]) - .output() + let mut source = OpenOptions::new() + .create(true) + .write(true) + .open(path.join("source").with_extension(LANGUAGE_EXTENSION)) .unwrap(); - assert_eq!( - binary_output.stdout, - [], - "{}", - std::str::from_utf8(&binary_output.stdout).unwrap() - ); - assert_eq!( - binary_output.stderr, - [], - "{}", - std::str::from_utf8(&binary_output.stderr).unwrap() - ); - assert_eq!(binary_output.status.code(), Some(0)); - - // Write binary hash - let mut binary_buffer = Vec::new(); - let mut binary_file = OpenOptions::new().read(true).open(&binary_path).unwrap(); - binary_file.read_to_end(&mut binary_buffer).unwrap(); - let binary_hash = - HEXUPPER.encode(sha256_digest(binary_buffer.as_slice()).unwrap().as_ref()); - let binary_file_name = binary_path.file_stem().unwrap(); - writeln!( - lock.as_mut().unwrap(), - "{},{binary_hash}", - binary_file_name.to_str().unwrap() - ) - .unwrap(); - } else { - std::io::stdout().write_all(assembly.as_bytes()).unwrap(); + source.write_all(b"\ + include https://raw.githubusercontent.com/JonathanWoollett-Light/language/master/syscalls.lang\n\ + x := \"Hello, World!\\n\"\n\ + write 1 x\n\ + exit 0\n\ + ").unwrap(); } + Args::Build(path) => build(path), + Args::Run(path) => run(path), + _ => todo!(), } } @@ -460,7 +475,7 @@ mod tests { } else { loop { match explorer.next() { - Explore::Current(current) => {} + Explore::Current(_) => {} Explore::Finished(finished) => break finished, } } @@ -474,7 +489,7 @@ mod tests { fn test_optimization( nodes: NonNull, expected_build: &[Statement], - expected_read: HashSet, + expected_read: HashSet, expected_finish: &[Statement], ) -> NonNull { println!("test_optimization"); @@ -570,20 +585,21 @@ mod tests { } fn ident(s: &str) -> TypeKey { - TypeKey::Variable(Variable { - addressing: Addressing::Direct, + TypeKey::Variable(VariableAlias { identifier: s.bytes().collect::>(), index: None, }) } + const SYSCALLS: &str = include_str!("../syscalls.lang"); + #[test] fn one() { - const SOURCE: &str = "exit 0"; + let source = format!("{SYSCALLS}\nexit 0"); // Parsing let nodes = test_parsing( - SOURCE, + &source, &[Statement { comptime: false, op: Op::Syscall(Syscall::Exit), @@ -1757,7 +1773,7 @@ mod tests { arg: vec![Value::Variable(Variable::new("a"))], }, ], - HashSet::from([Variable::from("a")]), + HashSet::from([VariableAlias::from("a")]), &[ Statement { comptime: false, @@ -2054,7 +2070,7 @@ mod tests { arg: vec![Value::Literal(Literal::Integer(0))], }, ], - HashSet::from([Variable::from("a")]), + HashSet::from([VariableAlias::from("a")]), &[ Statement { comptime: false, @@ -3079,27 +3095,60 @@ mod tests { let path = test_exploration( inlined, &[ - TypeValueState::from([(TypeKey::from(Variable::from("a")), TypeValue::from(0i64))]), - TypeValueState::from([(TypeKey::from(Variable::from("a")), TypeValue::from(0i32))]), - TypeValueState::from([(TypeKey::from(Variable::from("a")), TypeValue::from(0i16))]), - TypeValueState::from([(TypeKey::from(Variable::from("a")), TypeValue::from(0i8))]), - TypeValueState::from([(TypeKey::from(Variable::from("a")), TypeValue::from(0u64))]), - TypeValueState::from([(TypeKey::from(Variable::from("a")), TypeValue::from(0u32))]), - TypeValueState::from([(TypeKey::from(Variable::from("a")), TypeValue::from(0u16))]), - TypeValueState::from([(TypeKey::from(Variable::from("a")), TypeValue::from(0u8))]), + TypeValueState::from([( + TypeKey::from(VariableAlias::from("a")), + TypeValue::from(0i64), + )]), + TypeValueState::from([( + TypeKey::from(VariableAlias::from("a")), + TypeValue::from(0i32), + )]), + TypeValueState::from([( + TypeKey::from(VariableAlias::from("a")), + TypeValue::from(0i16), + )]), + TypeValueState::from([( + TypeKey::from(VariableAlias::from("a")), + TypeValue::from(0i8), + )]), + TypeValueState::from([( + TypeKey::from(VariableAlias::from("a")), + TypeValue::from(0u64), + )]), + TypeValueState::from([( + TypeKey::from(VariableAlias::from("a")), + TypeValue::from(0u32), + )]), + TypeValueState::from([( + TypeKey::from(VariableAlias::from("a")), + TypeValue::from(0u16), + )]), + TypeValueState::from([( + TypeKey::from(VariableAlias::from("a")), + TypeValue::from(0u8), + )]), ], None, &[ - TypeValueState::from([(TypeKey::from(Variable::from("a")), TypeValue::from(0u8))]), + TypeValueState::from([( + TypeKey::from(VariableAlias::from("a")), + TypeValue::from(0u8), + )]), TypeValueState::from([ - (TypeKey::from(Variable::from("a")), TypeValue::from(0u8)), + ( + TypeKey::from(VariableAlias::from("a")), + TypeValue::from(0u8), + ), ( TypeKey::from(Register::X8), TypeValue::try_from(93u64).unwrap(), ), ]), TypeValueState::from([ - (TypeKey::from(Variable::from("a")), TypeValue::from(0u8)), + ( + TypeKey::from(VariableAlias::from("a")), + TypeValue::from(0u8), + ), ( TypeKey::from(Register::X8), TypeValue::try_from(93u64).unwrap(), @@ -3110,7 +3159,10 @@ mod tests { ), ]), TypeValueState::from([ - (TypeKey::from(Variable::from("a")), TypeValue::from(0u8)), + ( + TypeKey::from(VariableAlias::from("a")), + TypeValue::from(0u8), + ), ( TypeKey::from(Register::X8), TypeValue::try_from(93u64).unwrap(), @@ -3121,7 +3173,10 @@ mod tests { ), ]), TypeValueState::from([ - (TypeKey::from(Variable::from("a")), TypeValue::from(0u8)), + ( + TypeKey::from(VariableAlias::from("a")), + TypeValue::from(0u8), + ), ( TypeKey::from(Register::X8), TypeValue::try_from(93u64).unwrap(), diff --git a/src/middle.rs b/src/middle.rs index 888d611..acab2b7 100644 --- a/src/middle.rs +++ b/src/middle.rs @@ -1023,8 +1023,8 @@ pub unsafe fn roots(node: NonNull) -> Vec> { #[derive(Debug, Eq, PartialEq, Default, Clone, Hash)] pub struct VariableAlias { - identifier: Identifier, - index: Option>, + pub identifier: Identifier, + pub index: Option>, } impl From<&str> for VariableAlias { diff --git a/tests/integration_tests.rs b/tests/integration_tests.rs index 656c6f3..ae6dfa5 100644 --- a/tests/integration_tests.rs +++ b/tests/integration_tests.rs @@ -1,94 +1,46 @@ -use std::fs::{remove_file, OpenOptions}; +use std::fs::{remove_dir_all, OpenOptions}; use std::io::Write; +use std::path::PathBuf; use std::process::Command; use uuid::Uuid; const BINARY: &str = env!("CARGO_BIN_EXE_language"); +const SOURCE_FILE: &str = "source.abc"; +use std::str::from_utf8; + #[test] -fn helloworld() { - const SOURCE: &str = "x := \"Hello, World!\n\"\nwrite 1 x\nexit 0"; - const EXPECTED_ASSEMBLY: &[u8] = b".global _start\n_start:\nmov x8, #64\nmov x0, #1\nldr x1, =a\nmov x2, #14\nsvc #0\nmov x8, #93\nmov x0, #0\nsvc #0\n.data\na: .byte 72,101,108,108,111,44,32,87,111,114,108,100,33,10\n"; - const EXPECTED_EXIT_CODE: i32 = 0; - const EXPECTED_STDOUT: &[u8] = b"Hello, World!\n"; +fn helloworld_new() { + const SOURCE: &[u8] = b"include https://raw.githubusercontent.com/JonathanWoollett-Light/language/master/syscalls.lang\nx := \"Hello, World!\\n\"\nwrite 1 &x\nexit 0"; + let directory = PathBuf::from(format!("/tmp/a{}", Uuid::new_v4())); let output = Command::new(BINARY) - .args(["--source", SOURCE]) + .args(["--new", &directory.display().to_string()]) .output() .unwrap(); - assert_eq!(output.stderr, &[]); - assert_eq!( - output.stdout, - EXPECTED_ASSEMBLY, - "\n{:?} !=\n{:?}", - std::str::from_utf8(&output.stdout).unwrap(), - std::str::from_utf8(EXPECTED_ASSEMBLY).unwrap() - ); + assert_eq!(output.stderr, &[], "{}", from_utf8(&output.stderr).unwrap()); + assert_eq!(output.stdout, &[], "{}", from_utf8(&output.stdout).unwrap()); assert_eq!(output.status.code(), Some(0)); - let path = format!("/tmp/{}", Uuid::new_v4()); - let assembly_path = format!("{path}.s"); - let mut file = OpenOptions::new() - .create(true) + let mut source_file = OpenOptions::new() + .truncate(true) .write(true) - .open(&assembly_path) + .open(directory.join(SOURCE_FILE)) .unwrap(); - file.write_all(&output.stdout).unwrap(); - let object_path = format!("{path}.o"); - let output = Command::new("as") - .args(["-o", &object_path, &assembly_path]) - .output() - .unwrap(); - assert_eq!( - output.stderr, - [], - "{}", - std::str::from_utf8(&output.stderr).unwrap() - ); - assert_eq!( - output.stdout, - [], - "{}", - std::str::from_utf8(&output.stdout).unwrap() - ); - assert_eq!(output.status.code(), Some(0)); - remove_file(assembly_path).unwrap(); + source_file.write_all(SOURCE).unwrap(); - let output = Command::new("ld") - .args(["-s", "-o", &path, &object_path]) + let output = Command::new(BINARY) + .args(["--run", &directory.display().to_string()]) .output() .unwrap(); - assert_eq!( - output.stderr, - [], - "{}", - std::str::from_utf8(&output.stderr).unwrap() - ); + assert_eq!(output.stderr, &[], "{}", from_utf8(&output.stderr).unwrap()); assert_eq!( output.stdout, - [], + b"Hello, World!\n", "{}", - std::str::from_utf8(&output.stdout).unwrap() + from_utf8(&output.stdout).unwrap() ); assert_eq!(output.status.code(), Some(0)); - remove_file(object_path).unwrap(); - let output = Command::new(&path).output().unwrap(); - assert_eq!( - output.stderr, - [], - "{}", - std::str::from_utf8(&output.stderr).unwrap() - ); - assert_eq!( - output.stdout, - EXPECTED_STDOUT, - "{}", - std::str::from_utf8(&output.stdout).unwrap() - ); - assert_eq!(output.status.code(), Some(EXPECTED_EXIT_CODE)); - remove_file(path).unwrap(); + remove_dir_all(directory).unwrap(); } - -#[test] -fn new_project() {}