1#![cfg_attr(not(test), no_std)]
90
91extern crate alloc;
92
93use core::fmt::Display;
94
95use alloc::{
96 boxed::Box,
97 collections::linked_list::LinkedList,
98 format,
99 string::{String, ToString},
100 vec::Vec,
101};
102
103pub mod coq;
104pub mod r#macro;
105pub mod parser;
106pub mod runtime;
107pub mod semantics;
108
109pub use blisp_embedded::embedded;
110use r#macro::{process_macros, Macros};
111use runtime::FFI;
112
113#[derive(Debug, Clone, Copy)]
114pub enum FileType {
115 Prelude,
116 User,
117 Eval,
118 Extern(u64),
119}
120
121#[derive(Debug, Clone, Copy)]
123pub struct Pos {
124 pub file_id: FileType,
125 pub line: usize, pub column: usize, }
128
129impl Display for Pos {
130 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
131 write!(f, "{:?}:{}:{}", self.file_id, self.line, self.column)
132 }
133}
134
135#[derive(Debug)]
137pub struct LispErr {
138 pub msg: String,
139 pub pos: Pos,
140}
141
142impl LispErr {
143 fn new(msg: String, pos: Pos) -> LispErr {
144 LispErr { msg, pos }
145 }
146}
147
148pub struct TypingContext {
149 exprs: LinkedList<parser::Expr>,
150 ext_funs: Vec<Box<dyn FFI + Send>>,
151 macros: Macros,
152}
153
154pub fn init(code: &str, ext_funs: Vec<Box<dyn FFI + Send>>) -> Result<TypingContext, LispErr> {
167 let prelude = include_str!("prelude.lisp");
168 let mut ps = parser::Parser::new(prelude, FileType::Prelude);
170 let mut exprs = match ps.parse() {
171 Ok(e) => e,
172 Err(e) => {
173 let msg = format!("Syntax Error: {}", e.msg);
174 return Err(LispErr::new(msg, e.pos));
175 }
176 };
177
178 for (i, fun) in ext_funs.iter().enumerate() {
179 let mut ps = parser::Parser::new(fun.blisp_extern(), FileType::Extern(i as u64));
180 match ps.parse() {
181 Ok(mut e) => {
182 exprs.append(&mut e);
183 }
184 Err(e) => {
185 let msg = format!("Syntax Error: {}", e.msg);
186 return Err(LispErr::new(msg, e.pos));
187 }
188 }
189 }
190
191 let mut ps = parser::Parser::new(code, FileType::User);
192 match ps.parse() {
193 Ok(mut e) => {
194 exprs.append(&mut e);
195
196 let macros = match process_macros(&mut exprs) {
197 Ok(macros) => macros,
198 Err(e) => {
199 let msg = format!("Macro Error: {}", e.msg);
200 return Err(LispErr::new(msg, e.pos));
201 }
202 };
203
204 Ok(TypingContext {
205 exprs,
206 ext_funs,
207 macros,
208 })
209 }
210 Err(e) => {
211 let msg = format!("Syntax Error: {}", e.msg);
212 Err(LispErr::new(msg, e.pos))
213 }
214 }
215}
216
217pub fn typing(exprs: TypingContext) -> Result<semantics::Context, LispErr> {
231 match semantics::exprs2context(exprs) {
232 Ok(c) => Ok(c),
233 Err(e) => {
234 let msg = format!("Typing Error: {}", e.msg);
235 Err(LispErr::new(msg, e.pos))
236 }
237 }
238}
239
240pub fn eval(
258 code: &str,
259 ctx: &semantics::Context,
260) -> Result<LinkedList<Result<String, String>>, LispErr> {
261 runtime::eval(code, ctx)
262}
263
264pub fn transpile(ctx: &semantics::Context) -> String {
265 let mut s = "".to_string();
266 for (_, d) in ctx.data.iter() {
267 s = format!("{}{}\n", s, coq::to_coq_data(d));
268 }
269
270 for (_, f) in ctx.funs.iter() {
271 s = format!("{}{}\n", s, coq::to_coq_func(f));
272 }
273
274 format!("{}\n\n{}", coq::import(), s)
275}
276
277#[cfg(test)]
278mod tests {
279 use super::*;
280
281 #[test]
282 fn test_macro() {
283 let expr = "
284(macro add
285 ((add $e1 $e2) (+ $e1 $e2))
286 ((add $e1 $e2 $e3 ...) (+ $e1 (add $e2 $e3 ...))))
287
288(macro minus
289 ((_ $e1 $e2) (- $e1 $e2))
290 ((_ $e1 $e2 $e3 ...) (- $e1 (minus $e2 $e3 ...))))
291
292(macro tuple_to_list
293 ((_ []) ((lambda (x) x) '()))
294 ((_ [$e ...]) ((lambda (x) x) '($e ...))))
295
296(macro none ((_ _) ([])))
297
298(tuple_to_list [])
299(tuple_to_list [1 2 3])
300
301(add 1 2 3 4 5)
302
303(defun test_add () (Pure (-> () Int))
304 (add 1 2 3 4 (minus 5 6 7) 8))
305
306(add 1)
307
308(none 123)
309";
310
311 let typing_context = init(expr, vec![]).unwrap();
312
313 for expr in typing_context.exprs.iter() {
314 println!("{expr}");
315 }
316 }
317
318 fn eval_result(code: &str, ctx: &semantics::Context) {
319 for r in eval(code, ctx).unwrap() {
320 println!("{} -> {}", code, r.unwrap());
321 }
322 }
323
324 #[test]
325 fn ops() {
326 let exprs = init("", vec![]).unwrap();
327 let ctx = typing(exprs).unwrap();
328 eval_result("(neq (Some \"Hello\") 10)", &ctx);
329 eval_result("(chars \"Hello, World!\")", &ctx);
330 eval_result("(str '(`H` `e` `l` `l` `o`))", &ctx);
331 eval_result("`\\``", &ctx);
332 eval_result("(= `h` `h`)", &ctx);
333 eval_result("(<< 8 4)", &ctx);
334 eval_result("(>> 128 4)", &ctx);
335 eval_result("\"Hello, World!\"", &ctx);
336 eval_result("(= \"Hello, World!\" \"Hello, World!\")", &ctx);
337 eval_result("(= (Some 1) (Some 2))", &ctx);
338 eval_result("(< (Some 1) (Some 2))", &ctx);
339 eval_result("(> (Some 1) (Some 2))", &ctx);
340 eval_result("(= \"Hello\" \"Hel\")", &ctx);
341 eval_result("(eq \"Hello\" 10)", &ctx);
342 eval_result("(lt \"Hello\" 10)", &ctx);
343 eval_result("(lt 5 10)", &ctx);
344 eval_result("(+ 0x10 0x20)", &ctx);
345 eval_result("(+ 0b111 0b101)", &ctx);
346 eval_result("(+ 0o777 0o444)", &ctx);
347 eval_result("(+ 10 20)", &ctx);
348 eval_result("(pow 10 20)", &ctx);
349 eval_result("(band 1 0)", &ctx);
350 eval_result("(band 1 1)", &ctx);
351 eval_result("(bor 1 0)", &ctx);
352 eval_result("(bor 1 1)", &ctx);
353 eval_result("(bxor 1 0)", &ctx);
354 eval_result("(bxor 1 1)", &ctx);
355 eval_result("(sqrt 16)", &ctx);
356 eval_result("(sqrt -1)", &ctx);
357 }
358
359 #[test]
360 fn lambda() {
361 let expr = "(export lambda-test (f)
362 (Pure (-> ((Pure (-> (Int Int) Int))) Int))
363 (f 10 20))
364";
365 let exprs = init(expr, vec![]).unwrap();
366 let ctx = typing(exprs).unwrap();
367 let e = "(lambda-test (lambda (x y) (* x y)))";
368 eval_result(e, &ctx);
369
370 let e = "(lambda-test +)";
371 eval_result(e, &ctx);
372 }
373
374 #[test]
375 fn list() {
376 let expr = "
377(export head (x) (Pure (-> ('(Int)) (Option Int)))
378 (match x
379 ((Cons n _) (Some n))
380 (_ None)))
381(export tail (x) (Pure (-> ('(Int)) (Option Int)))
382 ; match expression
383 (match x
384 (Nil None)
385 ((Cons n Nil) (Some n))
386 ((Cons _ l) (tail l))))
387";
388 let exprs = init(expr, vec![]).unwrap();
389 let ctx = typing(exprs).unwrap();
390
391 let e = "(head '(30 40 50))";
392 eval_result(e, &ctx);
393
394 let e = "(tail '(30 40 50))";
395 eval_result(e, &ctx);
396 }
397
398 #[test]
399 fn tuple() {
400 let expr = "(export first (x) (Pure (-> ([Int Bool]) Int))
401 (match x
402 ([n _] n)))
403";
404 let exprs = init(expr, vec![]).unwrap();
405 let ctx = typing(exprs).unwrap();
406 let e = "(first [10 false])";
407 eval_result(e, &ctx);
408 }
409
410 #[test]
411 fn prelude() {
412 let expr = "
413(export factorial (n) (Pure (-> (Int) Int))
414 (factorial' n 1))
415(defun factorial' (n total) (Pure (-> (Int Int) Int))
416 (if (<= n 0)
417 total
418 (factorial' (- n 1) (* n total))))
419";
420 let exprs = init(expr, vec![]).unwrap();
421 let ctx = typing(exprs).unwrap();
422
423 let e = "(Some 10)";
424 eval_result(e, &ctx);
425
426 let e = "(car '(1 2 3))";
427 eval_result(e, &ctx);
428
429 let e = "(cdr '(1 2 3))";
430 eval_result(e, &ctx);
431
432 let e = "(map (lambda (x) (* x 2)) '(8 9 10))";
433 eval_result(e, &ctx);
434
435 let e = "(fold + 0 '(1 2 3 4 5 6 7 8 9))";
436 eval_result(e, &ctx);
437
438 let e = "(reverse '(1 2 3 4 5 6 7 8 9))";
439 eval_result(e, &ctx);
440
441 let e = "(filter (lambda (x) (= (% x 2) 0)) '(1 2 3 4 5 6 7 8 9))";
442 eval_result(e, &ctx);
443
444 let e = "(factorial 2000)";
445 eval_result(e, &ctx);
446 }
447
448 #[test]
449 fn callback() {
450 let expr = "
451(export callback (x y z) (IO (-> (Int Int Int) (Option Int)))
452 (call-rust x y z))";
453 let exprs = init(expr, vec![]).unwrap();
454 let mut ctx = typing(exprs).unwrap();
455
456 use num_bigint::BigInt;
457 use std::boxed::Box;
458 let fun = |x: &BigInt, y: &BigInt, z: &BigInt| {
459 let n = x * y * z;
460 println!("n = {}", n);
461 Some(n)
462 };
463 ctx.set_callback(Box::new(fun));
464
465 let e = "(callback 100 2000 30000)";
466 eval_result(e, &ctx);
467 }
468
469 #[test]
470 fn do_transpile() {
471 let expr = "
472 (defun snoc (l y)
473 (Pure (-> (
474 '(t) t)
475 '(t)))
476 (match l
477 (nil (Cons y nil))
478 ((Cons h b) (Cons h (snoc b y)))))
479
480 (defun rev (l)
481 (Pure (-> (
482 '(t))
483 '(t)))
484 (match l
485 (nil nil)
486 ((Cons h t) (snoc (rev t) h))))
487 ";
488 let exprs = init(expr, vec![]).unwrap();
489 let ctx = typing(exprs).unwrap();
490
491 println!("{}", transpile(&ctx));
492 }
493
494 #[test]
495 fn test_multibyte() {
496 let expr = "あ";
497 let _exprs = init(expr, vec![]).unwrap();
498
499 let expr = "";
500 let exprs = init(expr, vec![]).unwrap();
501 let ctx = typing(exprs).unwrap();
502
503 let e = "\"あ\"";
504 let r = eval(e, &ctx).unwrap();
505 println!("{r:?}");
506
507 let e = "`あ`";
508 let r = eval(e, &ctx).unwrap();
509 println!("{r:?}");
510 }
511}