Implement group command refactor function compilation

This commit is contained in:
Moritz Hölting 2024-04-02 16:47:50 +02:00
parent 757ff8a54e
commit fedb55c50a
6 changed files with 152 additions and 48 deletions

View File

@ -10,6 +10,7 @@ default = ["zip"]
zip = ["dep:zip"]
[dependencies]
chksum-md5 = "0.0.0"
getset = "0.1.2"
serde = { version = "1.0.197", features = ["derive"] }
serde_json = "1.0.114"

View File

@ -1,8 +1,8 @@
use std::ops::{BitAnd, BitOr, Deref, Not};
use std::ops::{BitAnd, BitOr, Not};
use serde::{Deserialize, Serialize};
use crate::util::compile::{CompileOptions, MutCompilerState, MutFunctionCompilerState};
use crate::util::compile::{CompileOptions, FunctionCompilerState, MutCompilerState};
use super::Command;
@ -32,7 +32,7 @@ impl Execute {
&self,
options: &CompileOptions,
global_state: &MutCompilerState,
function_state: &MutFunctionCompilerState,
function_state: &FunctionCompilerState,
) -> Vec<String> {
if let Self::Run(cmd) = self {
cmd.compile(options, global_state, function_state)
@ -52,7 +52,7 @@ impl Execute {
require_grouping: bool,
options: &CompileOptions,
global_state: &MutCompilerState,
function_state: &MutFunctionCompilerState,
function_state: &FunctionCompilerState,
) -> Vec<String> {
match self {
Self::Align(align, next) => format_execute(
@ -172,16 +172,20 @@ impl Execute {
global_state,
function_state,
),
Self::Run(command) if !require_grouping => command
.compile(options, global_state, function_state)
.into_iter()
.map(|c| prefix.clone() + "run " + &c)
.collect(),
Self::Run(command) => Command::Group(vec![command.deref().clone()])
.compile(options, global_state, function_state)
.into_iter()
.map(|c| prefix.clone() + "run " + &c)
.collect(),
Self::Run(command) => match &**command {
Command::Execute(ex) => ex.compile_internal(
prefix,
require_grouping,
options,
global_state,
function_state,
),
command => command
.compile(options, global_state, function_state)
.into_iter()
.map(|c| prefix.clone() + "run " + &c)
.collect(),
},
Self::Runs(commands) if !require_grouping => commands
.iter()
.flat_map(|c| c.compile(options, global_state, function_state))
@ -203,7 +207,7 @@ fn format_execute(
require_grouping: bool,
options: &CompileOptions,
global_state: &MutCompilerState,
function_state: &MutFunctionCompilerState,
function_state: &FunctionCompilerState,
) -> Vec<String> {
next.compile_internal(
prefix + new,
@ -221,12 +225,16 @@ fn compile_if_cond(
prefix: String,
options: &CompileOptions,
global_state: &MutCompilerState,
function_state: &MutFunctionCompilerState,
function_state: &FunctionCompilerState,
) -> Vec<String> {
let str_cond = cond.clone().compile(options, global_state, function_state);
let require_grouping = el.is_some() || str_cond.len() > 1;
let then = if require_grouping {
let mut group_cmd = vec![Command::Execute(then.clone())];
let mut group_cmd = match then.clone() {
Execute::Run(cmd) => vec![*cmd],
Execute::Runs(cmds) => cmds,
ex => vec![Command::Execute(ex)],
};
if el.is_some() {
group_cmd.push("data modify storage shulkerbox:cond if_success set value true".into());
}
@ -318,7 +326,7 @@ impl Condition {
&self,
_options: &CompileOptions,
_global_state: &MutCompilerState,
_function_state: &MutFunctionCompilerState,
_function_state: &FunctionCompilerState,
) -> Vec<String> {
match self.normalize() {
Self::Atom(a) => vec!["if ".to_string() + &a],

View File

@ -4,9 +4,10 @@ mod execute;
pub use execute::{Condition, Execute};
use chksum_md5 as md5;
use serde::{Deserialize, Serialize};
use crate::util::compile::{CompileOptions, MutCompilerState, MutFunctionCompilerState};
use crate::util::compile::{CompileOptions, FunctionCompilerState, MutCompilerState};
use super::Function;
@ -34,19 +35,13 @@ impl Command {
&self,
options: &CompileOptions,
global_state: &MutCompilerState,
function_state: &MutFunctionCompilerState,
function_state: &FunctionCompilerState,
) -> Vec<String> {
match self {
Self::Raw(command) => vec![command.clone()],
Self::Debug(message) => compile_debug(message, options),
Self::Execute(ex) => ex.compile(options, global_state, function_state),
Self::Group(commands) => {
// TODO: implement correctly
commands
.iter()
.flat_map(|c| c.compile(options, global_state, function_state))
.collect()
}
Self::Group(commands) => compile_group(commands, options, global_state, function_state),
}
}
}
@ -77,3 +72,41 @@ fn compile_debug(message: &str, option: &CompileOptions) -> Vec<String> {
Vec::new()
}
}
fn compile_group(
commands: &[Command],
options: &CompileOptions,
global_state: &MutCompilerState,
function_state: &FunctionCompilerState,
) -> Vec<String> {
if commands.len() > 1 {
let generated_functions = {
let generated_functions = function_state.generated_functions();
let amount = generated_functions.get();
generated_functions.set(amount + 1);
amount
};
let function_path = {
let pre_hash_path =
function_state.path().to_owned() + ":" + &generated_functions.to_string();
let hash = md5::hash(pre_hash_path).to_hex_lowercase();
"sb/".to_string() + function_state.path() + "/" + &hash[..16]
};
let namespace = function_state.namespace();
let mut function = Function::new(namespace, &function_path);
function.get_commands_mut().extend(commands.iter().cloned());
function_state.add_function(&function_path, function);
vec![format!("function {namespace}:{function_path}")]
} else {
commands
.iter()
.flat_map(|c| c.compile(options, global_state, function_state))
.collect()
}
}

View File

@ -1,7 +1,5 @@
//! Function struct and implementation
use std::sync::Mutex;
use getset::Getters;
use serde::{Deserialize, Serialize};
@ -48,13 +46,16 @@ impl Function {
}
/// Compile the function into a virtual file.
pub fn compile(&self, options: &CompileOptions, state: &MutCompilerState) -> VFile {
let function_state = Mutex::new(FunctionCompilerState::default());
pub fn compile(
&self,
options: &CompileOptions,
global_state: &MutCompilerState,
function_state: &FunctionCompilerState,
) -> VFile {
let content = self
.commands
.iter()
.flat_map(|c| c.compile(options, state, &function_state))
.flat_map(|c| c.compile(options, global_state, function_state))
.collect::<Vec<String>>()
.join("\n");
VFile::Text(content)

View File

@ -3,12 +3,15 @@
use serde::{Deserialize, Serialize};
use crate::{
util::compile::{CompileOptions, MutCompilerState},
util::compile::{CompileOptions, FunctionCompilerState, MutCompilerState},
virtual_fs::VFolder,
};
use super::{function::Function, tag::Tag};
use std::collections::HashMap;
use std::{
collections::{HashMap, VecDeque},
sync::{Arc, Mutex},
};
/// Namespace of a datapack
#[derive(Debug, Clone, Serialize, Deserialize)]
@ -76,16 +79,33 @@ impl Namespace {
let mut root_folder = VFolder::new();
// Compile functions
for (path, function) in &self.functions {
let mut functions = self
.functions
.iter()
.map(|(name, content)| (name.clone(), content.clone()))
.collect::<VecDeque<_>>();
if !self.main_function.get_commands().is_empty() {
functions.push_front(("main".to_string(), self.main_function.clone()));
}
let functions = Arc::new(Mutex::new(functions));
loop {
let Some((path, function)) = ({
let mut functions = functions.lock().unwrap();
let entry = functions.pop_front();
drop(functions);
entry
}) else {
break;
};
let function_state =
FunctionCompilerState::new(&path, &self.name, Arc::downgrade(&functions));
root_folder.add_file(
&format!("functions/{}.mcfunction", path),
function.compile(options, state),
);
}
if !self.main_function.get_commands().is_empty() {
root_folder.add_file(
"functions/main.mcfunction",
self.main_function.compile(options, state),
function.compile(options, state, &function_state),
);
}

View File

@ -1,9 +1,16 @@
//! Compile options for the compiler.
use std::sync::Mutex;
use std::{
cell::Cell,
collections::VecDeque,
sync::{Mutex, Weak},
};
use getset::Getters;
use serde::{Deserialize, Serialize};
use crate::datapack::Function;
/// Compile options for the compiler.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CompileOptions {
@ -24,7 +31,41 @@ pub struct CompilerState {}
pub type MutCompilerState = Mutex<CompilerState>;
/// State of the compiler for each function that can change during compilation.
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct FunctionCompilerState {}
/// Mutex for the function compiler state.
pub type MutFunctionCompilerState = Mutex<FunctionCompilerState>;
#[derive(Debug, Clone, Getters)]
pub struct FunctionCompilerState {
/// Number of generated functions in the current function.
#[get = "pub"]
generated_functions: Cell<usize>,
/// Path of the current function.
#[get = "pub"]
path: String,
/// Namespace of the current function.
#[get = "pub"]
namespace: String,
/// Queue of functions to be generated.
functions: FunctionQueue,
}
type FunctionQueue = Weak<Mutex<VecDeque<(String, Function)>>>;
impl FunctionCompilerState {
/// Create a new function compiler state.
pub fn new(path: &str, namespace: &str, functions: FunctionQueue) -> Self {
Self {
generated_functions: Cell::new(0),
namespace: namespace.to_string(),
path: path.to_string(),
functions,
}
}
/// Add a function to the queue.
pub fn add_function(&self, name: &str, function: Function) {
if let Some(queue) = self.functions.upgrade() {
queue
.lock()
.unwrap()
.push_back((name.to_string(), function));
}
}
}