mirror of
https://github.com/Noratrieb/dilaria.git
synced 2026-01-14 17:35:03 +01:00
parse fn
This commit is contained in:
parent
aa0a9cb0e5
commit
1824c9839f
4 changed files with 127 additions and 41 deletions
38
src/ast.rs
38
src/ast.rs
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
|
|
|
|||
7
test.sl
7
test.sl
|
|
@ -1 +1,6 @@
|
|||
(1 + 5 and 5) / 2;
|
||||
fn test() {
|
||||
let uwu = 2;
|
||||
if uwu {
|
||||
print;
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue