cl-interpret: Literal[String] a la python

This commit is contained in:
John 2025-07-20 15:57:11 -04:00
parent 259c9f8bb6
commit 239785b322
6 changed files with 100 additions and 31 deletions

View File

@ -178,6 +178,7 @@ pub const Builtins: &[Builtin] = &builtins![
fn len(list) @env {
Ok(match list {
ConValue::Empty => 0,
ConValue::Str(s) => s.chars().count() as _,
ConValue::String(s) => s.chars().count() as _,
ConValue::Ref(r) => {
return len(env, &[env.get_id(*r).ok_or(Error::StackOverflow(*r))?.clone()])
@ -203,6 +204,7 @@ pub const Builtins: &[Builtin] = &builtins![
fn chars(string) @env {
Ok(match string {
ConValue::Str(s) => ConValue::Array(s.chars().map(Into::into).collect()),
ConValue::String(s) => ConValue::Array(s.chars().map(Into::into).collect()),
ConValue::Ref(r) => {
return chars(env, &[env.get_id(*r).ok_or(Error::StackOverflow(*r))?.clone()])
@ -259,7 +261,15 @@ pub const Math: &[Builtin] = &builtins![
Ok(match (lhs, rhs) {
(ConValue::Empty, ConValue::Empty) => ConValue::Empty,
(ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a + b),
(ConValue::String(a), ConValue::String(b)) => (a.to_string() + &b.to_string()).into(),
(ConValue::Str(a), ConValue::Str(b)) => (a.to_string() + b).into(),
(ConValue::Str(a), ConValue::String(b)) => (a.to_string() + b).into(),
(ConValue::String(a), ConValue::Str(b)) => (a.to_string() + b).into(),
(ConValue::String(a), ConValue::String(b)) => (a.to_string() + b).into(),
(ConValue::Str(s), ConValue::Char(c)) => { let mut s = s.to_string(); s.push(*c); s.into() }
(ConValue::String(s), ConValue::Char(c)) => { let mut s = s.to_string(); s.push(*c); s.into() }
(ConValue::Char(a), ConValue::Char(b)) => {
ConValue::String([a, b].into_iter().collect::<String>())
}
_ => Err(Error::TypeError())?
})
}
@ -375,6 +385,9 @@ pub const Math: &[Builtin] = &builtins![
(ConValue::Int(a), ConValue::Int(b)) => a.cmp(b) as _,
(ConValue::Bool(a), ConValue::Bool(b)) => a.cmp(b) as _,
(ConValue::Char(a), ConValue::Char(b)) => a.cmp(b) as _,
(ConValue::Str(a), ConValue::Str(b)) => a.cmp(b) as _,
(ConValue::Str(a), ConValue::String(b)) => a.to_ref().cmp(b.as_str()) as _,
(ConValue::String(a), ConValue::Str(b)) => a.as_str().cmp(b.to_ref()) as _,
(ConValue::String(a), ConValue::String(b)) => a.cmp(b) as _,
_ => Err(error_format!("Incomparable values: {head}, {tail}"))?
}))

View File

@ -51,8 +51,10 @@ pub enum ConValue {
Bool(bool),
/// A unicode character
Char(char),
/// A string
String(Sym),
/// A string literal
Str(Sym),
/// A dynamic string
String(String),
/// A reference
Ref(usize),
/// A reference to an array
@ -97,6 +99,7 @@ impl ConValue {
ConValue::Float(_) => "f64",
ConValue::Bool(_) => "bool",
ConValue::Char(_) => "char",
ConValue::Str(_) => "str",
ConValue::String(_) => "String",
ConValue::Ref(_) => "Ref",
ConValue::Slice(_, _) => "Slice",
@ -128,6 +131,11 @@ impl ConValue {
Err(Error::TypeError())?
};
match self {
ConValue::Str(string) => string
.chars()
.nth(index as _)
.map(ConValue::Char)
.ok_or(Error::OobIndex(index as usize, string.chars().count())),
ConValue::String(string) => string
.chars()
.nth(index as _)
@ -216,6 +224,9 @@ macro cmp ($($fn:ident: $empty:literal, $op:tt);*$(;)?) {$(
(Self::Float(a), Self::Float(b)) => Ok(Self::Bool(a $op b)),
(Self::Bool(a), Self::Bool(b)) => Ok(Self::Bool(a $op b)),
(Self::Char(a), Self::Char(b)) => Ok(Self::Bool(a $op b)),
(Self::Str(a), Self::Str(b)) => Ok(Self::Bool(&**a $op &**b)),
(Self::Str(a), Self::String(b)) => Ok(Self::Bool(&**a $op &**b)),
(Self::String(a), Self::Str(b)) => Ok(Self::Bool(&**a $op &**b)),
(Self::String(a), Self::String(b)) => Ok(Self::Bool(&**a $op &**b)),
_ => Err(Error::TypeError())
}
@ -235,7 +246,7 @@ macro from ($($T:ty => $v:expr),*$(,)?) {
}
impl From<&Sym> for ConValue {
fn from(value: &Sym) -> Self {
ConValue::String(*value)
ConValue::Str(*value)
}
}
from! {
@ -243,11 +254,11 @@ from! {
f64 => ConValue::Float,
bool => ConValue::Bool,
char => ConValue::Char,
Sym => ConValue::String,
&str => ConValue::String,
Sym => ConValue::Str,
&str => ConValue::Str,
Expr => ConValue::Quote,
String => ConValue::String,
Rc<str> => ConValue::String,
Rc<str> => ConValue::Str,
Function => ConValue::Function,
Vec<ConValue> => ConValue::Tuple,
&'static Builtin => ConValue::Builtin,
@ -282,10 +293,14 @@ ops! {
(ConValue::Empty, ConValue::Empty) => ConValue::Empty,
(ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a.wrapping_add(b)),
(ConValue::Float(a), ConValue::Float(b)) => ConValue::Float(a + b),
(ConValue::Str(a), ConValue::Str(b)) => (a.to_string() + &*b).into(),
(ConValue::Str(a), ConValue::String(b)) => (a.to_string() + &*b).into(),
(ConValue::String(a), ConValue::Str(b)) => (a.to_string() + &*b).into(),
(ConValue::String(a), ConValue::String(b)) => (a.to_string() + &*b).into(),
(ConValue::Str(s), ConValue::Char(c)) => { let mut s = s.to_string(); s.push(c); s.into() }
(ConValue::String(s), ConValue::Char(c)) => { let mut s = s.to_string(); s.push(c); s.into() }
(ConValue::Char(a), ConValue::Char(b)) => {
ConValue::String([a, b].into_iter().collect::<String>().into())
ConValue::String([a, b].into_iter().collect::<String>())
}
_ => Err(Error::TypeError())?
]
@ -354,6 +369,7 @@ impl std::fmt::Display for ConValue {
ConValue::Float(v) => v.fmt(f),
ConValue::Bool(v) => v.fmt(f),
ConValue::Char(v) => v.fmt(f),
ConValue::Str(v) => v.fmt(f),
ConValue::String(v) => v.fmt(f),
ConValue::Ref(v) => write!(f, "&<{}>", v),
ConValue::Slice(id, len) => write!(f, "&<{id}>[{len}..]"),

View File

@ -699,7 +699,7 @@ fn cast(env: &Environment, value: ConValue, ty: Sym) -> IResult<ConValue> {
// TODO: This, better
ConValue::Float(_) if ty.starts_with('f') => return Ok(value),
ConValue::Float(f) => f as _,
_ if (*ty).eq("str") => return Ok(ConValue::String(format!("{value}").into())),
_ if (*ty).eq("str") => return Ok(ConValue::Str(format!("{value}").into())),
_ => Err(Error::TypeError())?,
};
Ok(match &*ty {
@ -958,7 +958,7 @@ impl Interpret for For {
&ConValue::Slice(head, len) => Box::new((head..head + len).map(ConValue::Ref)),
// In the production compiler this may be fully unrolled
ConValue::Tuple(t) => Box::new(t.iter().cloned()),
ConValue::String(s) => Box::new(s.chars().map(ConValue::Char)),
ConValue::Str(s) => Box::new(s.chars().map(ConValue::Char)),
_ => Err(Error::TypeError())?,
};
loop {

View File

@ -139,6 +139,9 @@ pub fn append_sub(
(Pattern::Literal(Literal::Int(a)), ConValue::Int(b)) => {
(b == *a as _).then_some(()).ok_or(Error::NotAssignable())
}
(Pattern::Literal(Literal::String(a)), ConValue::Str(b)) => {
(*a == *b).then_some(()).ok_or(Error::NotAssignable())
}
(Pattern::Literal(Literal::String(a)), ConValue::String(b)) => {
(*a == *b).then_some(()).ok_or(Error::NotAssignable())
}
@ -157,6 +160,9 @@ pub fn append_sub(
(Pattern::Literal(Literal::Float(a)), ConValue::Float(b)) => {
(b < *a as _).then_some(()).ok_or(Error::NotAssignable())
}
(Pattern::Literal(Literal::String(a)), ConValue::Str(b)) => {
(&*b < a).then_some(()).ok_or(Error::NotAssignable())
}
(Pattern::Literal(Literal::String(a)), ConValue::String(b)) => {
(&*b < a).then_some(()).ok_or(Error::NotAssignable())
}
@ -207,10 +213,17 @@ pub fn append_sub(
(
Pattern::Literal(Literal::String(a)),
Pattern::Literal(Literal::String(c)),
ConValue::String(b),
ConValue::Str(b),
) => (a.as_str() <= b.to_ref() && b.to_ref() < c.as_str())
.then_some(())
.ok_or(Error::NotAssignable()),
(
Pattern::Literal(Literal::String(a)),
Pattern::Literal(Literal::String(c)),
ConValue::String(b),
) => (a.as_str() <= b.as_str() && b.as_str() < c.as_str())
.then_some(())
.ok_or(Error::NotAssignable()),
_ => Err(Error::NotAssignable()),
},
@ -239,10 +252,17 @@ pub fn append_sub(
(
Pattern::Literal(Literal::String(a)),
Pattern::Literal(Literal::String(c)),
ConValue::String(b),
ConValue::Str(b),
) => (a.as_str() <= b.to_ref() && b.to_ref() <= c.as_str())
.then_some(())
.ok_or(Error::NotAssignable()),
(
Pattern::Literal(Literal::String(a)),
Pattern::Literal(Literal::String(c)),
ConValue::String(b),
) => (a.as_str() <= b.as_str() && b.as_str() <= c.as_str())
.then_some(())
.ok_or(Error::NotAssignable()),
_ => Err(Error::NotAssignable()),
},

View File

@ -26,23 +26,29 @@ pub fn run(args: Args) -> Result<(), Box<dyn Error>> {
fn eval(string) @env {
use cl_interpret::error::Error;
let string = match *string {
ConValue::String(string) => string,
let string = match string {
ConValue::Str(string) => string.to_ref(),
ConValue::String(string) => string.as_str(),
ConValue::Ref(v) => {
let string = env.get_id(v).cloned().unwrap_or_default();
let string = env.get_id(*v).cloned().unwrap_or_default();
return eval(env, &[string])
}
_ => Err(Error::TypeError())?
};
match Parser::new("eval", Lexer::new(string.to_ref())).parse::<cl_ast::Stmt>() {
Err(e) => Ok(ConValue::String(format!("{e}").into())),
match Parser::new("eval", Lexer::new(string)).parse::<cl_ast::Stmt>() {
Err(e) => Ok(ConValue::Str(format!("{e}").into())),
Ok(v) => v.interpret(env),
}
}
/// Executes a file
fn import(ConValue::String(path)) @env {
load_file(env, &**path).or(Ok(ConValue::Empty))
fn import(path) @env {
use cl_interpret::error::Error;
match path {
ConValue::Str(path) => load_file(env, &**path).or(Ok(ConValue::Empty)),
ConValue::String(path) => load_file(env, &**path).or(Ok(ConValue::Empty)),
_ => Err(Error::TypeError())
}
}
fn putchar(ConValue::Char(c)) {
@ -51,12 +57,18 @@ pub fn run(args: Args) -> Result<(), Box<dyn Error>> {
}
/// Gets a line of input from stdin
fn get_line(ConValue::String(prompt)) {
match repline::Repline::new("", prompt.to_ref(), "").read() {
Ok(line) => Ok(ConValue::String(line.into())),
Err(repline::Error::CtrlD(line)) => Ok(ConValue::String(line.into())),
fn get_line(prompt) {
use cl_interpret::error::Error;
let prompt = match prompt {
ConValue::Str(prompt) => prompt.to_ref(),
ConValue::String(prompt) => prompt.as_str(),
_ => Err(Error::TypeError())?,
};
match repline::Repline::new("", prompt, "").read() {
Ok(line) => Ok(ConValue::String(line)),
Err(repline::Error::CtrlD(line)) => Ok(ConValue::String(line)),
Err(repline::Error::CtrlC(_)) => Err(cl_interpret::error::Error::Break(ConValue::Empty)),
Err(e) => Ok(ConValue::String(e.to_string().into())),
Err(e) => Ok(ConValue::Str(e.to_string().into())),
}
}
});

View File

@ -2,6 +2,7 @@
fn f(__fmt: str) -> str {
let __out = "";
let __expr = "";
let __label = "";
let __depth = 0;
for __c in chars(__fmt) {
match __c {
@ -14,19 +15,26 @@ fn f(__fmt: str) -> str {
'}' => {
__depth -= 1
if __depth <= 0 {
__out += fmt(eval(__expr))
__expr = ""
__out = fmt(__out, __label, eval(__expr));
(__expr, __label) = ("", "");
continue
}
},
':' => if __depth == 1 {
__out += __expr + ": "
':' => if __depth == 1 && __label.len() == 0 {
__label = __expr + __c
continue
},
'=' => if __depth == 1 && __label.len() == 0 {
__label = __expr + __c
continue
},
_ => {}
}
if __depth > 0 {
__expr += __c
} else __out += __c;
match (__depth, __label.len()) {
(0, _) => __out += __c,
(_, 0) => __expr += __c,
(_, _) => __label += __c,
}
}
__out
}