1#![feature(decl_macro)]
5#![cfg_attr(test, feature(assert_matches))]
6#![allow(unused_imports)]
7
8pub use cl_interpret::{convalue::ConValue as Value, env::Environment};
9
10use cl_ast::{Block, Module, ast_visitor::Fold};
11use cl_interpret::{convalue::ConValue, interpret::Interpret};
12use cl_lexer::Lexer;
13use cl_parser::{Parser, error::Error as ParseError, inliner::ModuleInliner};
14use std::{path::Path, sync::OnceLock};
15
16pub macro conlang (
44 $($t:tt)*
45) {{
46 static FN: OnceLock<Result<Block, ParseError>> = OnceLock::new();
48
49 |env: &mut Environment| -> Result<ConValue, EvalError> {
50 FN.get_or_init(|| {
51 let path = AsRef::<Path>::as_ref(&concat!(env!("CARGO_MANIFEST_DIR"),"/../../", file!())).with_extension("");
53 let mut mi = ModuleInliner::new(path);
54 let code = mi.fold_block(
55 Parser::new(
56 concat!(file!(), ":", line!(), ":"),
57 Lexer::new(stringify!({ $($t)* })),
58 )
59 .parse::<Block>()?,
60 );
61 if let Some((ie, pe)) = mi.into_errs() {
62 for (file, err) in ie {
63 eprintln!("{}: {err}", file.display());
64 }
65 for (file, err) in pe {
66 eprintln!("{}: {err}", file.display());
67 }
68 }
69 Ok(code)
70 })
71 .as_ref()
72 .map_err(Clone::clone)?
73 .interpret(env)
74 .map_err(Into::into)
75 }
76}}
77
78#[derive(Clone, Debug)]
79pub enum EvalError {
80 Parse(cl_parser::error::Error),
81 Interpret(cl_interpret::error::Error),
82}
83
84impl From<cl_parser::error::Error> for EvalError {
85 fn from(value: cl_parser::error::Error) -> Self {
86 Self::Parse(value)
87 }
88}
89impl From<cl_interpret::error::Error> for EvalError {
90 fn from(value: cl_interpret::error::Error) -> Self {
91 Self::Interpret(value)
92 }
93}
94impl std::error::Error for EvalError {}
95impl std::fmt::Display for EvalError {
96 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
97 match self {
98 EvalError::Parse(error) => error.fmt(f),
99 EvalError::Interpret(error) => error.fmt(f),
100 }
101 }
102}
103
104#[cfg(test)]
105mod tests {
106 use std::assert_matches::assert_matches;
107
108 use super::*;
109
110 #[test]
111 fn it_works() -> Result<(), EvalError> {
112 let mut env = Environment::new();
113
114 let result = conlang! {
115 fn add(left, right) -> isize {
116 left + right
117 }
118
119 add(2, 2)
120 }(&mut env);
121
122 assert_matches!(result, Ok(Value::Int(4)));
123
124 Ok(())
125 }
126}