Skip to content

Commit

Permalink
fetch to new parser
Browse files Browse the repository at this point in the history
  • Loading branch information
andogq committed Sep 2, 2024
1 parent 2323d18 commit 977cd47
Show file tree
Hide file tree
Showing 22 changed files with 286 additions and 1,491 deletions.
2 changes: 1 addition & 1 deletion src/hir/expression/assign.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ mod test {
)
.unwrap();

let Expression::Assign(assign) = dbg!(assign) else {
let Expression::Assign(assign) = assign else {
panic!("expected to parse assignment")
};

Expand Down
41 changes: 16 additions & 25 deletions src/hir/expression/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ use super::*;
ast_node! {
Block<M> {
statements: Vec<Statement<M>>,
terminated: bool,
span,
ty_info,
}
Expand All @@ -29,14 +28,14 @@ impl<M: AstMetadata> Parsable for Block<M> {
};

// Parse statements
let (statements, terminated) = parser
.parse_delimited::<Statement<UntypedAstMetadata>, Precedence>(
compiler,
lexer,
Token::SemiColon,
);

dbg!(&statements, terminated);
let mut statements = Vec::new();
while lexer
.peek_token()
.map(|t| !matches!(t, Token::RightBrace))
.unwrap_or(false)
{
statements.push(parser.parse(compiler, lexer, Precedence::Lowest)?);
}

// Parse ending bracket
let end_span = match lexer.next_spanned().ok_or(ParseError::UnexpectedEOF)? {
Expand All @@ -52,7 +51,6 @@ impl<M: AstMetadata> Parsable for Block<M> {

Ok(Expression::Block(Block {
statements,
terminated,
span: start_span.start..end_span.end,
ty_info: None,
}))
Expand Down Expand Up @@ -108,7 +106,6 @@ impl SolveType for Block<UntypedAstMetadata> {

Ok(Block {
span: self.span,
terminated: self.terminated,
statements,
ty_info,
})
Expand Down Expand Up @@ -139,19 +136,14 @@ mod test {
}

#[rstest]
#[case::empty("{ }", false, 0)]
#[case::single_terminated("{ true; }", true, 1)]
#[case::single_unterminated("{ true }", false, 1)]
#[case::double_terminated("{ true; true; }", true, 2)]
#[case::double_unterminated("{ true; true }", false, 2)]
#[case::triple_terminated("{ true; true; true; }", true, 3)]
#[case::triple_unterminated("{ true; true; true }", false, 3)]
fn success(
parser: Parser,
#[case] source: &str,
#[case] terminated: bool,
#[case] count: usize,
) {
#[case::empty("{ }", 0)]
#[case::single_terminated("{ true; }", 1)]
#[case::single_unterminated("{ true }", 1)]
#[case::double_terminated("{ true; true; }", 2)]
#[case::double_unterminated("{ true; true }", 2)]
#[case::triple_terminated("{ true; true; true; }", 3)]
#[case::triple_unterminated("{ true; true; true }", 3)]
fn success(parser: Parser, #[case] source: &str, #[case] count: usize) {
let b: Expression<UntypedAstMetadata> = parser
.parse(
&mut Compiler::default(),
Expand All @@ -164,7 +156,6 @@ mod test {
panic!("expected to parse block");
};

assert_eq!(b.terminated, terminated);
assert_eq!(b.statements.len(), count);
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/hir/expression/cast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ mod test {
)
.unwrap();

let Expression::Cast(cast) = dbg!(cast) else {
let Expression::Cast(cast) = cast else {
panic!("expected to parse cast");
};

Expand Down
9 changes: 2 additions & 7 deletions src/hir/expression/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,13 +67,8 @@ impl<M: AstMetadata<Span = Span, TyInfo: Default>> Expression<M> {
Self::Ident(Ident::new(name, span, M::TyInfo::default()))
}

pub fn block(statements: Vec<Statement<M>>, terminated: bool, span: Span) -> Self {
Self::Block(Block::new(
statements,
terminated,
span,
M::TyInfo::default(),
))
pub fn block(statements: Vec<Statement<M>>, span: Span) -> Self {
Self::Block(Block::new(statements, span, M::TyInfo::default()))
}

pub fn _if(
Expand Down
13 changes: 12 additions & 1 deletion src/hir/statement/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,16 @@ impl SolveType for Statement<UntypedAstMetadata> {
}
}

impl<M: AstMetadata> Parsable for Statement<M> {
fn register(parser: &mut Parser) {
Return::<UntypedAstMetadata>::register(parser);
Let::<UntypedAstMetadata>::register(parser);
ExpressionStatement::<UntypedAstMetadata>::register(parser);
Break::<UntypedAstMetadata>::register(parser);
Continue::<UntypedAstMetadata>::register(parser);
}
}

impl<M: AstMetadata<TyInfo: Default>> Statement<M> {
pub fn _return(expression: Expression<M>, span: M::Span) -> Self {
Self::Return(Return::new(expression, span, M::TyInfo::default()))
Expand All @@ -50,9 +60,10 @@ impl<M: AstMetadata<TyInfo: Default>> Statement<M> {
Self::Let(Let::new(name, value, span, M::TyInfo::default()))
}

pub fn expression(expression: Expression<M>, span: M::Span) -> Self {
pub fn expression(expression: Expression<M>, terminated: bool, span: M::Span) -> Self {
Self::ExpressionStatement(ExpressionStatement::new(
expression,
terminated,
span,
M::TyInfo::default(),
))
Expand Down
38 changes: 33 additions & 5 deletions src/hir/statement/s_break.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ impl<M: AstMetadata> Parsable for Break<M> {
assert!(parser.register_prefix::<Statement<UntypedAstMetadata>>(
Token::Break,
|_, _, lexer| {
let span = match lexer.next_spanned().ok_or(ParseError::UnexpectedEOF)? {
let break_span = match lexer.next_spanned().ok_or(ParseError::UnexpectedEOF)? {
(Token::Break, span) => span,
(token, _) => {
return Err(ParseError::ExpectedToken {
Expand All @@ -25,8 +25,20 @@ impl<M: AstMetadata> Parsable for Break<M> {
}
};

// Parse out the semicolon
let semicolon_span = match lexer.next_spanned().ok_or(ParseError::UnexpectedEOF)? {
(Token::SemiColon, span) => span,
(token, _) => {
return Err(ParseError::ExpectedToken {
expected: Box::new(Token::SemiColon),
found: Box::new(token),
reason: "expected break statement to finish with semicolon".to_string(),
});
}
};

Ok(Statement::Break(Break {
span,
span: break_span.start..semicolon_span.end,
ty_info: None,
}))
}
Expand Down Expand Up @@ -62,12 +74,16 @@ mod test {

use super::*;

#[rstest]
#[case("break")]
fn success(#[case] source: &str) {
#[fixture]
fn parser() -> Parser {
let mut parser = Parser::new();
Break::<UntypedAstMetadata>::register(&mut parser);
parser
}

#[rstest]
#[case("break;")]
fn success(parser: Parser, #[case] source: &str) {
let b: Statement<UntypedAstMetadata> = parser
.parse(
&mut Compiler::default(),
Expand All @@ -78,5 +94,17 @@ mod test {

assert!(matches!(b, Statement::Break(_)));
}

#[rstest]
#[case::missing_semicolon("break")]
fn fail(parser: Parser, #[case] source: &str) {
assert!(parser
.parse::<Statement<UntypedAstMetadata>, _>(
&mut Compiler::default(),
&mut Lexer::from(source),
Precedence::Lowest,
)
.is_err());
}
}
}
38 changes: 35 additions & 3 deletions src/hir/statement/s_continue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ impl<M: AstMetadata> Parsable for Continue<M> {
assert!(parser.register_prefix::<Statement<UntypedAstMetadata>>(
Token::Continue,
|_, _, lexer| {
let span = match lexer.next_spanned().ok_or(ParseError::UnexpectedEOF)? {
let continue_span = match lexer.next_spanned().ok_or(ParseError::UnexpectedEOF)? {
(Token::Continue, span) => span,
(token, _) => {
return Err(ParseError::ExpectedToken {
Expand All @@ -25,8 +25,21 @@ impl<M: AstMetadata> Parsable for Continue<M> {
}
};

// Parse out the semicolon
let semicolon_span = match lexer.next_spanned().ok_or(ParseError::UnexpectedEOF)? {
(Token::SemiColon, span) => span,
(token, _) => {
return Err(ParseError::ExpectedToken {
expected: Box::new(Token::SemiColon),
found: Box::new(token),
reason: "expected continue statement to finish with semicolon"
.to_string(),
});
}
};

Ok(Statement::Continue(Continue {
span,
span: continue_span.start..semicolon_span.end,
ty_info: None,
}))
}
Expand Down Expand Up @@ -62,8 +75,15 @@ mod test {

use super::*;

#[fixture]
fn parser() -> Parser {
let mut parser = Parser::new();
Continue::<UntypedAstMetadata>::register(&mut parser);
parser
}

#[rstest]
#[case("continue")]
#[case("continue;")]
fn success(#[case] source: &str) {
let mut parser = Parser::new();
Continue::<UntypedAstMetadata>::register(&mut parser);
Expand All @@ -78,5 +98,17 @@ mod test {

assert!(matches!(c, Statement::Continue(_)));
}

#[rstest]
#[case::missing_semicolon("continue")]
fn fail(parser: Parser, #[case] source: &str) {
assert!(parser
.parse::<Statement<UntypedAstMetadata>, _>(
&mut Compiler::default(),
&mut Lexer::from(source),
Precedence::Lowest,
)
.is_err());
}
}
}
49 changes: 42 additions & 7 deletions src/hir/statement/s_expression.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use super::*;
ast_node! {
ExpressionStatement<M> {
expression: Expression<M>,
terminated: bool,
span,
ty_info,
}
Expand All @@ -17,8 +18,20 @@ impl<M: AstMetadata> Parsable for ExpressionStatement<M> {
let expression: Expression<UntypedAstMetadata> =
parser.parse(compiler, lexer, Precedence::Lowest)?;

let terminating_span = lexer
.next_if(|(token, _)| matches!(token, Ok(Token::SemiColon)))
.map(|(_, span)| span);

let expression_span = expression.span().clone();
let span = expression_span.start
..terminating_span
.as_ref()
.map(|span| span.end)
.unwrap_or(expression_span.end);

Ok(Statement::ExpressionStatement(ExpressionStatement {
span: expression.span().clone(),
span,
terminated: terminating_span.is_some(),
expression,
ty_info: None,
}))
Expand All @@ -41,8 +54,16 @@ impl SolveType for ExpressionStatement<UntypedAstMetadata> {
let ty_info = expression.get_ty_info().clone();

Ok(ExpressionStatement {
ty_info,
ty_info: TyInfo {
ty: if self.terminated {
Ty::Unit
} else {
ty_info.ty
},
return_ty: ty_info.return_ty,
},
expression,
terminated: self.terminated,
span: self.span,
})
}
Expand Down Expand Up @@ -71,10 +92,12 @@ mod test {
}

#[rstest]
#[case::integer("1", |e| matches!(e, Expression::Integer(_)))]
#[case::integer_unterminated("1", false, |e| matches!(e, Expression::Integer(_)))]
#[case::integer_unterminated("1;", true, |e| matches!(e, Expression::Integer(_)))]
fn success(
parser: Parser,
#[case] source: &str,
#[case] expect_terminated: bool,
#[case] tester: fn(Expression<UntypedAstMetadata>) -> bool,
) {
let s: Statement<UntypedAstMetadata> = parser
Expand All @@ -85,10 +108,17 @@ mod test {
)
.unwrap();

let Statement::ExpressionStatement(ExpressionStatement { expression, .. }) = s else {
let Statement::ExpressionStatement(ExpressionStatement {
expression,
terminated,
..
}) = s
else {
panic!("expected expression statement");
};

assert_eq!(terminated, expect_terminated);

assert!(tester(expression));
}
}
Expand All @@ -97,9 +127,14 @@ mod test {
use super::*;

#[rstest]
#[case(Ty::Int)]
fn infer(#[case] ty: Ty) {
let s = Statement::expression(Expression::integer(0, Span::default()), Span::default());
#[case(Ty::Int, false)]
#[case(Ty::Unit, true)]
fn infer(#[case] ty: Ty, #[case] terminated: bool) {
let s = Statement::expression(
Expression::integer(0, Span::default()),
terminated,
Span::default(),
);

let ty_info = s
.solve(&mut Compiler::default(), &mut Scope::new())
Expand Down
Loading

0 comments on commit 977cd47

Please sign in to comment.