mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-01 07:41:12 +00:00
Parse basic operators
This commit is contained in:
parent
8fcc9504af
commit
9863268793
4 changed files with 64 additions and 37 deletions
|
@ -11,12 +11,18 @@ use operator::Operator;
|
|||
use parse::ast::{Attempting, Expr};
|
||||
use parse::number_literal::number_literal;
|
||||
use parse::parser::{
|
||||
and, attempt, lazy, loc, map, map_with_arena, one_of3, optional, string, unexpected,
|
||||
unexpected_eof, val, Parser, State,
|
||||
and, attempt, loc, map, map_with_arena, one_of3, optional, string, unexpected, unexpected_eof,
|
||||
ParseResult, Parser, State,
|
||||
};
|
||||
use parse::string_literal::string_literal;
|
||||
|
||||
pub fn expr<'a>() -> impl Parser<'a, Expr<'a>> {
|
||||
// Recursive parsers must not directly invoke functions which return (impl Parser),
|
||||
// as this causes rustc to stack overflow.
|
||||
parse_expr
|
||||
}
|
||||
|
||||
fn parse_expr<'a>(arena: &'a Bump, state: State<'a>) -> ParseResult<'a, Expr<'a>> {
|
||||
map_with_arena(
|
||||
and(
|
||||
attempt(
|
||||
|
@ -27,7 +33,7 @@ pub fn expr<'a>() -> impl Parser<'a, Expr<'a>> {
|
|||
string_literal(),
|
||||
)),
|
||||
),
|
||||
optional(and(loc(operator()), loc(val(Expr::Str("blah"))))),
|
||||
optional(and(loc(operator()), loc(parse_expr))),
|
||||
),
|
||||
|arena, (loc_expr1, opt_operator)| match opt_operator {
|
||||
Some((loc_op, loc_expr2)) => {
|
||||
|
@ -38,15 +44,15 @@ pub fn expr<'a>() -> impl Parser<'a, Expr<'a>> {
|
|||
None => loc_expr1.value,
|
||||
},
|
||||
)
|
||||
.parse(arena, state)
|
||||
}
|
||||
|
||||
pub fn operator<'a>() -> impl Parser<'a, Operator> {
|
||||
val(Operator::Plus)
|
||||
// one_of3(
|
||||
// map(string("+"), |_| Operator::Plus),
|
||||
// map(string("-"), |_| Operator::Minus),
|
||||
// map(string("*"), |_| Operator::Star),
|
||||
// )
|
||||
one_of3(
|
||||
map(string("+"), |_| Operator::Plus),
|
||||
map(string("-"), |_| Operator::Minus),
|
||||
map(string("*"), |_| Operator::Star),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn record_literal<'a>() -> impl Parser<'a, Expr<'a>> {
|
||||
|
|
|
@ -42,8 +42,6 @@ where
|
|||
let mut chars_parsed = 1;
|
||||
|
||||
while let Some(next_ch) = chars.next() {
|
||||
chars_parsed += 1;
|
||||
|
||||
let err_unexpected = || {
|
||||
Err(unexpected(
|
||||
next_ch,
|
||||
|
@ -54,7 +52,7 @@ where
|
|||
};
|
||||
|
||||
// Returns true iff so far we have parsed the given char and no other chars.
|
||||
let so_far_parsed = |ch| chars_parsed == 2 && first_ch == ch;
|
||||
let so_far_parsed = |ch| chars_parsed == 1 && first_ch == ch;
|
||||
|
||||
// We don't support negative escaped ints (e.g. 0x01 is supported but -0x01 is not).
|
||||
// If you want that, do something like (negate 0x01).
|
||||
|
@ -96,6 +94,8 @@ where
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
chars_parsed += 1;
|
||||
}
|
||||
|
||||
// At this point we have a number, and will definitely succeed.
|
||||
|
|
|
@ -190,21 +190,6 @@ pub trait Parser<'a, Output> {
|
|||
fn parse(&self, &'a Bump, State<'a>) -> ParseResult<'a, Output>;
|
||||
}
|
||||
|
||||
pub struct BoxedParser<'a, Output> {
|
||||
parser: &'a (dyn Parser<'a, Output> + 'a),
|
||||
}
|
||||
|
||||
impl<'a, Output> BoxedParser<'a, Output> {
|
||||
fn new<P>(arena: &'a Bump, parser: P) -> Self
|
||||
where
|
||||
P: Parser<'a, Output> + 'a,
|
||||
{
|
||||
BoxedParser {
|
||||
parser: arena.alloc(parser),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, F, Output> Parser<'a, Output> for F
|
||||
where
|
||||
F: Fn(&'a Bump, State<'a>) -> ParseResult<'a, Output>,
|
||||
|
@ -221,15 +206,6 @@ where
|
|||
move |_, state| Ok((value.clone(), state))
|
||||
}
|
||||
|
||||
/// Needed for recursive parsers
|
||||
pub fn lazy<'a, F, P, Val>(get_parser: F) -> impl Parser<'a, Val>
|
||||
where
|
||||
F: Fn() -> P,
|
||||
P: Parser<'a, Val>,
|
||||
{
|
||||
move |arena, state| get_parser().parse(arena, state)
|
||||
}
|
||||
|
||||
pub fn map<'a, P, F, Before, After>(parser: P, transform: F) -> impl Parser<'a, After>
|
||||
where
|
||||
P: Parser<'a, Before>,
|
||||
|
|
|
@ -16,10 +16,11 @@ mod helpers;
|
|||
mod test_parse {
|
||||
use bumpalo::Bump;
|
||||
use helpers::parse_with;
|
||||
use roc::operator::Operator::*;
|
||||
use roc::parse::ast::Attempting;
|
||||
use roc::parse::ast::Expr::{self, *};
|
||||
use roc::parse::parser::{Fail, FailReason};
|
||||
use roc::region::Region;
|
||||
use roc::region::{Located, Region};
|
||||
use std::{f64, i64};
|
||||
|
||||
fn assert_parses_to<'a>(input: &'a str, expected_expr: Expr<'a>) {
|
||||
|
@ -237,6 +238,50 @@ mod test_parse {
|
|||
assert_parses_to("{}", EmptyRecord);
|
||||
}
|
||||
|
||||
// OPERATORS
|
||||
|
||||
#[test]
|
||||
fn one_plus_two() {
|
||||
let arena = Bump::new();
|
||||
let tuple = arena.alloc((
|
||||
Located::new(0, 0, 0, 1, Int("1")),
|
||||
Located::new(0, 1, 0, 2, Plus),
|
||||
Located::new(0, 2, 0, 3, Int("2")),
|
||||
));
|
||||
let expected = Operator(tuple);
|
||||
let actual = parse_with(&arena, "1+2");
|
||||
|
||||
assert_eq!(Ok(expected), actual);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn minus_twelve_minus_five() {
|
||||
let arena = Bump::new();
|
||||
let tuple = arena.alloc((
|
||||
Located::new(0, 0, 0, 3, Int("-12")),
|
||||
Located::new(0, 3, 0, 4, Minus),
|
||||
Located::new(0, 4, 0, 5, Int("5")),
|
||||
));
|
||||
let expected = Operator(tuple);
|
||||
let actual = parse_with(&arena, "-12-5");
|
||||
|
||||
assert_eq!(Ok(expected), actual);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ten_times_eleven() {
|
||||
let arena = Bump::new();
|
||||
let tuple = arena.alloc((
|
||||
Located::new(0, 0, 0, 2, Int("10")),
|
||||
Located::new(0, 2, 0, 3, Star),
|
||||
Located::new(0, 3, 0, 5, Int("11")),
|
||||
));
|
||||
let expected = Operator(tuple);
|
||||
let actual = parse_with(&arena, "10*11");
|
||||
|
||||
assert_eq!(Ok(expected), actual);
|
||||
}
|
||||
|
||||
// TODO test hex/oct/binary parsing
|
||||
//
|
||||
// TODO test for \t \r and \n in string literals *outside* unicode escape sequence!
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue