cl-embed: Calculator example update!

This commit is contained in:
2025-07-18 05:26:39 -04:00
parent 148ef34a01
commit e165e029dc
3 changed files with 136 additions and 56 deletions

View File

@@ -1,25 +1,27 @@
//! Demonstrates the cl_embed library
use cl_embed::*;
use repline::{Response, prebaked};
fn main() -> Result<(), repline::Error> {
let mut env = Environment::new();
if let Err(e) = conlang_include!("calculator/expression.cl")(&mut env) {
panic!("{e}")
}
prebaked::read_and("", "calc >", " ? >", |line| {
calc(line).map_err(Into::into)
env.bind("line", line);
let res = conlang! {
let (expr, rest) = parse(line.chars(), Power::None);
execute(expr)
}(&mut env)?;
println!("{res}");
Ok(Response::Accept)
})
}
fn calc(line: &str) -> Result<Response, EvalError> {
let mut env = Environment::new();
env.bind("line", line);
let res = conlang!(
mod expression;
use expression::{eval, parse};
let (expr, rest) = parse(line.chars(), 0);
eval(expr)
)(&mut env)?;
println!("{res}");
Ok(Response::Accept)
}

View File

@@ -7,7 +7,7 @@
pub use cl_interpret::{convalue::ConValue as Value, env::Environment};
use cl_ast::{Block, Module, ast_visitor::Fold};
use cl_ast::{Block, File, Module, ast_visitor::Fold};
use cl_interpret::{convalue::ConValue, interpret::Interpret};
use cl_lexer::Lexer;
use cl_parser::{Parser, error::Error as ParseError, inliner::ModuleInliner};
@@ -40,7 +40,7 @@ use std::{path::Path, sync::OnceLock};
/// # Ok(())
/// # }
/// ```
pub macro conlang (
pub macro conlang(
$($t:tt)*
) {{
// Parse once
@@ -49,11 +49,13 @@ pub macro conlang (
|env: &mut Environment| -> Result<ConValue, EvalError> {
FN.get_or_init(|| {
// TODO: embed the full module tree at compile time
let path = AsRef::<Path>::as_ref(&concat!(env!("CARGO_MANIFEST_DIR"),"/../../", file!())).with_extension("");
let path =
AsRef::<Path>::as_ref(&concat!(env!("CARGO_MANIFEST_DIR"), "/../../", file!()))
.with_extension("");
let mut mi = ModuleInliner::new(path);
let code = mi.fold_block(
Parser::new(
concat!(file!(), ":", line!(), ":"),
concat!(file!(), ":", line!(), ":", column!()),
Lexer::new(stringify!({ $($t)* })),
)
.parse::<Block>()?,
@@ -75,6 +77,60 @@ pub macro conlang (
}
}}
pub macro conlang_include{
($path:literal, $name:ident) => {
|env: &mut Environment| -> Result<ConValue, EvalError> {
// TODO: embed the full module tree at compile time
let path = AsRef::<Path>::as_ref(&concat!(env!("CARGO_MANIFEST_DIR"), "/../../", file!()))
.with_file_name(concat!($path));
let mut mi = ModuleInliner::new(path);
let code = mi.fold_module(Module {
name: stringify!($name).into(),
file: Some(
Parser::new(
concat!(file!(), ":", line!(), ":", column!()),
Lexer::new(include_str!($path)),
)
.parse()?,
),
});
if let Some((ie, pe)) = mi.into_errs() {
for (file, err) in ie {
eprintln!("{}: {err}", file.display());
}
for (file, err) in pe {
eprintln!("{}: {err}", file.display());
}
}
code.interpret(env).map_err(Into::into)
}
},
($path:literal) => {
|env: &mut Environment| -> Result<ConValue, EvalError> {
// TODO: embed the full module tree at compile time
let path = AsRef::<Path>::as_ref(&concat!(env!("CARGO_MANIFEST_DIR"), "/../../", file!()))
.with_file_name(concat!($path));
let mut mi = ModuleInliner::new(path);
let code = mi.fold_file(
Parser::new(
concat!(file!(), ":", line!(), ":", column!()),
Lexer::new(include_str!($path)),
)
.parse()?,
);
if let Some((ie, pe)) = mi.into_errs() {
for (file, err) in ie {
eprintln!("{}: {err}", file.display());
}
for (file, err) in pe {
eprintln!("{}: {err}", file.display());
}
}
code.interpret(env).map_err(Into::into)
}
}
}
#[derive(Clone, Debug)]
pub enum EvalError {
Parse(cl_parser::error::Error),