feat(argus-parser): complete the syntax parser
This commit is contained in:
parent
3adf2ff723
commit
17042a2544
4 changed files with 101 additions and 88 deletions
|
|
@ -3,15 +3,15 @@ name = "argus-parser"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[lib]
|
[[example]]
|
||||||
name = "argus_parser"
|
name = "dump_parse_tree"
|
||||||
|
required-features = ["reporting"]
|
||||||
[[bin]]
|
|
||||||
name = "argus_parser"
|
|
||||||
path = "src/main.rs"
|
|
||||||
|
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
argus-core = { version = "0.1.0", path = "../argus-core" }
|
argus-core = { version = "0.1.0", path = "../argus-core" }
|
||||||
ariadne = "0.3.0"
|
ariadne = { version = "0.3.0", optional = true }
|
||||||
chumsky = { version = "1.0.0-alpha.4", features = ["default", "label"] }
|
chumsky = { version = "1.0.0-alpha.4", features = ["default", "label"] }
|
||||||
|
|
||||||
|
[features]
|
||||||
|
|
||||||
|
reporting = ["dep:ariadne"]
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,14 @@
|
||||||
use std::{env, fs};
|
use std::env;
|
||||||
|
|
||||||
use argus_parser::lexer;
|
use argus_parser::{lexer, parser};
|
||||||
// use crate::parser::{parser, Error as ParseError};
|
|
||||||
use ariadne::{sources, Color, Label, Report, ReportKind};
|
use ariadne::{sources, Color, Label, Report, ReportKind};
|
||||||
|
use chumsky::prelude::Input;
|
||||||
use chumsky::Parser;
|
use chumsky::Parser;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let src = env::args().nth(1).expect("Expected expression");
|
let src = env::args().nth(1).expect("Expected expression");
|
||||||
|
|
||||||
let (tokens, mut errs) = lexer().parse(src.as_str()).into_output_errors();
|
let (tokens, errs) = lexer().parse(src.as_str()).into_output_errors();
|
||||||
|
|
||||||
println!("*** Outputting tokens ***");
|
println!("*** Outputting tokens ***");
|
||||||
if let Some(tokens) = &tokens {
|
if let Some(tokens) = &tokens {
|
||||||
|
|
@ -33,7 +33,7 @@ fn main() {
|
||||||
|
|
||||||
errs.into_iter()
|
errs.into_iter()
|
||||||
.map(|e| e.map_token(|c| c.to_string()))
|
.map(|e| e.map_token(|c| c.to_string()))
|
||||||
// .chain(parse_errs.into_iter().map(|e| e.map_token(|tok| tok.to_string())))
|
.chain(parse_errs.into_iter().map(|e| e.map_token(|tok| tok.to_string())))
|
||||||
.for_each(|e| {
|
.for_each(|e| {
|
||||||
Report::build(ReportKind::Error, src.clone(), e.span().start)
|
Report::build(ReportKind::Error, src.clone(), e.span().start)
|
||||||
.with_message(e.to_string())
|
.with_message(e.to_string())
|
||||||
|
|
@ -94,16 +94,20 @@ pub fn lexer<'src>() -> impl Parser<'src, &'src str, Output<'src>, Error<'src>>
|
||||||
let floating_number = just('-')
|
let floating_number = just('-')
|
||||||
.or_not()
|
.or_not()
|
||||||
.then(digits)
|
.then(digits)
|
||||||
.then(frac.or_not())
|
.then(choice((frac.then(exp).slice(), frac.slice(), exp.slice())))
|
||||||
.then(exp.or_not())
|
// .then(frac.or_not())
|
||||||
|
// .then(exp.or_not())
|
||||||
.map_slice(|s: &str| Token::Float(s.parse().unwrap()))
|
.map_slice(|s: &str| Token::Float(s.parse().unwrap()))
|
||||||
.boxed();
|
.boxed();
|
||||||
|
|
||||||
let signed_int = one_of("+-")
|
let signed_int = one_of("+-")
|
||||||
.or_not()
|
// .or_not()
|
||||||
.then(digits)
|
.then(digits)
|
||||||
|
.then(frac.not().or(exp.not()))
|
||||||
.map_slice(|s: &str| Token::Int(s.parse().unwrap()));
|
.map_slice(|s: &str| Token::Int(s.parse().unwrap()));
|
||||||
let unsigned_int = digits.map_slice(|s: &str| Token::UInt(s.parse().unwrap()));
|
let unsigned_int = digits
|
||||||
|
.then(frac.not().or(exp.not()))
|
||||||
|
.map_slice(|s: &str| Token::UInt(s.parse().unwrap()));
|
||||||
|
|
||||||
let number = choice((floating_number, signed_int, unsigned_int));
|
let number = choice((floating_number, signed_int, unsigned_int));
|
||||||
|
|
||||||
|
|
@ -160,10 +164,16 @@ pub fn lexer<'src>() -> impl Parser<'src, &'src str, Output<'src>, Error<'src>>
|
||||||
"false" => Token::Bool(false),
|
"false" => Token::Bool(false),
|
||||||
"G" => Token::Always,
|
"G" => Token::Always,
|
||||||
"alw" => Token::Always,
|
"alw" => Token::Always,
|
||||||
|
"always" => Token::Always,
|
||||||
|
"globally" => Token::Always,
|
||||||
"F" => Token::Eventually,
|
"F" => Token::Eventually,
|
||||||
"ev" => Token::Eventually,
|
"ev" => Token::Eventually,
|
||||||
|
"eventually" => Token::Eventually,
|
||||||
|
"finally" => Token::Eventually,
|
||||||
"X" => Token::Next,
|
"X" => Token::Next,
|
||||||
|
"next" => Token::Next,
|
||||||
"U" => Token::Until,
|
"U" => Token::Until,
|
||||||
|
"until" => Token::Until,
|
||||||
_ => Token::Ident(ident),
|
_ => Token::Ident(ident),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -145,13 +145,6 @@ impl<'src> Expr<'src> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn var(name: &'src str) -> Self {
|
|
||||||
Self::Var {
|
|
||||||
name,
|
|
||||||
kind: Type::Unknown,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn unary_op(op: UnaryOps, arg: Box<Spanned<Self>>, interval: Option<Spanned<Interval<'src>>>) -> Self {
|
fn unary_op(op: UnaryOps, arg: Box<Spanned<Self>>, interval: Option<Spanned<Interval<'src>>>) -> Self {
|
||||||
let mut arg = arg;
|
let mut arg = arg;
|
||||||
(*arg).0.make_typed(op.default_type());
|
(*arg).0.make_typed(op.default_type());
|
||||||
|
|
@ -189,8 +182,7 @@ type ParserInput<'tokens, 'src> = SpannedInput<Token<'src>, Span, &'tokens [(Tok
|
||||||
pub fn num_expr_parser<'tokens, 'src: 'tokens>(
|
pub fn num_expr_parser<'tokens, 'src: 'tokens>(
|
||||||
) -> impl Parser<'tokens, ParserInput<'tokens, 'src>, Spanned<Expr<'src>>, Error<'tokens, 'src>> + Clone {
|
) -> impl Parser<'tokens, ParserInput<'tokens, 'src>, Spanned<Expr<'src>>, Error<'tokens, 'src>> + Clone {
|
||||||
recursive(|num_expr| {
|
recursive(|num_expr| {
|
||||||
let var = select! { Token::Ident(ident) => Expr::Var{ name: ident.clone(), kind: Type::default()} }
|
let var = select! { Token::Ident(name) => Expr::Var{ name, kind: Type::default()} }.labelled("variable");
|
||||||
.labelled("variable");
|
|
||||||
|
|
||||||
let num_literal = select! {
|
let num_literal = select! {
|
||||||
Token::Int(val) => Expr::Int(val),
|
Token::Int(val) => Expr::Int(val),
|
||||||
|
|
@ -223,24 +215,32 @@ pub fn num_expr_parser<'tokens, 'src: 'tokens>(
|
||||||
|
|
||||||
// Product ops (multiply and divide) have equal precedence
|
// Product ops (multiply and divide) have equal precedence
|
||||||
let product_op = {
|
let product_op = {
|
||||||
let op = just(Token::Times)
|
let op = choice((
|
||||||
.to(BinaryOps::Mul)
|
just(Token::Times).to(BinaryOps::Mul),
|
||||||
.or(just(Token::Divide).to(BinaryOps::Div));
|
just(Token::Divide).to(BinaryOps::Div),
|
||||||
neg_op.clone().foldl(op.then(neg_op).repeated(), |a, (op, b)| {
|
));
|
||||||
|
neg_op
|
||||||
|
.clone()
|
||||||
|
.foldl(op.then(neg_op).repeated(), |a, (op, b)| {
|
||||||
let span = a.1.start..b.1.end;
|
let span = a.1.start..b.1.end;
|
||||||
(Expr::binary_op(op, (Box::new(a), Box::new(b)), None), span.into())
|
(Expr::binary_op(op, (Box::new(a), Box::new(b)), None), span.into())
|
||||||
})
|
})
|
||||||
|
.boxed()
|
||||||
};
|
};
|
||||||
|
|
||||||
// Sum ops (add and subtract) have equal precedence
|
// Sum ops (add and subtract) have equal precedence
|
||||||
let sum_op = {
|
let sum_op = {
|
||||||
let op = just(Token::Plus)
|
let op = choice((
|
||||||
.to(BinaryOps::Add)
|
just(Token::Plus).to(BinaryOps::Add),
|
||||||
.or(just(Token::Minus).to(BinaryOps::Sub));
|
just(Token::Minus).to(BinaryOps::Sub),
|
||||||
product_op.clone().foldl(op.then(product_op).repeated(), |a, (op, b)| {
|
));
|
||||||
|
product_op
|
||||||
|
.clone()
|
||||||
|
.foldl(op.then(product_op).repeated(), |a, (op, b)| {
|
||||||
let span = a.1.start..b.1.end;
|
let span = a.1.start..b.1.end;
|
||||||
(Expr::binary_op(op, (Box::new(a), Box::new(b)), None), span.into())
|
(Expr::binary_op(op, (Box::new(a), Box::new(b)), None), span.into())
|
||||||
})
|
})
|
||||||
|
.boxed()
|
||||||
};
|
};
|
||||||
|
|
||||||
sum_op.labelled("numeric expression").as_context()
|
sum_op.labelled("numeric expression").as_context()
|
||||||
|
|
@ -272,8 +272,9 @@ pub fn parser<'tokens, 'src: 'tokens>(
|
||||||
span.into(),
|
span.into(),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
.boxed()
|
||||||
};
|
};
|
||||||
let num_expr = num_expr_parser();
|
let num_expr = num_expr_parser().boxed();
|
||||||
|
|
||||||
recursive(|expr| {
|
recursive(|expr| {
|
||||||
let literal = select! {
|
let literal = select! {
|
||||||
|
|
@ -284,32 +285,28 @@ pub fn parser<'tokens, 'src: 'tokens>(
|
||||||
let var = select! { Token::Ident(ident) => Expr::Var{ name: ident.clone(), kind: Type::default()} }
|
let var = select! { Token::Ident(ident) => Expr::Var{ name: ident.clone(), kind: Type::default()} }
|
||||||
.labelled("variable");
|
.labelled("variable");
|
||||||
|
|
||||||
// Relational ops (<, <=, >, >=) have equal precedence
|
// Relational ops (<, <=, >, >=, ==, !=) have equal precedence
|
||||||
let relational_op = {
|
let relational_op = {
|
||||||
let op = just(Token::Lt).to(BinaryOps::Lt).or(just(Token::Le)
|
let op = choice((
|
||||||
.to(BinaryOps::Le)
|
just(Token::Lt).to(BinaryOps::Lt),
|
||||||
.or(just(Token::Gt).to(BinaryOps::Gt).or(just(Token::Ge).to(BinaryOps::Ge))));
|
just(Token::Le).to(BinaryOps::Le),
|
||||||
num_expr.clone().foldl(op.then(num_expr).repeated(), |a, (op, b)| {
|
just(Token::Gt).to(BinaryOps::Gt),
|
||||||
let span = a.1.start..b.1.end;
|
just(Token::Ge).to(BinaryOps::Ge),
|
||||||
(Expr::binary_op(op, (Box::new(a), Box::new(b)), None), span.into())
|
just(Token::Eq).to(BinaryOps::Eq),
|
||||||
})
|
just(Token::Neq).to(BinaryOps::Neq),
|
||||||
};
|
));
|
||||||
|
num_expr
|
||||||
// Equality ops (==, !=) have equal precedence
|
|
||||||
let equality_op = {
|
|
||||||
let op = just(Token::Eq)
|
|
||||||
.to(BinaryOps::Eq)
|
|
||||||
.or(just(Token::Neq).to(BinaryOps::Neq));
|
|
||||||
relational_op
|
|
||||||
.clone()
|
.clone()
|
||||||
.foldl(op.then(relational_op).repeated(), |a, (op, b)| {
|
.then(op.then(num_expr))
|
||||||
|
.map(|(a, (op, b))| {
|
||||||
let span = a.1.start..b.1.end;
|
let span = a.1.start..b.1.end;
|
||||||
(Expr::binary_op(op, (Box::new(a), Box::new(b)), None), span.into())
|
(Expr::binary_op(op, (Box::new(a), Box::new(b)), None), span.into())
|
||||||
})
|
})
|
||||||
|
.boxed()
|
||||||
}
|
}
|
||||||
.labelled("atomic predicate");
|
.labelled("atomic predicate");
|
||||||
|
|
||||||
let atom = equality_op
|
let atom = relational_op
|
||||||
.or(var.or(literal).map_with_span(|expr, span| (expr, span)))
|
.or(var.or(literal).map_with_span(|expr, span| (expr, span)))
|
||||||
// Atoms can also just be normal expressions, but surrounded with parentheses
|
// Atoms can also just be normal expressions, but surrounded with parentheses
|
||||||
.or(expr.clone().delimited_by(just(Token::LParen), just(Token::RParen)))
|
.or(expr.clone().delimited_by(just(Token::LParen), just(Token::RParen)))
|
||||||
|
|
@ -328,28 +325,23 @@ pub fn parser<'tokens, 'src: 'tokens>(
|
||||||
.foldr(atom, |op, rhs| {
|
.foldr(atom, |op, rhs| {
|
||||||
let span = op.1.start..rhs.1.end;
|
let span = op.1.start..rhs.1.end;
|
||||||
(Expr::unary_op(op.0, Box::new(rhs), None), span.into())
|
(Expr::unary_op(op.0, Box::new(rhs), None), span.into())
|
||||||
});
|
})
|
||||||
|
.boxed();
|
||||||
|
|
||||||
let next_op = just(Token::Next)
|
let unary_temporal_op = {
|
||||||
.map_with_span(|_, span: Span| (UnaryOps::Next, span))
|
let op = choice((
|
||||||
.then(interval.or_not())
|
just(Token::Next).to(UnaryOps::Next),
|
||||||
|
just(Token::Eventually).to(UnaryOps::Eventually),
|
||||||
|
just(Token::Always).to(UnaryOps::Always),
|
||||||
|
));
|
||||||
|
op.map_with_span(|op, span: Span| (op, span))
|
||||||
|
.then(interval.clone().or_not())
|
||||||
.repeated()
|
.repeated()
|
||||||
.foldr(not_op, |(op, interval), rhs| {
|
.foldr(not_op, |(op, interval), rhs| {
|
||||||
let span = op.1.start..rhs.1.end;
|
let span = op.1.start..rhs.1.end;
|
||||||
(Expr::unary_op(op.0, Box::new(rhs), interval), span.into())
|
(Expr::unary_op(op.0, Box::new(rhs), interval), span.into())
|
||||||
});
|
|
||||||
|
|
||||||
let unary_temporal_op = {
|
|
||||||
let op = just(Token::Eventually)
|
|
||||||
.to(UnaryOps::Eventually)
|
|
||||||
.or(just(Token::Always).to(UnaryOps::Always));
|
|
||||||
op.map_with_span(|op, span: Span| (op, span))
|
|
||||||
.then(interval.or_not())
|
|
||||||
.repeated()
|
|
||||||
.foldr(next_op, |(op, interval), rhs| {
|
|
||||||
let span = op.1.start..rhs.1.end;
|
|
||||||
(Expr::unary_op(op.0, Box::new(rhs), interval), span.into())
|
|
||||||
})
|
})
|
||||||
|
.boxed()
|
||||||
};
|
};
|
||||||
|
|
||||||
let binary_temporal_op = unary_temporal_op
|
let binary_temporal_op = unary_temporal_op
|
||||||
|
|
@ -363,7 +355,8 @@ pub fn parser<'tokens, 'src: 'tokens>(
|
||||||
Expr::binary_op(op, (Box::new(lhs), Box::new(rhs)), interval),
|
Expr::binary_op(op, (Box::new(lhs), Box::new(rhs)), interval),
|
||||||
span.into(),
|
span.into(),
|
||||||
)
|
)
|
||||||
});
|
})
|
||||||
|
.boxed();
|
||||||
|
|
||||||
let and_op = {
|
let and_op = {
|
||||||
let op = just(Token::And).to(BinaryOps::And);
|
let op = just(Token::And).to(BinaryOps::And);
|
||||||
|
|
@ -373,34 +366,44 @@ pub fn parser<'tokens, 'src: 'tokens>(
|
||||||
let span = a.1.start..b.1.end;
|
let span = a.1.start..b.1.end;
|
||||||
(Expr::binary_op(op, (Box::new(a), Box::new(b)), None), span.into())
|
(Expr::binary_op(op, (Box::new(a), Box::new(b)), None), span.into())
|
||||||
})
|
})
|
||||||
|
.boxed()
|
||||||
};
|
};
|
||||||
|
|
||||||
let or_op = {
|
let or_op = {
|
||||||
let op = just(Token::Or).to(BinaryOps::Or);
|
let op = just(Token::Or).to(BinaryOps::Or);
|
||||||
and_op.clone().foldl(op.then(and_op).repeated(), |a, (op, b)| {
|
and_op
|
||||||
|
.clone()
|
||||||
|
.foldl(op.then(and_op).repeated(), |a, (op, b)| {
|
||||||
let span = a.1.start..b.1.end;
|
let span = a.1.start..b.1.end;
|
||||||
(Expr::binary_op(op, (Box::new(a), Box::new(b)), None), span.into())
|
(Expr::binary_op(op, (Box::new(a), Box::new(b)), None), span.into())
|
||||||
})
|
})
|
||||||
|
.boxed()
|
||||||
};
|
};
|
||||||
|
|
||||||
let xor_op = {
|
let xor_op = {
|
||||||
let op = just(Token::Xor).to(BinaryOps::Xor);
|
let op = just(Token::Xor).to(BinaryOps::Xor);
|
||||||
or_op.clone().foldl(op.then(or_op).repeated(), |a, (op, b)| {
|
or_op
|
||||||
|
.clone()
|
||||||
|
.foldl(op.then(or_op).repeated(), |a, (op, b)| {
|
||||||
let span = a.1.start..b.1.end;
|
let span = a.1.start..b.1.end;
|
||||||
(Expr::binary_op(op, (Box::new(a), Box::new(b)), None), span.into())
|
(Expr::binary_op(op, (Box::new(a), Box::new(b)), None), span.into())
|
||||||
})
|
})
|
||||||
|
.boxed()
|
||||||
};
|
};
|
||||||
|
|
||||||
let implies_equiv_op = {
|
let implies_equiv_op = {
|
||||||
let op = just(Token::Implies)
|
let op = just(Token::Implies)
|
||||||
.to(BinaryOps::Implies)
|
.to(BinaryOps::Implies)
|
||||||
.or(just(Token::Equiv).to(BinaryOps::Equiv));
|
.or(just(Token::Equiv).to(BinaryOps::Equiv));
|
||||||
xor_op.clone().foldl(op.then(xor_op).repeated(), |a, (op, b)| {
|
xor_op
|
||||||
|
.clone()
|
||||||
|
.foldl(op.then(xor_op).repeated(), |a, (op, b)| {
|
||||||
let span = a.1.start..b.1.end;
|
let span = a.1.start..b.1.end;
|
||||||
(Expr::binary_op(op, (Box::new(a), Box::new(b)), None), span.into())
|
(Expr::binary_op(op, (Box::new(a), Box::new(b)), None), span.into())
|
||||||
})
|
})
|
||||||
|
.boxed()
|
||||||
};
|
};
|
||||||
|
|
||||||
implies_equiv_op.labelled("expression").as_context()
|
implies_equiv_op.labelled("boolean expression").as_context()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue