mirror of
https://github.com/Noratrieb/dilaria.git
synced 2026-01-16 18:35:02 +01:00
add spans to AST
This commit is contained in:
parent
d848818824
commit
8f99a1d630
4 changed files with 155 additions and 61 deletions
62
src/ast.rs
62
src/ast.rs
|
|
@ -1,8 +1,9 @@
|
||||||
//!
|
//!
|
||||||
//! 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)]
|
#![allow(dead_code)]
|
||||||
|
|
||||||
|
use crate::errors::Span;
|
||||||
|
|
||||||
/// imagine interning or something here
|
/// imagine interning or something here
|
||||||
pub type Symbol = String;
|
pub type Symbol = String;
|
||||||
|
|
||||||
|
|
@ -20,25 +21,28 @@ pub enum Stmt {
|
||||||
If(IfStmt),
|
If(IfStmt),
|
||||||
Loop(Block),
|
Loop(Block),
|
||||||
While(WhileStmt),
|
While(WhileStmt),
|
||||||
Break,
|
Break(Break),
|
||||||
Return(Option<Expr>),
|
Return(Option<Expr>),
|
||||||
Expr(Expr),
|
Expr(Expr),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct Declaration {
|
pub struct Declaration {
|
||||||
|
pub span: Span,
|
||||||
name: Symbol,
|
name: Symbol,
|
||||||
init: Expr,
|
init: Expr,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct Assignment {
|
pub struct Assignment {
|
||||||
|
pub span: Span,
|
||||||
pub lhs: Symbol,
|
pub lhs: Symbol,
|
||||||
pub rhs: Expr,
|
pub rhs: Expr,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct FnDecl {
|
pub struct FnDecl {
|
||||||
|
pub span: Span,
|
||||||
pub name: Symbol,
|
pub name: Symbol,
|
||||||
pub params: Vec<Symbol>,
|
pub params: Vec<Symbol>,
|
||||||
pub body: Block,
|
pub body: Block,
|
||||||
|
|
@ -46,6 +50,7 @@ pub struct FnDecl {
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct IfStmt {
|
pub struct IfStmt {
|
||||||
|
pub span: Span,
|
||||||
pub condition: Expr,
|
pub condition: Expr,
|
||||||
pub body: Block,
|
pub body: Block,
|
||||||
pub else_part: Box<ElsePart>,
|
pub else_part: Box<ElsePart>,
|
||||||
|
|
@ -59,29 +64,59 @@ pub enum ElsePart {
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct WhileStmt {
|
pub struct WhileStmt {
|
||||||
|
pub span: Span,
|
||||||
pub cond: Expr,
|
pub cond: Expr,
|
||||||
pub body: Block,
|
pub body: Block,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
pub struct Break {
|
||||||
|
pub span: Span,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub enum Expr {
|
pub enum Expr {
|
||||||
Literal(Literal),
|
Literal(Literal),
|
||||||
UnaryOp,
|
UnaryOp(Box<UnaryOp>),
|
||||||
BinaryOp,
|
BinaryOp(Box<BinaryOp>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Expr {
|
||||||
|
pub fn span(&self) -> Span {
|
||||||
|
match self {
|
||||||
|
Expr::Literal(lit) => lit.span(),
|
||||||
|
Expr::UnaryOp(unary) => unary.span,
|
||||||
|
Expr::BinaryOp(binary) => binary.span,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub enum Literal {
|
pub enum Literal {
|
||||||
String(String),
|
String(String, Span),
|
||||||
Number(f64),
|
Number(f64, Span),
|
||||||
Array(Vec<Expr>),
|
Array(Vec<Expr>, Span),
|
||||||
Object,
|
Object(Span),
|
||||||
Boolean(bool),
|
Boolean(bool, Span),
|
||||||
Null,
|
Null(Span),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Literal {
|
||||||
|
pub fn span(&self) -> Span {
|
||||||
|
match self {
|
||||||
|
Literal::String(_, span) => *span,
|
||||||
|
Literal::Number(_, span) => *span,
|
||||||
|
Literal::Array(_, span) => *span,
|
||||||
|
Literal::Object(span) => *span,
|
||||||
|
Literal::Boolean(_, span) => *span,
|
||||||
|
Literal::Null(span) => *span,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct UnaryOp {
|
pub struct UnaryOp {
|
||||||
|
pub span: Span,
|
||||||
pub expr: Expr,
|
pub expr: Expr,
|
||||||
pub kind: UnaryOpKind,
|
pub kind: UnaryOpKind,
|
||||||
}
|
}
|
||||||
|
|
@ -94,6 +129,7 @@ pub enum UnaryOpKind {
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct BinaryOp {
|
pub struct BinaryOp {
|
||||||
|
pub span: Span,
|
||||||
pub lhs: Expr,
|
pub lhs: Expr,
|
||||||
pub rhs: Expr,
|
pub rhs: Expr,
|
||||||
pub kind: BinaryOpKind,
|
pub kind: BinaryOpKind,
|
||||||
|
|
@ -115,9 +151,3 @@ pub enum BinaryOpKind {
|
||||||
Div,
|
Div,
|
||||||
Mod,
|
Mod,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
|
||||||
pub enum Call {
|
|
||||||
Function(Expr, Vec<Expr>),
|
|
||||||
Field(Expr, Vec<Expr>),
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -3,27 +3,53 @@
|
||||||
|
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, PartialOrd, PartialEq, Ord, Eq, Hash)]
|
pub use span::Span;
|
||||||
pub struct Span {
|
|
||||||
start: usize,
|
|
||||||
len: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Span {
|
mod span {
|
||||||
pub fn new(start: usize, len: usize) -> Self {
|
|
||||||
Self { start, len }
|
#[derive(Debug, Copy, Clone, PartialOrd, PartialEq, Ord, Eq, Hash)]
|
||||||
|
pub struct Span {
|
||||||
|
pub start: usize,
|
||||||
|
pub end: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn start_end(start: usize, end: usize) -> Self {
|
impl Span {
|
||||||
Self::new(start, end - start)
|
pub fn new(start: usize, len: usize) -> Self {
|
||||||
}
|
Self {
|
||||||
|
start,
|
||||||
|
end: start + len,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn single(start: usize) -> Self {
|
pub fn start_end(start: usize, end: usize) -> Self {
|
||||||
Self { start, len: 1 }
|
Self::new(start, end)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dummy() -> Self {
|
pub fn single(start: usize) -> Self {
|
||||||
Self { start: 0, len: 0 }
|
Self {
|
||||||
|
start,
|
||||||
|
end: start + 1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn dummy() -> Self {
|
||||||
|
Self { start: 0, end: 0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Extends the span by the second one
|
||||||
|
/// The other one has to be after the current one
|
||||||
|
pub fn extend(&self, other: Span) -> Span {
|
||||||
|
debug_assert!(self.start <= other.start);
|
||||||
|
debug_assert!(self.end <= other.end);
|
||||||
|
Span {
|
||||||
|
start: self.start,
|
||||||
|
end: other.end,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn len(&self) -> usize {
|
||||||
|
self.end - self.start
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -57,7 +83,7 @@ where
|
||||||
"{}{}{}{}",
|
"{}{}{}{}",
|
||||||
" ".repeat(offset_on_line),
|
" ".repeat(offset_on_line),
|
||||||
RED,
|
RED,
|
||||||
"^".repeat(error.span().len),
|
"^".repeat(error.span().len()),
|
||||||
RESET,
|
RESET,
|
||||||
);
|
);
|
||||||
if let Some(note) = error.note() {
|
if let Some(note) = error.note() {
|
||||||
|
|
|
||||||
|
|
@ -126,7 +126,7 @@ impl<'code> Lexer<'code> {
|
||||||
if self.expect(expect_char) {
|
if self.expect(expect_char) {
|
||||||
let _ = self.code.next(); // consume first one
|
let _ = self.code.next(); // consume first one
|
||||||
Token {
|
Token {
|
||||||
span: Span::new(start, 2),
|
span: Span::new(start, start + 2),
|
||||||
kind: true_type,
|
kind: true_type,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -191,7 +191,7 @@ impl<'code> Iterator for Lexer<'code> {
|
||||||
if self.expect('=') {
|
if self.expect('=') {
|
||||||
let _ = self.code.next(); // consume =;
|
let _ = self.code.next(); // consume =;
|
||||||
break Token {
|
break Token {
|
||||||
span: Span::new(start, 2),
|
span: Span::new(start, start + 2),
|
||||||
kind: TokenType::BangEqual,
|
kind: TokenType::BangEqual,
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
90
src/parse.rs
90
src/parse.rs
|
|
@ -96,23 +96,39 @@ impl<'code> Parser<'code> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unary(&mut self) -> ParseResult<'code, Expr> {
|
fn unary(&mut self) -> ParseResult<'code, Expr> {
|
||||||
match self.next().ok_or(ParseErr::EOF)?.kind {
|
let next = self.next().ok_or(ParseErr::EOF)?;
|
||||||
TokenType::Not => todo!(),
|
match next.kind {
|
||||||
TokenType::Minus => todo!(),
|
TokenType::Not => {
|
||||||
|
let expr = self.expression()?;
|
||||||
|
Ok(Expr::UnaryOp(Box::new(UnaryOp {
|
||||||
|
span: next.span,
|
||||||
|
expr,
|
||||||
|
kind: UnaryOpKind::Not,
|
||||||
|
})))
|
||||||
|
}
|
||||||
|
TokenType::Minus => {
|
||||||
|
let expr = self.expression()?;
|
||||||
|
Ok(Expr::UnaryOp(Box::new(UnaryOp {
|
||||||
|
span: next.span,
|
||||||
|
expr,
|
||||||
|
kind: UnaryOpKind::Neg,
|
||||||
|
})))
|
||||||
|
}
|
||||||
_ => todo!(),
|
_ => todo!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn primary(&mut self) -> ParseResult<'code, Expr> {
|
fn primary(&mut self) -> ParseResult<'code, Expr> {
|
||||||
match self.next().ok_or(ParseErr::EOF)?.kind {
|
let next = self.next().ok_or(ParseErr::EOF)?;
|
||||||
TokenType::String(literal) => Ok(Expr::Literal(Literal::String(literal))),
|
match next.kind {
|
||||||
TokenType::Number(literal) => Ok(Expr::Literal(Literal::Number(literal))),
|
TokenType::String(literal) => Ok(Expr::Literal(Literal::String(literal, next.span))),
|
||||||
TokenType::False => Ok(Expr::Literal(Literal::Boolean(false))),
|
TokenType::Number(literal) => Ok(Expr::Literal(Literal::Number(literal, next.span))),
|
||||||
TokenType::True => Ok(Expr::Literal(Literal::Boolean(true))),
|
TokenType::False => Ok(Expr::Literal(Literal::Boolean(false, next.span))),
|
||||||
TokenType::Null => Ok(Expr::Literal(Literal::Null)),
|
TokenType::True => Ok(Expr::Literal(Literal::Boolean(true, next.span))),
|
||||||
|
TokenType::Null => Ok(Expr::Literal(Literal::Null(next.span))),
|
||||||
TokenType::BraceO => {
|
TokenType::BraceO => {
|
||||||
self.expect(TokenType::BraceC)?;
|
self.expect(TokenType::BraceC)?;
|
||||||
Ok(Expr::Literal(Literal::Object))
|
Ok(Expr::Literal(Literal::Object(next.span)))
|
||||||
}
|
}
|
||||||
TokenType::BracketO => {
|
TokenType::BracketO => {
|
||||||
let mut elements = Vec::new();
|
let mut elements = Vec::new();
|
||||||
|
|
@ -121,8 +137,11 @@ impl<'code> Parser<'code> {
|
||||||
elements.push(expr);
|
elements.push(expr);
|
||||||
self.expect(TokenType::Comma)?;
|
self.expect(TokenType::Comma)?;
|
||||||
}
|
}
|
||||||
self.expect(TokenType::BracketC);
|
let closing_bracket = self.expect(TokenType::BracketC)?;
|
||||||
Ok(Expr::Literal(Literal::Array(elements)))
|
Ok(Expr::Literal(Literal::Array(
|
||||||
|
elements,
|
||||||
|
next.span.extend(closing_bracket.span),
|
||||||
|
)))
|
||||||
}
|
}
|
||||||
TokenType::ParenO => todo!(),
|
TokenType::ParenO => todo!(),
|
||||||
_ => todo!(),
|
_ => todo!(),
|
||||||
|
|
@ -130,9 +149,9 @@ impl<'code> Parser<'code> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn object_literal(&mut self) -> ParseResult<'code, Expr> {
|
fn object_literal(&mut self) -> ParseResult<'code, Expr> {
|
||||||
self.expect(TokenType::BraceO)?;
|
let open_span = self.expect(TokenType::BraceO)?.span;
|
||||||
self.expect(TokenType::BraceC)?;
|
let close_span = self.expect(TokenType::BraceC)?.span;
|
||||||
Ok(Expr::Literal(Literal::Object))
|
Ok(Expr::Literal(Literal::Object(open_span.extend(close_span))))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn array_literal(&mut self) -> ParseResult<'code, Expr> {
|
fn array_literal(&mut self) -> ParseResult<'code, Expr> {
|
||||||
|
|
@ -149,10 +168,10 @@ impl<'code> Parser<'code> {
|
||||||
self.tokens.peek()
|
self.tokens.peek()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expect(&mut self, kind: TokenType<'code>) -> ParseResult<'code, ()> {
|
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 {
|
||||||
Ok(())
|
Ok(token)
|
||||||
} else {
|
} else {
|
||||||
Err(ParseErr::MismatchedKind { expected: kind })
|
Err(ParseErr::MismatchedKind { expected: kind })
|
||||||
}
|
}
|
||||||
|
|
@ -200,10 +219,17 @@ mod test {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mod primary {
|
mod unary {
|
||||||
|
use super::{parser, token};
|
||||||
use crate::ast::{Expr, Literal};
|
use crate::ast::{Expr, Literal};
|
||||||
use crate::lex::{Token, TokenType};
|
use crate::lex::{Token, TokenType};
|
||||||
use crate::parse::test::{parser, token};
|
}
|
||||||
|
|
||||||
|
mod primary {
|
||||||
|
use super::{parser, token};
|
||||||
|
use crate::ast::{Expr, Literal};
|
||||||
|
use crate::errors::Span;
|
||||||
|
use crate::lex::{Token, TokenType};
|
||||||
|
|
||||||
fn parse_primary<'a, T: Into<Vec<Token<'a>>>>(tokens: T) -> Expr {
|
fn parse_primary<'a, T: Into<Vec<Token<'a>>>>(tokens: T) -> Expr {
|
||||||
let mut parser = parser(tokens);
|
let mut parser = parser(tokens);
|
||||||
|
|
@ -214,49 +240,61 @@ mod test {
|
||||||
fn string() {
|
fn string() {
|
||||||
let tokens = [TokenType::Number(10.0)].map(token);
|
let tokens = [TokenType::Number(10.0)].map(token);
|
||||||
let literal = parse_primary(tokens);
|
let literal = parse_primary(tokens);
|
||||||
assert_eq!(Expr::Literal(Literal::Number(10.0)), literal);
|
assert_eq!(Expr::Literal(Literal::Number(10.0, Span::dummy())), literal);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn number() {
|
fn number() {
|
||||||
let tokens = [TokenType::String("uwu".to_string())].map(token);
|
let tokens = [TokenType::String("uwu".to_string())].map(token);
|
||||||
let literal = parse_primary(tokens);
|
let literal = parse_primary(tokens);
|
||||||
assert_eq!(Expr::Literal(Literal::String("uwu".to_string())), literal);
|
assert_eq!(
|
||||||
|
Expr::Literal(Literal::String("uwu".to_string(), Span::dummy())),
|
||||||
|
literal
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn empty_object() {
|
fn empty_object() {
|
||||||
let tokens = [TokenType::BraceO, TokenType::BraceC].map(token);
|
let tokens = [TokenType::BraceO, TokenType::BraceC].map(token);
|
||||||
let literal = parse_primary(tokens);
|
let literal = parse_primary(tokens);
|
||||||
assert_eq!(Expr::Literal(Literal::Object), literal);
|
assert_eq!(Expr::Literal(Literal::Object(Span::dummy())), literal);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn empty_array() {
|
fn empty_array() {
|
||||||
let tokens = [TokenType::BracketO, TokenType::BracketC].map(token);
|
let tokens = [TokenType::BracketO, TokenType::BracketC].map(token);
|
||||||
let literal = parse_primary(tokens);
|
let literal = parse_primary(tokens);
|
||||||
assert_eq!(Expr::Literal(Literal::Array(Vec::new())), literal);
|
assert_eq!(
|
||||||
|
Expr::Literal(Literal::Array(Vec::new(), Span::dummy())),
|
||||||
|
literal
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn r#false() {
|
fn r#false() {
|
||||||
let tokens = [TokenType::False].map(token);
|
let tokens = [TokenType::False].map(token);
|
||||||
let literal = parse_primary(tokens);
|
let literal = parse_primary(tokens);
|
||||||
assert_eq!(Expr::Literal(Literal::Boolean(false)), literal);
|
assert_eq!(
|
||||||
|
Expr::Literal(Literal::Boolean(false, Span::dummy())),
|
||||||
|
literal
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn r#true() {
|
fn r#true() {
|
||||||
let tokens = [TokenType::True].map(token);
|
let tokens = [TokenType::True].map(token);
|
||||||
let literal = parse_primary(tokens);
|
let literal = parse_primary(tokens);
|
||||||
assert_eq!(Expr::Literal(Literal::Boolean(true)), literal);
|
assert_eq!(
|
||||||
|
Expr::Literal(Literal::Boolean(true, Span::dummy())),
|
||||||
|
literal
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn null() {
|
fn null() {
|
||||||
let tokens = [TokenType::Null].map(token);
|
let tokens = [TokenType::Null].map(token);
|
||||||
let literal = parse_primary(tokens);
|
let literal = parse_primary(tokens);
|
||||||
assert_eq!(Expr::Literal(Literal::Null), literal);
|
assert_eq!(Expr::Literal(Literal::Null(Span::dummy())), literal);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue