file literal.

main
bog 2024-03-08 04:27:03 +01:00
parent 586676b519
commit 8420c7cce5
10 changed files with 224 additions and 44 deletions

47
Cargo.lock generated
View File

@ -2,6 +2,53 @@
# It is not intended for manual editing.
version = 3
[[package]]
name = "aho-corasick"
version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0"
dependencies = [
"memchr",
]
[[package]]
name = "alchimake"
version = "0.1.0"
dependencies = [
"regex",
]
[[package]]
name = "memchr"
version = "2.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149"
[[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"

View File

@ -6,3 +6,4 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
regex = "1.10.3"

59
src/app.rs Normal file
View File

@ -0,0 +1,59 @@
use std::path::PathBuf;
use crate::cli::parse;
use crate::core::conf::Conf;
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>> {
Ok(())
}
}

View File

@ -23,19 +23,19 @@ pub struct Context {
pub help: String
}
type Callback = Box<dyn Fn(Option<String>, Context)>;
type Callback<'a> = Box<dyn FnMut(Option<String>, Context) + 'a>;
pub struct Arg {
pub struct Arg<'a> {
pub flags: Vec<String>,
pub description: Option<String>,
pub callback: Option<Callback>
pub callback: Option<Callback<'a>>
}
pub struct Args {
args: Vec<Arg>,
pub struct Args<'a> {
args: Vec<Arg<'a>>,
}
impl Args {
impl<'a> Args<'a> {
pub fn new() -> Self {
Self {
args: vec![]
@ -45,6 +45,7 @@ impl Args {
pub fn help(&self) -> String {
let mut res = String::from("Usage: alchimake [OPTION]...\n");
res += "OPTIONS:\n";
for arg in self.args.iter() {
if let Some(description) = &arg.description {
res += format!(
@ -67,7 +68,7 @@ impl Args {
for arg in self.args.iter_mut() {
for flag in arg.flags.iter() {
if &flag == cli_arg {
if let Some(ref callback) = arg.callback {
if let Some(ref mut callback) = arg.callback {
let value = getval(&args, &flag)?;
callback(value.clone(), Context {
help: help.clone()
@ -99,9 +100,16 @@ impl Args {
}
pub fn callback(&mut self,
callback: Callback) -> &mut Self{
callback: Callback<'a>) -> &mut Self{
let idx = self.args.len() - 1;
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
}
}

18
src/core/conf.rs Normal file
View File

@ -0,0 +1,18 @@
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(".")
}
}
}

View File

@ -1,27 +1,54 @@
use regex::Regex;
use std::collections::HashMap;
use std::error::Error;
use crate::core::{
value::Value,
expr::Expr,
sym::Sym,
cmd::Command
cmd::Command,
conf::Conf
};
pub struct Evaluator {
sym: Sym,
commands: HashMap<String, Box<dyn Command>>
commands: HashMap<String, Box<dyn Command>>,
conf: Conf
}
impl Evaluator {
pub fn new(sym: Sym) -> Self {
pub fn new(sym: Sym, conf: Conf) -> Self {
Self {
sym,
commands: HashMap::new()
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) {
@ -89,14 +116,9 @@ impl Evaluator {
}
}
// pub struct Evaluator {
// sym: Sym,
// commands: HashMap<String, Box<dyn Command>>
// }
//
impl Clone for Evaluator {
fn clone(&self) -> Self {
let mut c = Evaluator::new(self.sym.clone());
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());
}
@ -112,7 +134,11 @@ mod test {
-> TestResult
where U: Fn(&mut Evaluator) {
let sym = Sym::new();
let mut eval = Evaluator::new(sym);
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)?;
@ -204,4 +230,39 @@ where U: Fn(&mut Evaluator) {
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(())
}
}

View File

@ -5,7 +5,8 @@ use crate::core::{
value::Value,
eval::Evaluator,
sym::Sym,
cmd::Command
cmd::Command,
conf::Conf
};
#[derive(Clone)]
@ -186,7 +187,7 @@ mod test {
-> TestResult
where T: Fn(&mut Executor) {
let sym = Sym::new();
let eval = Evaluator::new(sym);
let eval = Evaluator::new(sym, Conf::new());
let mut exec = Executor::new(eval);
init(&mut exec);

View File

@ -6,5 +6,6 @@ use crate::core::value::Value;
pub enum Expr {
BuiltIn(Value),
Ident(String),
Call(String, Vec<Expr>)
Call(String, Vec<Expr>),
File(String)
}

View File

@ -5,3 +5,4 @@ pub mod eval;
pub mod sym;
pub mod cmd;
pub mod exec;
pub mod conf;

View File

@ -1,29 +1,12 @@
mod cli;
mod core;
mod app;
use crate::cli::parse;
use crate::app::App;
fn main() -> 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.parse(&sys_args.iter().map(|v| v.as_str()).collect())?;
Ok(())
let mut app = App::new();
app.init()?;
app.start()
}