This commit is contained in:
nora 2021-10-31 18:30:57 +01:00
parent aa0a9cb0e5
commit 1824c9839f
4 changed files with 127 additions and 41 deletions

View file

@ -1,12 +1,17 @@
//! //!
//! The AST module contains all structs and enums for the abstract syntax tree generated by the parser //! The AST module contains all structs and enums for the abstract syntax tree generated by the parser
#![allow(dead_code)]
use crate::errors::Span; use crate::errors::Span;
/// imagine interning or something here /// imagine interning or something here
pub type Symbol = String; pub type Symbol = String;
#[derive(Debug, Clone, PartialEq)]
pub struct Ident {
pub name: Symbol,
pub span: Span,
}
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub struct Program(pub Vec<Stmt>); pub struct Program(pub Vec<Stmt>);
@ -30,42 +35,25 @@ pub enum Stmt {
Expr(Expr), Expr(Expr),
} }
impl Stmt {
pub fn span(&self) -> Span {
match self {
Stmt::Declaration(decl) => decl.span,
Stmt::Assignment(assign) => assign.span,
Stmt::FnDecl(decl) => decl.span,
Stmt::If(if_stmt) => if_stmt.span,
Stmt::Loop(_, span) => *span,
Stmt::While(while_stmt) => while_stmt.span,
Stmt::Break(span) => *span,
Stmt::Return(_, span) => *span,
Stmt::Block(block) => block.span,
Stmt::Expr(expr) => expr.span(),
}
}
}
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub struct Declaration { pub struct Declaration {
pub span: Span, pub span: Span,
name: Symbol, pub name: Ident,
init: Expr, pub init: Expr,
} }
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub struct Assignment { pub struct Assignment {
pub span: Span, pub span: Span,
pub lhs: Symbol, pub lhs: Expr,
pub rhs: Expr, pub rhs: Expr,
} }
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub struct FnDecl { pub struct FnDecl {
pub span: Span, pub span: Span,
pub name: Symbol, pub name: Ident,
pub params: Vec<Symbol>, pub params: Vec<Ident>,
pub body: Block, pub body: Block,
} }
@ -101,7 +89,7 @@ pub struct WhileStmt {
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub enum Expr { pub enum Expr {
Ident(Symbol, Span), Ident(Ident),
Literal(Literal), Literal(Literal),
UnaryOp(Box<UnaryOp>), UnaryOp(Box<UnaryOp>),
BinaryOp(Box<BinaryOp>), BinaryOp(Box<BinaryOp>),
@ -113,7 +101,7 @@ impl Expr {
Expr::Literal(lit) => lit.span(), Expr::Literal(lit) => lit.span(),
Expr::UnaryOp(unary) => unary.span, Expr::UnaryOp(unary) => unary.span,
Expr::BinaryOp(binary) => binary.span, Expr::BinaryOp(binary) => binary.span,
Expr::Ident(_, span) => *span, Expr::Ident(Ident { span, .. }) => *span,
} }
} }
} }

View file

@ -1,5 +1,3 @@
#![allow(dead_code)]
#[cfg(test)] #[cfg(test)]
mod test; mod test;
@ -86,15 +84,47 @@ impl<'code> Parser<'code> {
} }
fn declaration(&mut self) -> ParseResult<'code, Stmt> { fn declaration(&mut self) -> ParseResult<'code, Stmt> {
todo!() let keyword_span = self.expect(TokenType::Let)?.span;
let name = self.ident()?;
self.expect(TokenType::Equal)?;
let init = self.expression()?;
self.expect(TokenType::Semi)?;
Ok(Stmt::Declaration(Declaration {
span: keyword_span.extend(init.span()),
name,
init,
}))
} }
fn assignment(&mut self) -> ParseResult<'code, Stmt> { fn assignment(&mut self) -> ParseResult<'code, Stmt> {
todo!() todo!("oh god no")
} }
fn fn_decl(&mut self) -> ParseResult<'code, Stmt> { fn fn_decl(&mut self) -> ParseResult<'code, Stmt> {
todo!() let keyword_span = self.expect(TokenType::Fn)?.span;
let name = self.ident()?;
let args = self.fn_args()?;
let body = self.block()?;
Ok(Stmt::FnDecl(FnDecl {
span: keyword_span.extend(body.span),
name,
params: args,
body,
}))
}
fn fn_args(&mut self) -> ParseResult<'code, Vec<Ident>> {
self.expect(TokenType::ParenO)?;
let mut params = Vec::new();
while self.peek_kind().ok_or(ParseErr::EOF("function argument"))? != &TokenType::ParenC {
let ident = self.ident()?;
params.push(ident);
// todo (ident ident) would be allowed here, but should not
self.maybe_consume(TokenType::Comma);
}
self.expect(TokenType::ParenC)?;
Ok(params)
} }
fn if_stmt(&mut self) -> ParseResult<'code, IfStmt> { fn if_stmt(&mut self) -> ParseResult<'code, IfStmt> {
@ -276,7 +306,7 @@ impl<'code> Parser<'code> {
} }
} }
fn primary(&mut self) -> ParseResult<'code, Expr> { fn primary<'parser>(&'parser mut self) -> ParseResult<'code, Expr> {
let next = self.next().ok_or(ParseErr::EOF("primary"))?; let next = self.next().ok_or(ParseErr::EOF("primary"))?;
match next.kind { match next.kind {
TokenType::String(literal) => Ok(Expr::Literal(Literal::String(literal, next.span))), TokenType::String(literal) => Ok(Expr::Literal(Literal::String(literal, next.span))),
@ -293,12 +323,34 @@ impl<'code> Parser<'code> {
} }
TokenType::Ident(name) => { TokenType::Ident(name) => {
let name_owned = name.to_owned(); let name_owned = name.to_owned();
Ok(Expr::Ident(name_owned, next.span)) Ok(Expr::Ident(Ident {
name: name_owned,
span: next.span,
}))
} }
_ => Err(ParseErr::InvalidTokenPrimary(next)), _ => Err(ParseErr::InvalidTokenPrimary(next)),
} }
} }
fn ident(&mut self) -> ParseResult<'code, Ident> {
let Token { kind, span } = self.next().ok_or(ParseErr::EOF("identifier"))?;
match kind {
TokenType::Ident(name) => {
let name_owned = name.to_owned();
Ok(Ident {
name: name_owned,
span,
})
}
_ => {
return Err(ParseErr::MismatchedKind {
expected: TokenType::Ident("<ident>"),
actual: Token { span, kind },
})
}
}
}
fn object_literal(&mut self, open_span: Span) -> ParseResult<'code, Expr> { fn object_literal(&mut self, open_span: Span) -> ParseResult<'code, Expr> {
let close_span = self.expect(TokenType::BraceC)?.span; let close_span = self.expect(TokenType::BraceC)?.span;
Ok(Expr::Literal(Literal::Object(open_span.extend(close_span)))) Ok(Expr::Literal(Literal::Object(open_span.extend(close_span))))
@ -307,14 +359,14 @@ impl<'code> Parser<'code> {
fn array_literal(&mut self, open_span: Span) -> ParseResult<'code, Expr> { fn array_literal(&mut self, open_span: Span) -> ParseResult<'code, Expr> {
let mut elements = Vec::new(); let mut elements = Vec::new();
while self while self
.peek() .peek_kind()
.ok_or(ParseErr::EOFExpecting(TokenType::BracketC))? .ok_or(ParseErr::EOFExpecting(TokenType::BracketC))?
.kind != &TokenType::BracketC
!= TokenType::BracketC
{ {
let expr = self.expression()?; let expr = self.expression()?;
elements.push(expr); elements.push(expr);
self.expect(TokenType::Comma)?; // todo [expr expr] would be allowed here, but should not
self.maybe_consume(TokenType::Comma);
} }
let closing_bracket = self.expect(TokenType::BracketC)?; let closing_bracket = self.expect(TokenType::BracketC)?;
Ok(Expr::Literal(Literal::Array( Ok(Expr::Literal(Literal::Array(
@ -340,6 +392,14 @@ impl<'code> Parser<'code> {
self.peek().map(|token| &token.kind) self.peek().map(|token| &token.kind)
} }
fn maybe_consume(&mut self, kind: TokenType<'code>) -> Option<Token> {
if self.peek_kind() == Some(&kind) {
self.next()
} else {
None
}
}
fn expect(&mut self, kind: TokenType<'code>) -> ParseResult<'code, Token> { fn expect(&mut self, kind: TokenType<'code>) -> ParseResult<'code, Token> {
if let Some(token) = self.next() { if let Some(token) = self.next() {
if token.kind == kind { if token.kind == kind {

View file

@ -4,9 +4,12 @@ use prelude::*;
mod prelude { mod prelude {
pub(super) use super::{parser, test_literal_bin_op, test_number_literal, token}; pub(super) use super::{parser, test_literal_bin_op, test_number_literal, token};
pub(super) use crate::ast::{BinaryOp, BinaryOpKind, Expr, Literal}; pub(super) use crate::ast::*;
pub(super) use crate::errors::Span; pub(super) use crate::errors::Span;
pub(super) use crate::lex::{Token, TokenType}; pub(super) use crate::lex::{
Token,
TokenType::{self, *},
};
} }
fn token(kind: TokenType) -> Token { fn token(kind: TokenType) -> Token {
@ -50,10 +53,34 @@ fn test_number_literal<F: FnOnce(Vec<Token<'_>>) -> Expr>(parser: F) {
assert_eq!(Expr::Literal(Literal::Number(10.0, Span::dummy())), unary); assert_eq!(Expr::Literal(Literal::Number(10.0, Span::dummy())), unary);
} }
mod r#loop {
use super::prelude::*;
fn parse_loop(tokens: Vec<Token>) -> Stmt {
let mut parser = parser(tokens);
parser.loop_stmt().unwrap()
}
#[test]
fn empty() {
let tokens = [Loop, BraceO, BraceC].map(token).into();
let ast = parse_loop(tokens);
assert_eq!(
Stmt::Loop(
Block {
stmts: vec![],
span: Span::dummy()
},
Span::dummy()
),
ast
);
}
}
mod expr { mod expr {
use super::prelude::*; use super::prelude::*;
use crate::ast::{UnaryOp, UnaryOpKind}; use crate::ast::{UnaryOp, UnaryOpKind};
use TokenType::*;
fn parse_expr(tokens: Vec<Token>) -> Expr { fn parse_expr(tokens: Vec<Token>) -> Expr {
let mut parser = parser(tokens); let mut parser = parser(tokens);
@ -357,7 +384,13 @@ mod primary {
fn ident() { fn ident() {
let tokens = [TokenType::Ident("tokens")].map(token).into(); let tokens = [TokenType::Ident("tokens")].map(token).into();
let literal = parse_primary(tokens); let literal = parse_primary(tokens);
assert_eq!(Expr::Ident("tokens".to_string(), Span::dummy()), literal); assert_eq!(
Expr::Ident(Ident {
name: "tokens".to_string(),
span: Span::dummy()
}),
literal
);
} }
#[test] #[test]

View file

@ -1 +1,6 @@
(1 + 5 and 5) / 2; fn test() {
let uwu = 2;
if uwu {
print;
}
}