From d41e06e31bf5b30f73f70f535f1b5755c3c513bb Mon Sep 17 00:00:00 2001 From: Aleksey Yakovlev Date: Wed, 10 Jul 2024 15:25:52 +0700 Subject: [PATCH] added eval --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 3 ++ sample.hexo | 2 +- src/compiler/compiler_source.rs | 30 ++++++++++++- src/compiler/native_fn/implementations.rs | 54 ++++++++++++----------- src/compiler/native_fn/index.rs | 6 +-- src/compiler/native_fn/signature.rs | 11 ++++- src/compiler/rst/compiler.rs | 33 ++++++++------ 9 files changed, 96 insertions(+), 47 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4aa7619..4df835f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -225,7 +225,7 @@ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "hexo" -version = "0.8.0" +version = "0.9.0" dependencies = [ "clap", "console", diff --git a/Cargo.toml b/Cargo.toml index 8e1d00b..1d94c42 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "hexo" -version = "0.8.0" +version = "0.9.0" edition = "2021" license = "Apache-2.0" repository = "https://github.com/lexa-diky/hexo" diff --git a/README.md b/README.md index caeb5d9..363ee66 100644 --- a/README.md +++ b/README.md @@ -90,6 +90,9 @@ To call a function use glyph '#' fallowed by function name and arguments: > #pad_left(AA, 4) // will emit '00 00 00 AA' > #pad_right(AA, 4) // will emit 'AA 00 00 00' > #pad('AA', left: 10x4, right: 10x8) // wil pad left by 4 bytes and right by 8 bytes + +// Hexo compiler +> #eval('> 01 02 03') // will evaluate passed argument and return resulting compilation ``` ### Example diff --git a/sample.hexo b/sample.hexo index 2eae6d0..8ce030a 100644 --- a/sample.hexo +++ b/sample.hexo @@ -1 +1 @@ -> #pad('AA', left: 10x4, right: 10x8) +> #eval(#read_file('samples/java_object/input.hexo')) \ No newline at end of file diff --git a/src/compiler/compiler_source.rs b/src/compiler/compiler_source.rs index c6cbc0a..359ae92 100644 --- a/src/compiler/compiler_source.rs +++ b/src/compiler/compiler_source.rs @@ -1,6 +1,8 @@ +use std::fmt::format; use std::fs::File; use std::io::Read; use std::path::{Path, PathBuf}; +use crate::util::id::HexoId; use crate::util::logger; pub(crate) trait CompilerSource { @@ -34,6 +36,33 @@ impl CompilerSource for FileCompilerSource { } } +pub(crate) struct LiteralCompilerSource { + content: String, + path: PathBuf, +} + +impl CompilerSource for LiteralCompilerSource { + fn read(&self) -> Result { + Ok(self.content.clone()) + } + + fn path(&self) -> &Path { + self.path.as_path() + } +} + +impl LiteralCompilerSource { + pub(crate) fn anonymous(content: String) -> LiteralCompilerSource { + LiteralCompilerSource { + content: content, + path: Path::new( + format!("hexo://anonymous/{}", HexoId::next()).as_str() + ).to_path_buf(), + } + } +} + + #[cfg(test)] pub(crate) mod tests { use std::fs::File; @@ -57,7 +86,6 @@ pub(crate) mod tests { } impl EagerCompilerSource { - pub(crate) fn new>(path: P) -> Result { let pat_ref = path.as_ref(); let mut source_file = File::open(pat_ref)?; diff --git a/src/compiler/native_fn/implementations.rs b/src/compiler/native_fn/implementations.rs index 51f270d..add37e5 100644 --- a/src/compiler/native_fn/implementations.rs +++ b/src/compiler/native_fn/implementations.rs @@ -2,16 +2,14 @@ use crate::util::byte_buffer::ByteBuffer; use std::collections::HashMap; use std::fs::File; use std::io::Read; - +use crate::compiler::compiler_source::LiteralCompilerSource; use crate::compiler::native_fn::error::Error; use crate::compiler::native_fn::signature::{NativeFunction, NativeFunctionSignature}; pub(crate) fn create_len_native_function() -> NativeFunction { NativeFunction { - signature: NativeFunctionSignature { - name: String::from("len"), - }, - executor: |arguments: HashMap| { + signature: NativeFunctionSignature::new("len"), + executor: |arguments: HashMap, _| { let mut result = ByteBuffer::default(); let arg0 = get_named_argument(&arguments, "utf8") .unwrap_or_else(|| get_argument_at(&arguments, 0, "len").unwrap()); @@ -25,10 +23,8 @@ pub(crate) fn create_len_native_function() -> NativeFunction { pub(crate) fn create_pad_left_native_function() -> NativeFunction { NativeFunction { - signature: NativeFunctionSignature { - name: String::from("pad_left"), - }, - executor: |arguments: HashMap| { + signature: NativeFunctionSignature::new("pad_left"), + executor: |arguments: HashMap, _| { let mut arg0 = get_argument_at(&arguments, 0, "pad_left")?.clone(); let arg1 = get_argument_at(&arguments, 1, "pad_left")?; @@ -41,10 +37,8 @@ pub(crate) fn create_pad_left_native_function() -> NativeFunction { pub(crate) fn create_pad_right_native_function() -> NativeFunction { NativeFunction { - signature: NativeFunctionSignature { - name: String::from("pad_right"), - }, - executor: |arguments: HashMap| { + signature: NativeFunctionSignature::new("pad_right"), + executor: |arguments: HashMap, _| { let mut arg0: ByteBuffer = get_argument_at(&arguments, 0, "pad_right")?.clone(); let arg1 = get_argument_at(&arguments, 1, "pad_right")?; @@ -57,10 +51,8 @@ pub(crate) fn create_pad_right_native_function() -> NativeFunction { pub(crate) fn create_cmd_native_function() -> NativeFunction { NativeFunction { - signature: NativeFunctionSignature { - name: String::from("cmd"), - }, - executor: |arguments: HashMap| { + signature: NativeFunctionSignature::new("cmd"), + executor: |arguments: HashMap, _| { let command = get_argument_at(&arguments, 0, "cmd")? .to_string() .map_err(|e| Error::Unknown(e.to_string()))?; @@ -78,10 +70,8 @@ pub(crate) fn create_cmd_native_function() -> NativeFunction { pub(crate) fn create_read_file_native_function() -> NativeFunction { return NativeFunction { - signature: NativeFunctionSignature { - name: String::from("read_file"), - }, - executor: |arguments: HashMap| { + signature: NativeFunctionSignature::new("read_file"), + executor: |arguments: HashMap, _| { let arg0 = get_argument_at(&arguments, 0, "read_file")?; let file_path = arg0 @@ -104,10 +94,8 @@ pub(crate) fn create_read_file_native_function() -> NativeFunction { pub(crate) fn create_pad_native_function() -> NativeFunction { return NativeFunction { - signature: NativeFunctionSignature { - name: String::from("pad"), - }, - executor: |arguments: HashMap| { + signature: NativeFunctionSignature::new("pad"), + executor: |arguments: HashMap, _| { let mut buffer = get_argument_at(&arguments, 0, "pad")?.clone(); let left_padding = get_named_argument(&arguments, "left").map(|b| b.as_usize_unsafe()); @@ -126,6 +114,22 @@ pub(crate) fn create_pad_native_function() -> NativeFunction { }; } +pub(crate) fn create_eval_native_function() -> NativeFunction { + return NativeFunction { + signature: NativeFunctionSignature::new("eval"), + executor: |arguments: HashMap, compiler| { + let buffer = get_argument_at(&arguments, 0, "eval")?.clone(); + let source = LiteralCompilerSource::anonymous( + buffer.to_string() + .map_err(|e| Error::Unknown(e.to_string()))?, + ); + let result = compiler.compile(&source) + .map_err(|e| Error::Unknown(e.to_string()))?; + Ok(ByteBuffer::from(result.content)) + }, + }; +} + fn get_argument_at<'a>( arguments: &'a HashMap, pos: usize, diff --git a/src/compiler/native_fn/index.rs b/src/compiler/native_fn/index.rs index b2eff3a..6c5c10c 100644 --- a/src/compiler/native_fn/index.rs +++ b/src/compiler/native_fn/index.rs @@ -1,8 +1,5 @@ use crate::compiler::native_fn::signature::NativeFunction; -use crate::compiler::native_fn::{ - create_cmd_native_function, create_len_native_function, create_pad_left_native_function, - create_pad_native_function, create_pad_right_native_function, create_read_file_native_function, -}; +use crate::compiler::native_fn::{create_cmd_native_function, create_eval_native_function, create_len_native_function, create_pad_left_native_function, create_pad_native_function, create_pad_right_native_function, create_read_file_native_function}; #[derive(Clone, Debug)] pub(crate) struct NativeFunctionIndex { @@ -28,6 +25,7 @@ impl NativeFunctionIndex { create_cmd_native_function(), create_read_file_native_function(), create_pad_native_function(), + create_eval_native_function() ] } } diff --git a/src/compiler/native_fn/signature.rs b/src/compiler/native_fn/signature.rs index ed912f9..db0a672 100644 --- a/src/compiler/native_fn/signature.rs +++ b/src/compiler/native_fn/signature.rs @@ -1,13 +1,22 @@ use crate::compiler::native_fn::error::Error; use crate::util::byte_buffer::ByteBuffer; use std::collections::HashMap; +use crate::compiler::HexoCompiler; #[derive(Clone, Debug)] pub(crate) struct NativeFunctionSignature { pub(crate) name: String, } -type NativeFunctionExecutor = fn(HashMap) -> Result; +impl NativeFunctionSignature { + pub(crate) fn new(name: &str) -> NativeFunctionSignature { + NativeFunctionSignature { + name: String::from(name), + } + } +} + +type NativeFunctionExecutor = fn(HashMap, &HexoCompiler) -> Result; #[derive(Clone, Debug)] pub(crate) struct NativeFunction { diff --git a/src/compiler/rst/compiler.rs b/src/compiler/rst/compiler.rs index 8eec16a..0bc6d5e 100644 --- a/src/compiler/rst/compiler.rs +++ b/src/compiler/rst/compiler.rs @@ -23,9 +23,9 @@ impl RstCompiler<'_> { pub(crate) fn compile(&self, cst: &CstFile) -> Result { let context_id = HexoId::next(); - let mut context = Self::build_context(context_id, cst.path(), cst.main())?; + let mut context = self.build_context(context_id, cst.path(), cst.main())?; - let bb = Self::build_bytes(context_id, &mut context, cst.main().emits())?; + let bb = self.build_bytes(context_id, &mut context, cst.main().emits())?; Ok(HexoFile { path: cst.path().to_path_buf(), @@ -35,6 +35,7 @@ impl RstCompiler<'_> { } fn build_bytes( + &self, context_id: HexoId, context: &mut CompilationContext, emits: &Vec, @@ -42,13 +43,14 @@ impl RstCompiler<'_> { let mut byte_buffer = ByteBuffer::default(); for emit in emits { - Self::build_bytes_into(context_id, context, emit.atoms(), &mut byte_buffer)? + self.build_bytes_into(context_id, context, emit.atoms(), &mut byte_buffer)? } Ok(byte_buffer) } fn build_bytes_into( + &self, context_id: HexoId, context: &mut CompilationContext, atoms: &CstAtomVec, @@ -63,7 +65,7 @@ impl RstCompiler<'_> { Self::build_constant_into(context_id, context, name, buffer)? } CstAtom::Function { name, params } => { - Self::build_function_into(context_id, context, name.clone(), params, buffer)? + self.build_function_into(context_id, context, name.clone(), params, buffer)? } } } @@ -72,6 +74,7 @@ impl RstCompiler<'_> { } fn build_function_into( + &self, context_id: HexoId, context: &mut CompilationContext, function_name: String, @@ -85,13 +88,13 @@ impl RstCompiler<'_> { for param in params { let mut param_buffer = ByteBuffer::default(); - Self::build_bytes_into(context_id, context, param.value(), &mut param_buffer) + self.build_bytes_into(context_id, context, param.value(), &mut param_buffer) .unwrap(); params_buffer.insert(param.name().to_string(), param_buffer); } - executor(params_buffer.clone()) + executor(params_buffer.clone(), self.parent) .map(|bb| buffer.push_byte_buffer(&bb)) .map_err(Error::NativeFunctionExecution)?; @@ -107,7 +110,7 @@ impl RstCompiler<'_> { for param in params { let mut param_buffer = ByteBuffer::default(); - Self::build_bytes_into(context_id, context, param.value(), &mut param_buffer).unwrap(); + self.build_bytes_into(context_id, context, param.value(), &mut param_buffer).unwrap(); context.bind_local_constant( function_binding.identifier, @@ -119,7 +122,7 @@ impl RstCompiler<'_> { } for emit in &function_binding.emits { - Self::build_bytes_into(function_binding.identifier, context, emit.atoms(), buffer) + self.build_bytes_into(function_binding.identifier, context, emit.atoms(), buffer) .unwrap(); } @@ -142,35 +145,38 @@ impl RstCompiler<'_> { } fn build_context( + &self, context_id: HexoId, file_path: &Path, cst: &CstFunctionStatement, ) -> Result { let mut root_context = CompilationContext::new(file_path); - Self::build_context_into(context_id, &cst, &mut root_context)?; + self.build_context_into(context_id, &cst, &mut root_context)?; Ok(root_context) } fn build_context_into( + &self, context_id: HexoId, cst: &&CstFunctionStatement, root_context: &mut CompilationContext, ) -> Result<(), Error> { - Self::build_context_constants_into(context_id, cst, root_context)?; - Self::build_context_functions_into(context_id, cst, root_context)?; + self.build_context_constants_into(context_id, cst, root_context)?; + self.build_context_functions_into(context_id, cst, root_context)?; Ok(()) } fn build_context_constants_into( + &self, context_id: HexoId, cst: &&CstFunctionStatement, context: &mut CompilationContext, ) -> Result<(), Error> { for constant in cst.constants() { let mut buff = ByteBuffer::default(); - Self::build_bytes_into(context_id, context, constant.atoms(), &mut buff)?; + self.build_bytes_into(context_id, context, constant.atoms(), &mut buff)?; context.bind_local_constant( context_id, ConstantBinding { @@ -184,6 +190,7 @@ impl RstCompiler<'_> { } fn build_context_functions_into( + &self, context_id: HexoId, cst: &&CstFunctionStatement, root_context: &mut CompilationContext, @@ -199,7 +206,7 @@ impl RstCompiler<'_> { }, ); - Self::build_context_into(inner_function_context_id, &function, root_context)?; + self.build_context_into(inner_function_context_id, &function, root_context)?; root_context.bind_parents(inner_function_context_id, vec![context_id]); }