parse docstrings
This commit is contained in:
parent
a35d5293a9
commit
ad76f41b52
|
@ -30,7 +30,7 @@
|
||||||
// * [x] `loop` and `recur`
|
// * [x] `loop` and `recur`
|
||||||
// * [ ] string patterns
|
// * [ ] string patterns
|
||||||
// * [ ] string interpolation
|
// * [ ] string interpolation
|
||||||
// * [ ] docstrings
|
// * [x] docstrings
|
||||||
// * [~] write `base` in Rust
|
// * [~] write `base` in Rust
|
||||||
// * [ ] turn this into a library function
|
// * [ ] turn this into a library function
|
||||||
// * [ ] compile this into WASM
|
// * [ ] compile this into WASM
|
||||||
|
@ -58,7 +58,12 @@ use crate::base::*;
|
||||||
|
|
||||||
pub fn main() {
|
pub fn main() {
|
||||||
let src = "
|
let src = "
|
||||||
true
|
fn foo {
|
||||||
|
\"this is a docstring\"
|
||||||
|
() -> :foo
|
||||||
|
(_) -> :bar
|
||||||
|
}
|
||||||
|
foo ()
|
||||||
";
|
";
|
||||||
let (tokens, lex_errs) = lexer().parse(src).into_output_errors();
|
let (tokens, lex_errs) = lexer().parse(src).into_output_errors();
|
||||||
if !lex_errs.is_empty() {
|
if !lex_errs.is_empty() {
|
||||||
|
|
|
@ -54,7 +54,7 @@ pub enum Ast<'src> {
|
||||||
Synthetic(Box<Spanned<Self>>, Box<Spanned<Self>>, Vec<Spanned<Self>>),
|
Synthetic(Box<Spanned<Self>>, Box<Spanned<Self>>, Vec<Spanned<Self>>),
|
||||||
When(Vec<Spanned<WhenClause<'src>>>),
|
When(Vec<Spanned<WhenClause<'src>>>),
|
||||||
Match(Box<Spanned<Self>>, Vec<MatchClause<'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),
|
FnDeclaration(&'src str),
|
||||||
Panic(Box<Spanned<Self>>),
|
Panic(Box<Spanned<Self>>),
|
||||||
Do(Vec<Spanned<Self>>),
|
Do(Vec<Spanned<Self>>),
|
||||||
|
@ -149,7 +149,7 @@ impl fmt::Display for Ast<'_> {
|
||||||
.join("\n")
|
.join("\n")
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Ast::Fn(name, clauses) => {
|
Ast::Fn(name, clauses, _) => {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
"fn: {}\n{}",
|
"fn: {}\n{}",
|
||||||
|
@ -407,10 +407,11 @@ where
|
||||||
Token::Nil => Ast::Nil,
|
Token::Nil => Ast::Nil,
|
||||||
Token::Boolean(b) => Ast::Boolean(b),
|
Token::Boolean(b) => Ast::Boolean(b),
|
||||||
Token::Number(n) => Ast::Number(n),
|
Token::Number(n) => Ast::Number(n),
|
||||||
Token::String(s) => Ast::String(s),
|
|
||||||
}
|
}
|
||||||
.map_with(|v, e| (v, e.span()));
|
.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
|
let tuple = simple
|
||||||
.clone()
|
.clone()
|
||||||
.separated_by(separators.clone())
|
.separated_by(separators.clone())
|
||||||
|
@ -505,6 +506,7 @@ where
|
||||||
.or(tuple.clone())
|
.or(tuple.clone())
|
||||||
.or(list)
|
.or(list)
|
||||||
.or(dict)
|
.or(dict)
|
||||||
|
.or(string)
|
||||||
.labelled("simple expression"),
|
.labelled("simple expression"),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -599,12 +601,6 @@ where
|
||||||
|
|
||||||
let conditional = when.or(if_).or(match_);
|
let conditional = when.or(if_).or(match_);
|
||||||
|
|
||||||
//todo:
|
|
||||||
// * [x] do
|
|
||||||
// * [ ] loop
|
|
||||||
// * [x] repeat
|
|
||||||
// * [x] panic!
|
|
||||||
|
|
||||||
let panic = just(Token::Reserved("panic!"))
|
let panic = just(Token::Reserved("panic!"))
|
||||||
.ignore_then(nonbinding.clone())
|
.ignore_then(nonbinding.clone())
|
||||||
.map_with(|expr, e| (Ast::Panic(Box::new(expr)), e.span()));
|
.map_with(|expr, e| (Ast::Panic(Box::new(expr)), e.span()));
|
||||||
|
@ -653,14 +649,17 @@ where
|
||||||
|
|
||||||
let lambda = just(Token::Reserved("fn"))
|
let lambda = just(Token::Reserved("fn"))
|
||||||
.ignore_then(fn_unguarded.clone())
|
.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()
|
.clone()
|
||||||
.separated_by(terminators.clone())
|
.separated_by(terminators.clone())
|
||||||
.allow_leading()
|
.allow_leading()
|
||||||
.allow_trailing()
|
.allow_trailing()
|
||||||
.collect()
|
.collect();
|
||||||
|
|
||||||
|
let loop_multiclause = fn_clauses
|
||||||
|
.clone()
|
||||||
.delimited_by(just(Token::Punctuation("{")), just(Token::Punctuation("}")));
|
.delimited_by(just(Token::Punctuation("{")), just(Token::Punctuation("}")));
|
||||||
|
|
||||||
let fn_single_clause = fn_clause.clone().map_with(|c, _| vec![c]);
|
let fn_single_clause = fn_clause.clone().map_with(|c, _| vec![c]);
|
||||||
|
@ -668,7 +667,7 @@ where
|
||||||
let r#loop = just(Token::Reserved("loop"))
|
let r#loop = just(Token::Reserved("loop"))
|
||||||
.ignore_then(tuple.clone())
|
.ignore_then(tuple.clone())
|
||||||
.then_ignore(just(Token::Reserved("with")))
|
.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()));
|
.map_with(|(init, body), e| (Ast::Loop(Box::new(init), body), e.span()));
|
||||||
|
|
||||||
nonbinding.define(
|
nonbinding.define(
|
||||||
|
@ -725,19 +724,29 @@ where
|
||||||
} else {
|
} else {
|
||||||
unreachable!()
|
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"))
|
let fn_compound = just(Token::Reserved("fn"))
|
||||||
.ignore_then(word)
|
.ignore_then(word)
|
||||||
.then(fn_multiclause.clone())
|
.then(fn_multiclause)
|
||||||
.map_with(|(word, clauses), e| {
|
.map_with(|(word, (docstr, clauses, _)), e| {
|
||||||
let name = if let Ast::Word(word) = word.0 {
|
let name = if let Ast::Word(word) = word.0 {
|
||||||
word
|
word
|
||||||
} else {
|
} else {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
};
|
};
|
||||||
(Ast::Fn(name, clauses), e.span())
|
(Ast::Fn(name, clauses, docstr), e.span())
|
||||||
});
|
});
|
||||||
|
|
||||||
let fn_ = fn_named.or(fn_compound).or(fn_decl);
|
let fn_ = fn_named.or(fn_compound).or(fn_decl);
|
||||||
|
|
|
@ -414,7 +414,7 @@ pub fn eval<'src, 'a>(
|
||||||
let value = eval(&value.0, ctx)?;
|
let value = eval(&value.0, ctx)?;
|
||||||
match_clauses(&value, clauses, ctx)
|
match_clauses(&value, clauses, ctx)
|
||||||
}
|
}
|
||||||
Ast::Fn(name, clauses) => {
|
Ast::Fn(name, clauses, ..) => {
|
||||||
let the_fn = Value::Fn::<'src>(Rc::new(Fn::<'src> {
|
let the_fn = Value::Fn::<'src>(Rc::new(Fn::<'src> {
|
||||||
name,
|
name,
|
||||||
body: clauses,
|
body: clauses,
|
||||||
|
|
Loading…
Reference in New Issue
Block a user