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
#![allow(dead_code)]
use crate::errors::Span;
/// imagine interning or something here
pub type Symbol = String;
#[derive(Debug, Clone, PartialEq)]
pub struct Ident {
pub name: Symbol,
pub span: Span,
}
#[derive(Debug, Clone, PartialEq)]
pub struct Program(pub Vec<Stmt>);
@ -30,42 +35,25 @@ pub enum Stmt {
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)]
pub struct Declaration {
pub span: Span,
name: Symbol,
init: Expr,
pub name: Ident,
pub init: Expr,
}
#[derive(Debug, Clone, PartialEq)]
pub struct Assignment {
pub span: Span,
pub lhs: Symbol,
pub lhs: Expr,
pub rhs: Expr,
}
#[derive(Debug, Clone, PartialEq)]
pub struct FnDecl {
pub span: Span,
pub name: Symbol,
pub params: Vec<Symbol>,
pub name: Ident,
pub params: Vec<Ident>,
pub body: Block,
}
@ -101,7 +89,7 @@ pub struct WhileStmt {
#[derive(Debug, Clone, PartialEq)]
pub enum Expr {
Ident(Symbol, Span),
Ident(Ident),
Literal(Literal),
UnaryOp(Box<UnaryOp>),
BinaryOp(Box<BinaryOp>),
@ -113,7 +101,7 @@ impl Expr {
Expr::Literal(lit) => lit.span(),
Expr::UnaryOp(unary) => unary.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)]
mod test;
@ -86,15 +84,47 @@ impl<'code> Parser<'code> {
}
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> {
todo!()
todo!("oh god no")
}
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> {
@ -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"))?;
match next.kind {
TokenType::String(literal) => Ok(Expr::Literal(Literal::String(literal, next.span))),
@ -293,12 +323,34 @@ impl<'code> Parser<'code> {
}
TokenType::Ident(name) => {
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)),
}
}
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> {
let close_span = self.expect(TokenType::BraceC)?.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> {
let mut elements = Vec::new();
while self
.peek()
.peek_kind()
.ok_or(ParseErr::EOFExpecting(TokenType::BracketC))?
.kind
!= TokenType::BracketC
!= &TokenType::BracketC
{
let expr = self.expression()?;
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)?;
Ok(Expr::Literal(Literal::Array(
@ -340,6 +392,14 @@ impl<'code> Parser<'code> {
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> {
if let Some(token) = self.next() {
if token.kind == kind {

View file

@ -4,9 +4,12 @@ use prelude::*;
mod prelude {
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::lex::{Token, TokenType};
pub(super) use crate::lex::{
Token,
TokenType::{self, *},
};
}
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);
}
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 {
use super::prelude::*;
use crate::ast::{UnaryOp, UnaryOpKind};
use TokenType::*;
fn parse_expr(tokens: Vec<Token>) -> Expr {
let mut parser = parser(tokens);
@ -357,7 +384,13 @@ mod primary {
fn ident() {
let tokens = [TokenType::Ident("tokens")].map(token).into();
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]

View file

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