1use std::sync::Arc;
2
3use sim_kernel::{Cx, Error, Expr, Result, Symbol, Value};
4use sim_lib_standard_core::{
5 Arity, CoercionPolicy, GuestRuntimeKit, SharedOrganRuntime, TruthPolicy,
6};
7
8use crate::{
9 LuaEnv, LuaOp, LuaResult,
10 call::call_lua_value,
11 closure::{lua_closure_value, lua_varargs_values},
12 forms::{LuaForm, binding_symbol, bool_literal, lua_form, required_head, symbol_list},
13 load::install_lua_load_stdlib,
14 loops::{eval_generic_for, eval_numeric_for},
15 lua_binary, lua_core_profile, lua_get, lua_len, lua_rawget, lua_rawset, lua_table_from_values,
16 stdlib_base::install_lua_base_stdlib,
17 stdlib_coroutine::install_lua_coroutine_stdlib,
18 stdlib_debug::install_lua_debug_stdlib,
19 stdlib_io::install_lua_io_stdlib,
20 stdlib_math::install_lua_math_stdlib,
21 stdlib_os::install_lua_os_stdlib,
22 stdlib_package::install_lua_package_stdlib,
23 stdlib_string::install_lua_string_stdlib,
24 stdlib_table::install_lua_table_stdlib,
25 stdlib_utf8::install_lua_utf8_stdlib,
26};
27
28#[derive(Clone, Debug)]
30pub struct LuaEvalPolicy {
31 kit: GuestRuntimeKit,
32}
33
34impl LuaEvalPolicy {
35 pub fn new(cx: &mut Cx) -> Result<Self> {
37 let mut runtime = SharedOrganRuntime::new();
38 let profile = lua_core_profile();
39 let profile_symbol = profile.symbol.clone();
40 runtime.register_profile(profile)?;
41 runtime.register_kit(&profile_symbol, lua_runtime_kit(cx)?)?;
42 let kit = runtime
43 .kit(&profile_symbol)
44 .cloned()
45 .ok_or(Error::UnknownSymbol {
46 symbol: profile_symbol,
47 })?;
48 Ok(Self { kit })
49 }
50
51 pub fn kit(&self) -> &GuestRuntimeKit {
53 &self.kit
54 }
55
56 pub fn install_stdlib(&self, cx: &mut Cx, env: &mut LuaEnv) -> Result<()> {
58 install_lua_base_stdlib(cx, self, env)?;
59 install_lua_coroutine_stdlib(cx, self, env)?;
60 install_lua_load_stdlib(cx, self, env)?;
61 install_lua_math_stdlib(cx, self, env)?;
62 install_lua_package_stdlib(cx, self, env)?;
63 install_lua_io_stdlib(cx, self, env)?;
64 install_lua_os_stdlib(cx, self, env)?;
65 install_lua_debug_stdlib(cx, self, env)?;
66 install_lua_table_stdlib(cx, self, env)?;
67 install_lua_string_stdlib(cx, self, env)?;
68 install_lua_utf8_stdlib(cx, self, env)
69 }
70
71 pub fn eval(&self, cx: &mut Cx, env: &mut LuaEnv, expr: &Expr) -> Result<LuaResult> {
73 if let Some((form, args)) = lua_form(expr) {
74 return match form {
75 LuaForm::Chunk | LuaForm::Block => self.eval_block(cx, env, args),
76 LuaForm::Local => self.eval_local(cx, env, args),
77 LuaForm::LocalValues => self.eval_local_values(cx, env, args),
78 LuaForm::Assign => self.eval_assign(cx, env, args),
79 LuaForm::If => self.eval_if(cx, env, args),
80 LuaForm::Call => self.eval_call_form(cx, env, args),
81 LuaForm::Closure => self.eval_closure(cx, env, args),
82 LuaForm::Varargs => self.eval_varargs(env, args),
83 LuaForm::Return => self.eval_return(cx, env, args),
84 LuaForm::Break => self.eval_break(args),
85 LuaForm::NumericFor => {
86 eval_numeric_for(cx, self, env, args, |policy, cx, env, expr| {
87 policy.eval_one(cx, env, expr)
88 })
89 }
90 LuaForm::GenericFor => {
91 eval_generic_for(cx, self, env, args, |policy, cx, env, expr| {
92 policy.eval_one(cx, env, expr)
93 })
94 }
95 LuaForm::Stdlib => self.eval_stdlib(cx, env, args),
96 LuaForm::Table => self.eval_table(cx, env, args),
97 LuaForm::Get => self.eval_get(cx, env, args),
98 LuaForm::RawGet => self.eval_rawget(cx, env, args),
99 LuaForm::RawSet => self.eval_rawset(cx, env, args),
100 LuaForm::Len => self.eval_len(cx, env, args),
101 LuaForm::Binary(op) => self.eval_binary(cx, env, op, args),
102 };
103 }
104
105 match expr {
106 Expr::Block(body) => self.eval_block(cx, env, body),
107 Expr::Call { operator, args } => self.eval_call(cx, env, operator, args),
108 _ => self.eval_atom(cx, env, expr).map(LuaResult::one),
109 }
110 }
111
112 fn eval_block(&self, cx: &mut Cx, env: &mut LuaEnv, body: &[Expr]) -> Result<LuaResult> {
113 let mut last = vec![self.kit.nil.clone()];
114 for (index, expr) in body.iter().enumerate() {
115 let result = self.eval(cx, env, expr)?;
116 if result.is_return() || result.is_break() {
117 return Ok(result);
118 }
119 let values = result.into_values();
120 last = if index + 1 == body.len() {
121 values
122 } else {
123 self.kit.adjust_values(values, Arity::AtLeastOne)
124 };
125 }
126 Ok(LuaResult::values(last))
127 }
128
129 fn eval_local(&self, cx: &mut Cx, env: &mut LuaEnv, args: &[Expr]) -> Result<LuaResult> {
130 let (name_expr, value_exprs) = required_head(args, "lua local")?;
131 if value_exprs.len() > 1 {
132 return Err(Error::Eval("lua local accepts one initializer".to_owned()));
133 }
134 let name = binding_symbol(name_expr, "lua local")?;
135 let value = match value_exprs.first() {
136 Some(value_expr) => self.eval_one(cx, env, value_expr)?,
137 None => self.kit.nil.clone(),
138 };
139 env.define(name, value.clone())?;
140 Ok(LuaResult::one(value))
141 }
142
143 fn eval_local_values(&self, cx: &mut Cx, env: &mut LuaEnv, args: &[Expr]) -> Result<LuaResult> {
144 let (names_expr, value_exprs) = required_head(args, "lua local-values")?;
145 let names = symbol_list(names_expr, "lua local-values")?;
146 let values = self.assignment_values(cx, env, value_exprs, names.len())?;
147 for (name, value) in names.into_iter().zip(values.iter().cloned()) {
148 env.define(name, value)?;
149 }
150 Ok(LuaResult::values(values))
151 }
152
153 fn eval_assign(&self, cx: &mut Cx, env: &mut LuaEnv, args: &[Expr]) -> Result<LuaResult> {
154 let (name_expr, value_exprs) = required_head(args, "lua assign")?;
155 if value_exprs.len() != 1 {
156 return Err(Error::Eval("lua assign requires one value".to_owned()));
157 }
158 let name = binding_symbol(name_expr, "lua assign")?;
159 let value = self.eval_one(cx, env, &value_exprs[0])?;
160 let assigned = env.assign(&name, value)?;
161 Ok(LuaResult::one(assigned))
162 }
163
164 fn eval_if(&self, cx: &mut Cx, env: &mut LuaEnv, args: &[Expr]) -> Result<LuaResult> {
165 if !(2..=3).contains(&args.len()) {
166 return Err(Error::Eval(
167 "lua if requires condition, then, and optional else".to_owned(),
168 ));
169 }
170 let condition = self.eval_one(cx, env, &args[0])?;
171 if self.kit.is_truthy(cx, &condition)? {
172 self.eval(cx, env, &args[1])
173 } else if let Some(else_expr) = args.get(2) {
174 self.eval(cx, env, else_expr)
175 } else {
176 Ok(LuaResult::one(self.kit.nil.clone()))
177 }
178 }
179
180 fn eval_call_form(&self, cx: &mut Cx, env: &mut LuaEnv, args: &[Expr]) -> Result<LuaResult> {
181 let (operator, value_exprs) = required_head(args, "lua call")?;
182 self.eval_call(cx, env, operator, value_exprs)
183 }
184
185 fn eval_call(
186 &self,
187 cx: &mut Cx,
188 env: &mut LuaEnv,
189 operator: &Expr,
190 args: &[Expr],
191 ) -> Result<LuaResult> {
192 let callee = self.eval_one(cx, env, operator)?;
193 let values = self.eval_argument_values(cx, env, args)?;
194 call_lua_value(cx, self, callee, values).map(LuaResult::values)
195 }
196
197 fn eval_closure(&self, cx: &mut Cx, env: &mut LuaEnv, args: &[Expr]) -> Result<LuaResult> {
198 if !(4..=5).contains(&args.len()) {
199 return Err(Error::Eval(
200 "lua closure requires name, params, vararg flag, body, and optional captures"
201 .to_owned(),
202 ));
203 }
204 let name = binding_symbol(&args[0], "lua closure")?;
205 let params = symbol_list(&args[1], "lua closure params")?;
206 let vararg = bool_literal(&args[2], "lua closure vararg flag")?;
207 let captures = match args.get(4) {
208 Some(expr) => symbol_list(expr, "lua closure captures")?,
209 None => Vec::new(),
210 };
211 lua_closure_value(cx, env, name, params, vararg, args[3].clone(), captures)
212 .map(LuaResult::one)
213 }
214
215 fn eval_varargs(&self, env: &mut LuaEnv, args: &[Expr]) -> Result<LuaResult> {
216 if !args.is_empty() {
217 return Err(Error::Eval("lua varargs accepts no operands".to_owned()));
218 }
219 let value = env.get(&Symbol::new("..."))?;
220 let values = lua_varargs_values(&value)
221 .ok_or_else(|| Error::Eval("lua varargs local is not a vararg bundle".to_owned()))?;
222 Ok(LuaResult::values(values))
223 }
224
225 fn eval_return(&self, cx: &mut Cx, env: &mut LuaEnv, args: &[Expr]) -> Result<LuaResult> {
226 Ok(LuaResult::return_values(
227 self.eval_multi_exprs(cx, env, args)?,
228 ))
229 }
230
231 fn eval_break(&self, args: &[Expr]) -> Result<LuaResult> {
232 if !args.is_empty() {
233 return Err(Error::Eval("lua break accepts no operands".to_owned()));
234 }
235 Ok(LuaResult::break_signal())
236 }
237
238 fn eval_stdlib(&self, cx: &mut Cx, env: &mut LuaEnv, args: &[Expr]) -> Result<LuaResult> {
239 if !args.is_empty() {
240 return Err(Error::Eval("lua stdlib accepts no operands".to_owned()));
241 }
242 self.install_stdlib(cx, env)?;
243 Ok(LuaResult::one(self.kit.nil.clone()))
244 }
245
246 fn eval_table(&self, cx: &mut Cx, env: &mut LuaEnv, args: &[Expr]) -> Result<LuaResult> {
247 if !args.len().is_multiple_of(2) {
248 return Err(Error::Eval(
249 "lua table requires key/value expression pairs".to_owned(),
250 ));
251 }
252 let mut entries = Vec::with_capacity(args.len() / 2);
253 for pair in args.chunks_exact(2) {
254 entries.push((
255 self.eval_one(cx, env, &pair[0])?,
256 self.eval_one(cx, env, &pair[1])?,
257 ));
258 }
259 lua_table_from_values(cx, entries).map(LuaResult::one)
260 }
261
262 fn eval_get(&self, cx: &mut Cx, env: &mut LuaEnv, args: &[Expr]) -> Result<LuaResult> {
263 let [table, key] = args else {
264 return Err(Error::Eval("lua get requires table and key".to_owned()));
265 };
266 let table = self.eval_one(cx, env, table)?;
267 let key = self.eval_one(cx, env, key)?;
268 Ok(LuaResult::one(
269 lua_get(cx, &table, &key)?.unwrap_or_else(|| self.kit.nil.clone()),
270 ))
271 }
272
273 fn eval_rawget(&self, cx: &mut Cx, env: &mut LuaEnv, args: &[Expr]) -> Result<LuaResult> {
274 let [table, key] = args else {
275 return Err(Error::Eval("lua rawget requires table and key".to_owned()));
276 };
277 let table = self.eval_one(cx, env, table)?;
278 let key = self.eval_one(cx, env, key)?;
279 Ok(LuaResult::one(
280 lua_rawget(cx, &table, &key)?.unwrap_or_else(|| self.kit.nil.clone()),
281 ))
282 }
283
284 fn eval_rawset(&self, cx: &mut Cx, env: &mut LuaEnv, args: &[Expr]) -> Result<LuaResult> {
285 let [table, key, value] = args else {
286 return Err(Error::Eval(
287 "lua rawset requires table, key, and value".to_owned(),
288 ));
289 };
290 let table = self.eval_one(cx, env, table)?;
291 let key = self.eval_one(cx, env, key)?;
292 let value = self.eval_one(cx, env, value)?;
293 lua_rawset(cx, &table, key, value.clone())?;
294 Ok(LuaResult::one(value))
295 }
296
297 fn eval_len(&self, cx: &mut Cx, env: &mut LuaEnv, args: &[Expr]) -> Result<LuaResult> {
298 let [value] = args else {
299 return Err(Error::Eval("lua len requires one value".to_owned()));
300 };
301 let value = self.eval_one(cx, env, value)?;
302 lua_len(cx, env, value).map(LuaResult::one)
303 }
304
305 fn eval_binary(
306 &self,
307 cx: &mut Cx,
308 env: &mut LuaEnv,
309 op: LuaOp,
310 args: &[Expr],
311 ) -> Result<LuaResult> {
312 let [left, right] = args else {
313 return Err(Error::Eval(format!(
314 "lua operator {} requires two operands",
315 op.name()
316 )));
317 };
318 let left = self.eval_one(cx, env, left)?;
319 let right = self.eval_one(cx, env, right)?;
320 lua_binary(cx, env, op, left, right).map(LuaResult::one)
321 }
322
323 fn eval_one(&self, cx: &mut Cx, env: &mut LuaEnv, expr: &Expr) -> Result<Value> {
324 match self.eval(cx, env, expr)? {
325 LuaResult::Values(values) => Ok(self
326 .kit
327 .adjust_values(values, Arity::AtLeastOne)
328 .into_iter()
329 .next()
330 .unwrap_or_else(|| self.kit.nil.clone())),
331 LuaResult::Return(_) => Err(Error::Eval(
332 "lua return cannot be used as a value expression".to_owned(),
333 )),
334 LuaResult::Break => Err(Error::Eval(
335 "lua break cannot be used as a value expression".to_owned(),
336 )),
337 }
338 }
339
340 fn eval_values(&self, cx: &mut Cx, env: &mut LuaEnv, expr: &Expr) -> Result<Vec<Value>> {
341 match self.eval(cx, env, expr)? {
342 LuaResult::Values(values) => {
343 if let [value] = values.as_slice()
344 && let Some(values) = lua_varargs_values(value)
345 {
346 return Ok(values);
347 }
348 Ok(values)
349 }
350 LuaResult::Return(_) => Err(Error::Eval(
351 "lua return cannot be used as a value expression".to_owned(),
352 )),
353 LuaResult::Break => Err(Error::Eval(
354 "lua break cannot be used as a value expression".to_owned(),
355 )),
356 }
357 }
358
359 fn eval_multi_exprs(
360 &self,
361 cx: &mut Cx,
362 env: &mut LuaEnv,
363 exprs: &[Expr],
364 ) -> Result<Vec<Value>> {
365 let Some((last, prefix)) = exprs.split_last() else {
366 return Ok(Vec::new());
367 };
368 let mut values = Vec::with_capacity(exprs.len());
369 for expr in prefix {
370 values.push(self.eval_one(cx, env, expr)?);
371 }
372 values.extend(self.eval_values(cx, env, last)?);
373 Ok(values)
374 }
375
376 fn eval_argument_values(
377 &self,
378 cx: &mut Cx,
379 env: &mut LuaEnv,
380 exprs: &[Expr],
381 ) -> Result<Vec<Value>> {
382 self.eval_multi_exprs(cx, env, exprs)
383 }
384
385 fn assignment_values(
386 &self,
387 cx: &mut Cx,
388 env: &mut LuaEnv,
389 exprs: &[Expr],
390 count: usize,
391 ) -> Result<Vec<Value>> {
392 Ok(self
393 .kit
394 .adjust_values(self.eval_multi_exprs(cx, env, exprs)?, Arity::Exact(count)))
395 }
396
397 fn eval_atom(&self, cx: &mut Cx, env: &mut LuaEnv, expr: &Expr) -> Result<Value> {
398 match expr {
399 Expr::Nil => Ok(self.kit.nil.clone()),
400 Expr::Bool(value) => cx.factory().bool(*value),
401 Expr::Number(number) => cx
402 .factory()
403 .number_literal(number.domain.clone(), number.canonical.clone()),
404 Expr::String(value) => cx.factory().string(value.clone()),
405 Expr::Bytes(value) => cx.factory().bytes(value.clone()),
406 Expr::Symbol(symbol) => {
407 if env.contains(symbol) {
408 env.get(symbol)
409 } else {
410 cx.factory().symbol(symbol.clone())
411 }
412 }
413 Expr::Local(symbol) => env.get(symbol),
414 Expr::List(items) => {
415 let mut values = Vec::with_capacity(items.len());
416 for item in items {
417 values.push(self.eval_one(cx, env, item)?);
418 }
419 cx.factory().list(values)
420 }
421 Expr::Vector(items) => {
422 let mut values = Vec::with_capacity(items.len());
423 for item in items {
424 values.push(self.eval_one(cx, env, item)?);
425 }
426 cx.factory().list(values)
427 }
428 Expr::Map(entries) => {
429 let mut values = Vec::with_capacity(entries.len() * 2);
430 for (key, value) in entries {
431 values.push(self.eval_one(cx, env, key)?);
432 values.push(self.eval_one(cx, env, value)?);
433 }
434 cx.factory().list(values)
435 }
436 Expr::Set(items) => {
437 let mut values = Vec::with_capacity(items.len());
438 for item in items {
439 values.push(self.eval_one(cx, env, item)?);
440 }
441 cx.factory().list(values)
442 }
443 Expr::Block(body) => match self.eval_block(cx, env, body)? {
444 LuaResult::Values(values) => Ok(self
445 .kit
446 .adjust_values(values, Arity::AtLeastOne)
447 .into_iter()
448 .next()
449 .unwrap_or_else(|| self.kit.nil.clone())),
450 LuaResult::Return(_) => Err(Error::Eval(
451 "lua return cannot be used as a value expression".to_owned(),
452 )),
453 LuaResult::Break => Err(Error::Eval(
454 "lua break cannot be used as a value expression".to_owned(),
455 )),
456 },
457 Expr::Quote { expr, .. } => cx.factory().expr((**expr).clone()),
458 Expr::Annotated { expr, .. } => self.eval_one(cx, env, expr),
459 Expr::Extension { .. }
460 | Expr::Infix { .. }
461 | Expr::Prefix { .. }
462 | Expr::Postfix { .. } => cx.factory().expr(expr.clone()),
463 Expr::Call { .. } => unreachable!("calls are handled before atom evaluation"),
464 }
465 }
466}
467
468fn lua_runtime_kit(cx: &mut Cx) -> Result<GuestRuntimeKit> {
469 Ok(GuestRuntimeKit::new(
470 Arc::new(LuaTruthPolicy),
471 Arc::new(LuaCoercionPolicy),
472 cx.factory().nil()?,
473 ))
474}
475
476struct LuaTruthPolicy;
477
478impl TruthPolicy for LuaTruthPolicy {
479 fn is_truthy(&self, cx: &mut Cx, value: &Value) -> Result<bool> {
480 Ok(!matches!(
481 value.object().as_expr(cx)?,
482 Expr::Nil | Expr::Bool(false)
483 ))
484 }
485}
486
487struct LuaCoercionPolicy;
488
489impl CoercionPolicy for LuaCoercionPolicy {
490 fn to_number(&self, _cx: &mut Cx, _value: &Value) -> Result<Option<Value>> {
491 Ok(None)
492 }
493
494 fn to_string(&self, _cx: &mut Cx, _value: &Value) -> Result<Option<Value>> {
495 Ok(None)
496 }
497}