mirror of
https://github.com/danbulant/rush
synced 2026-05-19 04:18:35 +00:00
basic parser working
This commit is contained in:
parent
dfbc6ecf17
commit
4501a4af58
2 changed files with 170 additions and 30 deletions
198
src/parser.rs
198
src/parser.rs
|
|
@ -1,14 +1,14 @@
|
|||
use chumsky::{error::{EmptyErr, Rich, Simple}, prelude::{choice, just, none_of, one_of, recursive}, text, IterParser, Parser};
|
||||
use chumsky::{error::{EmptyErr, Rich, Simple}, prelude::{any, choice, end, just, none_of, one_of, recursive}, text, IterParser, Parser};
|
||||
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct Index {
|
||||
pub struct Index {
|
||||
value: Box<Value>,
|
||||
index: Box<Value>
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
enum Primitive {
|
||||
pub enum Primitive {
|
||||
Number(f64),
|
||||
String(String),
|
||||
Variable(String),
|
||||
|
|
@ -16,38 +16,38 @@ enum Primitive {
|
|||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
enum Bindable {
|
||||
Primitive(Primitive),
|
||||
pub enum Bindable {
|
||||
Primitive(Primitive)
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct Command {
|
||||
pub struct Command {
|
||||
name: Box<Value>,
|
||||
args: Vec<Value>
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct Set {
|
||||
pub struct Set {
|
||||
name: Box<Bindable>,
|
||||
value: Box<Value>
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct If {
|
||||
pub struct If {
|
||||
condition: Box<Command>,
|
||||
body: Vec<Statement>,
|
||||
else_body: Option<Vec<Statement>>
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct While {
|
||||
pub struct While {
|
||||
condition: Box<Command>,
|
||||
body: Vec<Statement>,
|
||||
else_body: Option<Vec<Statement>>
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct For {
|
||||
pub struct For {
|
||||
name: Box<Bindable>,
|
||||
iterable: Box<Value>,
|
||||
body: Vec<Statement>,
|
||||
|
|
@ -55,7 +55,14 @@ struct For {
|
|||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct Loop {
|
||||
pub struct Loop {
|
||||
body: Vec<Statement>
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Function {
|
||||
name: String,
|
||||
args: Vec<Bindable>,
|
||||
body: Vec<Statement>
|
||||
}
|
||||
|
||||
|
|
@ -67,11 +74,14 @@ pub enum Statement {
|
|||
While(While),
|
||||
If(If),
|
||||
Loop(Loop),
|
||||
Break
|
||||
Function(Function),
|
||||
Return(Option<Value>),
|
||||
Break,
|
||||
Continue,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
enum Value {
|
||||
pub enum Value {
|
||||
Primitive(Primitive),
|
||||
Group(Vec<Statement>)
|
||||
}
|
||||
|
|
@ -145,10 +155,11 @@ pub fn parse<'a>() -> impl Parser<'a, &'a str, Vec<Statement>, chumsky::extra::D
|
|||
direct_string.clone(),
|
||||
));
|
||||
let eol = one_of("\n\r;");
|
||||
// let r#break = just("break").map(|_| Statement::Break);
|
||||
|
||||
let variable = just('$').ignore_then(text::ident());
|
||||
|
||||
let comment = just('#').then(any().and_is(just('\n').not()).repeated());
|
||||
|
||||
recursive(|expr| {
|
||||
let primitive = choice((
|
||||
number.map(Primitive::Number),
|
||||
|
|
@ -156,36 +167,165 @@ pub fn parse<'a>() -> impl Parser<'a, &'a str, Vec<Statement>, chumsky::extra::D
|
|||
string.map(Primitive::String),
|
||||
));
|
||||
|
||||
let bindable = primitive.clone();
|
||||
let bindable = primitive.clone().map(Bindable::Primitive);
|
||||
|
||||
let group = just('(')
|
||||
.ignore_then(expr.clone())
|
||||
.then_ignore(just(')'))
|
||||
let bindable_group = bindable
|
||||
.clone()
|
||||
.padded()
|
||||
.separated_by(just(","))
|
||||
.collect()
|
||||
.delimited_by(just('('), just(')'));
|
||||
|
||||
let group = expr.clone()
|
||||
.delimited_by(just('('), just(')'))
|
||||
.map(|v| Value::Group(v));
|
||||
|
||||
let block = expr.clone()
|
||||
.delimited_by(just('{'), just('}'));
|
||||
|
||||
let value = choice((
|
||||
group,
|
||||
primitive.map(Value::Primitive),
|
||||
));
|
||||
|
||||
let command = value
|
||||
.separated_by(text::whitespace().at_least(1))
|
||||
.at_least(1)
|
||||
.allow_trailing()
|
||||
.allow_leading()
|
||||
.collect()
|
||||
.map(|args: Vec<Value>| {
|
||||
let name = args[0].clone();
|
||||
let args = args[1..].to_vec();
|
||||
let cmdname = value.clone()
|
||||
.and_is(choice((
|
||||
just("set"),
|
||||
just("if"),
|
||||
just("while"),
|
||||
just("for"),
|
||||
just("loop"),
|
||||
just("break"),
|
||||
just("continue"),
|
||||
just("return"),
|
||||
just("fn"),
|
||||
)).then(end()).not());
|
||||
|
||||
let args = value.clone()
|
||||
.separated_by(text::inline_whitespace().at_least(1))
|
||||
.allow_leading()
|
||||
.allow_trailing()
|
||||
.collect();
|
||||
|
||||
let command =
|
||||
cmdname
|
||||
.padded_by(text::inline_whitespace())
|
||||
.then(args)
|
||||
.map(|(name, args): (Value, Vec<Value>)| {
|
||||
Command {
|
||||
name: Box::new(name),
|
||||
args: args.into_iter().map(|v| v.clone()).collect()
|
||||
}
|
||||
});
|
||||
|
||||
let statement = command.map(Statement::Command);
|
||||
let set = just("set")
|
||||
.then_ignore(text::inline_whitespace().at_least(1))
|
||||
.ignore_then(bindable.clone())
|
||||
.then_ignore(just('=').padded())
|
||||
.then(value.clone())
|
||||
.map(|(name, value): (Bindable, Value)| {
|
||||
Set {
|
||||
name: Box::new(name),
|
||||
value: Box::new(value)
|
||||
}
|
||||
});
|
||||
|
||||
statement.separated_by(eol).at_least(1).collect()
|
||||
let else_ = just("else")
|
||||
.then(text::inline_whitespace().at_least(1))
|
||||
.ignore_then(choice((
|
||||
block.clone(),
|
||||
expr.clone()
|
||||
)));
|
||||
|
||||
let if_ = just("if")
|
||||
.then_ignore(text::inline_whitespace().at_least(1))
|
||||
.ignore_then(command.clone())
|
||||
.then(block.clone().padded())
|
||||
.then(else_.clone().or_not())
|
||||
.map(|((cond, body), else_body): ((Command, Vec<Statement>), _)| {
|
||||
If {
|
||||
condition: Box::new(cond),
|
||||
body,
|
||||
else_body
|
||||
}
|
||||
});
|
||||
|
||||
let while_ = just("while")
|
||||
.then_ignore(text::inline_whitespace().at_least(1))
|
||||
.ignore_then(command.clone())
|
||||
.then(block.clone().padded())
|
||||
.then(else_.clone().or_not())
|
||||
.map(|((cond, body), else_body): ((Command, Vec<Statement>), _)| {
|
||||
While {
|
||||
condition: Box::new(cond),
|
||||
body,
|
||||
else_body
|
||||
}
|
||||
});
|
||||
|
||||
let for_ = just("for")
|
||||
.then_ignore(text::inline_whitespace().at_least(1))
|
||||
.ignore_then(bindable.clone())
|
||||
.then_ignore(just("in").padded())
|
||||
.then(value.clone())
|
||||
.then(block.clone().padded())
|
||||
.then(else_.clone().or_not())
|
||||
.map(|(((name, iterable), body), else_body): (((Bindable, Value), Vec<Statement>), _)| {
|
||||
For {
|
||||
name: Box::new(name),
|
||||
iterable: Box::new(iterable),
|
||||
body,
|
||||
else_body
|
||||
}
|
||||
});
|
||||
|
||||
let loop_ = just("loop")
|
||||
.ignore_then(block.clone().padded())
|
||||
.map(|body: Vec<Statement>| {
|
||||
Loop {
|
||||
body
|
||||
}
|
||||
});
|
||||
|
||||
let return_ = just("return")
|
||||
.then_ignore(text::inline_whitespace().at_least(1))
|
||||
.ignore_then(value.clone().or_not())
|
||||
.map(|v: Option<Value>| {
|
||||
Statement::Return(v)
|
||||
});
|
||||
|
||||
let function = just("fn")
|
||||
.then_ignore(text::inline_whitespace().at_least(1))
|
||||
.ignore_then(text::ident())
|
||||
.then(bindable_group.clone())
|
||||
.then(block.clone().padded())
|
||||
.map(|((name, args), body): ((&str, Vec<Bindable>), Vec<Statement>)| {
|
||||
Function {
|
||||
name: name.to_string(),
|
||||
args: args,
|
||||
body
|
||||
}
|
||||
});
|
||||
|
||||
let statement = choice((
|
||||
set.map(Statement::Set),
|
||||
if_.map(Statement::If),
|
||||
while_.map(Statement::While),
|
||||
for_.map(Statement::For),
|
||||
loop_.map(Statement::Loop),
|
||||
function.map(Statement::Function),
|
||||
return_,
|
||||
just("break").to(Statement::Break),
|
||||
just("continue").to(Statement::Continue),
|
||||
command.map(Statement::Command),
|
||||
));
|
||||
|
||||
statement
|
||||
.padded_by(text::inline_whitespace().ignored().or(comment.ignored()))
|
||||
.separated_by(eol.repeated().at_least(1))
|
||||
.at_least(1)
|
||||
.allow_trailing()
|
||||
.allow_leading()
|
||||
.collect()
|
||||
})
|
||||
}
|
||||
|
|
@ -1 +1 @@
|
|||
test ( test 2 )
|
||||
fn test() {echo}
|
||||
|
|
|
|||
Loading…
Reference in a new issue