Full ast parsing

This commit is contained in:
Greg Shuflin 2021-11-18 15:17:47 -08:00
parent b7b4e75f01
commit 7a8ab3d571
3 changed files with 64 additions and 11 deletions

View File

@ -79,6 +79,22 @@ fn statement_delimiter(input: Span) -> ParseResult<()> {
tok(alt((value((), line_ending), value((), char(';')))))(input)
}
pub fn program(input: Span) -> ParseResult<AST> {
let id = fresh_id(&input);
//TODO `rest` should be empty
let (rest, statements) = context("AST",
map(
tuple((
many0(statement_delimiter),
separated_list0(statement_delimiter, statement),
many0(statement_delimiter),
)), |(_, items, _)| items.into())
)(input)?;
let ast = AST { id, statements };
Ok((rest, ast))
}
pub fn block(input: Span) -> ParseResult<Block> {
context(
"block",
@ -97,16 +113,33 @@ pub fn block(input: Span) -> ParseResult<Block> {
fn statement(input: Span) -> ParseResult<Statement> {
let (input, pos) = position(input)?;
let pos: usize = pos.location_offset();
let location = pos.location_offset().into();
let id = fresh_id(&input);
context(
let (rest, kind) = context(
"Parsing-statement",
map(expression, move |expr| Statement {
id,
location: pos.into(),
kind: StatementKind::Expression(expr),
}),
)(input)
alt((
map(expression, StatementKind::Expression),
map(declaration, StatementKind::Declaration),
))
)(input)?;
Ok((rest, Statement { id, location, kind }))
}
fn declaration(input: Span) -> ParseResult<Declaration> {
alt((binding, module))(input)
}
fn binding(input: Span) -> ParseResult<Declaration> {
let parser =
tuple((kw("let"), opt(kw("mut")), tok(identifier), opt(type_anno), tok(char('=')), expression));
map(parser, |(_, maybe_mut, ident, type_anno, _, expr)|
Declaration::Binding { name: rc_string(ident.fragment()), constant: maybe_mut.is_none(),
type_anno, expr })(input)
}
fn module(input: Span) -> ParseResult<Declaration> {
map(tuple((kw("module"), tok(identifier), block)),
|(_, name, items)| Declaration::Module { name: rc_string(name.fragment()), items })(input)
}
pub fn expression(input: Span) -> ParseResult<Expression> {

View File

@ -28,6 +28,12 @@ impl Parser {
peg_parser::schala_parser::program(input, self).map_err(ParseError::from_peg)
}
pub(crate) fn parse_comb(&mut self, input: &str) -> Result<AST, ParseError> {
let id_store: IdStore<ASTItem> = IdStore::new();
let span = Span::new_extra(input, Rc::new(RefCell::new(id_store)));
combinator::program(span).map_err(|err| convert_err(input, err)).map(|(_, output)| output)
}
#[cfg(test)]
fn expression(&mut self, input: &str) -> Result<Expression, ParseError> {
peg_parser::schala_parser::expression(input, self).map_err(ParseError::from_peg)

View File

@ -98,6 +98,20 @@ macro_rules! assert_ast {
};
}
macro_rules! assert_ast_comb {
($input:expr, $statements:expr) => {
let mut parser = Parser::new();
let ast = parser.parse_comb($input);
let expected = AST { id: Default::default(), statements: $statements.into() };
if ast.is_err() {
println!("Parse error: {}", ast.unwrap_err().msg);
panic!();
}
assert_eq!(ast.unwrap(), expected);
};
}
macro_rules! assert_fail {
($input:expr, $failure:expr) => {
let mut parser = Parser::new();
@ -180,7 +194,7 @@ fn binexps() {
use StatementKind::Expression;
assert_expr_comb!("0xf_f+1", binop("+", expr(NatLiteral(255)), expr(NatLiteral(1))));
assert_ast!(
assert_ast_comb!(
"3; 4; 4.3",
vec![
stmt(Expression(expr(NatLiteral(3)))),
@ -1315,7 +1329,7 @@ fn blocks() {
let mut parser = Parser::new();
for case in cases.iter() {
let block = parser.block(case);
let block = parser.block_comb(case);
assert_eq!(block.unwrap(), vec![exst(Value(qn!(a)))].into());
}
@ -1397,7 +1411,7 @@ fn comments() {
assert_fail_expr!(source, binop("+", expr(NatLiteral(1)), expr(NatLiteral(2))));
let source = "5//no man\n";
assert_ast!(source, vec![exst(NatLiteral(5))]);
assert_ast_comb!(source, vec![exst(NatLiteral(5))]);
}
//TODO support backtick operators like this