dpscript/ir/compiler/
node.rs1use once_cell::sync::Lazy;
2use regex::Regex;
3use std::{
4 fs::{self, File},
5 io::Write,
6 path::PathBuf,
7};
8
9use crate::{IRCheckerContext, IRLiteral, IRNode, Result, UnsourcedCompilerError};
10
11use super::TagData;
12
13pub const FIXER_REGEX: Lazy<Regex> =
14 Lazy::new(|| Regex::new(r"(?m)([^:\s]+:[^\s]+)\s([^\s]+)\s\[").unwrap());
15
16impl IRNode {
17 pub fn compile(&self, cx: &IRCheckerContext, dir: &PathBuf) -> Result<String> {
18 match self {
19 Self::Function(func) => {
20 let id = func.id.to_lowercase();
21 let mut split = id.split(":");
22 let ns = split.next().unwrap();
23 let name = split.next().unwrap();
24
25 let path = dir
26 .join("data")
27 .join(ns)
28 .join("functions")
29 .join(format!("{}.mcfunction", name));
30
31 let root = path.parent().unwrap();
32
33 if !root.exists() {
34 fs::create_dir_all(root)?;
35 }
36
37 let mut file = File::create(path)?;
38
39 for item in &func.body {
40 let data = item.compile(cx, dir)?;
41
42 if data.is_empty() {
43 continue;
44 }
45
46 writeln!(file, "{}", data)?;
47 }
48
49 Ok(String::new())
50 }
51
52 Self::Tag(tag) => {
53 let mut split = tag.name.split(":");
54 let ns = split.next().unwrap();
55 let name = split.next().unwrap();
56 let path = dir.join("data").join(ns).join(format!("{}.json", name));
57 let root = path.parent().unwrap();
58
59 if !root.exists() {
60 fs::create_dir_all(root)?;
61 }
62
63 let mut values = Vec::new();
64
65 for item in &tag.entries {
66 if !values.contains(item) {
67 values.push(item.clone());
68 }
69 }
70
71 let data = TagData {
72 replace: false,
73 values,
74 };
75
76 fs::write(path, serde_json::to_string_pretty(&data)?)?;
77
78 Ok(String::new())
79 }
80
81 Self::Literal(lit) => match lit {
82 IRLiteral::String(s) => Ok(s.clone()),
83 IRLiteral::PathOf(_) | IRLiteral::StoreOf(_) => Err(UnsourcedCompilerError {
84 err: "path!() and store!() expressions are not allowed during compilation!"
85 .into(),
86 }
87 .into()),
88 },
89
90 Self::Group(group) => {
91 let mut data = Vec::new();
92
93 for item in group {
94 let out = item.compile(cx, dir)?;
95
96 if out.is_empty() {
97 continue;
98 }
99
100 data.push(out);
101 }
102
103 Ok(data.join("\n"))
104 }
105
106 Self::Command(cmd) => {
107 let mut buf = Vec::new();
108
109 for node in &cmd.cmd {
110 buf.push(node.compile(cx, dir)?);
111 }
112
113 Ok(FIXER_REGEX.replace(&buf.join(" "), "$1 $2[").to_string())
114 }
115
116 Self::None => Ok(String::new()),
117 Self::Definition(_) => Ok(String::new()),
119
120 _ => Err(UnsourcedCompilerError {
121 err: format!("Unexpected node for compilation: {:?}", self),
122 }
123 .into()),
124 }
125 }
126}