This commit is contained in:
Greg Shuflin 2021-11-17 12:45:55 -08:00
parent f1ffeb155a
commit d37be75478
2 changed files with 111 additions and 111 deletions

View File

@ -1,17 +1,20 @@
use std::{cell::RefCell, rc::Rc};
use nom::{ use nom::{
Err,
branch::alt, branch::alt,
bytes::complete::{take_till, tag}, bytes::complete::{tag, take_till},
character::complete::{alpha1, alphanumeric0, not_line_ending,none_of, char, one_of, space0, space1, multispace0, line_ending}, character::complete::{
combinator::{opt, peek, not, value, map, recognize}, alpha1, alphanumeric0, char, line_ending, multispace0, none_of, not_line_ending, one_of, space0,
error::{context, VerboseError, ParseError}, space1,
multi::{fold_many1, many1, many0, separated_list1, separated_list0}, },
sequence::{pair, tuple, preceded}, combinator::{map, not, opt, peek, recognize, value},
IResult, Parser, error::{context, ParseError, VerboseError},
multi::{fold_many1, many0, many1, separated_list0, separated_list1},
sequence::{pair, preceded, tuple},
Err, IResult, Parser,
}; };
use nom_locate::{position, LocatedSpan}; use nom_locate::{position, LocatedSpan};
use std::rc::Rc;
use std::cell::RefCell;
use crate::identifier::{Id, IdStore}; use crate::identifier::{Id, IdStore};
type StoreRef = Rc<RefCell<IdStore<ASTItem>>>; type StoreRef = Rc<RefCell<IdStore<ASTItem>>>;
@ -29,65 +32,50 @@ fn fresh_id(span: &Span) -> Id<ASTItem> {
table_handle.fresh() table_handle.fresh()
} }
fn tok<'a, O>(input_parser: impl Parser<Span<'a>, O, VerboseError<Span<'a>>>) -> impl FnMut(Span<'a>) fn tok<'a, O>(
-> IResult<Span<'a>, O, VerboseError<Span<'a>>> { input_parser: impl Parser<Span<'a>, O, VerboseError<Span<'a>>>,
) -> impl FnMut(Span<'a>) -> IResult<Span<'a>, O, VerboseError<Span<'a>>> {
context("tok", context("tok", map(tuple((ws0, input_parser)), |(_, output)| output))
map(tuple((ws0, input_parser)), |(_, output)|
output))
} }
fn kw<'a>(keyword_str: &'static str) -> impl FnMut(Span<'a>) -> ParseResult<()> { fn kw<'a>(keyword_str: &'static str) -> impl FnMut(Span<'a>) -> ParseResult<()> {
context("keyword", context("keyword", tok(value((), tag(keyword_str))))
tok(value((), tag(keyword_str))))
} }
// whitespace does consume at least one piece of whitespace - use ws0 for maybe none // whitespace does consume at least one piece of whitespace - use ws0 for maybe none
fn whitespace(input: Span) -> ParseResult<()> { fn whitespace(input: Span) -> ParseResult<()> {
context("whitespace", context("whitespace", alt((block_comment, line_comment, value((), space1))))(input)
alt((
block_comment,
line_comment,
value((), space1),
)))(input)
} }
fn ws0(input: Span) -> ParseResult<()> { fn ws0(input: Span) -> ParseResult<()> {
context("WS0", context("WS0", value((), many0(whitespace)))(input)
value((), many0(whitespace)))(input)
} }
fn line_comment(input: Span) -> ParseResult<()> { fn line_comment(input: Span) -> ParseResult<()> {
value((), value((), tuple((tag("//"), not_line_ending)))(input)
tuple((tag("//"), not_line_ending)),
)(input)
} }
fn block_comment(input: Span) -> ParseResult<()> { fn block_comment(input: Span) -> ParseResult<()> {
context("Block-comment", context(
value((), "Block-comment",
value(
(),
tuple(( tuple((
tag("/*"), tag("/*"),
many0(alt(( many0(alt((value((), none_of("*/")), value((), none_of("/*")), block_comment))),
value((), none_of("*/")), tag("*/"),
value((), none_of("/*")), )),
block_comment, ),
))),
tag("*/")
))))(input)
}
fn statement_delimiter(input: Span) -> ParseResult<()> {
tok(alt((
value((), line_ending),
value((), char(';'))
))
)(input) )(input)
} }
fn statement_delimiter(input: Span) -> ParseResult<()> {
tok(alt((value((), line_ending), value((), char(';')))))(input)
}
fn block(input: Span) -> ParseResult<Block> { fn block(input: Span) -> ParseResult<Block> {
context("block", context(
"block",
map( map(
tuple(( tuple((
tok(char('{')), tok(char('{')),
@ -95,26 +83,29 @@ fn block(input: Span) -> ParseResult<Block> {
separated_list0(statement_delimiter, statement), separated_list0(statement_delimiter, statement),
many0(statement_delimiter), many0(statement_delimiter),
tok(char('}')), tok(char('}')),
)), |(_, _, items, _, _)| items.into()))(input) )),
|(_, _, items, _, _)| items.into(),
),
)(input)
} }
fn statement(input: Span) -> ParseResult<Statement> { fn statement(input: Span) -> ParseResult<Statement> {
let (input, pos) = position(input)?; let (input, pos) = position(input)?;
let pos: usize = pos.location_offset(); let pos: usize = pos.location_offset();
let id = fresh_id(&input); let id = fresh_id(&input);
context("Parsing-statement", context(
"Parsing-statement",
map(expression, move |expr| Statement { map(expression, move |expr| Statement {
id, id,
location: pos.into(), location: pos.into(),
kind: StatementKind::Expression(expr), kind: StatementKind::Expression(expr),
}))(input) }),
)(input)
} }
fn expression(input: Span) -> ParseResult<Expression> { fn expression(input: Span) -> ParseResult<Expression> {
let id = fresh_id(&input); let id = fresh_id(&input);
map(pair(expression_kind, opt(type_anno)), move |(kind, maybe_anno)| { map(pair(expression_kind, opt(type_anno)), move |(kind, maybe_anno)| Expression::new(id, kind))(input)
Expression::new(id, kind)
})(input)
} }
fn type_anno(input: Span) -> ParseResult<TypeIdentifier> { fn type_anno(input: Span) -> ParseResult<TypeIdentifier> {
@ -140,13 +131,7 @@ pub fn expression_kind(input: Span) -> ParseResult<ExpressionKind> {
} }
fn primary_expr(input: Span) -> ParseResult<ExpressionKind> { fn primary_expr(input: Span) -> ParseResult<ExpressionKind> {
context("primary-expr", context("primary-expr", alt((number_literal, bool_literal, identifier_expr)))(input)
alt((
number_literal,
bool_literal,
identifier_expr,
)))(input)
} }
fn identifier_expr(input: Span) -> ParseResult<ExpressionKind> { fn identifier_expr(input: Span) -> ParseResult<ExpressionKind> {
@ -155,27 +140,23 @@ fn identifier_expr(input: Span) -> ParseResult<ExpressionKind> {
fn qualified_identifier(input: Span) -> ParseResult<QualifiedName> { fn qualified_identifier(input: Span) -> ParseResult<QualifiedName> {
let id = fresh_id(&input); let id = fresh_id(&input);
tok( tok(map(separated_list1(tag("::"), map(identifier, |x| rc_string(x.fragment()))), move |items| {
map( QualifiedName { id, components: items }
separated_list1(tag("::"), map(identifier, |x| rc_string(x.fragment()))), }))(input)
move |items| QualifiedName { id, components: items }
))(input)
} }
fn identifier(input: Span) -> ParseResult<Span> { fn identifier(input: Span) -> ParseResult<Span> {
recognize( recognize(tuple((alt((tag("_"), alpha1)), alphanumeric0)))(input)
tuple((
alt((tag("_"), alpha1)),
alphanumeric0,
)))(input)
} }
fn bool_literal(input: Span) -> ParseResult<ExpressionKind> { fn bool_literal(input: Span) -> ParseResult<ExpressionKind> {
context("bool-literal", context(
"bool-literal",
alt(( alt((
map(kw("true"), |_| ExpressionKind::BoolLiteral(true)), map(kw("true"), |_| ExpressionKind::BoolLiteral(true)),
map(kw("false"), |_| ExpressionKind::BoolLiteral(false)), map(kw("false"), |_| ExpressionKind::BoolLiteral(false)),
)))(input) )),
)(input)
} }
fn number_literal(input: Span) -> ParseResult<ExpressionKind> { fn number_literal(input: Span) -> ParseResult<ExpressionKind> {
@ -282,14 +263,11 @@ mod test {
} }
macro_rules! span { macro_rules! span {
($func:expr, $input:expr) => { ($func:expr, $input:expr) => {{
{
let id_store: IdStore<ASTItem> = IdStore::new(); let id_store: IdStore<ASTItem> = IdStore::new();
let span = Span::new_extra($input, let span = Span::new_extra($input, Rc::new(RefCell::new(id_store)));
Rc::new(RefCell::new(id_store)));
$func(span).map(|(span, x)| (*span.fragment(), x)) $func(span).map(|(span, x)| (*span.fragment(), x))
} }};
};
} }
#[test] #[test]
@ -313,7 +291,10 @@ mod test {
} }
assert_eq!(span!(expression_kind, " /*gay*/ true").unwrap().1, ExpressionKind::BoolLiteral(true)); assert_eq!(span!(expression_kind, " /*gay*/ true").unwrap().1, ExpressionKind::BoolLiteral(true));
assert_eq!(span!(expression_kind, " /*yolo*/ barnaby").unwrap().1, ExpressionKind::Value(qn!(barnaby))); assert_eq!(
span!(expression_kind, " /*yolo*/ barnaby").unwrap().1,
ExpressionKind::Value(qn!(barnaby))
);
} }
#[test] #[test]
@ -328,10 +309,12 @@ mod test {
}"#; }"#;
let parsed = span!(block, source).map_err(|err| match err { let parsed = span!(block, source).map_err(|err| match err {
Err::Error(err) | Err::Failure(err) => { Err::Error(err) | Err::Failure(err) => {
let err = VerboseError { errors: err.errors.into_iter().map(|(sp, kind)| (*sp.fragment(), kind)).collect() }; let err = VerboseError {
errors: err.errors.into_iter().map(|(sp, kind)| (*sp.fragment(), kind)).collect(),
};
nom::error::convert_error(source, err) nom::error::convert_error(source, err)
}, }
_ => panic!() _ => panic!(),
}); });
if let Err(err) = parsed { if let Err(err) = parsed {
@ -339,16 +322,35 @@ mod test {
panic!("parse error desu!"); panic!("parse error desu!");
} }
assert_eq!(parsed.unwrap().1, vec![ assert_eq!(
Statement { id: Default::default(), location: parsed.unwrap().1,
Default::default(), kind: StatementKind::Expression(Expression::new(Default::default(), vec![
ExpressionKind::NatLiteral(45))) }, Statement {
Statement { id: Default::default(), location: id: Default::default(),
Default::default(), kind: StatementKind::Expression(Expression::new(Default::default(), location: Default::default(),
ExpressionKind::NatLiteral(11))) }, kind: StatementKind::Expression(Expression::new(
Statement { id: Default::default(), location: Default::default(),
Default::default(), kind: StatementKind::Expression(Expression::new(Default::default(), ExpressionKind::NatLiteral(45)
ExpressionKind::NatLiteral(15))) }, ))
].into()); },
Statement {
id: Default::default(),
location: Default::default(),
kind: StatementKind::Expression(Expression::new(
Default::default(),
ExpressionKind::NatLiteral(11)
))
},
Statement {
id: Default::default(),
location: Default::default(),
kind: StatementKind::Expression(Expression::new(
Default::default(),
ExpressionKind::NatLiteral(15)
))
},
]
.into()
);
} }
} }

View File

@ -1352,5 +1352,3 @@ fn backtick_operators() {
assert_eq!(output, vec![digit!("1"), op!("plus"), digit!("2")]); assert_eq!(output, vec![digit!("1"), op!("plus"), digit!("2")]);
} }
*/ */