Compare commits
No commits in common. "55239ba7c095acc2b4930a2e0dbe0c154bab49c9" and "1cc295a63bef041574b3a7626b27f56569313ac8" have entirely different histories.
55239ba7c0
...
1cc295a63b
|
@ -2,291 +2,6 @@
|
||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
version = 3
|
version = 3
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "addr2line"
|
|
||||||
version = "0.21.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb"
|
|
||||||
dependencies = [
|
|
||||||
"gimli",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "adler"
|
|
||||||
version = "1.0.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "aho-corasick"
|
|
||||||
version = "1.1.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0"
|
|
||||||
dependencies = [
|
|
||||||
"memchr",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "alchimake"
|
name = "alchimake"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
|
||||||
"regex",
|
|
||||||
"sha256",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "async-trait"
|
|
||||||
version = "0.1.77"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "c980ee35e870bd1a4d2c8294d4c04d0499e67bca1e4b5cefcc693c2fa00caea9"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "backtrace"
|
|
||||||
version = "0.3.69"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837"
|
|
||||||
dependencies = [
|
|
||||||
"addr2line",
|
|
||||||
"cc",
|
|
||||||
"cfg-if",
|
|
||||||
"libc",
|
|
||||||
"miniz_oxide",
|
|
||||||
"object",
|
|
||||||
"rustc-demangle",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "block-buffer"
|
|
||||||
version = "0.10.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
|
|
||||||
dependencies = [
|
|
||||||
"generic-array",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "bytes"
|
|
||||||
version = "1.5.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "cc"
|
|
||||||
version = "1.0.90"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "8cd6604a82acf3039f1144f54b8eb34e91ffba622051189e71b781822d5ee1f5"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "cfg-if"
|
|
||||||
version = "1.0.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "cpufeatures"
|
|
||||||
version = "0.2.12"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "crypto-common"
|
|
||||||
version = "0.1.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
|
|
||||||
dependencies = [
|
|
||||||
"generic-array",
|
|
||||||
"typenum",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "digest"
|
|
||||||
version = "0.10.7"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
|
|
||||||
dependencies = [
|
|
||||||
"block-buffer",
|
|
||||||
"crypto-common",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "generic-array"
|
|
||||||
version = "0.14.7"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
|
|
||||||
dependencies = [
|
|
||||||
"typenum",
|
|
||||||
"version_check",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "gimli"
|
|
||||||
version = "0.28.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "hex"
|
|
||||||
version = "0.4.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "libc"
|
|
||||||
version = "0.2.153"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "memchr"
|
|
||||||
version = "2.7.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "miniz_oxide"
|
|
||||||
version = "0.7.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7"
|
|
||||||
dependencies = [
|
|
||||||
"adler",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "object"
|
|
||||||
version = "0.32.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441"
|
|
||||||
dependencies = [
|
|
||||||
"memchr",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "pin-project-lite"
|
|
||||||
version = "0.2.13"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "proc-macro2"
|
|
||||||
version = "1.0.78"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae"
|
|
||||||
dependencies = [
|
|
||||||
"unicode-ident",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "quote"
|
|
||||||
version = "1.0.35"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "regex"
|
|
||||||
version = "1.10.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15"
|
|
||||||
dependencies = [
|
|
||||||
"aho-corasick",
|
|
||||||
"memchr",
|
|
||||||
"regex-automata",
|
|
||||||
"regex-syntax",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "regex-automata"
|
|
||||||
version = "0.4.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea"
|
|
||||||
dependencies = [
|
|
||||||
"aho-corasick",
|
|
||||||
"memchr",
|
|
||||||
"regex-syntax",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "regex-syntax"
|
|
||||||
version = "0.8.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rustc-demangle"
|
|
||||||
version = "0.1.23"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "sha2"
|
|
||||||
version = "0.10.8"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
"cpufeatures",
|
|
||||||
"digest",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "sha256"
|
|
||||||
version = "1.5.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "18278f6a914fa3070aa316493f7d2ddfb9ac86ebc06fa3b83bffda487e9065b0"
|
|
||||||
dependencies = [
|
|
||||||
"async-trait",
|
|
||||||
"bytes",
|
|
||||||
"hex",
|
|
||||||
"sha2",
|
|
||||||
"tokio",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "syn"
|
|
||||||
version = "2.0.52"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b699d15b36d1f02c3e7c69f8ffef53de37aefae075d8488d4ba1a7788d574a07"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"unicode-ident",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "tokio"
|
|
||||||
version = "1.36.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "61285f6515fa018fb2d1e46eb21223fff441ee8db5d0f1435e8ab4f5cdb80931"
|
|
||||||
dependencies = [
|
|
||||||
"backtrace",
|
|
||||||
"bytes",
|
|
||||||
"pin-project-lite",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "typenum"
|
|
||||||
version = "1.17.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "unicode-ident"
|
|
||||||
version = "1.0.12"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "version_check"
|
|
||||||
version = "0.9.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
|
||||||
|
|
|
@ -6,5 +6,3 @@ edition = "2021"
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
regex = "1.10.3"
|
|
||||||
sha256 = "1.5.0"
|
|
||||||
|
|
63
src/app.rs
63
src/app.rs
|
@ -1,63 +0,0 @@
|
||||||
use std::path::PathBuf;
|
|
||||||
use crate::cli::parse;
|
|
||||||
use crate::core::conf::Conf;
|
|
||||||
use crate::core::build_env::BuildEnv;
|
|
||||||
|
|
||||||
pub struct App {
|
|
||||||
conf: Conf
|
|
||||||
}
|
|
||||||
|
|
||||||
impl App {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self {
|
|
||||||
conf: Conf::new()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn init(&mut self) -> Result<(), Box<dyn std::error::Error>> {
|
|
||||||
let mut args = parse::Args::new();
|
|
||||||
let sys_args: Vec<String> = std::env::args().collect();
|
|
||||||
|
|
||||||
args.register(&vec!["-h", "--help"])
|
|
||||||
.description("show this help")
|
|
||||||
.callback(Box::new(|_, ctx| {
|
|
||||||
println!("{}", ctx.help);
|
|
||||||
std::process::exit(0);
|
|
||||||
}));
|
|
||||||
|
|
||||||
args.register(&vec!["-v", "--version"])
|
|
||||||
.description("show alchimake version")
|
|
||||||
.callback(Box::new(|_, _| {
|
|
||||||
println!("Alchimake v0.0.0");
|
|
||||||
println!("Copyright (C) 2024 bog");
|
|
||||||
println!("Licensed under the GPLv3+ (see LICENSE)");
|
|
||||||
std::process::exit(0);
|
|
||||||
}));
|
|
||||||
|
|
||||||
args.register(&vec!["-s", "--source"])
|
|
||||||
.description("set the source directory")
|
|
||||||
.callback(Box::new(|value, _| {
|
|
||||||
if let Some(val) = value {
|
|
||||||
self.conf.src_dir = PathBuf::from(val);
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
|
|
||||||
args.register(&vec!["-b", "--build"])
|
|
||||||
.description("set the build directory")
|
|
||||||
.callback(Box::new(|value, _| {
|
|
||||||
if let Some(val) = value {
|
|
||||||
self.conf.build_dir = PathBuf::from(val);
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
|
|
||||||
args.parse(&sys_args.iter().map(|v| v.as_str()).collect())?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn start(&mut self) -> Result<(), Box<dyn std::error::Error>> {
|
|
||||||
let mut benv = BuildEnv::new(&self.conf);
|
|
||||||
benv.init_build_dir()?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -23,19 +23,19 @@ pub struct Context {
|
||||||
pub help: String
|
pub help: String
|
||||||
}
|
}
|
||||||
|
|
||||||
type Callback<'a> = Box<dyn FnMut(Option<String>, Context) + 'a>;
|
type Callback = Box<dyn Fn(Option<String>, Context)>;
|
||||||
|
|
||||||
pub struct Arg<'a> {
|
pub struct Arg {
|
||||||
pub flags: Vec<String>,
|
pub flags: Vec<String>,
|
||||||
pub description: Option<String>,
|
pub description: Option<String>,
|
||||||
pub callback: Option<Callback<'a>>
|
pub callback: Option<Callback>
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Args<'a> {
|
pub struct Args {
|
||||||
args: Vec<Arg<'a>>,
|
args: Vec<Arg>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Args<'a> {
|
impl Args {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
args: vec![]
|
args: vec![]
|
||||||
|
@ -45,7 +45,6 @@ impl<'a> Args<'a> {
|
||||||
pub fn help(&self) -> String {
|
pub fn help(&self) -> String {
|
||||||
let mut res = String::from("Usage: alchimake [OPTION]...\n");
|
let mut res = String::from("Usage: alchimake [OPTION]...\n");
|
||||||
res += "OPTIONS:\n";
|
res += "OPTIONS:\n";
|
||||||
|
|
||||||
for arg in self.args.iter() {
|
for arg in self.args.iter() {
|
||||||
if let Some(description) = &arg.description {
|
if let Some(description) = &arg.description {
|
||||||
res += format!(
|
res += format!(
|
||||||
|
@ -68,7 +67,7 @@ impl<'a> Args<'a> {
|
||||||
for arg in self.args.iter_mut() {
|
for arg in self.args.iter_mut() {
|
||||||
for flag in arg.flags.iter() {
|
for flag in arg.flags.iter() {
|
||||||
if &flag == cli_arg {
|
if &flag == cli_arg {
|
||||||
if let Some(ref mut callback) = arg.callback {
|
if let Some(ref callback) = arg.callback {
|
||||||
let value = getval(&args, &flag)?;
|
let value = getval(&args, &flag)?;
|
||||||
callback(value.clone(), Context {
|
callback(value.clone(), Context {
|
||||||
help: help.clone()
|
help: help.clone()
|
||||||
|
@ -100,16 +99,9 @@ impl<'a> Args<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn callback(&mut self,
|
pub fn callback(&mut self,
|
||||||
callback: Callback<'a>) -> &mut Self{
|
callback: Callback) -> &mut Self{
|
||||||
let idx = self.args.len() - 1;
|
let idx = self.args.len() - 1;
|
||||||
self.args[idx].callback = Some(Box::new(callback));
|
self.args[idx].callback = Some(Box::new(callback));
|
||||||
self.args.sort_by_cached_key(|a| {
|
|
||||||
if let Some(val) = a.flags.get(0) {
|
|
||||||
val.clone()
|
|
||||||
} else {
|
|
||||||
String::from("")
|
|
||||||
}
|
|
||||||
});
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,131 +0,0 @@
|
||||||
use std::error::Error;
|
|
||||||
use std::io::Read;
|
|
||||||
use std::path::{Path, PathBuf};
|
|
||||||
use crate::core::conf::Conf;
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
struct FileInfo {
|
|
||||||
pub path: PathBuf,
|
|
||||||
pub sha: String
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct BuildEnv {
|
|
||||||
conf: Conf,
|
|
||||||
files: Vec<FileInfo>,
|
|
||||||
checksum_file_path: PathBuf
|
|
||||||
}
|
|
||||||
|
|
||||||
impl BuildEnv {
|
|
||||||
pub fn new(conf: &Conf) -> Self {
|
|
||||||
Self {
|
|
||||||
conf: conf.clone(),
|
|
||||||
files: vec![],
|
|
||||||
checksum_file_path: conf.build_dir.join("checksum.txt")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn init_build_dir(&mut self) -> Result<(), Box<dyn Error>>{
|
|
||||||
if !self.conf.build_dir.as_path().exists() {
|
|
||||||
std::fs::create_dir(&self.conf.build_dir)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
if !self.checksum_file_path.as_path().exists() {
|
|
||||||
std::fs::write(&self.checksum_file_path, b"")?;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.load_checksum()?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_up_to_date(&mut self, file_path: &Path) -> Result<bool, Box<dyn Error>> {
|
|
||||||
let mut f = std::fs::File::open(file_path)?;
|
|
||||||
let mut content = String::from("");
|
|
||||||
f.read_to_string(&mut content)?;
|
|
||||||
let sha: String = sha256::digest(content);
|
|
||||||
|
|
||||||
if let Some(idx) = self.files.iter().position(|x| {
|
|
||||||
x.path.canonicalize().unwrap()
|
|
||||||
== file_path.canonicalize().unwrap()
|
|
||||||
}) {
|
|
||||||
return Ok(self.files.get(idx).unwrap().sha == sha);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(false)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn update(&mut self, file_path: &Path) -> Result <(), Box<dyn Error>>{
|
|
||||||
let mut f = std::fs::File::open(file_path)?;
|
|
||||||
let mut content = String::from("");
|
|
||||||
f.read_to_string(&mut content)?;
|
|
||||||
let sha = sha256::digest(content);
|
|
||||||
|
|
||||||
if let Some(idx) = self.files.iter().position(|x| {
|
|
||||||
x.path.canonicalize().unwrap()
|
|
||||||
== file_path.canonicalize().unwrap()
|
|
||||||
}) {
|
|
||||||
self.files.get_mut(idx).unwrap().sha = sha;
|
|
||||||
} else {
|
|
||||||
self.files.push(FileInfo {
|
|
||||||
path: PathBuf::from(file_path),
|
|
||||||
sha
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
self.save_checksum()?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn load_checksum(&mut self) -> Result<(), Box<dyn Error>>{
|
|
||||||
let mut file = std::fs::File::open(
|
|
||||||
self.checksum_file_path.as_path()
|
|
||||||
)?;
|
|
||||||
|
|
||||||
let mut content = String::from("");
|
|
||||||
file.read_to_string(&mut content)?;
|
|
||||||
|
|
||||||
self.files.clear();
|
|
||||||
|
|
||||||
for line in content.split('\n') {
|
|
||||||
if line.len() == 0 {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
let info: Vec<String> = line.split(' ').map(
|
|
||||||
|s| s.to_string()
|
|
||||||
).collect();
|
|
||||||
|
|
||||||
let f = FileInfo {
|
|
||||||
path: PathBuf::from(info.get(0).unwrap()),
|
|
||||||
sha: info.get(1).unwrap().to_owned()
|
|
||||||
};
|
|
||||||
|
|
||||||
self.files.push(f);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn save_checksum(&self) -> Result<(), Box<dyn Error>> {
|
|
||||||
let mut content = String::from("");
|
|
||||||
|
|
||||||
for file in self.files.iter() {
|
|
||||||
content += format!("{} {}",
|
|
||||||
file.path.canonicalize()?.to_str().unwrap(),
|
|
||||||
file.sha
|
|
||||||
).as_str();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::fs::write(
|
|
||||||
self.checksum_file_path.as_path(),
|
|
||||||
content.as_bytes()
|
|
||||||
)?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod test {
|
|
||||||
}
|
|
|
@ -1,15 +0,0 @@
|
||||||
use crate::core::value::Value;
|
|
||||||
use crate::core::expr::Expr;
|
|
||||||
|
|
||||||
pub trait Command {
|
|
||||||
fn params(&self) -> Vec<Expr> { vec![] }
|
|
||||||
fn requires(&self) -> Vec<Expr> { vec![] }
|
|
||||||
fn provides(&self) -> Vec<Expr> { vec![] }
|
|
||||||
fn call(&mut self, args: Vec<Value>) -> Value;
|
|
||||||
fn clone_box(&self) -> Box<dyn Command>;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod test {
|
|
||||||
use super::*;
|
|
||||||
}
|
|
|
@ -1,18 +0,0 @@
|
||||||
use std::path::PathBuf;
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct Conf {
|
|
||||||
pub src_dir: PathBuf,
|
|
||||||
pub build_dir: PathBuf
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Conf {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self {
|
|
||||||
src_dir: PathBuf::from("."),
|
|
||||||
build_dir: PathBuf::from(".")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
268
src/core/eval.rs
268
src/core/eval.rs
|
@ -1,268 +0,0 @@
|
||||||
use regex::Regex;
|
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::error::Error;
|
|
||||||
use crate::core::{
|
|
||||||
value::Value,
|
|
||||||
expr::Expr,
|
|
||||||
sym::Sym,
|
|
||||||
cmd::Command,
|
|
||||||
conf::Conf
|
|
||||||
};
|
|
||||||
|
|
||||||
pub struct Evaluator {
|
|
||||||
sym: Sym,
|
|
||||||
commands: HashMap<String, Box<dyn Command>>,
|
|
||||||
conf: Conf
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Evaluator {
|
|
||||||
pub fn new(sym: Sym, conf: Conf) -> Self {
|
|
||||||
Self {
|
|
||||||
sym,
|
|
||||||
commands: HashMap::new(),
|
|
||||||
conf
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn run(&mut self, expr: &Expr) -> Result<Value, Box<dyn Error>> {
|
|
||||||
match expr {
|
|
||||||
Expr::File(rel_path) => {
|
|
||||||
fn replace_path(dir: &std::path::Path, prefix: &str, rel_path: &str)
|
|
||||||
-> Result<Value, Box<dyn Error>> {
|
|
||||||
let re = Regex::new(&format!("{}://([^)]*)", prefix)).unwrap();
|
|
||||||
if let Some(path) = re.captures(rel_path) {
|
|
||||||
Ok(Value::String(
|
|
||||||
dir.join(
|
|
||||||
path[1].to_string()
|
|
||||||
).to_str().unwrap().to_string(),
|
|
||||||
))
|
|
||||||
} else {
|
|
||||||
Err(String::from("wrong path").into())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Ok(res) = replace_path(&self.conf.src_dir, "src", rel_path) {
|
|
||||||
Ok(res)
|
|
||||||
} else if let Ok(res) = replace_path(&self.conf.build_dir, "build", rel_path) {
|
|
||||||
Ok(res)
|
|
||||||
} else {
|
|
||||||
Err(format!("wrong path {}", rel_path).into())
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Expr::BuiltIn(value) => Ok(value.clone()),
|
|
||||||
Expr::Ident(value) => {
|
|
||||||
if let Some(val) = self.sym.get(value) {
|
|
||||||
Ok(val)
|
|
||||||
} else {
|
|
||||||
Err(format!("'{}' is not declared", value).into())
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
Expr::Call(value, args) => {
|
|
||||||
let mut val_args: Vec<Value> = vec![];
|
|
||||||
|
|
||||||
for arg in args {
|
|
||||||
val_args.push(self.run(arg)?);
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut name = String::from("");
|
|
||||||
|
|
||||||
match self.sym.get(value) {
|
|
||||||
Some(Value::Command(n)) => {name = n;}
|
|
||||||
None => {
|
|
||||||
return Err(
|
|
||||||
format!(
|
|
||||||
"command '{}' is not declared",
|
|
||||||
value).into()
|
|
||||||
);
|
|
||||||
},
|
|
||||||
_ => {
|
|
||||||
return Err(
|
|
||||||
format!(
|
|
||||||
"'{}' is not a command",
|
|
||||||
value).into()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
match self.commands.get_mut(&name) {
|
|
||||||
Some(cmd) => {
|
|
||||||
Ok(cmd.call(val_args))
|
|
||||||
},
|
|
||||||
|
|
||||||
None => Err(
|
|
||||||
format!(
|
|
||||||
"command '{}' is not declared",
|
|
||||||
value).into()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
_ => Err(format!("unknown expr {:?}", expr).into())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new_command(&mut self, name: &str, cmd: Box<dyn Command>) {
|
|
||||||
self.commands.insert(name.to_string(), cmd);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn clone_sym(&self) -> Sym {
|
|
||||||
self.sym.clone()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn getsym<U>(&mut self, callback: U)
|
|
||||||
where U: Fn(&mut Sym) {
|
|
||||||
callback(&mut self.sym);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Clone for Evaluator {
|
|
||||||
fn clone(&self) -> Self {
|
|
||||||
let mut c = Evaluator::new(self.sym.clone(), self.conf.clone());
|
|
||||||
for cmd in self.commands.iter() {
|
|
||||||
c.commands.insert(cmd.0.to_string(), cmd.1.clone_box());
|
|
||||||
}
|
|
||||||
c
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mod test {
|
|
||||||
use super::*;
|
|
||||||
type TestResult = Result<(), Box<dyn std::error::Error>>;
|
|
||||||
|
|
||||||
fn test_eval_init<U>(expr: Expr, value: Value, init: U)
|
|
||||||
-> TestResult
|
|
||||||
where U: Fn(&mut Evaluator) {
|
|
||||||
let sym = Sym::new();
|
|
||||||
let mut conf = Conf::new();
|
|
||||||
conf.src_dir = std::path::PathBuf::from("/root/source");
|
|
||||||
conf.build_dir = std::path::PathBuf::from("/root/build");
|
|
||||||
|
|
||||||
let mut eval = Evaluator::new(sym, conf);
|
|
||||||
init(&mut eval);
|
|
||||||
let res = eval.run(&expr)?;
|
|
||||||
|
|
||||||
assert_eq!(res, value);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn test_eval(expr: Expr, value: Value) -> TestResult {
|
|
||||||
test_eval_init(expr, value, |_| {})
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn builtins() -> TestResult {
|
|
||||||
test_eval(
|
|
||||||
Expr::BuiltIn(Value::Int(42)),
|
|
||||||
Value::Int(42)
|
|
||||||
)?;
|
|
||||||
|
|
||||||
test_eval(
|
|
||||||
Expr::BuiltIn(Value::String("hello".to_string())),
|
|
||||||
Value::String("hello".to_string())
|
|
||||||
)?;
|
|
||||||
|
|
||||||
test_eval(
|
|
||||||
Expr::BuiltIn(Value::Symbol("hello".to_string())),
|
|
||||||
Value::Symbol("hello".to_string()),
|
|
||||||
)?;
|
|
||||||
|
|
||||||
test_eval(
|
|
||||||
Expr::BuiltIn(Value::Array(vec![
|
|
||||||
Value::Bool(true),
|
|
||||||
Value::Float(3.2),
|
|
||||||
])),
|
|
||||||
|
|
||||||
Value::Array(vec![
|
|
||||||
Value::Bool(true),
|
|
||||||
Value::Float(3.2),
|
|
||||||
]),
|
|
||||||
)?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn ident() -> TestResult {
|
|
||||||
test_eval_init(
|
|
||||||
Expr::Ident(String::from("X")),
|
|
||||||
Value::Symbol(String::from("hello")),
|
|
||||||
|eval| {
|
|
||||||
eval.getsym(|s| {
|
|
||||||
s.assign("X", Value::Symbol("hello".to_string()));
|
|
||||||
})
|
|
||||||
}
|
|
||||||
)?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn command() -> TestResult {
|
|
||||||
#[derive(Clone)]
|
|
||||||
struct MockedCmd {
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Command for MockedCmd {
|
|
||||||
fn call(&mut self, args: Vec<Value>) -> Value {
|
|
||||||
if let Some(Value::Int(val)) = args.get(0) {
|
|
||||||
Value::Int(val * 2)
|
|
||||||
} else {
|
|
||||||
Value::Int(0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn clone_box(&self) -> Box<dyn Command> {
|
|
||||||
Box::new(self.clone())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
test_eval_init(
|
|
||||||
Expr::Call(String::from("X"), vec![Expr::BuiltIn(Value::Int(12))]),
|
|
||||||
Value::Int(24),
|
|
||||||
|eval| {
|
|
||||||
eval.new_command("CMD", Box::new(MockedCmd {}));
|
|
||||||
eval.getsym(|s| {
|
|
||||||
s.assign("X", Value::Command(String::from("CMD")));
|
|
||||||
})
|
|
||||||
}
|
|
||||||
)?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn files() -> TestResult {
|
|
||||||
test_eval(
|
|
||||||
Expr::File(String::from("build://")),
|
|
||||||
Value::String(String::from("/root/build/"))
|
|
||||||
)?;
|
|
||||||
|
|
||||||
test_eval(
|
|
||||||
Expr::File(String::from("build://hello/world.txt")),
|
|
||||||
Value::String(String::from("/root/build/hello/world.txt"))
|
|
||||||
)?;
|
|
||||||
|
|
||||||
test_eval(
|
|
||||||
Expr::File(String::from("build://../parent")),
|
|
||||||
Value::String(String::from("/root/build/../parent"))
|
|
||||||
)?;
|
|
||||||
|
|
||||||
test_eval(
|
|
||||||
Expr::File(String::from("src://")),
|
|
||||||
Value::String(String::from("/root/source/"))
|
|
||||||
)?;
|
|
||||||
|
|
||||||
test_eval(
|
|
||||||
Expr::File(String::from("src://hello/world.txt")),
|
|
||||||
Value::String(String::from("/root/source/hello/world.txt"))
|
|
||||||
)?;
|
|
||||||
|
|
||||||
test_eval(
|
|
||||||
Expr::File(String::from("src://../parent")),
|
|
||||||
Value::String(String::from("/root/source/../parent"))
|
|
||||||
)?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
452
src/core/exec.rs
452
src/core/exec.rs
|
@ -1,452 +0,0 @@
|
||||||
use std::error::Error;
|
|
||||||
use crate::core::{
|
|
||||||
instr::Instr,
|
|
||||||
expr::Expr,
|
|
||||||
value::Value,
|
|
||||||
eval::Evaluator,
|
|
||||||
sym::Sym,
|
|
||||||
cmd::Command,
|
|
||||||
conf::Conf
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
struct UserCmd {
|
|
||||||
pub pams: Vec<Expr>,
|
|
||||||
pub reqs: Vec<Expr>,
|
|
||||||
pub provs: Vec<Expr>,
|
|
||||||
pub body: Vec<Instr>,
|
|
||||||
pub eval: Evaluator
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Command for UserCmd {
|
|
||||||
fn params(&self) -> Vec<Expr> {
|
|
||||||
self.pams.clone()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn requires(&self) -> Vec<Expr> {
|
|
||||||
self.reqs.clone()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn provides(&self) -> Vec<Expr> {
|
|
||||||
self.provs.clone()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn call(&mut self, args: Vec<Value>) -> Value {
|
|
||||||
let mut exec = Executor::new(self.eval.clone());
|
|
||||||
let pams = self.params();
|
|
||||||
|
|
||||||
for (i, arg) in args.iter().enumerate() {
|
|
||||||
let Expr::Ident(ref name) = pams[i] else {
|
|
||||||
return Value::Nil;
|
|
||||||
};
|
|
||||||
|
|
||||||
exec.getsym(move |s| {
|
|
||||||
s.assign(name, arg.clone());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut result = Value::Nil;
|
|
||||||
|
|
||||||
for instr in self.body.iter() {
|
|
||||||
match exec.run(&instr) {
|
|
||||||
Ok(value) => { result = value; }
|
|
||||||
Err(err) => { println!("=> {:?}", err); }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
result
|
|
||||||
}
|
|
||||||
|
|
||||||
fn clone_box(&self) -> Box<dyn Command> {
|
|
||||||
Box::new(self.clone())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Executor {
|
|
||||||
eval: Evaluator
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Executor {
|
|
||||||
pub fn new(eval: Evaluator) -> Self {
|
|
||||||
Self {
|
|
||||||
eval
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub fn getsym<U>(&mut self, callback: U)
|
|
||||||
where U: Fn(&mut Sym) {
|
|
||||||
self.eval.getsym(|s| {
|
|
||||||
callback(s);
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn run(&mut self, instr: &Instr)
|
|
||||||
-> Result<Value, Box<dyn Error>> {
|
|
||||||
match instr {
|
|
||||||
Instr::Module(instrs) => {
|
|
||||||
let mut res: Value = Value::Nil;
|
|
||||||
for instr in instrs {
|
|
||||||
res = self.run(instr)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(res)
|
|
||||||
},
|
|
||||||
|
|
||||||
// ignoring tasks
|
|
||||||
Instr::Task(_, _, _) => { Ok(Value::Nil) },
|
|
||||||
|
|
||||||
Instr::Expr(expr) => {
|
|
||||||
let value = self.eval.run(&expr)?;
|
|
||||||
Ok(value)
|
|
||||||
},
|
|
||||||
|
|
||||||
Instr::Assign(name, exprs) => {
|
|
||||||
let mut values: Vec<Value> = vec![];
|
|
||||||
for expr in exprs {
|
|
||||||
values.push(self.eval.run(expr)?);
|
|
||||||
}
|
|
||||||
self.eval.getsym(|s| {
|
|
||||||
if values.len() == 1 {
|
|
||||||
s.assign(name, values[0].clone());
|
|
||||||
} else {
|
|
||||||
s.assign(name, Value::Array(values.iter().cloned().collect()));
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
Ok(Value::Nil)
|
|
||||||
},
|
|
||||||
|
|
||||||
Instr::AssignIf(name, exprs) => {
|
|
||||||
let mut values: Vec<Value> = vec![];
|
|
||||||
for expr in exprs {
|
|
||||||
values.push(self.eval.run(expr)?);
|
|
||||||
}
|
|
||||||
self.eval.getsym(|s| {
|
|
||||||
if values.len() == 1 {
|
|
||||||
s.assign_if(name, values[0].clone());
|
|
||||||
} else {
|
|
||||||
s.assign_if(name, Value::Array(values.iter().cloned().collect()));
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
Ok(Value::Nil)
|
|
||||||
},
|
|
||||||
|
|
||||||
Instr::AssignArray(name, exprs) => {
|
|
||||||
let mut values: Vec<Value> = vec![];
|
|
||||||
for expr in exprs {
|
|
||||||
values.push(self.eval.run(expr)?);
|
|
||||||
}
|
|
||||||
self.eval.getsym(|s| {
|
|
||||||
if values.len() == 1 {
|
|
||||||
s.assign_array(name, values[0].clone());
|
|
||||||
} else {
|
|
||||||
for val in values.iter() {
|
|
||||||
s.assign_array(name, val.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
Ok(Value::Nil)
|
|
||||||
},
|
|
||||||
|
|
||||||
Instr::Command(name, params,
|
|
||||||
requires, provides, body) => {
|
|
||||||
let cmd = UserCmd {
|
|
||||||
pams: params.clone(),
|
|
||||||
reqs: requires.clone(),
|
|
||||||
provs: provides.clone(),
|
|
||||||
body: body.to_vec(),
|
|
||||||
eval: self.eval.clone()
|
|
||||||
};
|
|
||||||
self.eval.new_command(name, Box::new(cmd));
|
|
||||||
|
|
||||||
self.getsym(|s| {
|
|
||||||
s.assign(name, Value::Command(
|
|
||||||
name.clone()
|
|
||||||
));
|
|
||||||
});
|
|
||||||
|
|
||||||
Ok(Value::Nil)
|
|
||||||
},
|
|
||||||
_ => {
|
|
||||||
Err(format!(
|
|
||||||
"cannot execute unknown instruction: {:?}",
|
|
||||||
instr
|
|
||||||
).into())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod test {
|
|
||||||
use super::*;
|
|
||||||
type TestResult = Result<(), Box<dyn Error>>;
|
|
||||||
|
|
||||||
fn test_exec<T>(instr: Instr, oracle: Value, init: T)
|
|
||||||
-> TestResult
|
|
||||||
where T: Fn(&mut Executor) {
|
|
||||||
let sym = Sym::new();
|
|
||||||
let eval = Evaluator::new(sym, Conf::new());
|
|
||||||
let mut exec = Executor::new(eval);
|
|
||||||
|
|
||||||
init(&mut exec);
|
|
||||||
|
|
||||||
let value = exec.run(
|
|
||||||
&instr
|
|
||||||
)?;
|
|
||||||
|
|
||||||
assert_eq!(value, oracle);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn expr() -> TestResult {
|
|
||||||
test_exec(
|
|
||||||
Instr::Module(vec![
|
|
||||||
Instr::Expr(Expr::BuiltIn(Value::Int(74)))
|
|
||||||
]),
|
|
||||||
Value::Int(74),
|
|
||||||
|_| {}
|
|
||||||
)?;
|
|
||||||
|
|
||||||
test_exec(
|
|
||||||
Instr::Module(vec![
|
|
||||||
Instr::Expr(Expr::Ident(String::from("Y")))
|
|
||||||
]),
|
|
||||||
Value::Float(22.5),
|
|
||||||
|e| { e.getsym(|s|{
|
|
||||||
s.assign("Y", Value::Float(22.5));
|
|
||||||
}); }
|
|
||||||
)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn assign() -> TestResult {
|
|
||||||
// Assign
|
|
||||||
// ======
|
|
||||||
test_exec(
|
|
||||||
Instr::Module(vec![
|
|
||||||
Instr::Assign(
|
|
||||||
String::from("hello"),
|
|
||||||
vec![
|
|
||||||
Expr::BuiltIn(Value::String("bim".to_string())),
|
|
||||||
Expr::BuiltIn(Value::Int(12)),
|
|
||||||
Expr::BuiltIn(Value::Float(3.4))
|
|
||||||
]
|
|
||||||
),
|
|
||||||
Instr::Expr(Expr::Ident(String::from("hello")))
|
|
||||||
]),
|
|
||||||
Value::Array(vec![
|
|
||||||
Value::String("bim".to_string()),
|
|
||||||
Value::Int(12),
|
|
||||||
Value::Float(3.4)
|
|
||||||
]),
|
|
||||||
|_| {}
|
|
||||||
)?;
|
|
||||||
test_exec(
|
|
||||||
Instr::Module(vec![
|
|
||||||
Instr::Assign(
|
|
||||||
String::from("hello"),
|
|
||||||
vec![
|
|
||||||
Expr::BuiltIn(Value::String("bim".to_string()))
|
|
||||||
]
|
|
||||||
),
|
|
||||||
Instr::Assign(
|
|
||||||
String::from("hello"),
|
|
||||||
vec![
|
|
||||||
Expr::BuiltIn(Value::String("bam".to_string()))
|
|
||||||
]
|
|
||||||
),
|
|
||||||
Instr::Expr(Expr::Ident(String::from("hello")))
|
|
||||||
]),
|
|
||||||
Value::String("bam".to_string()),
|
|
||||||
|_| {}
|
|
||||||
)?;
|
|
||||||
|
|
||||||
test_exec(
|
|
||||||
Instr::Module(vec![
|
|
||||||
Instr::Assign(
|
|
||||||
String::from("hello"),
|
|
||||||
vec![
|
|
||||||
Expr::BuiltIn(Value::String("bim".to_string()))
|
|
||||||
]
|
|
||||||
),
|
|
||||||
Instr::Expr(Expr::Ident(String::from("hello")))
|
|
||||||
]),
|
|
||||||
Value::String("bim".to_string()),
|
|
||||||
|_| {}
|
|
||||||
)?;
|
|
||||||
|
|
||||||
// Assign If
|
|
||||||
// =========
|
|
||||||
test_exec(
|
|
||||||
Instr::Module(vec![
|
|
||||||
Instr::AssignIf(
|
|
||||||
String::from("hello"),
|
|
||||||
vec![
|
|
||||||
Expr::BuiltIn(Value::String("bim".to_string()))
|
|
||||||
]
|
|
||||||
),
|
|
||||||
Instr::Expr(Expr::Ident(String::from("hello")))
|
|
||||||
]),
|
|
||||||
Value::String("bim".to_string()),
|
|
||||||
|_| {}
|
|
||||||
)?;
|
|
||||||
|
|
||||||
|
|
||||||
test_exec(
|
|
||||||
Instr::Module(vec![
|
|
||||||
Instr::AssignIf(
|
|
||||||
String::from("hello"),
|
|
||||||
vec![
|
|
||||||
Expr::BuiltIn(Value::String("bim".to_string()))
|
|
||||||
]
|
|
||||||
),
|
|
||||||
Instr::AssignIf(
|
|
||||||
String::from("hello"),
|
|
||||||
vec![
|
|
||||||
Expr::BuiltIn(Value::String("bam".to_string()))
|
|
||||||
]
|
|
||||||
),
|
|
||||||
Instr::Expr(Expr::Ident(String::from("hello")))
|
|
||||||
]),
|
|
||||||
Value::String("bim".to_string()),
|
|
||||||
|_| {}
|
|
||||||
)?;
|
|
||||||
|
|
||||||
// Assign Array
|
|
||||||
// ============
|
|
||||||
test_exec(
|
|
||||||
Instr::Module(vec![
|
|
||||||
Instr::Assign(
|
|
||||||
String::from("hello"),
|
|
||||||
vec![
|
|
||||||
Expr::BuiltIn(Value::String("bim".to_string())),
|
|
||||||
]
|
|
||||||
),
|
|
||||||
Instr::AssignArray(
|
|
||||||
String::from("hello"),
|
|
||||||
vec![
|
|
||||||
Expr::BuiltIn(Value::String("Pizza".to_string()))
|
|
||||||
]
|
|
||||||
),
|
|
||||||
Instr::Expr(Expr::Ident(String::from("hello")))
|
|
||||||
]),
|
|
||||||
Value::Array(vec![
|
|
||||||
Value::String("bim".to_string()),
|
|
||||||
Value::String("Pizza".to_string()),
|
|
||||||
]),
|
|
||||||
|_| {}
|
|
||||||
)?;
|
|
||||||
|
|
||||||
test_exec(
|
|
||||||
Instr::Module(vec![
|
|
||||||
Instr::AssignArray(
|
|
||||||
String::from("hello"),
|
|
||||||
vec![
|
|
||||||
Expr::BuiltIn(Value::String("bim".to_string())),
|
|
||||||
Expr::BuiltIn(Value::String("bam".to_string())),
|
|
||||||
Expr::BuiltIn(Value::String("boom".to_string()))
|
|
||||||
]
|
|
||||||
),
|
|
||||||
Instr::AssignArray(
|
|
||||||
String::from("hello"),
|
|
||||||
vec![
|
|
||||||
Expr::BuiltIn(Value::String("I".to_string())),
|
|
||||||
Expr::BuiltIn(Value::String("Love".to_string())),
|
|
||||||
Expr::BuiltIn(Value::String("Pizza".to_string()))
|
|
||||||
]
|
|
||||||
),
|
|
||||||
Instr::Expr(Expr::Ident(String::from("hello")))
|
|
||||||
]),
|
|
||||||
Value::Array(vec![
|
|
||||||
Value::String("bim".to_string()),
|
|
||||||
Value::String("bam".to_string()),
|
|
||||||
Value::String("boom".to_string()),
|
|
||||||
Value::String("I".to_string()),
|
|
||||||
Value::String("Love".to_string()),
|
|
||||||
Value::String("Pizza".to_string()),
|
|
||||||
]),
|
|
||||||
|_| {}
|
|
||||||
)?;
|
|
||||||
|
|
||||||
test_exec(
|
|
||||||
Instr::Module(vec![
|
|
||||||
Instr::AssignArray(
|
|
||||||
String::from("hello"),
|
|
||||||
vec![
|
|
||||||
Expr::BuiltIn(Value::String("bim".to_string()))
|
|
||||||
]
|
|
||||||
),
|
|
||||||
Instr::Expr(Expr::Ident(String::from("hello")))
|
|
||||||
]),
|
|
||||||
Value::Array(vec![Value::String("bim".to_string())]),
|
|
||||||
|_| {}
|
|
||||||
)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn command() -> TestResult {
|
|
||||||
#[derive(Clone)]
|
|
||||||
struct AddIntCmd {}
|
|
||||||
impl Command for AddIntCmd {
|
|
||||||
fn call(&mut self, args: Vec<Value>) -> Value {
|
|
||||||
let mut res: i32 = 0;
|
|
||||||
|
|
||||||
for arg in args {
|
|
||||||
if let Value::Int(val) = arg {
|
|
||||||
res += val;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Value::Int(res)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn clone_box(&self) -> Box<dyn Command> {
|
|
||||||
Box::new(self.clone())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
test_exec(
|
|
||||||
Instr::Module(vec![
|
|
||||||
Instr::Command(
|
|
||||||
String::from("sum"), // name
|
|
||||||
vec![
|
|
||||||
Expr::Ident(String::from("x")),
|
|
||||||
Expr::Ident(String::from("y")),
|
|
||||||
],// args
|
|
||||||
vec![],// requires
|
|
||||||
vec![],// provides
|
|
||||||
vec![
|
|
||||||
Instr::Expr(
|
|
||||||
Expr::Call(String::from("ADD"), vec![
|
|
||||||
Expr::Ident(String::from("x")),
|
|
||||||
Expr::Ident(String::from("y"))
|
|
||||||
])
|
|
||||||
)
|
|
||||||
]
|
|
||||||
),
|
|
||||||
Instr::Expr(Expr::Call(String::from("sum"), vec![
|
|
||||||
Expr::BuiltIn(Value::Int(32)),
|
|
||||||
Expr::BuiltIn(Value::Int(16)),
|
|
||||||
]))
|
|
||||||
]),
|
|
||||||
Value::Int(48),
|
|
||||||
|exec| {
|
|
||||||
exec.eval.new_command(
|
|
||||||
"ADD",
|
|
||||||
Box::new(AddIntCmd {})
|
|
||||||
);
|
|
||||||
exec.getsym(|s| {
|
|
||||||
s.assign("ADD", Value::Command(String::from("ADD")))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
)?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,11 +0,0 @@
|
||||||
use crate::core::value::Value;
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
#[derive(PartialEq)]
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub enum Expr {
|
|
||||||
BuiltIn(Value),
|
|
||||||
Ident(String),
|
|
||||||
Call(String, Vec<Expr>),
|
|
||||||
File(String)
|
|
||||||
}
|
|
|
@ -1,14 +0,0 @@
|
||||||
use crate::core::expr::Expr;
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
#[derive(PartialEq)]
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub enum Instr {
|
|
||||||
Module(Vec<Instr>),
|
|
||||||
Expr(Expr),
|
|
||||||
Assign(String, Vec<Expr>),
|
|
||||||
AssignIf(String, Vec<Expr>),
|
|
||||||
AssignArray(String, Vec<Expr>),
|
|
||||||
Command(String, Vec<Expr>, Vec<Expr>, Vec<Expr>, Vec<Instr>),
|
|
||||||
Task(String, Vec<Expr>, Vec<Instr>)
|
|
||||||
}
|
|
|
@ -1,9 +0,0 @@
|
||||||
pub mod expr;
|
|
||||||
pub mod instr;
|
|
||||||
pub mod value;
|
|
||||||
pub mod eval;
|
|
||||||
pub mod sym;
|
|
||||||
pub mod cmd;
|
|
||||||
pub mod exec;
|
|
||||||
pub mod conf;
|
|
||||||
pub mod build_env;
|
|
|
@ -1,92 +0,0 @@
|
||||||
use std::collections::HashMap;
|
|
||||||
use crate::core::value::Value;
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub struct Sym {
|
|
||||||
table: HashMap<String, Value>
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Sym {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self {
|
|
||||||
table: HashMap::new()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get(&self, identifier: &str) -> Option<Value> {
|
|
||||||
self.table.get(identifier).cloned()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn assign(&mut self, identifier: &str, value: Value) {
|
|
||||||
self.table.insert(identifier.to_string(), value);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn assign_array(&mut self, identifier: &str, value: Value) {
|
|
||||||
match self.table.get(identifier) {
|
|
||||||
Some(Value::Array(arr)) => {
|
|
||||||
let mut new_arr: Vec<Value> = vec![];
|
|
||||||
new_arr.extend(arr.clone());
|
|
||||||
new_arr.push(value.clone());
|
|
||||||
self.table.insert(identifier.to_string(), Value::Array(new_arr));
|
|
||||||
},
|
|
||||||
|
|
||||||
Some(val) => {
|
|
||||||
let mut new_arr: Vec<Value> = vec![val.clone()];
|
|
||||||
new_arr.push(value.clone());
|
|
||||||
self.table.insert(identifier.to_string(), Value::Array(new_arr));
|
|
||||||
},
|
|
||||||
None => {
|
|
||||||
self.table.insert(identifier.to_string(), Value::Array(vec![
|
|
||||||
value.clone()
|
|
||||||
]));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn assign_if(&mut self, identifier: &str, value: Value) {
|
|
||||||
if self.table.get(identifier).is_none() {
|
|
||||||
self.table.insert(identifier.to_string(), value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod test {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn assign() {
|
|
||||||
let mut sym = Sym::new();
|
|
||||||
assert!(sym.get("X").is_none());
|
|
||||||
sym.assign("X", Value::Int(34));
|
|
||||||
assert_eq!(sym.get("X"), Some(Value::Int(34)));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn assign_array() {
|
|
||||||
let mut sym = Sym::new();
|
|
||||||
assert!(sym.get("X").is_none());
|
|
||||||
sym.assign_array("X", Value::Float(6.28));
|
|
||||||
|
|
||||||
assert_eq!(sym.get("X"), Some(Value::Array(vec![
|
|
||||||
Value::Float(6.28),
|
|
||||||
])));
|
|
||||||
|
|
||||||
sym.assign_array("X", Value::Bool(false));
|
|
||||||
|
|
||||||
assert_eq!(sym.get("X"), Some(Value::Array(vec![
|
|
||||||
Value::Float(6.28),
|
|
||||||
Value::Bool(false)
|
|
||||||
])));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn assign_if() {
|
|
||||||
let mut sym = Sym::new();
|
|
||||||
assert!(sym.get("X").is_none());
|
|
||||||
sym.assign_if("X", Value::Float(6.28));
|
|
||||||
assert_eq!(sym.get("X"), Some(Value::Float(6.28)));
|
|
||||||
sym.assign_if("X", Value::Int(79));
|
|
||||||
assert_eq!(sym.get("X"), Some(Value::Float(6.28)));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,15 +0,0 @@
|
||||||
use crate::core::cmd::Command;
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
#[derive(PartialEq)]
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub enum Value {
|
|
||||||
Nil,
|
|
||||||
Int(i32),
|
|
||||||
Float(f64),
|
|
||||||
Bool(bool),
|
|
||||||
String(String),
|
|
||||||
Symbol(String),
|
|
||||||
Array(Vec<Value>),
|
|
||||||
Command(String)
|
|
||||||
}
|
|
29
src/main.rs
29
src/main.rs
|
@ -1,11 +1,28 @@
|
||||||
mod cli;
|
mod cli;
|
||||||
mod core;
|
|
||||||
mod app;
|
|
||||||
|
|
||||||
use crate::app::App;
|
use crate::cli::parse;
|
||||||
|
|
||||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let mut app = App::new();
|
let mut args = parse::Args::new();
|
||||||
app.init()?;
|
let sys_args: Vec<String> = std::env::args().collect();
|
||||||
app.start()
|
|
||||||
|
args.register(&vec!["-h", "--help"])
|
||||||
|
.description("show this help")
|
||||||
|
.callback(Box::new(|_, ctx| {
|
||||||
|
println!("{}", ctx.help);
|
||||||
|
std::process::exit(0);
|
||||||
|
}));
|
||||||
|
|
||||||
|
args.register(&vec!["-v", "--version"])
|
||||||
|
.description("show alchimake version")
|
||||||
|
.callback(Box::new(|_, _| {
|
||||||
|
println!("Alchimake v0.0.0");
|
||||||
|
println!("Copyright (C) 2024 bog");
|
||||||
|
println!("Licensed under the GPLv3+ (see LICENSE)");
|
||||||
|
std::process::exit(0);
|
||||||
|
}));
|
||||||
|
|
||||||
|
args.parse(&sys_args.iter().map(|v| v.as_str()).collect())?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue