parse docstrings

This commit is contained in:
Scott Richmond 2024-11-21 22:36:57 -05:00
parent a35d5293a9
commit ad76f41b52
3 changed files with 34 additions and 20 deletions

View File

@ -30,7 +30,7 @@
// * [x] `loop` and `recur`
// * [ ] string patterns
// * [ ] string interpolation
// * [ ] docstrings
// * [x] docstrings
// * [~] write `base` in Rust
// * [ ] turn this into a library function
// * [ ] compile this into WASM
@ -58,7 +58,12 @@ use crate::base::*;
pub fn main() {
let src = "
true
fn foo {
\"this is a docstring\"
() -> :foo
(_) -> :bar
}
foo ()
";
let (tokens, lex_errs) = lexer().parse(src).into_output_errors();
if !lex_errs.is_empty() {

View File

@ -54,7 +54,7 @@ pub enum Ast<'src> {
Synthetic(Box<Spanned<Self>>, Box<Spanned<Self>>, Vec<Spanned<Self>>),
When(Vec<Spanned<WhenClause<'src>>>),
Match(Box<Spanned<Self>>, Vec<MatchClause<'src>>),
Fn(&'src str, Vec<MatchClause<'src>>),
Fn(&'src str, Vec<MatchClause<'src>>, Option<&'src str>),
FnDeclaration(&'src str),
Panic(Box<Spanned<Self>>),
Do(Vec<Spanned<Self>>),
@ -149,7 +149,7 @@ impl fmt::Display for Ast<'_> {
.join("\n")
)
}
Ast::Fn(name, clauses) => {
Ast::Fn(name, clauses, _) => {
write!(
f,
"fn: {}\n{}",
@ -407,10 +407,11 @@ where
Token::Nil => Ast::Nil,
Token::Boolean(b) => Ast::Boolean(b),
Token::Number(n) => Ast::Number(n),
Token::String(s) => Ast::String(s),
}
.map_with(|v, e| (v, e.span()));
let string = select! {Token::String(s) => Ast::String(s)}.map_with(|s, e| (s, e.span()));
let tuple = simple
.clone()
.separated_by(separators.clone())
@ -505,6 +506,7 @@ where
.or(tuple.clone())
.or(list)
.or(dict)
.or(string)
.labelled("simple expression"),
);
@ -599,12 +601,6 @@ where
let conditional = when.or(if_).or(match_);
//todo:
// * [x] do
// * [ ] loop
// * [x] repeat
// * [x] panic!
let panic = just(Token::Reserved("panic!"))
.ignore_then(nonbinding.clone())
.map_with(|expr, e| (Ast::Panic(Box::new(expr)), e.span()));
@ -653,14 +649,17 @@ where
let lambda = just(Token::Reserved("fn"))
.ignore_then(fn_unguarded.clone())
.map_with(|clause, e| (Ast::Fn("anonymous", vec![clause]), e.span()));
.map_with(|clause, e| (Ast::Fn("anonymous", vec![clause], None), e.span()));
let fn_multiclause = fn_clause
let fn_clauses = fn_clause
.clone()
.separated_by(terminators.clone())
.allow_leading()
.allow_trailing()
.collect()
.collect();
let loop_multiclause = fn_clauses
.clone()
.delimited_by(just(Token::Punctuation("{")), just(Token::Punctuation("}")));
let fn_single_clause = fn_clause.clone().map_with(|c, _| vec![c]);
@ -668,7 +667,7 @@ where
let r#loop = just(Token::Reserved("loop"))
.ignore_then(tuple.clone())
.then_ignore(just(Token::Reserved("with")))
.then(fn_multiclause.clone().or(fn_single_clause.clone()))
.then(loop_multiclause.clone().or(fn_single_clause.clone()))
.map_with(|(init, body), e| (Ast::Loop(Box::new(init), body), e.span()));
nonbinding.define(
@ -725,19 +724,29 @@ where
} else {
unreachable!()
};
(Ast::Fn(name, vec![clause]), e.span())
(Ast::Fn(name, vec![clause], None), e.span())
});
let docstr = select! {Token::String(s) => s};
let fn_multiclause = separators
.clone()
.or_not()
.ignore_then(docstr.or_not())
.then(fn_clauses.clone())
.delimited_by(just(Token::Punctuation("{")), just(Token::Punctuation("}")))
.map_with(|(docstr, clauses), e| (docstr, clauses, e.span()));
let fn_compound = just(Token::Reserved("fn"))
.ignore_then(word)
.then(fn_multiclause.clone())
.map_with(|(word, clauses), e| {
.then(fn_multiclause)
.map_with(|(word, (docstr, clauses, _)), e| {
let name = if let Ast::Word(word) = word.0 {
word
} else {
unreachable!()
};
(Ast::Fn(name, clauses), e.span())
(Ast::Fn(name, clauses, docstr), e.span())
});
let fn_ = fn_named.or(fn_compound).or(fn_decl);

View File

@ -414,7 +414,7 @@ pub fn eval<'src, 'a>(
let value = eval(&value.0, ctx)?;
match_clauses(&value, clauses, ctx)
}
Ast::Fn(name, clauses) => {
Ast::Fn(name, clauses, ..) => {
let the_fn = Value::Fn::<'src>(Rc::new(Fn::<'src> {
name,
body: clauses,