Full ast parsing
This commit is contained in:
parent
b7b4e75f01
commit
7a8ab3d571
@ -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> {
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user