diff --git a/src/parser/ast/expr.rs b/src/parser/ast/expr.rs index 7ce498f..2fd743e 100644 --- a/src/parser/ast/expr.rs +++ b/src/parser/ast/expr.rs @@ -1,55 +1,76 @@ use std::collections::HashMap; -use crate::tokeniser::tokentype::*; +use crate::{common::Loc, tokeniser::tokentype::*}; -use super::{typ::Type, Ast}; +use super::{typ::{Type, TypeBox}, Ast}; + +#[derive(Debug, Clone)] +pub struct ExprBox { + inner: Expr, + loc: Loc +} + +impl ExprBox { + pub fn new(loc: &Loc, expr: Expr) -> Self { + Self { loc: loc.clone(), inner: expr } + } + pub fn inner(&self) -> &Expr { + &self.inner + } + pub fn inner_mut(&mut self) -> &mut Expr { + &mut self.inner + } + pub fn loc(&self) -> &Loc { + &self.loc + } +} #[derive(Debug, Clone)] pub enum Expr { // Comment(Comment), - Group(Box), + Group(Box), UnOp { typ: Punctuation, - right: Box, + right: Box, }, BinOp { typ: Punctuation, - left: Box, - right: Box, + left: Box, + right: Box, }, Literal(super::literal::Literal), ArrayIndex { - name: Box, - index: Box, + name: Box, + index: Box, }, Path(Path), Call { - path: Box, - params: CallParams, // Expr ~ (, Expr)* + path: Box, + params: CallParams, // ExprBox ~ (, Expr)* }, //MethodCall { - // var_name: Box, + // var_name: Box, // method_name: Ident, // params: CallParams, //}, /// the left side only exists on the /.|->/ chain FieldAccess { - left: Box>, - right: Box, + left: Box>, + right: Box, }, PtrFieldAccess { - left: Box>, - right: Box, + left: Box>, + right: Box, }, ForLoop { init: Box, - test: Box, - on_loop: Box, + test: Box, + on_loop: Box, body: Block, }, WhileLoop { - test: Box, + test: Box, body: Block, }, InfLoop { @@ -58,20 +79,20 @@ pub enum Expr { If(IfExpr), Struct { path: Path, - fields: HashMap, + fields: HashMap, }, - Return(Box>), + Return(Box>), Break, Continue, Cast { - left: Box, - right: Box + left: Box, + right: Box }, } -impl Expr { +impl ExprBox { pub fn unwrap_path(&self) -> Path { - let Expr::Path(p) = self else {panic!("Unwrapping")}; + let Expr::Path(p) = self.inner.clone() else {panic!("Unwrapping")}; p.clone() } } @@ -79,7 +100,7 @@ impl Expr { #[derive(Debug, Clone)] -pub struct CallParams(pub Vec); +pub struct CallParams(pub Vec); #[derive(Debug, Clone)] pub struct Block(pub Vec); @@ -90,7 +111,7 @@ pub struct Path(pub Vec); #[derive(Debug, Clone)] pub struct IfExpr { - pub test: Box, + pub test: Box, pub body: Block, pub else_if: Option } diff --git a/src/parser/ast/literal.rs b/src/parser/ast/literal.rs index bfc8dff..eed9a73 100644 --- a/src/parser/ast/literal.rs +++ b/src/parser/ast/literal.rs @@ -2,7 +2,7 @@ use std::collections::HashMap; use crate::tokeniser::tokentype::*; -use super::{expr::Expr, typ::Type, Ast}; +use super::{expr::ExprBox, typ::TypeBox, Ast}; #[derive(Debug, Clone)] pub enum Literal { @@ -10,10 +10,10 @@ pub enum Literal { Ident(Ident), String(TString), Char(Char), - Array(Vec), + Array(Vec), ArrayRepeat { - typ: Box, - count: Box, + typ: Box, + count: Box, }, Struct { name: Ident, diff --git a/src/parser/ast/mod.rs b/src/parser/ast/mod.rs index 312cd4d..d801106 100644 --- a/src/parser/ast/mod.rs +++ b/src/parser/ast/mod.rs @@ -1,6 +1,6 @@ use std::collections::HashMap; -use typ::Type; +use statement::{Enum, Function, Struct, TypeAlias}; pub use crate::tokeniser::tokentype::*; @@ -12,17 +12,17 @@ pub mod typ; #[derive(Debug, Clone)] pub struct Program { pub ast: expr::Block, - pub structs: HashMap>, - pub enums: HashMap, - pub types: HashMap, - pub functions: HashMap, Type)>, - pub member_functions: HashMap, Type)>>, + pub structs: HashMap, + pub enums: HashMap, + pub types: HashMap, + pub functions: HashMap, + pub member_functions: HashMap>, } #[derive(Debug, Clone)] pub enum Ast { - Expr(expr::Expr), - Statement(statement::Statement), + Expr(expr::ExprBox), + Statement(statement::StatementBox), } diff --git a/src/parser/ast/statement.rs b/src/parser/ast/statement.rs index 04c584e..127b32e 100644 --- a/src/parser/ast/statement.rs +++ b/src/parser/ast/statement.rs @@ -1,44 +1,77 @@ -use std::collections::HashMap; -use super::{expr::{Block, Expr}, typ::Type, Ident, TString}; +use crate::common::Loc; +use super::{expr::{Block, ExprBox}, typ::{Type, TypeBox}, Ident, TString}; + +#[derive(Debug, Clone)] +pub struct StatementBox { + inner: Statement, + loc: Loc +} + +impl StatementBox { + pub fn new(loc: &Loc, stat: Statement) -> Self { + Self { loc: loc.clone(), inner: stat } + } + pub fn inner(&self) -> &Statement { + &self.inner + } + pub fn inner_mut(&mut self) -> &mut Statement { + &mut self.inner + } + pub fn loc(&self) -> &Loc { + &self.loc + } +} #[derive(Debug, Clone)] pub enum Statement { - Fn { - struct_name: Option, - name: Ident, - params: Vec<(Ident, Type)>, - ret_type: Option, - qual_const: bool, - qual_extern: Option, // abi - body: Option, // If None then its a type declaration - }, - TypeAlias { - name: Ident, - typ: Type, - }, - Struct { - name: Ident, - fields: Vec<(Ident, Type)>, - }, - Enum { - name: Ident, - fields: Vec, - }, + Fn(Function), + TypeAlias(TypeAlias), + Struct(Struct), + Enum(Enum), ConstVar { name: Ident, - typ: Type, - val: Expr + typ: TypeBox, + val: ExprBox }, StaticVar { name: Ident, - typ: Type, - val: Expr, + typ: TypeBox, + val: ExprBox, }, Let { name: Ident, - typ: Option, - val: Option, + typ: Option, + val: Option, }, } + +#[derive(Debug, Clone)] +pub struct TypeAlias { + pub name: Ident, + pub typ: TypeBox, +} + +#[derive(Debug, Clone)] +pub struct Struct { + pub name: Ident, + pub fields: Vec<(Ident, TypeBox)>, +} + +#[derive(Debug, Clone)] +pub struct Enum { + pub name: Ident, + pub fields: Vec, +} + +#[derive(Debug, Clone)] +pub struct Function { + pub struct_name: Option, + pub name: Ident, + pub params: Vec<(Ident, TypeBox)>, + pub ret_type: Option, + pub qual_const: bool, + pub qual_extern: Option, // abi + pub body: Option, // If None then its a type declaration +} diff --git a/src/parser/ast/typ.rs b/src/parser/ast/typ.rs index a78206b..c5c5b96 100644 --- a/src/parser/ast/typ.rs +++ b/src/parser/ast/typ.rs @@ -1,4 +1,27 @@ -use super::{expr::Expr, Ident, Number}; +use crate::common::Loc; + +use super::{expr::ExprBox, Ident}; + +#[derive(Debug, Clone)] +pub struct TypeBox { + inner: Type, + loc: Loc +} + +impl TypeBox { + pub fn new(loc: &Loc, stat: Type) -> Self { + Self { loc: loc.clone(), inner: stat } + } + pub fn inner(&self) -> &Type { + &self.inner + } + pub fn inner_mut(&mut self) -> &mut Type { + &mut self.inner + } + pub fn loc(&self) -> &Loc { + &self.loc + } +} #[derive(Debug, Clone)] pub enum Type { @@ -11,7 +34,7 @@ pub enum Type { }, ArrayRepeat { inner: Box, - count: Expr, + count: ExprBox, }, Owned(Ident), } diff --git a/src/parser/expr.rs b/src/parser/expr.rs index 6492b97..9eb8442 100644 --- a/src/parser/expr.rs +++ b/src/parser/expr.rs @@ -4,7 +4,7 @@ use anyhow::{bail, Result}; use crate::{debug, error, lerror, parser::{typ::parse_type, Punctuation}, tokeniser::Token}; -use super::{ast::{expr::{Block, CallParams, Expr, IfBranchExpr, IfExpr, Path}, literal::Literal, TokenType}, parse_item, utils, Delimiter, Keyword}; +use super::{ast::{expr::{Block, CallParams, Expr, ExprBox, IfBranchExpr, IfExpr, Path}, literal::Literal, TokenType}, parse_item, utils, Delimiter, Keyword}; const BINOP_LIST: &[TokenType] = &[ TokenType::Punct(Punctuation::Plus), @@ -37,7 +37,7 @@ const BINOP_LIST: &[TokenType] = &[ TokenType::Punct(Punctuation::Ge), ]; -pub fn parse_expr(tokens: &mut Vec, precedence: usize, consume_semi: bool) -> Result> { +pub fn parse_expr(tokens: &mut Vec, precedence: usize, consume_semi: bool) -> Result> { let res = if let Some(_) = utils::check(tokens, TokenType::Delim(Delimiter::ParenL)) { Some(parse_group(tokens)?) } else @@ -73,37 +73,33 @@ pub fn parse_expr(tokens: &mut Vec, precedence: usize, consume_semi: bool return Ok(Some(parse_inf_loop(tokens)?)); } else if let Some(_) = utils::check(tokens, TokenType::Keyword(Keyword::Return)) { return Ok(Some(parse_return(tokens)?)); - } else if let Some(_) = utils::check_consume(tokens, TokenType::Keyword(Keyword::Break)) { - return Ok(Some(Expr::Break)); - } else if let Some(_) = utils::check_consume(tokens, TokenType::Keyword(Keyword::Continue)) { - return Ok(Some(Expr::Continue)); - } else if let Some(_) = utils::check(tokens, TokenType::Keyword(Keyword::If)) { - return Ok(Some(Expr::If(parse_if(tokens)?))); + } else if let Some(kw) = utils::check_consume(tokens, TokenType::Keyword(Keyword::Break)) { + return Ok(Some(ExprBox::new(kw.loc(), Expr::Break))); + } else if let Some(kw) = utils::check_consume(tokens, TokenType::Keyword(Keyword::Continue)) { + return Ok(Some(ExprBox::new(kw.loc(), Expr::Continue))); + } else if let Some(kw) = utils::check(tokens, TokenType::Keyword(Keyword::If)) { + return Ok(Some(ExprBox::new(&kw.loc().clone(), Expr::If(parse_if(tokens)?)))); } else { None }; - if let Some(res) = res { - // check for binop - let res = match res { - _ if utils::check(tokens, TokenType::Punct(Punctuation::Fieldaccess)).is_some() => { - parse_field_access(tokens, res)? - } - _ if utils::check(tokens, TokenType::Punct(Punctuation::Arrow)).is_some() => { - parse_ptr_field_access(tokens, res)? - } - _ if utils::check(tokens, TokenType::Delim(Delimiter::ParenL)).is_some() => { - parse_fn_call(tokens, res)? - } - _ if utils::check(tokens, TokenType::Keyword(Keyword::As)).is_some() => { - parse_cast(tokens, res)? - } - _ if utils::check(tokens, TokenType::Delim(Delimiter::SquareL)).is_some() => { - parse_array_index(tokens, res)? - } - _ => res - }; + if let Some(mut res) = res { + if utils::check(tokens, TokenType::Punct(Punctuation::Fieldaccess)).is_some() { + res = parse_field_access(tokens, res)?; + } + if utils::check(tokens, TokenType::Punct(Punctuation::Arrow)).is_some() { + res =parse_ptr_field_access(tokens, res)?; + } + if utils::check(tokens, TokenType::Delim(Delimiter::ParenL)).is_some() { + res = parse_fn_call(tokens, res)?; + } + if utils::check(tokens, TokenType::Keyword(Keyword::As)).is_some() { + res = parse_cast(tokens, res)?; + } + if utils::check(tokens, TokenType::Delim(Delimiter::SquareL)).is_some() { + res = parse_array_index(tokens, res)?; + } if let Some(_) = utils::check_from_many(tokens, BINOP_LIST) { return Ok(Some(parse_binop(tokens, res, precedence)?)); @@ -117,19 +113,19 @@ pub fn parse_expr(tokens: &mut Vec, precedence: usize, consume_semi: bool Ok(res) } -fn parse_return(tokens: &mut Vec) -> Result { - _ = utils::check_consume(tokens, TokenType::Keyword(Keyword::Return)); +fn parse_return(tokens: &mut Vec) -> Result { + let kw = utils::check_consume_or_err(tokens, TokenType::Keyword(Keyword::Return), "")?; let item = parse_expr(tokens, 0, true)?; - Ok(Expr::Return(Box::new(item))) + Ok(ExprBox::new(kw.loc(), Expr::Return(Box::new(item)))) } -fn parse_cast(tokens: &mut Vec, left: Expr) -> Result { - _ = utils::check_consume_or_err(tokens, TokenType::Keyword(Keyword::As), "")?; +fn parse_cast(tokens: &mut Vec, left: ExprBox) -> Result { + let kw = utils::check_consume_or_err(tokens, TokenType::Keyword(Keyword::As), "")?; let typ = parse_type(tokens)?; - Ok(Expr::Cast { + Ok(ExprBox::new(kw.loc(), Expr::Cast { left: Box::new(left), right: Box::new(typ) - }) + })) } fn parse_if(tokens: &mut Vec) -> Result { let loc = utils::check_consume_or_err(tokens, TokenType::Keyword(Keyword::If), "")?; @@ -172,50 +168,50 @@ fn parse_if(tokens: &mut Vec) -> Result { }) } } -fn parse_while_loop(tokens: &mut Vec) -> Result { - let loc = utils::check_consume_or_err(tokens, TokenType::Keyword(Keyword::While), "")?; +fn parse_while_loop(tokens: &mut Vec) -> Result { + let kw = utils::check_consume_or_err(tokens, TokenType::Keyword(Keyword::While), "")?; let Some(test) = parse_expr(tokens, 0, false)? else { - lerror!(loc.loc(), "Expected test comparrison for while loop, got nothing"); + lerror!(kw.loc(), "Expected test comparrison for while loop, got nothing"); bail!("") }; let block = parse_block(tokens)?; - Ok(Expr::WhileLoop { + Ok(ExprBox::new(kw.loc(), Expr::WhileLoop { test: Box::new(test), body: block - }) + })) } -fn parse_for_loop(tokens: &mut Vec) -> Result { - let loc = utils::check_consume_or_err(tokens, TokenType::Keyword(Keyword::For), "")?; +fn parse_for_loop(tokens: &mut Vec) -> Result { + let kw = utils::check_consume_or_err(tokens, TokenType::Keyword(Keyword::For), "")?; let Some(pre) = parse_item(tokens)? else { - lerror!(loc.loc(), "Expected init stat for a for loop, got nothing"); + lerror!(kw.loc(), "Expected init stat for a for loop, got nothing"); bail!("") }; // Semicolon parsed out by parse_item above let Some(test) = parse_expr(tokens, 0, false)? else { - lerror!(loc.loc(), "Expected test comparrison for a for loop, got nothing"); + lerror!(kw.loc(), "Expected test comparrison for a for loop, got nothing"); bail!("") }; _ = utils::check_consume_or_err(tokens, TokenType::Punct(Punctuation::Semi), ""); let Some(post) = parse_expr(tokens, 0, false)? else { - lerror!(loc.loc(), "Expected post expression (usually an index increment) for a for loop, got nothing"); + lerror!(kw.loc(), "Expected post expression (usually an index increment) for a for loop, got nothing"); bail!("") }; let block = parse_block(tokens)?; - Ok(Expr::ForLoop { + Ok(ExprBox::new(kw.loc(), Expr::ForLoop { init: Box::new(pre), test: Box::new(test), on_loop: Box::new(post), body: block - }) + })) } -fn parse_inf_loop(tokens: &mut Vec) -> Result { - _ = utils::check_consume_or_err(tokens, TokenType::Keyword(Keyword::Loop), ""); +fn parse_inf_loop(tokens: &mut Vec) -> Result { + let kw = utils::check_consume_or_err(tokens, TokenType::Keyword(Keyword::Loop), "")?; let block = parse_block(tokens)?; - Ok(Expr::InfLoop { body: block }) + Ok(ExprBox::new(kw.loc(), Expr::InfLoop { body: block })) } -fn parse_fn_call(tokens: &mut Vec, left: Expr) -> Result { - _ = utils::check_consume_or_err(tokens, TokenType::Delim(Delimiter::ParenL), ""); +fn parse_fn_call(tokens: &mut Vec, left: ExprBox) -> Result { + let start = utils::check_consume_or_err(tokens, TokenType::Delim(Delimiter::ParenL), "")?; let mut params = Vec::new(); while !tokens.is_empty() { @@ -232,23 +228,23 @@ fn parse_fn_call(tokens: &mut Vec, left: Expr) -> Result { } } _ = utils::check_consume_or_err(tokens, TokenType::Delim(Delimiter::ParenR), ""); - Ok(Expr::Call { path: Box::new(left), params: CallParams(params) }) + Ok(ExprBox::new(start.loc(), Expr::Call { path: Box::new(left), params: CallParams(params) })) } -fn parse_array_index(tokens: &mut Vec, left: Expr) -> Result { - let loc = utils::check_consume_or_err(tokens, TokenType::Delim(Delimiter::SquareL), "")?; +fn parse_array_index(tokens: &mut Vec, left: ExprBox) -> Result { + let start = utils::check_consume_or_err(tokens, TokenType::Delim(Delimiter::SquareL), "")?; let Some(idx) = parse_expr(tokens, 0, false)? else { - lerror!(loc.loc(), "Expected index for in array index but found nothing."); + lerror!(start.loc(), "Expected index for in array index but found nothing."); bail!("") }; _ = utils::check_consume_or_err(tokens, TokenType::Delim(Delimiter::SquareR), ""); - Ok(Expr::ArrayIndex { + Ok(ExprBox::new(start.loc(), Expr::ArrayIndex { name: Box::new(left), index: Box::new(idx) - }) + })) } -fn parse_field_access(tokens: &mut Vec, left: Expr) -> Result { - _ = utils::check_consume_or_err(tokens, TokenType::Punct(Punctuation::Fieldaccess), "unreachable")?; +fn parse_field_access(tokens: &mut Vec, left: ExprBox) -> Result { + let start = utils::check_consume_or_err(tokens, TokenType::Punct(Punctuation::Fieldaccess), "unreachable")?; let right = if let Some(_) = utils::check_2_last(tokens, TokenType::Punct(Punctuation::Arrow)) { let right = parse_path(tokens)?; @@ -259,14 +255,14 @@ fn parse_field_access(tokens: &mut Vec, left: Expr) -> Result { } else { parse_path(tokens)? }; - Ok(Expr::FieldAccess { + Ok(ExprBox::new(start.loc(), Expr::FieldAccess { left: Box::new(Some(left)), right: Box::new(right) - }) + })) } -fn parse_ptr_field_access(tokens: &mut Vec, left: Expr) -> Result { - _ = utils::check_consume_or_err(tokens, TokenType::Punct(Punctuation::Arrow), "unreachable")?; +fn parse_ptr_field_access(tokens: &mut Vec, left: ExprBox) -> Result { + let start = utils::check_consume_or_err(tokens, TokenType::Punct(Punctuation::Arrow), "unreachable")?; let right = if let Some(_) = utils::check_2_last(tokens, TokenType::Punct(Punctuation::Arrow)) { let right = parse_path(tokens)?; parse_ptr_field_access(tokens, right)? @@ -276,28 +272,28 @@ fn parse_ptr_field_access(tokens: &mut Vec, left: Expr) -> Result { } else { parse_path(tokens)? }; - Ok(Expr::PtrFieldAccess { + Ok(ExprBox::new(start.loc(), Expr::PtrFieldAccess { left: Box::new(Some(left)), right: Box::new(right) - }) + })) } -fn parse_literal(tokens: &mut Vec) -> Result { +fn parse_literal(tokens: &mut Vec) -> Result { if let Some(tkn) = utils::check_consume(tokens, TokenType::string("", false)) { let TokenType::String(str) = tkn.tt() else {unreachable!()}; - return Ok(Expr::Literal(Literal::String(str.clone()))); + return Ok(ExprBox::new(tkn.loc(), Expr::Literal(Literal::String(str.clone())))); } else if let Some(tkn) = utils::check_consume(tokens, TokenType::number(0, 0, false)) { let TokenType::Number(val) = tkn.tt() else {unreachable!()}; - return Ok(Expr::Literal(Literal::Number(val.clone()))); + return Ok(ExprBox::new(tkn.loc(), Expr::Literal(Literal::Number(val.clone())))); } else if let Some(tkn) = utils::check_consume(tokens, TokenType::char('\0')) { let TokenType::Char(val) = tkn.tt() else {unreachable!()}; - return Ok(Expr::Literal(Literal::Char(val.clone()))); + return Ok(ExprBox::new(tkn.loc(), Expr::Literal(Literal::Char(val.clone())))); } else if let Some(start) = utils::check_consume(tokens, TokenType::Delim(Delimiter::SquareL)) { if let Some(_) = utils::check_consume(tokens, TokenType::Delim(Delimiter::SquareR)) { - return Ok(Expr::Literal(Literal::Array(Vec::new()))); + return Ok(ExprBox::new(start.loc(), Expr::Literal(Literal::Array(Vec::new())))); } if *tokens[tokens.len()-2].tt() == TokenType::Punct(Punctuation::Comma) { let first = parse_expr(tokens, 0, false)?; @@ -314,15 +310,15 @@ fn parse_literal(tokens: &mut Vec) -> Result { } } utils::check_consume_or_err(tokens, TokenType::Delim(Delimiter::SquareR), "")?; - return Ok(Expr::Literal(Literal::Array(values))); + return Ok(ExprBox::new(start.loc(), Expr::Literal(Literal::Array(values)))); } else if *tokens[tokens.len()-2].tt() == TokenType::Punct(Punctuation::Semi) { let typ = parse_type(tokens)?; let count = parse_expr(tokens, 0, false)?.unwrap(); utils::check_consume_or_err(tokens, TokenType::Delim(Delimiter::SquareR), "")?; - return Ok(Expr::Literal(Literal::ArrayRepeat { + return Ok(ExprBox::new(start.loc(), Expr::Literal(Literal::ArrayRepeat { typ: Box::new(typ), count: Box::new(count) - })); + }))); } else { if let Some(curr) = tokens.last() { lerror!(start.loc(), "Expected a , or ; as a separator in a literal array (normal, or repeating, respectively), but found {}", curr.tt()); @@ -335,8 +331,8 @@ fn parse_literal(tokens: &mut Vec) -> Result { unreachable!() } -fn parse_struct_literal(tokens: &mut Vec, name: Path) -> Result { - _ = utils::check_consume_or_err(tokens, TokenType::Delim(Delimiter::CurlyL), "")?; +fn parse_struct_literal(tokens: &mut Vec, name: Path) -> Result { + let start = utils::check_consume_or_err(tokens, TokenType::Delim(Delimiter::CurlyL), "")?; let mut fields = HashMap::new(); while !tokens.is_empty() { if let Some(_) = utils::check_consume(tokens, TokenType::Delim(Delimiter::CurlyR)) { @@ -352,21 +348,21 @@ fn parse_struct_literal(tokens: &mut Vec, name: Path) -> Result { break; } } - Ok(Expr::Struct { path: name, fields }) + Ok(ExprBox::new(start.loc(), Expr::Struct { path: name, fields })) } -fn parse_group(tokens: &mut Vec) -> Result { - let loc = utils::check_consume_or_err(tokens, TokenType::Delim(Delimiter::ParenL), "")?; +fn parse_group(tokens: &mut Vec) -> Result { + let start = utils::check_consume_or_err(tokens, TokenType::Delim(Delimiter::ParenL), "")?; let Some(expr) = parse_expr(tokens, 0, false)? else { - lerror!(loc.loc(), "Expected expr found nothing"); + lerror!(start.loc(), "Expected expr found nothing"); bail!("") }; utils::check_consume_or_err(tokens, TokenType::Delim(Delimiter::ParenR), "")?; - Ok(Expr::Group(Box::new(expr))) + Ok(ExprBox::new(start.loc(), Expr::Group(Box::new(expr)))) } -fn parse_path(tokens: &mut Vec) -> Result { +fn parse_path(tokens: &mut Vec) -> Result { let mut buf = Vec::new(); let part = utils::check_consume(tokens, TokenType::ident("")).unwrap(); @@ -379,10 +375,10 @@ fn parse_path(tokens: &mut Vec) -> Result { buf.push(part.tt().unwrap_ident()); } - Ok(Expr::Path(Path(buf))) + Ok(ExprBox::new(part.loc(), Expr::Path(Path(buf)))) } -fn parse_unop(tokens: &mut Vec) -> Result { +fn parse_unop(tokens: &mut Vec) -> Result { let typ = utils::check_consume_or_err_from_many(tokens, &[ TokenType::Punct(Punctuation::Not), TokenType::Punct(Punctuation::Plus), @@ -397,18 +393,20 @@ fn parse_unop(tokens: &mut Vec) -> Result { lerror!(&loc, "Expected expression after unary token, found nothing"); bail!("") }; - Ok(Expr::UnOp { + Ok(ExprBox::new(&loc, Expr::UnOp { typ, right: Box::new(right) - }) + })) } -fn parse_binop(tokens: &mut Vec, mut lhs: Expr, precedence: usize) -> Result { +fn parse_binop(tokens: &mut Vec, mut lhs: ExprBox, precedence: usize) -> Result { // TODO: https://en.wikipedia.org/wiki/Operator-precedence_parser#Pseudocode - loop { + loop { + let op_loc; let op = match tokens.last() { Some(op) if BINOP_LIST.contains(&op.tt()) => { + op_loc = op.loc().clone(); let TokenType::Punct(op) = op.tt() else {unreachable!()}; op.clone() } @@ -433,11 +431,11 @@ fn parse_binop(tokens: &mut Vec, mut lhs: Expr, precedence: usize) -> Res _ = tokens.pop(); let Some(rhs) = parse_expr(tokens, rp, false)? else {break;}; - lhs = Expr::BinOp { + lhs = ExprBox::new(&op_loc, Expr::BinOp { typ: op, left: Box::new(lhs), right: Box::new(rhs) - }; + }); } diff --git a/src/parser/stat.rs b/src/parser/stat.rs index 7cde2b4..acf7259 100644 --- a/src/parser/stat.rs +++ b/src/parser/stat.rs @@ -5,15 +5,15 @@ use crate::parser::ast::TokenType; use crate::parser::expr::parse_expr; use crate::parser::{Delimiter, Ident, Keyword, Punctuation}; use crate::tokeniser::Token; -use super::ast::typ::Type; +use super::ast::typ::{Type, TypeBox}; use super::expr::parse_block; use super::typ::parse_type; use super::utils; -use super::ast::statement::Statement; +use super::ast::statement::{Enum, Function, Statement, StatementBox, Struct, TypeAlias}; type Result = anyhow::Result; -pub fn parse_statement(tokens: &mut Vec) -> Result> { +pub fn parse_statement(tokens: &mut Vec) -> Result> { if let Some(_) = utils::check(tokens, TokenType::Keyword(Keyword::Fn)) { Ok(Some(parse_fn(tokens)?)) } else @@ -39,8 +39,8 @@ pub fn parse_statement(tokens: &mut Vec) -> Result> { } } -fn parse_enum(tokens: &mut Vec) -> Result { - _ = utils::check_consume(tokens, TokenType::Keyword(Keyword::Enum)); +fn parse_enum(tokens: &mut Vec) -> Result { + let kw = utils::check_consume_or_err(tokens, TokenType::Keyword(Keyword::Enum), "")?; let name = utils::check_consume_or_err(tokens, TokenType::ident(""), "")?.tt().unwrap_ident(); _ = utils::check_consume(tokens, TokenType::Delim(Delimiter::CurlyL)); let mut fields = Vec::new(); @@ -60,11 +60,11 @@ fn parse_enum(tokens: &mut Vec) -> Result { fields.push(field_name); } - Ok(Statement::Enum { name, fields }) + Ok(StatementBox::new(kw.loc(), Statement::Enum(Enum { name, fields }))) } -fn parse_struct(tokens: &mut Vec) -> Result { - _ = utils::check_consume(tokens, TokenType::Keyword(Keyword::Struct)); +fn parse_struct(tokens: &mut Vec) -> Result { + let kw = utils::check_consume_or_err(tokens, TokenType::Keyword(Keyword::Struct), "")?; let name = utils::check_consume_or_err(tokens, TokenType::ident(""), "")?.tt().unwrap_ident(); _ = utils::check_consume(tokens, TokenType::Delim(Delimiter::CurlyL)); let mut fields = Vec::new(); @@ -86,11 +86,11 @@ fn parse_struct(tokens: &mut Vec) -> Result { fields.push((field_name, typ)); } - Ok(Statement::Struct { name, fields }) + Ok(StatementBox::new(kw.loc(), Statement::Struct(Struct { name, fields }))) } -fn parse_static(tokens: &mut Vec) -> Result { - _ = utils::check_consume(tokens, TokenType::Keyword(Keyword::Static)); +fn parse_static(tokens: &mut Vec) -> Result { + let kw = utils::check_consume_or_err(tokens, TokenType::Keyword(Keyword::Static), "")?; let name = utils::check_consume_or_err(tokens, TokenType::ident(""), "")?.tt().unwrap_ident(); _ = utils::check_consume_or_err(tokens, TokenType::Punct(Punctuation::Colon), "")?; @@ -101,11 +101,11 @@ fn parse_static(tokens: &mut Vec) -> Result { bail!("") }; _ = utils::check_consume_or_err(tokens, TokenType::Punct(Punctuation::Semi), "")?; - Ok(Statement::StaticVar { name, typ, val }) + Ok(StatementBox::new(kw.loc(), Statement::StaticVar { name, typ, val })) } -fn parse_let(tokens: &mut Vec) -> Result { - _ = utils::check_consume(tokens, TokenType::Keyword(Keyword::Let)); +fn parse_let(tokens: &mut Vec) -> Result { + let kw = utils::check_consume_or_err(tokens, TokenType::Keyword(Keyword::Let), "")?; let name = utils::check_consume_or_err(tokens, TokenType::ident(""), "")?.tt().unwrap_ident(); let mut typ = None; let mut val = None; @@ -120,10 +120,10 @@ fn parse_let(tokens: &mut Vec) -> Result { val = Some(_val); } _ = utils::check_consume_or_err(tokens, TokenType::Punct(Punctuation::Semi), "")?; - Ok(Statement::Let { name, typ, val }) + Ok(StatementBox::new(kw.loc(), Statement::Let { name, typ, val })) } -fn parse_constant(tokens: &mut Vec) -> Result { - _ = utils::check_consume(tokens, TokenType::Keyword(Keyword::Const)); +fn parse_constant(tokens: &mut Vec) -> Result { + let kw = utils::check_consume_or_err(tokens, TokenType::Keyword(Keyword::Const), "")?; if let Some(_) = utils::check(tokens, TokenType::Keyword(Keyword::Fn)) { unimplemented!() @@ -137,22 +137,22 @@ fn parse_constant(tokens: &mut Vec) -> Result { bail!("") }; _ = utils::check_consume_or_err(tokens, TokenType::Punct(Punctuation::Semi), "")?; - Ok(Statement::ConstVar { name, typ, val }) + Ok(StatementBox::new(kw.loc(), Statement::ConstVar { name, typ, val })) } -fn parse_type_alias(tokens: &mut Vec) -> Result { - _ = utils::check_consume(tokens, TokenType::Keyword(Keyword::Type)); +fn parse_type_alias(tokens: &mut Vec) -> Result { + let kw = utils::check_consume_or_err(tokens, TokenType::Keyword(Keyword::Type), "")?; let name = utils::check_consume_or_err(tokens, TokenType::ident(""), "")?.tt().unwrap_ident(); _ = utils::check_consume_or_err(tokens, TokenType::Punct(Punctuation::Eq), "")?; let typ = parse_type(tokens)?; _ = utils::check_consume_or_err(tokens, TokenType::Punct(Punctuation::Semi), "")?; - Ok(Statement::TypeAlias { name, typ }) + Ok(StatementBox::new(kw.loc(), Statement::TypeAlias(TypeAlias { name, typ }))) } -fn parse_fn(tokens: &mut Vec) -> Result { +fn parse_fn(tokens: &mut Vec) -> Result { // Just remove the kw since we checked it before - _ = utils::check_consume(tokens, TokenType::Keyword(Keyword::Fn)); + let kw = utils::check_consume_or_err(tokens, TokenType::Keyword(Keyword::Fn), "")?; let mut struct_name = None; let mut name = utils::check_consume_or_err(tokens, TokenType::ident(""), "")?.tt().unwrap_ident(); @@ -176,7 +176,8 @@ fn parse_fn(tokens: &mut Vec) -> Result { _ = utils::check_consume_or_err(tokens, TokenType::Punct(Punctuation::Semi), "")?; body = None; } - Ok(Statement::Fn { + + Ok(StatementBox::new(kw.loc(), Statement::Fn(Function{ struct_name, name, params, @@ -184,12 +185,12 @@ fn parse_fn(tokens: &mut Vec) -> Result { qual_const: false, qual_extern: None, body, - }) + }))) } -fn parse_fn_params(tokens: &mut Vec) -> Result> { +fn parse_fn_params(tokens: &mut Vec) -> Result> { let mut args = Vec::new(); utils::check_consume_or_err(tokens, TokenType::Delim(Delimiter::ParenL), "")?; while !tokens.is_empty() { diff --git a/src/parser/typ.rs b/src/parser/typ.rs index 7617181..6e8da23 100644 --- a/src/parser/typ.rs +++ b/src/parser/typ.rs @@ -2,11 +2,15 @@ use anyhow::Result; use crate::{parser::Delimiter, tokeniser::Token}; -use super::{ast::{typ::Type, TokenType}, expr::parse_expr, utils, Keyword, Punctuation}; +use super::{ast::{typ::{Type, TypeBox}, TokenType}, expr::parse_expr, utils, Keyword, Punctuation}; -pub fn parse_type(tokens: &mut Vec) -> Result { +pub fn parse_type(tokens: &mut Vec) -> Result { let mut ref_cnt = Vec::new(); + let mut loc = None; while let Some(tok) = utils::check_consume(tokens, TokenType::Punct(Punctuation::Ampersand)) { + if let None = loc { + loc = Some(tok.loc().clone()); + } if let Some(tok) = utils::check_consume(tokens, TokenType::Keyword(Keyword::Mut)) { ref_cnt.push(tok.clone()); } else { @@ -15,23 +19,29 @@ pub fn parse_type(tokens: &mut Vec) -> Result { } let mut typ; - if let Some(_) = utils::check_consume(tokens, TokenType::Delim(super::Delimiter::SquareL)) { + if let Some(start) = utils::check_consume(tokens, TokenType::Delim(super::Delimiter::SquareL)) { + if let None = loc { + loc = Some(start.loc().clone()); + } let itm_typ = parse_type(tokens)?; if let Some(_) = utils::check_consume(tokens, TokenType::Punct(Punctuation::Semi)) { let count = parse_expr(tokens, 0, false)?.unwrap(); typ = Type::ArrayRepeat { - inner: Box::new(itm_typ), + inner: Box::new(itm_typ.inner().clone()), count } } else { typ = Type::Array { - inner: Box::new(itm_typ), + inner: Box::new(itm_typ.inner().clone()), } } _ = utils::check_consume_or_err(tokens, TokenType::Delim(Delimiter::SquareR), "")?; } else { let ident = utils::check_consume_or_err(tokens, TokenType::ident(""), "a")?; typ = Type::Owned(ident.tt().unwrap_ident()); + if let None = loc { + loc = Some(ident.loc().clone()); + } } while let Some(reft) = ref_cnt.pop() { match reft.tt() { @@ -50,5 +60,5 @@ pub fn parse_type(tokens: &mut Vec) -> Result { _ => unreachable!() } } - Ok(typ) + Ok(TypeBox::new(&loc.unwrap(), typ)) } diff --git a/tests/parser/enumerations.exp b/tests/parser/enumerations.exp index 1b216d3..b48ee12 100644 --- a/tests/parser/enumerations.exp +++ b/tests/parser/enumerations.exp @@ -2,29 +2,47 @@ Program { ast: Block( [ Statement( - Enum { - name: Ident( - "Foo", + StatementBox { + inner: Enum( + Enum { + name: Ident( + "Foo", + ), + fields: [], + }, ), - fields: [], + loc: Loc { + file: "parser/enumerations.mcl", + line: 1, + col: 5, + }, }, ), Statement( - Enum { - name: Ident( - "Bar", + StatementBox { + inner: Enum( + Enum { + name: Ident( + "Bar", + ), + fields: [ + Ident( + "A", + ), + Ident( + "B", + ), + Ident( + "C", + ), + ], + }, ), - fields: [ - Ident( - "A", - ), - Ident( - "B", - ), - Ident( - "C", - ), - ], + loc: Loc { + file: "parser/enumerations.mcl", + line: 3, + col: 5, + }, }, ), ], diff --git a/tests/parser/expressions.exp b/tests/parser/expressions.exp index 0fb834a..e6a06a5 100644 --- a/tests/parser/expressions.exp +++ b/tests/parser/expressions.exp @@ -1,53 +1,900 @@ Program { ast: Block( [ - Expr( - BinOp { - typ: Eq, - left: UnOp { - typ: Star, - right: Path( - Path( - [ - Ident( - "a", - ), - ], - ), + Statement( + StatementBox { + inner: Let { + name: Ident( + "a", + ), + typ: None, + val: Some( + ExprBox { + inner: BinOp { + typ: EqEq, + left: ExprBox { + inner: BinOp { + typ: Star, + left: ExprBox { + inner: Literal( + Number( + Number { + val: 1, + base: 10, + signed: false, + }, + ), + ), + loc: Loc { + file: "parser/expressions.mcl", + line: 1, + col: 10, + }, + }, + right: ExprBox { + inner: Literal( + Number( + Number { + val: 3, + base: 10, + signed: false, + }, + ), + ), + loc: Loc { + file: "parser/expressions.mcl", + line: 1, + col: 14, + }, + }, + }, + loc: Loc { + file: "parser/expressions.mcl", + line: 1, + col: 12, + }, + }, + right: ExprBox { + inner: Literal( + Number( + Number { + val: 4, + base: 10, + signed: false, + }, + ), + ), + loc: Loc { + file: "parser/expressions.mcl", + line: 1, + col: 18, + }, + }, + }, + loc: Loc { + file: "parser/expressions.mcl", + line: 1, + col: 16, + }, + }, ), }, - right: BinOp { - typ: EqEq, - left: BinOp { - typ: Star, - left: Literal( - Number( - Number { - val: 1, - base: 10, - signed: false, - }, - ), - ), - right: Literal( - Number( - Number { - val: 3, - base: 10, - signed: false, - }, - ), - ), - }, - right: Literal( - Number( - Number { - val: 4, - base: 10, - signed: false, - }, - ), + loc: Loc { + file: "parser/expressions.mcl", + line: 1, + col: 4, + }, + }, + ), + Statement( + StatementBox { + inner: Let { + name: Ident( + "b", ), + typ: None, + val: Some( + ExprBox { + inner: BinOp { + typ: EqEq, + left: ExprBox { + inner: BinOp { + typ: Div, + left: ExprBox { + inner: Literal( + Number( + Number { + val: 3, + base: 10, + signed: false, + }, + ), + ), + loc: Loc { + file: "parser/expressions.mcl", + line: 2, + col: 10, + }, + }, + right: ExprBox { + inner: Literal( + Number( + Number { + val: 4, + base: 10, + signed: false, + }, + ), + ), + loc: Loc { + file: "parser/expressions.mcl", + line: 2, + col: 12, + }, + }, + }, + loc: Loc { + file: "parser/expressions.mcl", + line: 2, + col: 11, + }, + }, + right: ExprBox { + inner: UnOp { + typ: Star, + right: ExprBox { + inner: Path( + Path( + [ + Ident( + "a", + ), + ], + ), + ), + loc: Loc { + file: "parser/expressions.mcl", + line: 2, + col: 17, + }, + }, + }, + loc: Loc { + file: "parser/expressions.mcl", + line: 2, + col: 16, + }, + }, + }, + loc: Loc { + file: "parser/expressions.mcl", + line: 2, + col: 14, + }, + }, + ), + }, + loc: Loc { + file: "parser/expressions.mcl", + line: 2, + col: 4, + }, + }, + ), + Statement( + StatementBox { + inner: Let { + name: Ident( + "c", + ), + typ: None, + val: Some( + ExprBox { + inner: BinOp { + typ: Div, + left: ExprBox { + inner: Group( + ExprBox { + inner: PtrFieldAccess { + left: Some( + ExprBox { + inner: Path( + Path( + [ + Ident( + "a", + ), + ], + ), + ), + loc: Loc { + file: "parser/expressions.mcl", + line: 3, + col: 11, + }, + }, + ), + right: ExprBox { + inner: FieldAccess { + left: Some( + ExprBox { + inner: Path( + Path( + [ + Ident( + "b", + ), + ], + ), + ), + loc: Loc { + file: "parser/expressions.mcl", + line: 3, + col: 13, + }, + }, + ), + right: ExprBox { + inner: PtrFieldAccess { + left: Some( + ExprBox { + inner: Path( + Path( + [ + Ident( + "c", + ), + ], + ), + ), + loc: Loc { + file: "parser/expressions.mcl", + line: 3, + col: 15, + }, + }, + ), + right: ExprBox { + inner: Path( + Path( + [ + Ident( + "d", + ), + ], + ), + ), + loc: Loc { + file: "parser/expressions.mcl", + line: 3, + col: 17, + }, + }, + }, + loc: Loc { + file: "parser/expressions.mcl", + line: 3, + col: 16, + }, + }, + }, + loc: Loc { + file: "parser/expressions.mcl", + line: 3, + col: 14, + }, + }, + }, + loc: Loc { + file: "parser/expressions.mcl", + line: 3, + col: 12, + }, + }, + ), + loc: Loc { + file: "parser/expressions.mcl", + line: 3, + col: 10, + }, + }, + right: ExprBox { + inner: Literal( + Number( + Number { + val: 2, + base: 10, + signed: false, + }, + ), + ), + loc: Loc { + file: "parser/expressions.mcl", + line: 3, + col: 22, + }, + }, + }, + loc: Loc { + file: "parser/expressions.mcl", + line: 3, + col: 20, + }, + }, + ), + }, + loc: Loc { + file: "parser/expressions.mcl", + line: 3, + col: 4, + }, + }, + ), + Statement( + StatementBox { + inner: Let { + name: Ident( + "d", + ), + typ: None, + val: Some( + ExprBox { + inner: BinOp { + typ: Div, + left: ExprBox { + inner: Literal( + Number( + Number { + val: 2, + base: 10, + signed: false, + }, + ), + ), + loc: Loc { + file: "parser/expressions.mcl", + line: 4, + col: 10, + }, + }, + right: ExprBox { + inner: PtrFieldAccess { + left: Some( + ExprBox { + inner: Path( + Path( + [ + Ident( + "a", + ), + ], + ), + ), + loc: Loc { + file: "parser/expressions.mcl", + line: 4, + col: 14, + }, + }, + ), + right: ExprBox { + inner: FieldAccess { + left: Some( + ExprBox { + inner: Path( + Path( + [ + Ident( + "b", + ), + ], + ), + ), + loc: Loc { + file: "parser/expressions.mcl", + line: 4, + col: 16, + }, + }, + ), + right: ExprBox { + inner: PtrFieldAccess { + left: Some( + ExprBox { + inner: Path( + Path( + [ + Ident( + "c", + ), + ], + ), + ), + loc: Loc { + file: "parser/expressions.mcl", + line: 4, + col: 18, + }, + }, + ), + right: ExprBox { + inner: Path( + Path( + [ + Ident( + "d", + ), + ], + ), + ), + loc: Loc { + file: "parser/expressions.mcl", + line: 4, + col: 20, + }, + }, + }, + loc: Loc { + file: "parser/expressions.mcl", + line: 4, + col: 19, + }, + }, + }, + loc: Loc { + file: "parser/expressions.mcl", + line: 4, + col: 17, + }, + }, + }, + loc: Loc { + file: "parser/expressions.mcl", + line: 4, + col: 15, + }, + }, + }, + loc: Loc { + file: "parser/expressions.mcl", + line: 4, + col: 12, + }, + }, + ), + }, + loc: Loc { + file: "parser/expressions.mcl", + line: 4, + col: 4, + }, + }, + ), + Statement( + StatementBox { + inner: Let { + name: Ident( + "e", + ), + typ: None, + val: Some( + ExprBox { + inner: BinOp { + typ: Div, + left: ExprBox { + inner: PtrFieldAccess { + left: Some( + ExprBox { + inner: Path( + Path( + [ + Ident( + "a", + ), + ], + ), + ), + loc: Loc { + file: "parser/expressions.mcl", + line: 5, + col: 10, + }, + }, + ), + right: ExprBox { + inner: FieldAccess { + left: Some( + ExprBox { + inner: Path( + Path( + [ + Ident( + "b", + ), + ], + ), + ), + loc: Loc { + file: "parser/expressions.mcl", + line: 5, + col: 12, + }, + }, + ), + right: ExprBox { + inner: PtrFieldAccess { + left: Some( + ExprBox { + inner: Path( + Path( + [ + Ident( + "c", + ), + ], + ), + ), + loc: Loc { + file: "parser/expressions.mcl", + line: 5, + col: 14, + }, + }, + ), + right: ExprBox { + inner: Path( + Path( + [ + Ident( + "d", + ), + ], + ), + ), + loc: Loc { + file: "parser/expressions.mcl", + line: 5, + col: 16, + }, + }, + }, + loc: Loc { + file: "parser/expressions.mcl", + line: 5, + col: 15, + }, + }, + }, + loc: Loc { + file: "parser/expressions.mcl", + line: 5, + col: 13, + }, + }, + }, + loc: Loc { + file: "parser/expressions.mcl", + line: 5, + col: 11, + }, + }, + right: ExprBox { + inner: Literal( + Number( + Number { + val: 2, + base: 10, + signed: false, + }, + ), + ), + loc: Loc { + file: "parser/expressions.mcl", + line: 5, + col: 20, + }, + }, + }, + loc: Loc { + file: "parser/expressions.mcl", + line: 5, + col: 18, + }, + }, + ), + }, + loc: Loc { + file: "parser/expressions.mcl", + line: 5, + col: 4, + }, + }, + ), + Statement( + StatementBox { + inner: Let { + name: Ident( + "f", + ), + typ: None, + val: Some( + ExprBox { + inner: BinOp { + typ: Div, + left: ExprBox { + inner: FieldAccess { + left: Some( + ExprBox { + inner: Path( + Path( + [ + Ident( + "a", + ), + ], + ), + ), + loc: Loc { + file: "parser/expressions.mcl", + line: 6, + col: 10, + }, + }, + ), + right: ExprBox { + inner: FieldAccess { + left: Some( + ExprBox { + inner: Path( + Path( + [ + Ident( + "b", + ), + ], + ), + ), + loc: Loc { + file: "parser/expressions.mcl", + line: 6, + col: 12, + }, + }, + ), + right: ExprBox { + inner: FieldAccess { + left: Some( + ExprBox { + inner: Path( + Path( + [ + Ident( + "c", + ), + ], + ), + ), + loc: Loc { + file: "parser/expressions.mcl", + line: 6, + col: 14, + }, + }, + ), + right: ExprBox { + inner: Path( + Path( + [ + Ident( + "d", + ), + ], + ), + ), + loc: Loc { + file: "parser/expressions.mcl", + line: 6, + col: 16, + }, + }, + }, + loc: Loc { + file: "parser/expressions.mcl", + line: 6, + col: 15, + }, + }, + }, + loc: Loc { + file: "parser/expressions.mcl", + line: 6, + col: 13, + }, + }, + }, + loc: Loc { + file: "parser/expressions.mcl", + line: 6, + col: 11, + }, + }, + right: ExprBox { + inner: Literal( + Number( + Number { + val: 2, + base: 10, + signed: false, + }, + ), + ), + loc: Loc { + file: "parser/expressions.mcl", + line: 6, + col: 20, + }, + }, + }, + loc: Loc { + file: "parser/expressions.mcl", + line: 6, + col: 18, + }, + }, + ), + }, + loc: Loc { + file: "parser/expressions.mcl", + line: 6, + col: 4, + }, + }, + ), + Statement( + StatementBox { + inner: Let { + name: Ident( + "g", + ), + typ: None, + val: Some( + ExprBox { + inner: BinOp { + typ: Star, + left: ExprBox { + inner: ArrayIndex { + name: ExprBox { + inner: FieldAccess { + left: Some( + ExprBox { + inner: Path( + Path( + [ + Ident( + "a", + ), + ], + ), + ), + loc: Loc { + file: "parser/expressions.mcl", + line: 7, + col: 10, + }, + }, + ), + right: ExprBox { + inner: Path( + Path( + [ + Ident( + "b", + ), + ], + ), + ), + loc: Loc { + file: "parser/expressions.mcl", + line: 7, + col: 12, + }, + }, + }, + loc: Loc { + file: "parser/expressions.mcl", + line: 7, + col: 11, + }, + }, + index: ExprBox { + inner: UnOp { + typ: Star, + right: ExprBox { + inner: FieldAccess { + left: Some( + ExprBox { + inner: Path( + Path( + [ + Ident( + "a", + ), + ], + ), + ), + loc: Loc { + file: "parser/expressions.mcl", + line: 7, + col: 15, + }, + }, + ), + right: ExprBox { + inner: Path( + Path( + [ + Ident( + "c", + ), + ], + ), + ), + loc: Loc { + file: "parser/expressions.mcl", + line: 7, + col: 17, + }, + }, + }, + loc: Loc { + file: "parser/expressions.mcl", + line: 7, + col: 16, + }, + }, + }, + loc: Loc { + file: "parser/expressions.mcl", + line: 7, + col: 14, + }, + }, + }, + loc: Loc { + file: "parser/expressions.mcl", + line: 7, + col: 13, + }, + }, + right: ExprBox { + inner: Literal( + Number( + Number { + val: 5, + base: 10, + signed: false, + }, + ), + ), + loc: Loc { + file: "parser/expressions.mcl", + line: 7, + col: 22, + }, + }, + }, + loc: Loc { + file: "parser/expressions.mcl", + line: 7, + col: 20, + }, + }, + ), + }, + loc: Loc { + file: "parser/expressions.mcl", + line: 7, + col: 4, }, }, ), diff --git a/tests/parser/expressions.mcl b/tests/parser/expressions.mcl index 42357fd..bf66b5d 100644 --- a/tests/parser/expressions.mcl +++ b/tests/parser/expressions.mcl @@ -1,8 +1,8 @@ -*a = 1 * 3 == 4; -b.c = 3/4 == *a; -c->d = (a->b.c->d) / 2; -*d->e.f = 2 / a->b.c->d; -e = a->b.c->d / 2; -f = a.b.c.d / 2; -g = a.b[*a.c] * 5; +let a = 1 * 3 == 4; +let b = 3/4 == *a; +let c = (a->b.c->d) / 2; +let d = 2 / a->b.c->d; +let e = a->b.c->d / 2; +let f = a.b.c.d / 2; +let g = a.b[*a.c] * 5; diff --git a/tests/parser/functions.exp b/tests/parser/functions.exp index adf58c4..bc3aaed 100644 --- a/tests/parser/functions.exp +++ b/tests/parser/functions.exp @@ -2,187 +2,298 @@ Program { ast: Block( [ Statement( - Fn { - struct_name: None, - name: Ident( - "main", - ), - params: [ - ( - Ident( - "argc", + StatementBox { + inner: Fn( + Function { + struct_name: None, + name: Ident( + "main", ), - Owned( - Ident( - "i32", - ), - ), - ), - ( - Ident( - "argv", - ), - Ref { - inner: Array { - inner: Owned( - Ident( - "Str", - ), + params: [ + ( + Ident( + "argc", ), - }, - mutable: false, - }, - ), - ], - ret_type: Some( - Owned( - Ident( - "i32", - ), - ), - ), - qual_const: false, - qual_extern: None, - body: Some( - Block( - [ - Expr( - Return( - Some( - Literal( - Number( - Number { - val: 0, - base: 10, - signed: false, - }, - ), + TypeBox { + inner: Owned( + Ident( + "i32", ), ), + loc: Loc { + file: "parser/functions.mcl", + line: 1, + col: 18, + }, + }, + ), + ( + Ident( + "argv", ), + TypeBox { + inner: Ref { + inner: Array { + inner: Owned( + Ident( + "Str", + ), + ), + }, + mutable: false, + }, + loc: Loc { + file: "parser/functions.mcl", + line: 1, + col: 27, + }, + }, ), ], - ), + ret_type: Some( + TypeBox { + inner: Owned( + Ident( + "i32", + ), + ), + loc: Loc { + file: "parser/functions.mcl", + line: 1, + col: 39, + }, + }, + ), + qual_const: false, + qual_extern: None, + body: Some( + Block( + [ + Expr( + ExprBox { + inner: Return( + Some( + ExprBox { + inner: Literal( + Number( + Number { + val: 0, + base: 10, + signed: false, + }, + ), + ), + loc: Loc { + file: "parser/functions.mcl", + line: 2, + col: 13, + }, + }, + ), + ), + loc: Loc { + file: "parser/functions.mcl", + line: 2, + col: 11, + }, + }, + ), + ], + ), + ), + }, ), + loc: Loc { + file: "parser/functions.mcl", + line: 1, + col: 3, + }, }, ), Statement( - Fn { - struct_name: Some( - Ident( - "Baz", - ), - ), - name: Ident( - "main", - ), - params: [ - ( - Ident( - "self", - ), - Ref { - inner: Owned( - Ident( - "Baz", - ), - ), - mutable: true, - }, - ), - ( - Ident( - "a", - ), - Ref { - inner: Owned( - Ident( - "Foo", - ), - ), - mutable: false, - }, - ), - ( - Ident( - "b", - ), - Ref { - inner: Owned( - Ident( - "Bar", - ), - ), - mutable: true, - }, - ), - ], - ret_type: Some( - Ref { - inner: Owned( + StatementBox { + inner: Fn( + Function { + struct_name: Some( Ident( - "Nya", + "Baz", ), ), - mutable: false, + name: Ident( + "main", + ), + params: [ + ( + Ident( + "self", + ), + TypeBox { + inner: Ref { + inner: Owned( + Ident( + "Baz", + ), + ), + mutable: true, + }, + loc: Loc { + file: "parser/functions.mcl", + line: 4, + col: 20, + }, + }, + ), + ( + Ident( + "a", + ), + TypeBox { + inner: Ref { + inner: Owned( + Ident( + "Foo", + ), + ), + mutable: false, + }, + loc: Loc { + file: "parser/functions.mcl", + line: 4, + col: 33, + }, + }, + ), + ( + Ident( + "b", + ), + TypeBox { + inner: Ref { + inner: Owned( + Ident( + "Bar", + ), + ), + mutable: true, + }, + loc: Loc { + file: "parser/functions.mcl", + line: 4, + col: 42, + }, + }, + ), + ], + ret_type: Some( + TypeBox { + inner: Ref { + inner: Owned( + Ident( + "Nya", + ), + ), + mutable: false, + }, + loc: Loc { + file: "parser/functions.mcl", + line: 4, + col: 54, + }, + }, + ), + qual_const: false, + qual_extern: None, + body: None, }, ), - qual_const: false, - qual_extern: None, - body: None, + loc: Loc { + file: "parser/functions.mcl", + line: 4, + col: 3, + }, }, ), Statement( - Fn { - struct_name: Some( - Ident( - "Baz", - ), - ), - name: Ident( - "main", - ), - params: [ - ( - Ident( - "a", - ), - Ref { - inner: Owned( - Ident( - "Foo", - ), - ), - mutable: false, - }, - ), - ( - Ident( - "b", - ), - Ref { - inner: Owned( - Ident( - "Bar", - ), - ), - mutable: true, - }, - ), - ], - ret_type: Some( - Ref { - inner: Owned( + StatementBox { + inner: Fn( + Function { + struct_name: Some( Ident( - "Nya", + "Baz", ), ), - mutable: false, + name: Ident( + "main", + ), + params: [ + ( + Ident( + "a", + ), + TypeBox { + inner: Ref { + inner: Owned( + Ident( + "Foo", + ), + ), + mutable: false, + }, + loc: Loc { + file: "parser/functions.mcl", + line: 5, + col: 17, + }, + }, + ), + ( + Ident( + "b", + ), + TypeBox { + inner: Ref { + inner: Owned( + Ident( + "Bar", + ), + ), + mutable: true, + }, + loc: Loc { + file: "parser/functions.mcl", + line: 5, + col: 26, + }, + }, + ), + ], + ret_type: Some( + TypeBox { + inner: Ref { + inner: Owned( + Ident( + "Nya", + ), + ), + mutable: false, + }, + loc: Loc { + file: "parser/functions.mcl", + line: 5, + col: 38, + }, + }, + ), + qual_const: false, + qual_extern: None, + body: None, }, ), - qual_const: false, - qual_extern: None, - body: None, + loc: Loc { + file: "parser/functions.mcl", + line: 5, + col: 3, + }, }, ), ], diff --git a/tests/parser/if-statements.exp b/tests/parser/if-statements.exp index 135e680..b61050e 100644 --- a/tests/parser/if-statements.exp +++ b/tests/parser/if-statements.exp @@ -2,35 +2,63 @@ Program { ast: Block( [ Expr( - If( - IfExpr { - test: BinOp { - typ: Gt, - left: Path( - Path( - [ - Ident( - "i", + ExprBox { + inner: If( + IfExpr { + test: ExprBox { + inner: BinOp { + typ: Gt, + left: ExprBox { + inner: Path( + Path( + [ + Ident( + "i", + ), + ], + ), ), - ], - ), - ), - right: Literal( - Number( - Number { - val: 3, - base: 10, - signed: false, + loc: Loc { + file: "parser/if-statements.mcl", + line: 2, + col: 5, + }, }, - ), + right: ExprBox { + inner: Literal( + Number( + Number { + val: 3, + base: 10, + signed: false, + }, + ), + ), + loc: Loc { + file: "parser/if-statements.mcl", + line: 2, + col: 9, + }, + }, + }, + loc: Loc { + file: "parser/if-statements.mcl", + line: 2, + col: 7, + }, + }, + body: Block( + [], ), + else_if: None, }, - body: Block( - [], - ), - else_if: None, + ), + loc: Loc { + file: "parser/if-statements.mcl", + line: 2, + col: 3, }, - ), + }, ), ], ), diff --git a/tests/parser/loops.exp b/tests/parser/loops.exp index 8825352..4158a85 100644 --- a/tests/parser/loops.exp +++ b/tests/parser/loops.exp @@ -2,106 +2,204 @@ Program { ast: Block( [ Expr( - ForLoop { - init: Statement( - Let { - name: Ident( - "i", - ), - typ: None, - val: Some( - Literal( - Number( - Number { - val: 0, - base: 10, - signed: false, + ExprBox { + inner: ForLoop { + init: Statement( + StatementBox { + inner: Let { + name: Ident( + "i", + ), + typ: None, + val: Some( + ExprBox { + inner: Literal( + Number( + Number { + val: 0, + base: 10, + signed: false, + }, + ), + ), + loc: Loc { + file: "parser/loops.mcl", + line: 1, + col: 14, + }, }, ), - ), - ), + }, + loc: Loc { + file: "parser/loops.mcl", + line: 1, + col: 8, + }, + }, + ), + test: ExprBox { + inner: BinOp { + typ: Lt, + left: ExprBox { + inner: Path( + Path( + [ + Ident( + "i", + ), + ], + ), + ), + loc: Loc { + file: "parser/loops.mcl", + line: 1, + col: 17, + }, + }, + right: ExprBox { + inner: Literal( + Number( + Number { + val: 10, + base: 10, + signed: false, + }, + ), + ), + loc: Loc { + file: "parser/loops.mcl", + line: 1, + col: 22, + }, + }, + }, + loc: Loc { + file: "parser/loops.mcl", + line: 1, + col: 19, + }, }, - ), - test: BinOp { - typ: Lt, - left: Path( - Path( - [ - Ident( - "i", + on_loop: ExprBox { + inner: BinOp { + typ: AddEq, + left: ExprBox { + inner: Path( + Path( + [ + Ident( + "i", + ), + ], + ), ), - ], - ), - ), - right: Literal( - Number( - Number { - val: 10, - base: 10, - signed: false, + loc: Loc { + file: "parser/loops.mcl", + line: 1, + col: 25, + }, }, - ), + right: ExprBox { + inner: Literal( + Number( + Number { + val: 1, + base: 10, + signed: false, + }, + ), + ), + loc: Loc { + file: "parser/loops.mcl", + line: 1, + col: 29, + }, + }, + }, + loc: Loc { + file: "parser/loops.mcl", + line: 1, + col: 27, + }, + }, + body: Block( + [], ), }, - on_loop: BinOp { - typ: AddEq, - left: Path( - Path( - [ - Ident( - "i", - ), - ], - ), - ), - right: Literal( - Number( - Number { - val: 1, - base: 10, - signed: false, - }, - ), - ), + loc: Loc { + file: "parser/loops.mcl", + line: 1, + col: 4, }, - body: Block( - [], - ), }, ), Expr( - WhileLoop { - test: BinOp { - typ: Gt, - left: Path( - Path( - [ - Ident( - "i", + ExprBox { + inner: WhileLoop { + test: ExprBox { + inner: BinOp { + typ: Gt, + left: ExprBox { + inner: Path( + Path( + [ + Ident( + "i", + ), + ], + ), ), - ], - ), - ), - right: Literal( - Number( - Number { - val: 3, - base: 10, - signed: false, + loc: Loc { + file: "parser/loops.mcl", + line: 2, + col: 8, + }, }, - ), + right: ExprBox { + inner: Literal( + Number( + Number { + val: 3, + base: 10, + signed: false, + }, + ), + ), + loc: Loc { + file: "parser/loops.mcl", + line: 2, + col: 12, + }, + }, + }, + loc: Loc { + file: "parser/loops.mcl", + line: 2, + col: 10, + }, + }, + body: Block( + [], ), }, - body: Block( - [], - ), + loc: Loc { + file: "parser/loops.mcl", + line: 2, + col: 6, + }, }, ), Expr( - InfLoop { - body: Block( - [], - ), + ExprBox { + inner: InfLoop { + body: Block( + [], + ), + }, + loc: Loc { + file: "parser/loops.mcl", + line: 3, + col: 5, + }, }, ), ], diff --git a/tests/parser/structs.exp b/tests/parser/structs.exp index 21c28f6..7778913 100644 --- a/tests/parser/structs.exp +++ b/tests/parser/structs.exp @@ -2,33 +2,58 @@ Program { ast: Block( [ Statement( - Struct { - name: Ident( - "foo_t", + StatementBox { + inner: Struct( + Struct { + name: Ident( + "foo_t", + ), + fields: [], + }, ), - fields: [], + loc: Loc { + file: "parser/structs.mcl", + line: 2, + col: 7, + }, }, ), Statement( - Struct { - name: Ident( - "bar_t", - ), - fields: [ - ( - Ident( - "a", + StatementBox { + inner: Struct( + Struct { + name: Ident( + "bar_t", ), - Ref { - inner: Owned( + fields: [ + ( Ident( - "bar_t", + "a", ), + TypeBox { + inner: Ref { + inner: Owned( + Ident( + "bar_t", + ), + ), + mutable: false, + }, + loc: Loc { + file: "parser/structs.mcl", + line: 5, + col: 9, + }, + }, ), - mutable: false, - }, - ), - ], + ], + }, + ), + loc: Loc { + file: "parser/structs.mcl", + line: 4, + col: 7, + }, }, ), ],