diff --git a/README.md b/README.md index 9d025cb..12a9dee 100644 --- a/README.md +++ b/README.md @@ -1 +1,6 @@ # uwuc + +# Building + +`uwucc` requires a nightly rust compiler because of the following features: +* `let_else` \ No newline at end of file diff --git a/parser/src/lib.rs b/parser/src/lib.rs index 62284c2..2b8e236 100644 --- a/parser/src/lib.rs +++ b/parser/src/lib.rs @@ -1,4 +1,5 @@ -#![allow(dead_code)] +#![feature(let_else)] +#![allow(dead_code)] // TODO: no #![warn(rust_2018_idioms)] use std::fmt::Debug; diff --git a/parser/src/parser.rs b/parser/src/parser.rs index 5e2b525..20c01af 100644 --- a/parser/src/parser.rs +++ b/parser/src/parser.rs @@ -19,14 +19,17 @@ pub struct ParserError { } impl ParserError { + #[track_caller] fn new(span: Span, message: String) -> Self { Self { span, message } } + #[track_caller] fn eof() -> Self { Self::new(Span::default(), "unexpected end of file".to_string()) } + #[track_caller] fn unsupported(span: Span, token: &Tok<'_>) -> Self { Self::new(span, format!("`{token}` is not supported")) } diff --git a/parser/src/parser/expr.rs b/parser/src/parser/expr.rs index 103b503..75ebef8 100644 --- a/parser/src/parser/expr.rs +++ b/parser/src/parser/expr.rs @@ -19,17 +19,19 @@ where } fn get_lhs(&mut self) -> Result> { - let (typ, span) = match self.next_t()? { - (Tok::Ident(ident), span) => (Atom::Ident(ident.to_string()), span), - (Tok::StringLiteral(literal), span) => (Atom::String(literal.to_string()), span), - (Tok::Constant(Constant::Int(int)), span) => (Atom::Int(int), span), - (Tok::Constant(Constant::Float(float)), span) => (Atom::Float(float), span), - (Tok::Constant(Constant::Char(char)), span) => (Atom::Char(char), span), - (Tok::Punct(punct), span) => { + let (typ, span) = match self.peek_t()? { + &(Tok::Ident(ident), span) => (Atom::Ident(ident.to_string()), span), + &(Tok::StringLiteral(literal), span) => (Atom::String(literal.to_string()), span), + &(Tok::Constant(Constant::Int(int)), span) => (Atom::Int(int), span), + &(Tok::Constant(Constant::Float(float)), span) => (Atom::Float(float), span), + &(Tok::Constant(Constant::Char(char)), span) => (Atom::Char(char), span), + &(Tok::Punct(punct), span) => { let r_bp = prefix_binding_power(&Tok::Punct(punct)); - let op = unary_op_from_token(&Tok::Punct(punct), span)?; + let Some(op) = unary_op_from_token(&Tok::Punct(punct)) else { panic!() }; let rhs = self.expr_bp(r_bp)?; + self.next_t()?; + return Ok(( Expr::Unary(ExprUnary { rhs: Box::new(rhs), @@ -40,12 +42,13 @@ where } (tok, span) => { return Err(ParserError::new( - span, + *span, format!("expected expression, found {tok}"), )); } }; + self.next_t()?; Ok((Expr::Atom(typ), span)) } @@ -54,11 +57,13 @@ where #[allow(clippy::while_let_loop)] // idc loop { - let (tok, span) = match self.next_t() { - Ok(tok) => tok, + let (tok, _) = match self.peek_t() { + Ok(&tok) => tok, Err(_) => break, }; - let op = binary_op_from_token(&tok, span)?; + let Some(op) = binary_op_from_token(&tok) else { break; }; + + self.next_t()?; let (l_bp, r_bp) = infix_binding_power(&tok); if l_bp < min_bp { @@ -83,28 +88,22 @@ where } } -fn unary_op_from_token(tok: &Tok<'_>, span: Span) -> Result { +fn unary_op_from_token(tok: &Tok<'_>) -> Option { match tok { - Tok::Punct(P::Ampersand) => Ok(UnaryOp::AddrOf), - Tok::Punct(P::Asterisk) => Ok(UnaryOp::Deref), - Tok::Punct(P::Plus) => Ok(UnaryOp::Plus), - Tok::Punct(P::Minus) => Ok(UnaryOp::Minus), - Tok::Punct(P::Tilde) => Ok(UnaryOp::Tilde), - Tok::Punct(P::Bang) => Ok(UnaryOp::Bang), - _ => Err(ParserError::new( - span, - format!("invalid unary operation: {tok}"), - )), + Tok::Punct(P::Ampersand) => Some(UnaryOp::AddrOf), + Tok::Punct(P::Asterisk) => Some(UnaryOp::Deref), + Tok::Punct(P::Plus) => Some(UnaryOp::Plus), + Tok::Punct(P::Minus) => Some(UnaryOp::Minus), + Tok::Punct(P::Tilde) => Some(UnaryOp::Tilde), + Tok::Punct(P::Bang) => Some(UnaryOp::Bang), + _ => None, } } -fn binary_op_from_token(tok: &Tok<'_>, span: Span) -> Result { +fn binary_op_from_token(tok: &Tok<'_>) -> Option { match tok { - Tok::Punct(P::Plus) => Ok(BinaryOp::Add), - Tok::Punct(P::Minus) => Ok(BinaryOp::Sub), - _ => Err(ParserError::new( - span, - format!("invalid binary operation: {tok}"), - )), + Tok::Punct(P::Plus) => Some(BinaryOp::Add), + Tok::Punct(P::Minus) => Some(BinaryOp::Sub), + _ => None, } } diff --git a/parser/src/parser/snapshots/parser__parser__tests__small_expression.snap b/parser/src/parser/snapshots/parser__parser__tests__small_expression.snap new file mode 100644 index 0000000..326056d --- /dev/null +++ b/parser/src/parser/snapshots/parser__parser__tests__small_expression.snap @@ -0,0 +1,63 @@ +--- +source: parser/src/parser/tests.rs +expression: parsed +--- +Ok( + [ + ( + Decl( + Normal( + NormalDecl { + decl_spec: DeclSpec { + ty: Int, + attrs: (empty), + }, + init_declarators: [ + ( + InitDecl { + declarator: Declarator { + decl: Ident( + ( + "x", + 5..6, + ), + ), + pointer: false, + }, + init: Some( + ( + Binary( + ExprBinary { + lhs: ( + Atom( + Int( + 1, + ), + ), + 9..10, + ), + rhs: ( + Atom( + Int( + 1, + ), + ), + 13..14, + ), + op: Add, + }, + ), + 9..14, + ), + ), + }, + 5..6, + ), + ], + }, + ), + ), + 1..6, + ), + ], +) diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 0000000..9eb27c7 --- /dev/null +++ b/rust-toolchain.toml @@ -0,0 +1,2 @@ +[toolchain] +channel = "nightly-2022-06-25"