From 374d2aef06a03ed4acb04d7462c19ba05ffa1c93 Mon Sep 17 00:00:00 2001 From: Andreev Gregory Date: Tue, 8 Apr 2025 01:46:36 +0300 Subject: [PATCH] I think I only now settled on my plan. Anyway, daily update --- Cargo.lock | 17 ++++-- Cargo.toml | 4 +- mtgott/Cargo.lock | 7 +++ mtgott/Cargo.toml | 4 ++ mtgott/src/bin/PRIKOL.rs | 8 +++ mtgott/src/bin/mtgott_cli.rs | 50 ++++++++++++++++ {src/mtgott => mtgott/src}/charclasses.rs | 0 {src/mtgott => mtgott/src}/dirsearch.rs | 58 ++++++++++-------- .../src}/lambda_compilation.rs | 4 +- src/mtgott/mod.rs => mtgott/src/lib.rs | 0 {src/mtgott => mtgott/src}/parser.rs | 12 ++-- {src/mtgott => mtgott/src}/runtime.rs | 60 ++++++++++++++++--- {tests => mtgott/tests}/parsing_test.rs | 0 src/bin/mtgott_cli.rs | 41 ------------- src/lib.rs | 1 - 15 files changed, 175 insertions(+), 91 deletions(-) create mode 100644 mtgott/Cargo.lock create mode 100644 mtgott/Cargo.toml create mode 100644 mtgott/src/bin/PRIKOL.rs create mode 100644 mtgott/src/bin/mtgott_cli.rs rename {src/mtgott => mtgott/src}/charclasses.rs (100%) rename {src/mtgott => mtgott/src}/dirsearch.rs (68%) rename {src/mtgott => mtgott/src}/lambda_compilation.rs (87%) rename src/mtgott/mod.rs => mtgott/src/lib.rs (100%) rename {src/mtgott => mtgott/src}/parser.rs (98%) rename {src/mtgott => mtgott/src}/runtime.rs (50%) rename {tests => mtgott/tests}/parsing_test.rs (100%) delete mode 100644 src/bin/mtgott_cli.rs diff --git a/Cargo.lock b/Cargo.lock index 6d72a69..2f65f0b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -330,9 +330,9 @@ checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" [[package]] name = "miniz_oxide" -version = "0.8.5" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e3e04debbb59698c15bacbb6d93584a8c0ca9cc3213cb423d31f760d8843ce5" +checksum = "ff70ce3e48ae43fa075863cef62e8b43b71a4f2382229920e0df362592919430" dependencies = [ "adler2", ] @@ -348,6 +348,10 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "mtgott" +version = "0.1.0" + [[package]] name = "object" version = "0.36.7" @@ -529,9 +533,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.14.0" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd" +checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9" [[package]] name = "socket2" @@ -582,9 +586,9 @@ dependencies = [ [[package]] name = "tokio" -version = "1.44.1" +version = "1.44.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f382da615b842244d4b8738c82ed1275e6c5dd90c459a30941cd07080b06c91a" +checksum = "e6b88822cbe49de4185e3a4cbf8321dd487cf5fe0c5c65695fef6346371e9c48" dependencies = [ "backtrace", "libc", @@ -763,6 +767,7 @@ version = "0.1.0" dependencies = [ "axum", "json5", + "mtgott", "serde_json", "tokio", ] diff --git a/Cargo.toml b/Cargo.toml index 748b4dd..bec4282 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,10 +1,10 @@ [package] name = "yyyi_ru" version = "0.1.0" -edition = "2024" [dependencies] axum = "0.8.3" tokio = { version = "1.44.1", features = ["rt-multi-thread"] } json5 = "0.4.1" -serde_json = "1.0.140" \ No newline at end of file +serde_json = "1.0.140" +mtgott = { path = "./mtgott" } diff --git a/mtgott/Cargo.lock b/mtgott/Cargo.lock new file mode 100644 index 0000000..d28c1d7 --- /dev/null +++ b/mtgott/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "mtgott" +version = "0.1.0" diff --git a/mtgott/Cargo.toml b/mtgott/Cargo.toml new file mode 100644 index 0000000..b98957b --- /dev/null +++ b/mtgott/Cargo.toml @@ -0,0 +1,4 @@ +[package] +name = "mtgott" +version = "0.1.0" + diff --git a/mtgott/src/bin/PRIKOL.rs b/mtgott/src/bin/PRIKOL.rs new file mode 100644 index 0000000..c4b2854 --- /dev/null +++ b/mtgott/src/bin/PRIKOL.rs @@ -0,0 +1,8 @@ + + +fn main() { + let func : & dyn for<'a> Fn(& 'a u32) -> &'a u32; + func = &|u: &u32| -> &u32 {u}; + let y = 6u32; + println!("{}", func(&y)); +} \ No newline at end of file diff --git a/mtgott/src/bin/mtgott_cli.rs b/mtgott/src/bin/mtgott_cli.rs new file mode 100644 index 0000000..90f1cb1 --- /dev/null +++ b/mtgott/src/bin/mtgott_cli.rs @@ -0,0 +1,50 @@ +extern crate mtgott; + +use std::env; +use std::process; +use crate::mtgott::charclasses::is_bad_name; +use crate::mtgott::dirsearch::get_root_html; +use crate::mtgott::runtime::{Value, generate_template}; +use std::collections::HashMap; +use mtgott::dirsearch::add_path_with_dots_to_root; + +fn usage() -> ! { + eprintln!("Usage: program [-D name value]..."); + process::exit(1); +} + +fn main() { + let mut args = env::args(); + args.next().unwrap(); + let path_arg = match args.next() { Some(s) => s, None => usage(), }; + let template_name = match args.next() { Some(s) => s, None => usage(), }; + let mut defines: Vec<(String, String)> = Vec::new(); + while let Some(arg) = args.next() { + if arg == "-D" { + let name = match args.next() { + Some(n) => n, + None => usage() + }; + let value = match args.next() { + Some(v) => v, + None => usage() + }; + for s in name.split('.') { + if is_bad_name(s) { + eprintln!("Bad name: {}", s); + process::exit(1); + } + } + defines.push((name, value)); + } else { + usage(); + } + } + let mut guest_root = Value::Dict(HashMap::new()); + for (name_path, val) in defines { + add_path_with_dots_to_root(&mut guest_root, &name_path, Value::Str(val)).unwrap(); + } + let dir_root = get_root_html(&path_arg).unwrap(); + let res = generate_template(&dir_root, &guest_root, &template_name).unwrap(); + print!("{res}") +} diff --git a/src/mtgott/charclasses.rs b/mtgott/src/charclasses.rs similarity index 100% rename from src/mtgott/charclasses.rs rename to mtgott/src/charclasses.rs diff --git a/src/mtgott/dirsearch.rs b/mtgott/src/dirsearch.rs similarity index 68% rename from src/mtgott/dirsearch.rs rename to mtgott/src/dirsearch.rs index c559c96..0b74868 100644 --- a/src/mtgott/dirsearch.rs +++ b/mtgott/src/dirsearch.rs @@ -1,4 +1,4 @@ -use std::{fs, io, fmt}; +use std::{fs}; use std::fs::{read_dir, metadata, canonicalize}; use std::path::PathBuf; use std::error::Error; @@ -6,7 +6,6 @@ use super::charclasses::{escape_for_html, is_bad_name}; use super::runtime::{HigherLevelFunc, Value, DebugState, val_lambda_check_argc}; use super::parser::{parse_one_file_simplified, parse_one_file_packed}; use super::lambda_compilation::{plemege_to_value}; -use std::rc::Rc; use std::collections::HashMap; pub fn search_dir_rec_helper bool>( @@ -46,7 +45,7 @@ pub fn search_dir_rec_helper bool>( pub fn search_dir bool>(p: &str, allowed_extensions: &[&str], is_valid_name: &F) -> Result>, Box> { let mut res: Vec> = (0..allowed_extensions.len()).map(|_| Vec::new()).collect(); - search_dir_rec_helper(&mut res, PathBuf::new(), String::new(), allowed_extensions, is_valid_name, 100)?; + search_dir_rec_helper(&mut res, PathBuf::from(p), String::new(), allowed_extensions, is_valid_name, 100)?; Ok(res) } @@ -69,36 +68,45 @@ pub fn search_mtgott_dir(p: &str, plain_ext: &str) -> Result Result<(), Box> { - let parts: Vec<&str> = slash_path.split('/').collect(); +/* Panics if somebody else borrowed root. splitter is usually / or . */ +fn add_path_to_root(root: &mut Value, unsplit_path: &str, splitter: char, obj: Value) -> Result<(), Box> { + let parts: Vec<&str> = unsplit_path.split(splitter).collect(); let mut cur: &mut Value = root; assert!(parts.len() > 0); - for i in 0..parts.len() { + for i in 0usize..parts.len() { match cur { Value::Dict(hashmap) => { - cur = Rc::get_mut(hashmap).unwrap().entry(String::from(parts[i])).or_insert(Default::default()); + cur = hashmap.entry(String::from(parts[i])).or_insert(Default::default()); } - _ => return Err(format!("Overlapping root elements {}", parts[..i].join("/")).into()) + _ => return Err(format!("Overlapping root elements {}", parts[..i].join(&*splitter)).into()) } } match cur { Value::Int(x) if *x == 0 => {}, - _ => return Err(format!("Overlapping root elements {}", slash_path).into()), + _ => return Err(format!("Overlapping root elements {}", unsplit_path).into()), } + *cur = obj; Ok(()) } +pub fn add_path_with_slashes_to_root(root: &mut Value, unsplit_path: &str, obj: Value) -> Result<(), Box> { + add_path_to_root(root, unsplit_path, '/', obj) +} + +pub fn add_path_with_dots_to_root(root: &mut Value, unsplit_path: &str, obj: Value) -> Result<(), Box> { + add_path_to_root(root, unsplit_path, '.', obj) +} + pub fn get_all_templates(p: &str, plain_ext: &str) -> Result> { let source = search_mtgott_dir(p, plain_ext)?; - let mut res: Value = Value::Dict(Rc::new(HashMap::new())); + let mut res: Value = Value::Dict(HashMap::new()); for cut_path in source.mtgott { let path = format!("{cut_path}.mtgott{plain_ext}"); let text_bytes = fs::read(PathBuf::from(p).join(&path))?; let text = std::str::from_utf8(&text_bytes)?; let plemege = parse_one_file_packed(text)?; let compiled = plemege_to_value(plemege, &path)?; - add_path_to_root(&mut res, &cut_path, compiled)? + add_path_to_root(&mut res, &cut_path, '/', compiled)? } for cut_path in source.imtgott { let path = format!("{cut_path}.imtgott{plain_ext}"); @@ -106,37 +114,37 @@ pub fn get_all_templates(p: &str, plain_ext: &str) -> Result Result>{ let mut root = get_all_templates(p, plain_ext)?; - add_path_to_root(&mut root, "sanitize", Value::Fn(sanitize))?; - add_path_to_root(&mut root, "cmd_tag_start", Value::Str(Rc::new(String::from("{%"))))?; - add_path_to_root(&mut root, "write_tag_start", Value::Str(Rc::new(String::from("{{"))))?; - add_path_to_root(&mut root, "roughinsert_tag_start", Value::Str(Rc::new(String::from("{["))))?; - add_path_to_root(&mut root, "magic_block_ending_tag", Value::Str(Rc::new(String::from("{%}"))))?; - add_path_to_root(&mut root, "element_ending_tag", Value::Str(Rc::new(String::from("{@}"))))?; + add_path_with_slashes_to_root(&mut root, "sanitize", Value::Fn(sanitize))?; + add_path_with_slashes_to_root(&mut root, "cmd_tag_start", Value::Str("{%".into()))?; + add_path_with_slashes_to_root(&mut root, "write_tag_start", Value::Str("{{".into()))?; + add_path_with_slashes_to_root(&mut root, "roughinsert_tag_start", Value::Str("{[".into()))?; + add_path_with_slashes_to_root(&mut root, "magic_block_ending_tag", Value::Str("{%}".into()))?; + add_path_with_slashes_to_root(&mut root, "element_ending_tag", Value::Str("{@}".into()))?; Ok(root) } pub fn get_root_html(p: &str) -> Result>{ - get_all_templates_plus_builtins(p, ".html", Rc::new( - |d_state: &DebugState, _: &Value, args: &[&Value]| -> Result> { + get_all_templates_plus_builtins(p, ".html", Box::new( + |d_state: &DebugState, _: &Value, _: &Value, args: &[&Value]| -> Result> { let _g = d_state.register("In sanitizer".into()); val_lambda_check_argc(args, 1)?; match args[0]{ - Value::Str(s) => Ok(Value::Str(Rc::new(escape_for_html(&s)))), - Value::Int(num) => Ok(Value::Str(Rc::new(num.to_string()))), - _ => Ok(Value::Str(Rc::new(escape_for_html(&format!("{:?}", args[0]))))) + Value::Str(s) => Ok(Value::Str(escape_for_html(&s))), + Value::Int(num) => Ok(Value::Str(num.to_string())), + _ => Ok(Value::Str(escape_for_html(&format!("{:?}", args[0])))) } })) } diff --git a/src/mtgott/lambda_compilation.rs b/mtgott/src/lambda_compilation.rs similarity index 87% rename from src/mtgott/lambda_compilation.rs rename to mtgott/src/lambda_compilation.rs index f0652dd..ccbd730 100644 --- a/src/mtgott/lambda_compilation.rs +++ b/mtgott/src/lambda_compilation.rs @@ -2,7 +2,6 @@ use super::runtime::*; use super::parser::*; use std::error::Error; use std::collections::HashMap; -use std::rc::Rc; fn cat_vec(arr: Vec) -> String { let total_len: usize = arr.iter().map(|s| { s.len() }).sum(); @@ -17,9 +16,10 @@ pub fn plemege_to_value(mut x: Plemege, file_path: &str) -> Result { + // Rc::new(|d_state: &DebugState, _: &Value, _: &Value, args: &[&Value]|) // todo Ok(Value::default()) } diff --git a/src/mtgott/mod.rs b/mtgott/src/lib.rs similarity index 100% rename from src/mtgott/mod.rs rename to mtgott/src/lib.rs diff --git a/src/mtgott/parser.rs b/mtgott/src/parser.rs similarity index 98% rename from src/mtgott/parser.rs rename to mtgott/src/parser.rs index 2dbd25c..fec6e87 100644 --- a/src/mtgott/parser.rs +++ b/mtgott/src/parser.rs @@ -1,5 +1,5 @@ use std::collections::HashMap; -use crate::mtgott::charclasses::{is_bad_name, is_digit, is_illegal_name, is_lnspace, is_normal_word_constituent, is_whitespace}; +use crate::charclasses::{is_bad_name, is_digit, is_illegal_name, is_lnspace, is_normal_word_constituent, is_whitespace}; use std::fmt::{self, Display, Formatter}; use std::error::Error; @@ -97,7 +97,7 @@ pub enum FileParsingErrorKind { recursion_limit_exceeded, } -use FileParsingErrorKind::*; +use self::FileParsingErrorKind::*; #[derive(Debug, PartialEq, Eq)] pub struct FileParsingError { @@ -396,7 +396,7 @@ impl<'a> Parser<'a> { let fin_static = |p: &Parser, tp1: usize, res: &mut Vec| { if tp1 < p.p { - res.push(SubElement::Static(String::from(&self.text[tp1..p.p]))) + res.push(SubElement::Static(String::from(&p.text[tp1..p.p]))) } }; @@ -421,9 +421,7 @@ impl<'a> Parser<'a> { if !matches!(expr, Expression::None){ res.push(SubElement::InsertExpr( Expression::Call( - Box::new(Expression::Attribute( - Box::new(Expression::Root), String::from("sanitize") - )), + Box::new(Expression::ToplevelAttribute("sanitize".into())), vec![expr]) )); } @@ -663,7 +661,7 @@ impl<'a> Parser<'a> { } let mut bg: Expression = match arg_names.iter().rposition(|&n| n == toplevel_name) { Some(i) => Expression::Argument(i as u64), - None => Expression::Attribute(Box::new(Expression::Root), String::from(toplevel_name)) + None => Expression::ToplevelAttribute(toplevel_name.into()) }; loop { self.skip_whitespace(); diff --git a/src/mtgott/runtime.rs b/mtgott/src/runtime.rs similarity index 50% rename from src/mtgott/runtime.rs rename to mtgott/src/runtime.rs index 95ef9b8..86a7c89 100644 --- a/src/mtgott/runtime.rs +++ b/mtgott/src/runtime.rs @@ -1,9 +1,7 @@ use std::collections::HashMap; use std::fmt; use std::fmt::Debug; -use std::ops::{Index, IndexMut}; use std::error::Error; -use std::rc::Rc; use std::cell::RefCell; pub struct DebugStateGuard<'a> ( @@ -27,16 +25,22 @@ impl<'a> DebugState { } } -pub type HigherLevelFunc = Rc Result>>; +pub type HigherLevelFunc = Box Result>>; pub enum Value { - Str(Rc), + Str(String), Int(u64), - Arr(Rc>), - Dict(Rc>), + Arr(Vec), + Dict(HashMap), Fn(HigherLevelFunc), } +impl Value { + fn as_dict(&self) -> &HashMap { + match self { Value::Dict(s) => s, _ => panic!(), } + } +} + /* Useful utility to put in every function you see */ pub fn val_lambda_check_argc(argv: &[&Value], argc_required: usize) -> Result<(), String> { if argv.len() == argc_required { @@ -46,7 +50,6 @@ pub fn val_lambda_check_argc(argv: &[&Value], argc_required: usize) -> Result<() } } - impl Default for Value { fn default() -> Self { Value::Int(0) @@ -82,3 +85,46 @@ impl<'t> PartialEq for Value { } } } + +fn get_sub_value<'a>(root: &'a Value, name: &str) -> Result<&'a Value, String> { + let mut cur: &Value = root; + let parts = name.split(".").map(String::from).collect(); + for i in 0usize..parts.len() { + match cur { + Value::Dict(hashmap) => { + match hashmap.get(&parts[i]) { + Some(nxt ) => { cur = nxt; } + None => return Err(format!("No such root element: {}", parts[..=i].join("/"))) + } + } + _ => return Err(format!("Not a dictionary: {}", parts[..i].join("/"))) + } + } + Ok(cur) +} + +/* If some `top-level-attribute` was not found in root, we search for it in guest_root. + * This is our way of passing arguments for template */ +pub fn generate_template(root: &Value, guest_root: &Value, name: &str) -> Result> { + let main = get_sub_value(root, name)?; + let main = match main { + Value::Dict(p) => { + match p.get("main".into()) { + Some(v2) => v2, + None => return Err(Box::new(format!("Called {name} template is a dictionary without `main()`"))) + } + } + _ => main, + }; + match main { + Value::Fn(main_func) => { + let d_stack = DebugState(RefCell::new(Vec::new())); + let rv = main_func(&d_stack, root, &[guest_root])?; + match rv { + Value::Str(answer) => Ok(answer), + _ => Err(Box::new(format!("template {name} returned not a string"))) + } + } + _ => Err(Box::new(format!("Called {name} template that is not a function"))) + } +} diff --git a/tests/parsing_test.rs b/mtgott/tests/parsing_test.rs similarity index 100% rename from tests/parsing_test.rs rename to mtgott/tests/parsing_test.rs diff --git a/src/bin/mtgott_cli.rs b/src/bin/mtgott_cli.rs deleted file mode 100644 index 8c71ad6..0000000 --- a/src/bin/mtgott_cli.rs +++ /dev/null @@ -1,41 +0,0 @@ -use std::env; -use std::process; -use std::path::PathBuf; -use yyyi_ru::mtgott::charclasses::is_bad_name; -use yyyi_ru::mtgott::dirsearch::{search_dir}; - -fn usage() -> ! { - eprintln!("Usage: program [-D name value]..."); - process::exit(1); -} - -fn main() { - let mut args = env::args(); - args.next().unwrap(); - let path_arg = match args.next() { - Some(s) => s, - None => usage(), - }; - let mut defines: Vec<(Vec, String)> = Vec::new(); - while let Some(arg) = args.next() { - if arg == "-D" { - let name = match args.next() { - Some(n) => n, - None => usage() - }; - let value = match args.next() { - Some(v) => v, - None => usage() - }; - defines.push((name.split('.').map(|s| { - if is_bad_name(s) { - eprintln!("Bad name: {}", s); - process::exit(1); - } - String::from(s) - }).collect(), value)); - } else { - usage(); - } - } -} diff --git a/src/lib.rs b/src/lib.rs index 7017990..5e6a3da 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,2 +1 @@ pub mod yyyi_ru; -pub mod mtgott; \ No newline at end of file