add ref-counted string type
This commit is contained in:
parent
2a83dbb96c
commit
c5c1717e57
21
src/base.rs
21
src/base.rs
|
@ -1,6 +1,7 @@
|
|||
// Solution to the #[derive(Clone)] problem: https://stackoverflow.com/questions/27883509/can-you-clone-a-closure
|
||||
use crate::value::*;
|
||||
use crate::vm::*;
|
||||
use std::rc::Rc;
|
||||
// use imbl::*;
|
||||
// use std::fmt;
|
||||
|
||||
|
@ -68,6 +69,24 @@ pub fn store<'src>(b: &Value<'src>, val: &Value<'src>) -> LResult<'src> {
|
|||
}
|
||||
}
|
||||
|
||||
// TODO: do better than returning just the docstr
|
||||
// name, patterns, AND docstring
|
||||
pub fn doc<'src>(f: &Value<'src>) -> LResult<'src> {
|
||||
match f {
|
||||
Value::Fn(f) => {
|
||||
let Fn { name, doc, .. } = **f;
|
||||
if let Some(docstr) = doc {
|
||||
Ok(Value::AllocatedString(Rc::new(format!("{name}: {docstr}"))))
|
||||
} else {
|
||||
Ok(Value::InternedString(
|
||||
doc.unwrap_or("no documentation found"),
|
||||
))
|
||||
}
|
||||
}
|
||||
_ => Ok(Value::InternedString("no documentation found")),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn base<'src>() -> Vec<(&'src str, Value<'src>)> {
|
||||
let mut base = vec![];
|
||||
|
||||
|
@ -83,6 +102,8 @@ pub fn base<'src>() -> Vec<(&'src str, Value<'src>)> {
|
|||
|
||||
base.push(("store", Value::Base(Base::Binary("store", store))));
|
||||
|
||||
base.push(("doc", Value::Base(Base::Unary("doc", doc))));
|
||||
|
||||
base
|
||||
}
|
||||
|
||||
|
|
|
@ -63,7 +63,7 @@ fn foo {
|
|||
() -> :foo
|
||||
(_) -> :bar
|
||||
}
|
||||
foo ()
|
||||
doc (foo)
|
||||
";
|
||||
let (tokens, lex_errs) = lexer().parse(src).into_output_errors();
|
||||
if !lex_errs.is_empty() {
|
||||
|
|
|
@ -33,6 +33,22 @@ impl<'src> fmt::Display for MatchClause<'src> {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub enum StringPart<'src> {
|
||||
Data(&'src str),
|
||||
Word(&'src str),
|
||||
}
|
||||
|
||||
impl<'src> fmt::Display for StringPart<'src> {
|
||||
fn fmt(self: &StringPart<'src>, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let rep = match self {
|
||||
StringPart::Data(s) => format!("{{{s}}}"),
|
||||
StringPart::Word(s) => s.to_string(),
|
||||
};
|
||||
write!(f, "{}", rep)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Dissectible)]
|
||||
pub enum Ast<'src> {
|
||||
Error,
|
||||
|
@ -43,6 +59,7 @@ pub enum Ast<'src> {
|
|||
Keyword(&'src str),
|
||||
Word(&'src str),
|
||||
String(&'src str),
|
||||
Interpolated(Vec<Spanned<StringPart<'src>>>),
|
||||
Block(Vec<Spanned<Self>>),
|
||||
If(Box<Spanned<Self>>, Box<Spanned<Self>>, Box<Spanned<Self>>),
|
||||
Tuple(Vec<Spanned<Self>>),
|
||||
|
@ -71,6 +88,16 @@ impl fmt::Display for Ast<'_> {
|
|||
Ast::Error => write!(f, "Error"),
|
||||
Ast::Nil => write!(f, "nil"),
|
||||
Ast::String(s) => write!(f, "String: \"{}\"", s),
|
||||
Ast::Interpolated(strs) => {
|
||||
write!(
|
||||
f,
|
||||
"String: \"{}\"",
|
||||
strs.iter()
|
||||
.map(|(s, _)| s.to_string())
|
||||
.collect::<Vec<_>>()
|
||||
.join("")
|
||||
)
|
||||
}
|
||||
Ast::Boolean(b) => write!(f, "Boolean: {}", b),
|
||||
Ast::Number(n) => write!(f, "Number: {}", n),
|
||||
Ast::Keyword(k) => write!(f, "Keyword: :{}", k),
|
||||
|
@ -277,6 +304,17 @@ impl fmt::Display for Pattern<'_> {
|
|||
}
|
||||
}
|
||||
|
||||
// TODO: write this
|
||||
// 1. we need an enum for a return type
|
||||
// either a string part or a word part
|
||||
// 2. our string types, both patterns and values, now contains a vec of nodes
|
||||
// 3. this should loop through the string and allow for escaping braces
|
||||
// consider using Rust-style escapes: {{}}, rather than \{\}
|
||||
// {{{foo}}}
|
||||
pub fn parse_string<'src>(s: &'src str) -> Vec<StringPart<'src>> {
|
||||
vec![]
|
||||
}
|
||||
|
||||
pub fn parser<'src, I>(
|
||||
) -> impl Parser<'src, I, Spanned<Ast<'src>>, extra::Err<Rich<'src, Token<'src>, Span>>> + Clone
|
||||
where
|
||||
|
|
17
src/value.rs
17
src/value.rs
|
@ -10,6 +10,7 @@ use struct_scalpel::Dissectible;
|
|||
pub struct Fn<'src> {
|
||||
pub name: &'src str,
|
||||
pub body: &'src Vec<MatchClause<'src>>,
|
||||
pub doc: &'src Option<&'src str>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Dissectible)]
|
||||
|
@ -19,7 +20,10 @@ pub enum Value<'src> {
|
|||
Boolean(bool),
|
||||
Number(f64),
|
||||
Keyword(&'src str),
|
||||
String(&'src str),
|
||||
// TODO: add a "runtime-generated" string type that wraps a Rust String
|
||||
// this is necessary for nice documentation and string interpolation
|
||||
InternedString(&'src str),
|
||||
AllocatedString(Rc<String>),
|
||||
// on the heap for now
|
||||
Tuple(Rc<Vec<Self>>),
|
||||
Args(Rc<Vec<Self>>),
|
||||
|
@ -49,7 +53,8 @@ impl<'src> Clone for Value<'src> {
|
|||
match self {
|
||||
Value::Nil => Value::Nil,
|
||||
Value::Boolean(b) => Value::Boolean(*b),
|
||||
Value::String(s) => Value::String(s),
|
||||
Value::InternedString(s) => Value::InternedString(s),
|
||||
Value::AllocatedString(s) => Value::AllocatedString(s.clone()),
|
||||
Value::Keyword(s) => Value::Keyword(s),
|
||||
Value::Number(n) => Value::Number(*n),
|
||||
Value::Tuple(t) => Value::Tuple(t.clone()),
|
||||
|
@ -72,7 +77,8 @@ impl fmt::Display for Value<'_> {
|
|||
Value::Boolean(b) => write!(f, "{}", b),
|
||||
Value::Number(n) => write!(f, "{}", n),
|
||||
Value::Keyword(k) => write!(f, ":{}", k),
|
||||
Value::String(s) => write!(f, "\"{}\"", s),
|
||||
Value::InternedString(s) => write!(f, "\"{}\"", s),
|
||||
Value::AllocatedString(s) => write!(f, "\"{}\"", s),
|
||||
Value::Fn(fun) => write!(f, "fn {}", fun.name),
|
||||
Value::Tuple(t) | Value::Args(t) => write!(
|
||||
f,
|
||||
|
@ -132,7 +138,8 @@ impl Value<'_> {
|
|||
Value::Boolean(_) => Value::Keyword("boolean"),
|
||||
Value::Keyword(_) => Value::Keyword("keyword"),
|
||||
Value::Tuple(_) => Value::Keyword("tuple"),
|
||||
Value::String(_) => Value::Keyword("string"),
|
||||
Value::InternedString(_) => Value::Keyword("string"),
|
||||
Value::AllocatedString(_) => Value::Keyword("string"),
|
||||
Value::List(_) => Value::Keyword("list"),
|
||||
Value::Dict(_) => Value::Keyword("dict"),
|
||||
Value::Fn(_) => Value::Keyword("fn"),
|
||||
|
@ -152,7 +159,7 @@ impl<'src> PartialEq for Value<'src> {
|
|||
(Value::Nil, Value::Nil) => true,
|
||||
(Value::Boolean(x), Value::Boolean(y)) => x == y,
|
||||
(Value::Number(x), Value::Number(y)) => x == y,
|
||||
(Value::String(x), Value::String(y)) => x == y,
|
||||
(Value::InternedString(x), Value::InternedString(y)) => x == y,
|
||||
(Value::Keyword(x), Value::Keyword(y)) => x == y,
|
||||
(Value::Tuple(x), Value::Tuple(y)) => x == y,
|
||||
(Value::List(x), Value::List(y)) => x == y,
|
||||
|
|
|
@ -62,7 +62,7 @@ pub fn match_pattern<'src, 'a>(
|
|||
(Pattern::Number(x), Value::Number(y)) => match_eq(x, y, ctx),
|
||||
(Pattern::Boolean(x), Value::Boolean(y)) => match_eq(x, y, ctx),
|
||||
(Pattern::Keyword(x), Value::Keyword(y)) => match_eq(x, y, ctx),
|
||||
(Pattern::String(x), Value::String(y)) => match_eq(x, y, ctx),
|
||||
(Pattern::String(x), Value::InternedString(y)) => match_eq(x, y, ctx),
|
||||
(Pattern::Word(w), val) => {
|
||||
ctx.push((w, val.clone()));
|
||||
Some(ctx)
|
||||
|
@ -281,7 +281,8 @@ pub fn eval<'src, 'a>(
|
|||
Ast::Boolean(b) => Ok(Value::Boolean(*b)),
|
||||
Ast::Number(n) => Ok(Value::Number(*n)),
|
||||
Ast::Keyword(k) => Ok(Value::Keyword(k)),
|
||||
Ast::String(s) => Ok(Value::String(s)),
|
||||
Ast::String(s) => Ok(Value::InternedString(s)),
|
||||
Ast::Interpolated(s) => todo!(),
|
||||
Ast::Block(exprs) => {
|
||||
let to = ctx.len();
|
||||
let mut result = Value::Nil;
|
||||
|
@ -414,10 +415,11 @@ pub fn eval<'src, 'a>(
|
|||
let value = eval(&value.0, ctx)?;
|
||||
match_clauses(&value, clauses, ctx)
|
||||
}
|
||||
Ast::Fn(name, clauses, ..) => {
|
||||
Ast::Fn(name, clauses, doc) => {
|
||||
let the_fn = Value::Fn::<'src>(Rc::new(Fn::<'src> {
|
||||
name,
|
||||
body: clauses,
|
||||
doc,
|
||||
}));
|
||||
ctx.push((name, the_fn.clone()));
|
||||
Ok(the_fn)
|
||||
|
|
Loading…
Reference in New Issue
Block a user