cl-interpret: Literal[String] a la python
This commit is contained in:
parent
259c9f8bb6
commit
239785b322
@ -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}"))?
|
||||
}))
|
||||
|
@ -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}..]"),
|
||||
|
@ -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 {
|
||||
|
@ -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()),
|
||||
},
|
||||
|
||||
|
@ -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())),
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -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
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user