parse hello world

This commit is contained in:
nora 2022-07-08 22:15:29 +02:00
parent 727cfc692c
commit f229dd7fdc
7 changed files with 239 additions and 29 deletions

View file

@ -78,11 +78,27 @@ pub struct ExprBinary {
pub op: BinaryOp,
}
#[derive(Debug, DebugPls)]
pub enum PostfixOp {
Call(Vec<Spanned<Expr>>),
Member(Ident),
ArrowMember(Ident),
Increment,
Decrement,
}
#[derive(Debug, DebugPls)]
pub struct ExprPostfix {
pub lhs: Box<Spanned<Expr>>,
pub op: PostfixOp,
}
#[derive(Debug, DebugPls)]
pub enum Expr {
Atom(Atom),
Unary(ExprUnary),
Binary(ExprBinary),
Postfix(ExprPostfix),
}
//
@ -92,7 +108,10 @@ pub enum Expr {
#[derive(Debug, DebugPls)]
pub enum Stmt {
Decl(Decl),
Labeled{label: Ident, stmt: Box<Spanned<Stmt>>},
Labeled {
label: Ident,
stmt: Box<Spanned<Stmt>>,
},
Compound(Vec<Spanned<Stmt>>),
If {
cond: Expr,

View file

@ -171,7 +171,7 @@ where
/// (6.7) declaration:
/// declaration-specifiers init-declarator-list.opt ;
/// static_assert-declaration
///
///
/// This does NOT eat the semicolon!
fn declaration(&mut self) -> Result<Spanned<Decl>> {
if let Some((tok, span)) = eat!(self, Tok::Kw(Kw::StaticAssert)) {
@ -201,7 +201,7 @@ where
/// init-declarator:
/// declarator
/// declarator = initializer
///
///
fn init_declarator_list(&mut self) -> Result<Vec<Spanned<InitDecl>>> {
let mut init_decls = Vec::new();
let mut first = true;
@ -477,7 +477,11 @@ where
let span2 = expect!(self, Tok::Punct(P::Semicolon));
return Ok((Stmt::Decl(decl), span.extend(span2)));
}
todo!()
// all other stmts are indicated by keywords ...
// it must be an expression stmt
let (expr, span) = self.expr()?;
Ok((Stmt::Expr(expr), span))
}
/// (6.8.2) compound-statement:

View file

@ -3,8 +3,11 @@
//! For more information, see https://matklad.github.io/2020/04/13/simple-but-powerful-pratt-parsing.html
use crate::{
ast::{ArithOpKind, Atom, BinaryOp, ComparisonKind, Expr, ExprBinary, ExprUnary, UnaryOp},
parser::{expect, Parser, ParserError, Result},
ast::{
ArithOpKind, Atom, BinaryOp, ComparisonKind, Expr, ExprBinary, ExprPostfix, ExprUnary,
PostfixOp, UnaryOp,
},
parser::{expect, Parser, ParserError, Result, eat},
pre::Punctuator as P,
token::{Constant, Token as Tok},
Span, Spanned,
@ -33,7 +36,9 @@ where
return lhs;
}
&(Tok::Punct(punct), span) => {
let r_bp = prefix_binding_power(&Tok::Punct(punct));
let r_bp = prefix_binding_power(&Tok::Punct(punct)).ok_or_else(|| {
ParserError::new(span, format!("expected expression, found {punct}"))
})?;
let Some(op) = unary_op_from_token(&Tok::Punct(punct)) else { panic!() };
let rhs = self.expr_bp(r_bp)?;
@ -64,7 +69,7 @@ where
#[allow(clippy::while_let_loop)] // idc
loop {
let (tok, _) = match self.peek_t() {
let (tok, tok_span) = match self.peek_t() {
Ok(&tok) => tok,
Err(_) => break,
};
@ -74,18 +79,48 @@ where
break;
}
let (tok, _) = self.next_t()?;
if let Tok::Punct(P::BracketOpen) = tok {
let rhs = self.expr_bp(0)?;
let span = expect!(self, Tok::Punct(P::BracketClose));
let span = lhs.1.extend(span);
lhs = (
Expr::Binary(ExprBinary {
lhs: Box::new(lhs),
rhs: Box::new(rhs),
op: BinaryOp::Index,
}),
span,
);
match tok {
Tok::Punct(P::BracketOpen) => {
let rhs = self.expr_bp(0)?;
let span = expect!(self, Tok::Punct(P::BracketClose));
let span = lhs.1.extend(span);
lhs = (
Expr::Binary(ExprBinary {
lhs: Box::new(lhs),
rhs: Box::new(rhs),
op: BinaryOp::Index,
}),
span,
);
}
Tok::Punct(P::ParenOpen) => {
let mut arguments = Vec::new();
let mut first = true;
let last_span;
loop {
if let Some((_, span)) = eat!(self, Tok::Punct(P::ParenClose)) {
last_span = span;
break;
}
if !first {
expect!(self, Tok::Punct(P::Comma));
}
first = false;
let arg = self.expr_bp(0)?;
arguments.push(arg);
}
let span = tok_span.extend(last_span);
lhs = (
Expr::Postfix(ExprPostfix {
lhs: Box::new(lhs),
op: PostfixOp::Call(arguments),
}),
span,
)
}
_ => {}
}
continue;
}
@ -189,13 +224,13 @@ mod powers {
pub const POSTFIX: u8 = 29;
}
fn prefix_binding_power(tok: &Tok<'_>) -> u8 {
match tok {
fn prefix_binding_power(tok: &Tok<'_>) -> Option<u8> {
Some(match tok {
Tok::Punct(P::Ampersand | P::Asterisk | P::Plus | P::Minus | P::Tilde | P::Bang) => {
powers::UNARY_OPERATOR
}
_ => panic!("invalid token in expression! {tok:?}"),
}
_ => return None,
})
}
fn infix_binding_power(tok: &Tok<'_>) -> (u8, u8) {
@ -233,7 +268,12 @@ fn infix_binding_power(tok: &Tok<'_>) -> (u8, u8) {
fn postfix_binding_power(tok: &Tok<'_>) -> Option<u8> {
match tok {
Tok::Punct(P::BracketOpen) => Some(45),
Tok::Punct(P::BracketOpen) => Some(powers::POSTFIX),
Tok::Punct(P::ParenOpen) => Some(powers::POSTFIX),
Tok::Punct(P::Dot) => Some(powers::POSTFIX),
Tok::Punct(P::Arrow) => Some(powers::POSTFIX),
Tok::Punct(P::PlusPlus) => Some(powers::POSTFIX),
Tok::Punct(P::MinusMinus) => Some(powers::POSTFIX),
_ => None,
}
}

View file

@ -0,0 +1,48 @@
---
source: parser/src/parser/tests.rs
expression: "(parsed_pretty, pretty_printed_source)"
---
(
Ok([
(
FunctionDef(FunctionDef {
decl: Normal(NormalDecl {
decl_spec: DeclSpec {
ty: Integer(IntTy { sign: Signed, kind: Int }),
attrs: "(empty)",
},
init_declarators: [
(
InitDecl {
declarator: Declarator {
decl: WithParams {
ident: ("main", 5..9),
params: [],
},
pointer: false,
},
init: None,
},
5..9,
),
],
}),
body: [
(
Expr(
Binary(ExprBinary {
lhs: (Atom(Int(1)), 18..19),
rhs: (Atom(Int(1)), 22..23),
op: Arith(Add),
}),
),
18..23,
),
(Expr(Atom(String("hello world!"))), 29..42),
],
}),
1..46,
),
]),
"int main() {\n (1 + 1)\n \"hello world!\"\n}\n",
)

View file

@ -0,0 +1,46 @@
---
source: parser/src/parser/tests.rs
expression: "(parsed_pretty, pretty_printed_source)"
---
(
Ok([
(
FunctionDef(FunctionDef {
decl: Normal(NormalDecl {
decl_spec: DeclSpec {
ty: Integer(IntTy { sign: Signed, kind: Int }),
attrs: "(empty)",
},
init_declarators: [
(
InitDecl {
declarator: Declarator {
decl: WithParams {
ident: ("main", 5..9),
params: [],
},
pointer: false,
},
init: None,
},
5..9,
),
],
}),
body: [
(
Expr(
Postfix(ExprPostfix {
lhs: (Atom(Ident(("puts", 18..22))), 18..22),
op: Call([(Atom(String("Hello, world!")), 23..37)]),
}),
),
22..39,
),
],
}),
1..42,
),
]),
"int main() {\n puts(\"Hello, world!\")\n}\n",
)

View file

@ -132,4 +132,27 @@ int main() {
}
"#
);
}
}
#[test]
fn expr_stmt() {
parse_test!(
r#"
int main() {
1 + 1;
"hello world!";
}
"#
);
}
#[test]
fn hello_world() {
parse_test!(
r#"
int main() {
puts("Hello, world!");
}
"#
);
}

View file

@ -5,9 +5,9 @@ type Result = std::io::Result<()>;
use crate::{
ast::{
ArithOpKind, Atom, BinaryOp, ComparisonKind, Decl, DeclAttr, DeclSpec, Declarator,
DirectDeclarator, Expr, ExprBinary, ExprUnary, ExternalDecl, FunctionDef,
FunctionParamDecl, InitDecl, IntTyKind, IntTySignedness, NormalDecl, Stmt, TypeSpecifier,
UnaryOp,
DirectDeclarator, Expr, ExprBinary, ExprPostfix, ExprUnary, ExternalDecl, FunctionDef,
FunctionParamDecl, InitDecl, IntTyKind, IntTySignedness, NormalDecl, PostfixOp, Stmt,
TypeSpecifier, UnaryOp,
},
Span, Spanned,
};
@ -335,6 +335,36 @@ impl<W: Write> PrettyPrinter<W> {
Ok(())
}
Expr::Binary(binary) => self.binary(binary),
Expr::Postfix(ExprPostfix { lhs, op }) => {
self.expr(&lhs.0)?;
match op {
PostfixOp::Call(args) => {
self.string("(")?;
let mut first = true;
for (expr, _) in args {
if !first {
self.string(", ")?;
}
first = false;
self.expr(expr)?;
}
self.string(")")?;
Ok(())
}
PostfixOp::Member((ident, _)) => {
self.string(".")?;
self.string(ident)?;
Ok(())
}
PostfixOp::ArrowMember((ident, _)) => {
self.string("->")?;
self.string(ident)?;
Ok(())
}
PostfixOp::Increment => self.string("++"),
PostfixOp::Decrement => self.string("--"),
}
}
}
}