1use super::{
3 BuiltinFunc, ErrOR, ErrorInfo, JFunc, JFuncResult, JObject, JResult, JValue, Json, Jsonpiler,
4 Section, functions::obj_json,
5};
6use core::fmt::Write as _;
7use std::{
8 collections::HashSet,
9 fs::File,
10 io::{self, BufWriter, Write as _},
11};
12macro_rules! include_once {
14 ($self:ident, $name:literal) => {{
15 if !$self.include_flag.contains($name) {
16 $self.include_flag.insert($name.into());
17 write!($self.sect.text, include_str!(concat!("asm/", $name, ".s")))?;
18 }
19 }};
20}
21impl Jsonpiler {
22 fn assert(&self, cond: bool, text: &str, info: &ErrorInfo) -> ErrOR<()> {
24 cond.then_some(()).ok_or_else(|| self.fmt_err(text, info).into())
25 }
26 #[inline]
40 pub fn build(&mut self, source: String, json_file: &str, filename: &str) -> ErrOR<()> {
41 let json = self.parse(source)?;
42 self.include_flag = HashSet::new();
43 self.seed = 0;
44 self.register("=", true, Jsonpiler::f_local_set);
45 self.register("$", true, Jsonpiler::f_local_get);
46 self.register("+", true, Jsonpiler::f_plus);
47 self.register("-", true, Jsonpiler::f_minus);
48 self.register("message", true, Jsonpiler::f_message);
49 self.register("begin", true, Jsonpiler::f_begin);
50 let mut start = String::new();
51 self.sect = Section::default();
52 let result = self.eval(&json, &mut start)?;
53 writeln!(
54 start,
55 " {}
56 call [qword ptr __imp_ExitProcess[rip]]
57 .seh_endproc",
58 if let JValue::LInt(int) = result.value {
59 format!("mov rcx, {int}")
60 } else if let JValue::VInt(var) = &result.value {
61 format!("mov rcx, qword ptr {var}[rip]")
62 } else {
63 "xor ecx, ecx".into()
64 }
65 )?;
66 self.write_file(&start, filename, json_file)?;
67 Ok(())
68 }
69 fn eval(&mut self, json: &Json, function: &mut String) -> JResult {
71 const ERR: &str = "Unreachable (eval)";
72 let JValue::LArray(list) = &json.value else {
73 let JValue::LObject(object) = &json.value else { return Ok(json.clone()) };
74 let mut evaluated = JObject::default();
75 for kv in object.iter() {
76 evaluated.insert(kv.0.clone(), self.eval(&kv.1, function)?);
77 }
78 return Ok(obj_json(JValue::LObject(evaluated), json.info.clone()));
79 };
80 let first_elem =
81 list.first().ok_or(self.fmt_err("An function call cannot be an empty list.", &json.info))?;
82 let first = &self.eval(first_elem, function)?;
83 if let JValue::LString(cmd) = &first.value {
84 if cmd == "lambda" {
85 let mut func_buffer = String::new();
86 let result = Ok(self.eval_lambda(json, &mut func_buffer)?);
87 self.sect.text.push_str(&func_buffer);
88 result
89 } else if self.f_table.contains_key(cmd.as_str()) {
90 let args = if self.f_table.get_mut(cmd.as_str()).ok_or(ERR)?.evaluated {
91 &self.eval_args(list.get(1..).unwrap_or(&[]), function)?
92 } else {
93 list.get(1..).unwrap_or(&[])
94 };
95 Ok(obj_json(
96 (self.f_table.get_mut(cmd.as_str()).ok_or(ERR)?.func)(self, first, args, function)?,
97 first.info.clone(),
98 ))
99 } else {
100 Err(self.fmt_err(&format!("Function '{cmd}' is undefined."), &first.info).into())
101 }
102 } else if let JValue::Function { name: n, ret: re, .. } = &first.value {
103 writeln!(function, " call {n}")?;
104 if let JValue::VInt(_) | JValue::LInt(_) = **re {
105 let na = self.get_name()?;
106 writeln!(self.sect.bss, " .lcomm {na}, 8")?;
107 writeln!(function, " mov qword ptr {na}[rip], rax")?;
108 Ok(obj_json(JValue::VInt(na), first.info.clone()))
109 } else {
110 Ok(Json::default())
111 }
112 } else {
113 Err(self.fmt_err("Expected a function or lambda as the first element.", &json.info).into())
114 }
115 }
116 fn eval_args(&mut self, args: &[Json], function: &mut String) -> ErrOR<Vec<Json>> {
118 let mut result = vec![];
119 for arg in args {
120 result.push(self.eval(arg, function)?);
121 }
122 Ok(result)
123 }
124 fn eval_lambda(&mut self, func: &Json, function: &mut String) -> JResult {
126 const ERR: &str = "Unreachable (eval_lambda)";
127 let tmp = self.vars.clone();
128 let JValue::LArray(func_list) = &func.value else {
129 return Err(self.fmt_err("Invalid function definition.", &func.info).into());
130 };
131 self.assert(func_list.len() >= 3, "Invalid function definition.", &func.info)?;
132 let lambda = func_list.first().ok_or(ERR)?;
133 self.assert(
134 matches!(&lambda.value, JValue::LString(st) if st == "lambda"),
135 r#"The first element of a lambda list requires "lambda"."#,
136 &lambda.info,
137 )?;
138 let params_json = func_list.get(1).ok_or(ERR)?;
139 let JValue::LArray(params) = ¶ms_json.value else {
140 return Err(
141 self
142 .fmt_err(
143 "The second element of a lambda list requires an argument list.",
144 ¶ms_json.info,
145 )
146 .into(),
147 );
148 };
149 self.assert(params.is_empty(), "PARAMS ISN'T IMPLEMENTED.", ¶ms_json.info)?;
150 let name = self.get_name()?;
151 writeln!(
152 function,
153 ".seh_proc {name}
154{name}:
155 push rbp
156 .seh_pushreg rbp
157 mov rbp, rsp
158 .seh_setframe rbp, 0
159 sub rsp, 32
160 .seh_stackalloc 32
161 .seh_endprologue
162 .seh_handler .L_SEH_HANDLER, @except",
163 )?;
164 let mut ret = JValue::Null;
165 for arg in func_list.get(2..).ok_or("Empty lambda body.")? {
166 ret = self.eval(arg, function)?.value;
167 }
168 writeln!(
169 function,
170 " {}
171 add rsp, 32
172 leave
173 ret
174 .seh_endproc",
175 if let JValue::LInt(int) = ret {
176 format!("mov rax, {int}")
177 } else if let JValue::VInt(var) = &ret {
178 format!("mov rax, qword ptr {var}[rip]")
179 } else {
180 "xor eax, eax".into()
181 }
182 )?;
183 self.vars = tmp;
184 Ok(obj_json(
185 JValue::Function { name, params: params.clone(), ret: Box::new(ret) },
186 lambda.info.clone(),
187 ))
188 }
189 #[expect(clippy::single_call_fn, reason = "")]
191 fn f_begin(&mut self, first: &Json, args: &[Json], _: &mut String) -> JFuncResult {
192 args.last().map_or_else(
193 || Err(self.fmt_err("'begin' requires at least one arguments.", &first.info).into()),
194 |last| Ok(last.value.clone()),
195 )
196 }
197 fn f_binary_op(
199 &mut self, first: &Json, args: &[Json], function: &mut String, mn: &str, op: &str,
200 ) -> JFuncResult {
201 let mut f_binary_mn = |json: &Json, mne: &str| -> ErrOR<()> {
202 if let JValue::LInt(int) = json.value {
203 Ok(writeln!(function, " {mne} rax, {int}")?)
204 } else if let JValue::VInt(var) = &json.value {
205 Ok(writeln!(function, " {mne} rax, qword ptr {var}[rip]")?)
206 } else {
207 Err(
208 self
209 .fmt_err(
210 &format!("'{op}' requires integer operands, but got {}", json.value),
211 &json.info,
212 )
213 .into(),
214 )
215 }
216 };
217 let operand_r = args
218 .first()
219 .ok_or(self.fmt_err(&format!("'{op}' requires at least one arguments."), &first.info))?;
220 f_binary_mn(operand_r, "mov")?;
221 for operand_l in args.get(1..).unwrap_or(&[]) {
222 f_binary_mn(operand_l, mn)?;
223 }
224 let ret = self.get_name()?;
225 writeln!(self.sect.bss, " .lcomm {ret}, 8")?;
226 writeln!(function, " mov qword ptr {ret}[rip], rax")?;
227 Ok(JValue::VInt(ret))
228 }
229 #[expect(clippy::single_call_fn, reason = "")]
231 fn f_local_get(&mut self, first: &Json, args: &[Json], _: &mut String) -> JFuncResult {
232 self.assert(args.len() == 1, "'$' requires one argument.", &first.info)?;
233 let Some(var) = args.first() else {
234 return Err(self.fmt_err("'$' requires one argument.", &first.info).into());
235 };
236 let JValue::LString(var_name) = &var.value else {
237 return Err(self.fmt_err("Variable name must be a string literal.", &var.info).into());
238 };
239 match self.vars.get(var_name) {
240 Some(value) => Ok(value.clone()),
241 None => Err(self.fmt_err(&format!("Undefined variables: '{var_name}'"), &var.info).into()),
242 }
243 }
244 #[expect(clippy::single_call_fn, reason = "")]
246 fn f_local_set(&mut self, first: &Json, args: &[Json], _: &mut String) -> JFuncResult {
247 self.assert(args.len() == 2, "'=' requires two arguments.", &first.info)?;
248 let JValue::LString(variable) = &args.first().ok_or("Unreachable (f_set_local)")?.value else {
249 return Err(
250 self
251 .fmt_err(
252 "Variable name must be a string literal.",
253 &args.first().ok_or("Unreachable (f_set_local)")?.info,
254 )
255 .into(),
256 );
257 };
258 let value = args.get(1).ok_or("Unreachable (f_set_local)")?;
259 match &value.value {
260 JValue::LString(st) => {
261 let name = self.get_name()?;
262 writeln!(self.sect.data, " {name}: .string \"{st}\"")?;
263 self.vars.insert(variable.clone(), JValue::VString(name.clone()))
264 }
265 JValue::Null => self.vars.insert(variable.clone(), JValue::Null),
266 JValue::LInt(int) => {
267 let name = self.get_name()?;
268 writeln!(self.sect.data, " {name}: .quad 0x{int:x}")?;
269 self.vars.insert(variable.clone(), JValue::VInt(name.clone()))
270 }
271 JValue::VString(_)
272 | JValue::VInt(_)
273 | JValue::Function { .. }
274 | JValue::VArray(_)
275 | JValue::VBool(..)
276 | JValue::VFloat(_)
277 | JValue::VObject(_) => self.vars.insert(variable.clone(), value.value.clone()),
278 JValue::LArray(_) | JValue::LBool(_) | JValue::LFloat(_) | JValue::LObject(_) => {
279 return Err(self.fmt_err("Assignment to an unimplemented type.", &value.info).into());
280 }
281 }
282 .map_or(Ok(()), |_| Err(self.fmt_err("Reassignment not implemented.", &first.info)))?;
283 Ok(JValue::Null)
284 }
285 #[expect(clippy::single_call_fn, reason = "")]
287 fn f_message(&mut self, first: &Json, args: &[Json], function: &mut String) -> JFuncResult {
288 self.assert(args.len() == 2, "'message' requires two arguments.", &first.info)?;
289 let title = self.string2var(args.first().ok_or("Unreachable (f_message)")?, "title")?;
290 let msg = self.string2var(args.get(1).ok_or("Unreachable (f_message)")?, "text")?;
291 let wtitle = self.get_name()?;
292 let wmsg = self.get_name()?;
293 let ret = self.get_name()?;
294 for data in [&wtitle, &wmsg, &ret] {
295 writeln!(self.sect.bss, " .lcomm {data}, 8")?;
296 }
297 include_once!(self, "func/U8TO16");
298 write!(
299 function,
300 include_str!("asm/message.s"),
301 msg, wmsg, title, wtitle, wmsg, wtitle, ret, wmsg, wtitle
302 )?;
303 Ok(JValue::VInt(ret))
304 }
305 #[expect(clippy::single_call_fn, reason = "")]
307 fn f_minus(&mut self, first: &Json, args: &[Json], function: &mut String) -> JFuncResult {
308 self.f_binary_op(first, args, function, "sub", "-")
309 }
310 #[expect(clippy::single_call_fn, reason = "")]
312 fn f_plus(&mut self, first: &Json, args: &[Json], function: &mut String) -> JFuncResult {
313 self.f_binary_op(first, args, function, "add", "+")
314 }
315 fn get_name(&mut self) -> Result<String, &str> {
317 let Some(seed) = self.seed.checked_add(1) else { return Err("SeedOverflowError") };
318 self.seed = seed;
319 Ok(format!(".LC{seed:x}"))
320 }
321 fn register(&mut self, name: &str, ev: bool, fu: JFunc) {
323 self.f_table.insert(name.into(), BuiltinFunc { evaluated: ev, func: fu });
324 }
325 fn string2var(&mut self, json: &Json, ctx: &str) -> ErrOR<String> {
327 if let JValue::LString(st) = &json.value {
328 let name = self.get_name()?;
329 writeln!(self.sect.data, " {name}: .string \"{st}\"")?;
330 Ok(name)
331 } else if let JValue::VString(var) = &json.value {
332 Ok(var.clone())
333 } else {
334 Err(self.fmt_err(&format!("'{ctx}' must be a string."), &json.info).into())
335 }
336 }
337 fn write_file(&self, start: &str, filename: &str, json_file: &str) -> io::Result<()> {
339 let mut writer = BufWriter::new(File::create(filename)?);
340 writer.write_all(format!(".file \"{json_file}\"\n.intel_syntax noprefix\n").as_bytes())?;
341 writer.write_all(include_bytes!("asm/data.s"))?;
342 writer.write_all(self.sect.data.as_bytes())?;
343 writer.write_all(include_bytes!("asm/bss.s"))?;
344 writer.write_all(self.sect.bss.as_bytes())?;
345 writer.write_all(include_bytes!("asm/start.s"))?;
346 writer.write_all(start.as_bytes())?;
347 writer.write_all(include_bytes!("asm/text.s"))?;
348 writer.write_all(self.sect.text.as_bytes())?;
349 writer.flush()?;
350 Ok(())
351 }
352}