Saved location in tokens post parsing, fixed parsing just skipping stuff

(shoulda thought of that)
This commit is contained in:
Gvidas Juknevičius 2024-12-22 02:01:04 +02:00
parent 323d3342a3
commit d2b0e57ce6
Signed by: MCorange
GPG Key ID: 12B1346D720B7FBB
15 changed files with 1755 additions and 542 deletions

View File

@ -1,55 +1,76 @@
use std::collections::HashMap; 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)] #[derive(Debug, Clone)]
pub enum Expr { pub enum Expr {
// Comment(Comment), // Comment(Comment),
Group(Box<Expr>), Group(Box<ExprBox>),
UnOp { UnOp {
typ: Punctuation, typ: Punctuation,
right: Box<Expr>, right: Box<ExprBox>,
}, },
BinOp { BinOp {
typ: Punctuation, typ: Punctuation,
left: Box<Expr>, left: Box<ExprBox>,
right: Box<Expr>, right: Box<ExprBox>,
}, },
Literal(super::literal::Literal), Literal(super::literal::Literal),
ArrayIndex { ArrayIndex {
name: Box<Expr>, name: Box<ExprBox>,
index: Box<Expr>, index: Box<ExprBox>,
}, },
Path(Path), Path(Path),
Call { Call {
path: Box<Expr>, path: Box<ExprBox>,
params: CallParams, // Expr ~ (, Expr)* params: CallParams, // ExprBox ~ (, Expr)*
}, },
//MethodCall { //MethodCall {
// var_name: Box<Expr>, // var_name: Box<ExprBox>,
// method_name: Ident, // method_name: Ident,
// params: CallParams, // params: CallParams,
//}, //},
/// the left side only exists on the /.|->/ chain /// the left side only exists on the /.|->/ chain
FieldAccess { FieldAccess {
left: Box<Option<Expr>>, left: Box<Option<ExprBox>>,
right: Box<Expr>, right: Box<ExprBox>,
}, },
PtrFieldAccess { PtrFieldAccess {
left: Box<Option<Expr>>, left: Box<Option<ExprBox>>,
right: Box<Expr>, right: Box<ExprBox>,
}, },
ForLoop { ForLoop {
init: Box<Ast>, init: Box<Ast>,
test: Box<Expr>, test: Box<ExprBox>,
on_loop: Box<Expr>, on_loop: Box<ExprBox>,
body: Block, body: Block,
}, },
WhileLoop { WhileLoop {
test: Box<Expr>, test: Box<ExprBox>,
body: Block, body: Block,
}, },
InfLoop { InfLoop {
@ -58,20 +79,20 @@ pub enum Expr {
If(IfExpr), If(IfExpr),
Struct { Struct {
path: Path, path: Path,
fields: HashMap<Ident, Expr>, fields: HashMap<Ident, ExprBox>,
}, },
Return(Box<Option<Expr>>), Return(Box<Option<ExprBox>>),
Break, Break,
Continue, Continue,
Cast { Cast {
left: Box<Expr>, left: Box<ExprBox>,
right: Box<Type> right: Box<TypeBox>
}, },
} }
impl Expr { impl ExprBox {
pub fn unwrap_path(&self) -> Path { 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() p.clone()
} }
} }
@ -79,7 +100,7 @@ impl Expr {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct CallParams(pub Vec<Expr>); pub struct CallParams(pub Vec<ExprBox>);
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Block(pub Vec<Ast>); pub struct Block(pub Vec<Ast>);
@ -90,7 +111,7 @@ pub struct Path(pub Vec<Ident>);
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct IfExpr { pub struct IfExpr {
pub test: Box<Expr>, pub test: Box<ExprBox>,
pub body: Block, pub body: Block,
pub else_if: Option<IfBranchExpr> pub else_if: Option<IfBranchExpr>
} }

View File

@ -2,7 +2,7 @@ use std::collections::HashMap;
use crate::tokeniser::tokentype::*; use crate::tokeniser::tokentype::*;
use super::{expr::Expr, typ::Type, Ast}; use super::{expr::ExprBox, typ::TypeBox, Ast};
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum Literal { pub enum Literal {
@ -10,10 +10,10 @@ pub enum Literal {
Ident(Ident), Ident(Ident),
String(TString), String(TString),
Char(Char), Char(Char),
Array(Vec<Expr>), Array(Vec<ExprBox>),
ArrayRepeat { ArrayRepeat {
typ: Box<Type>, typ: Box<TypeBox>,
count: Box<Expr>, count: Box<ExprBox>,
}, },
Struct { Struct {
name: Ident, name: Ident,

View File

@ -1,6 +1,6 @@
use std::collections::HashMap; use std::collections::HashMap;
use typ::Type; use statement::{Enum, Function, Struct, TypeAlias};
pub use crate::tokeniser::tokentype::*; pub use crate::tokeniser::tokentype::*;
@ -12,17 +12,17 @@ pub mod typ;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Program { pub struct Program {
pub ast: expr::Block, pub ast: expr::Block,
pub structs: HashMap<Ident, HashMap<Ident, usize>>, pub structs: HashMap<Ident, Struct>,
pub enums: HashMap<Ident, usize>, pub enums: HashMap<Ident, Enum>,
pub types: HashMap<Type, Type>, pub types: HashMap<Ident, TypeAlias>,
pub functions: HashMap<Ident, (Vec<(Ident, Type)>, Type)>, pub functions: HashMap<Ident, Function>,
pub member_functions: HashMap<Ident, HashMap<Ident, (Vec<(Ident, Type)>, Type)>>, pub member_functions: HashMap<Ident, HashMap<Ident, Function>>,
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum Ast { pub enum Ast {
Expr(expr::Expr), Expr(expr::ExprBox),
Statement(statement::Statement), Statement(statement::StatementBox),
} }

View File

@ -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)] #[derive(Debug, Clone)]
pub enum Statement { pub enum Statement {
Fn { Fn(Function),
struct_name: Option<Ident>, TypeAlias(TypeAlias),
name: Ident, Struct(Struct),
params: Vec<(Ident, Type)>, Enum(Enum),
ret_type: Option<Type>,
qual_const: bool,
qual_extern: Option<TString>, // abi
body: Option<Block>, // If None then its a type declaration
},
TypeAlias {
name: Ident,
typ: Type,
},
Struct {
name: Ident,
fields: Vec<(Ident, Type)>,
},
Enum {
name: Ident,
fields: Vec<Ident>,
},
ConstVar { ConstVar {
name: Ident, name: Ident,
typ: Type, typ: TypeBox,
val: Expr val: ExprBox
}, },
StaticVar { StaticVar {
name: Ident, name: Ident,
typ: Type, typ: TypeBox,
val: Expr, val: ExprBox,
}, },
Let { Let {
name: Ident, name: Ident,
typ: Option<Type>, typ: Option<TypeBox>,
val: Option<Expr>, val: Option<ExprBox>,
}, },
} }
#[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<Ident>,
}
#[derive(Debug, Clone)]
pub struct Function {
pub struct_name: Option<Ident>,
pub name: Ident,
pub params: Vec<(Ident, TypeBox)>,
pub ret_type: Option<TypeBox>,
pub qual_const: bool,
pub qual_extern: Option<TString>, // abi
pub body: Option<Block>, // If None then its a type declaration
}

View File

@ -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)] #[derive(Debug, Clone)]
pub enum Type { pub enum Type {
@ -11,7 +34,7 @@ pub enum Type {
}, },
ArrayRepeat { ArrayRepeat {
inner: Box<Type>, inner: Box<Type>,
count: Expr, count: ExprBox,
}, },
Owned(Ident), Owned(Ident),
} }

View File

@ -4,7 +4,7 @@ use anyhow::{bail, Result};
use crate::{debug, error, lerror, parser::{typ::parse_type, Punctuation}, tokeniser::Token}; 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] = &[ const BINOP_LIST: &[TokenType] = &[
TokenType::Punct(Punctuation::Plus), TokenType::Punct(Punctuation::Plus),
@ -37,7 +37,7 @@ const BINOP_LIST: &[TokenType] = &[
TokenType::Punct(Punctuation::Ge), TokenType::Punct(Punctuation::Ge),
]; ];
pub fn parse_expr(tokens: &mut Vec<Token>, precedence: usize, consume_semi: bool) -> Result<Option<Expr>> { pub fn parse_expr(tokens: &mut Vec<Token>, precedence: usize, consume_semi: bool) -> Result<Option<ExprBox>> {
let res = if let Some(_) = utils::check(tokens, TokenType::Delim(Delimiter::ParenL)) { let res = if let Some(_) = utils::check(tokens, TokenType::Delim(Delimiter::ParenL)) {
Some(parse_group(tokens)?) Some(parse_group(tokens)?)
} else } else
@ -73,37 +73,33 @@ pub fn parse_expr(tokens: &mut Vec<Token>, precedence: usize, consume_semi: bool
return Ok(Some(parse_inf_loop(tokens)?)); return Ok(Some(parse_inf_loop(tokens)?));
} else if let Some(_) = utils::check(tokens, TokenType::Keyword(Keyword::Return)) { } else if let Some(_) = utils::check(tokens, TokenType::Keyword(Keyword::Return)) {
return Ok(Some(parse_return(tokens)?)); return Ok(Some(parse_return(tokens)?));
} else if let Some(_) = utils::check_consume(tokens, TokenType::Keyword(Keyword::Break)) { } else if let Some(kw) = utils::check_consume(tokens, TokenType::Keyword(Keyword::Break)) {
return Ok(Some(Expr::Break)); return Ok(Some(ExprBox::new(kw.loc(), Expr::Break)));
} else if let Some(_) = utils::check_consume(tokens, TokenType::Keyword(Keyword::Continue)) { } else if let Some(kw) = utils::check_consume(tokens, TokenType::Keyword(Keyword::Continue)) {
return Ok(Some(Expr::Continue)); return Ok(Some(ExprBox::new(kw.loc(), Expr::Continue)));
} else if let Some(_) = utils::check(tokens, TokenType::Keyword(Keyword::If)) { } else if let Some(kw) = utils::check(tokens, TokenType::Keyword(Keyword::If)) {
return Ok(Some(Expr::If(parse_if(tokens)?))); return Ok(Some(ExprBox::new(&kw.loc().clone(), Expr::If(parse_if(tokens)?))));
} else { } else {
None None
}; };
if let Some(res) = res { if let Some(mut res) = res {
// check for binop if utils::check(tokens, TokenType::Punct(Punctuation::Fieldaccess)).is_some() {
let res = match res { res = parse_field_access(tokens, 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() {
} res =parse_ptr_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() {
} res = parse_fn_call(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() {
} res = parse_cast(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() {
} res = parse_array_index(tokens, res)?;
_ if utils::check(tokens, TokenType::Delim(Delimiter::SquareL)).is_some() => { }
parse_array_index(tokens, res)?
}
_ => res
};
if let Some(_) = utils::check_from_many(tokens, BINOP_LIST) { if let Some(_) = utils::check_from_many(tokens, BINOP_LIST) {
return Ok(Some(parse_binop(tokens, res, precedence)?)); return Ok(Some(parse_binop(tokens, res, precedence)?));
@ -117,19 +113,19 @@ pub fn parse_expr(tokens: &mut Vec<Token>, precedence: usize, consume_semi: bool
Ok(res) Ok(res)
} }
fn parse_return(tokens: &mut Vec<Token>) -> Result<Expr> { fn parse_return(tokens: &mut Vec<Token>) -> Result<ExprBox> {
_ = utils::check_consume(tokens, TokenType::Keyword(Keyword::Return)); let kw = utils::check_consume_or_err(tokens, TokenType::Keyword(Keyword::Return), "")?;
let item = parse_expr(tokens, 0, true)?; 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<Token>, left: Expr) -> Result<Expr> { fn parse_cast(tokens: &mut Vec<Token>, left: ExprBox) -> Result<ExprBox> {
_ = utils::check_consume_or_err(tokens, TokenType::Keyword(Keyword::As), "")?; let kw = utils::check_consume_or_err(tokens, TokenType::Keyword(Keyword::As), "")?;
let typ = parse_type(tokens)?; let typ = parse_type(tokens)?;
Ok(Expr::Cast { Ok(ExprBox::new(kw.loc(), Expr::Cast {
left: Box::new(left), left: Box::new(left),
right: Box::new(typ) right: Box::new(typ)
}) }))
} }
fn parse_if(tokens: &mut Vec<Token>) -> Result<IfExpr> { fn parse_if(tokens: &mut Vec<Token>) -> Result<IfExpr> {
let loc = utils::check_consume_or_err(tokens, TokenType::Keyword(Keyword::If), "")?; let loc = utils::check_consume_or_err(tokens, TokenType::Keyword(Keyword::If), "")?;
@ -172,50 +168,50 @@ fn parse_if(tokens: &mut Vec<Token>) -> Result<IfExpr> {
}) })
} }
} }
fn parse_while_loop(tokens: &mut Vec<Token>) -> Result<Expr> { fn parse_while_loop(tokens: &mut Vec<Token>) -> Result<ExprBox> {
let loc = utils::check_consume_or_err(tokens, TokenType::Keyword(Keyword::While), "")?; let kw = utils::check_consume_or_err(tokens, TokenType::Keyword(Keyword::While), "")?;
let Some(test) = parse_expr(tokens, 0, false)? else { 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!("") bail!("")
}; };
let block = parse_block(tokens)?; let block = parse_block(tokens)?;
Ok(Expr::WhileLoop { Ok(ExprBox::new(kw.loc(), Expr::WhileLoop {
test: Box::new(test), test: Box::new(test),
body: block body: block
}) }))
} }
fn parse_for_loop(tokens: &mut Vec<Token>) -> Result<Expr> { fn parse_for_loop(tokens: &mut Vec<Token>) -> Result<ExprBox> {
let loc = utils::check_consume_or_err(tokens, TokenType::Keyword(Keyword::For), "")?; let kw = utils::check_consume_or_err(tokens, TokenType::Keyword(Keyword::For), "")?;
let Some(pre) = parse_item(tokens)? else { 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!("") bail!("")
}; };
// Semicolon parsed out by parse_item above // Semicolon parsed out by parse_item above
let Some(test) = parse_expr(tokens, 0, false)? else { 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!("") bail!("")
}; };
_ = utils::check_consume_or_err(tokens, TokenType::Punct(Punctuation::Semi), ""); _ = utils::check_consume_or_err(tokens, TokenType::Punct(Punctuation::Semi), "");
let Some(post) = parse_expr(tokens, 0, false)? else { 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!("") bail!("")
}; };
let block = parse_block(tokens)?; let block = parse_block(tokens)?;
Ok(Expr::ForLoop { Ok(ExprBox::new(kw.loc(), Expr::ForLoop {
init: Box::new(pre), init: Box::new(pre),
test: Box::new(test), test: Box::new(test),
on_loop: Box::new(post), on_loop: Box::new(post),
body: block body: block
}) }))
} }
fn parse_inf_loop(tokens: &mut Vec<Token>) -> Result<Expr> { fn parse_inf_loop(tokens: &mut Vec<Token>) -> Result<ExprBox> {
_ = utils::check_consume_or_err(tokens, TokenType::Keyword(Keyword::Loop), ""); let kw = utils::check_consume_or_err(tokens, TokenType::Keyword(Keyword::Loop), "")?;
let block = parse_block(tokens)?; 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<Token>, left: Expr) -> Result<Expr> { fn parse_fn_call(tokens: &mut Vec<Token>, left: ExprBox) -> Result<ExprBox> {
_ = utils::check_consume_or_err(tokens, TokenType::Delim(Delimiter::ParenL), ""); let start = utils::check_consume_or_err(tokens, TokenType::Delim(Delimiter::ParenL), "")?;
let mut params = Vec::new(); let mut params = Vec::new();
while !tokens.is_empty() { while !tokens.is_empty() {
@ -232,23 +228,23 @@ fn parse_fn_call(tokens: &mut Vec<Token>, left: Expr) -> Result<Expr> {
} }
} }
_ = utils::check_consume_or_err(tokens, TokenType::Delim(Delimiter::ParenR), ""); _ = 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<Token>, left: Expr) -> Result<Expr> { fn parse_array_index(tokens: &mut Vec<Token>, left: ExprBox) -> Result<ExprBox> {
let loc = utils::check_consume_or_err(tokens, TokenType::Delim(Delimiter::SquareL), "")?; let start = utils::check_consume_or_err(tokens, TokenType::Delim(Delimiter::SquareL), "")?;
let Some(idx) = parse_expr(tokens, 0, false)? else { 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!("") bail!("")
}; };
_ = utils::check_consume_or_err(tokens, TokenType::Delim(Delimiter::SquareR), ""); _ = utils::check_consume_or_err(tokens, TokenType::Delim(Delimiter::SquareR), "");
Ok(Expr::ArrayIndex { Ok(ExprBox::new(start.loc(), Expr::ArrayIndex {
name: Box::new(left), name: Box::new(left),
index: Box::new(idx) index: Box::new(idx)
}) }))
} }
fn parse_field_access(tokens: &mut Vec<Token>, left: Expr) -> Result<Expr> { fn parse_field_access(tokens: &mut Vec<Token>, left: ExprBox) -> Result<ExprBox> {
_ = utils::check_consume_or_err(tokens, TokenType::Punct(Punctuation::Fieldaccess), "unreachable")?; 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 = if let Some(_) = utils::check_2_last(tokens, TokenType::Punct(Punctuation::Arrow)) {
let right = parse_path(tokens)?; let right = parse_path(tokens)?;
@ -259,14 +255,14 @@ fn parse_field_access(tokens: &mut Vec<Token>, left: Expr) -> Result<Expr> {
} else { } else {
parse_path(tokens)? parse_path(tokens)?
}; };
Ok(Expr::FieldAccess { Ok(ExprBox::new(start.loc(), Expr::FieldAccess {
left: Box::new(Some(left)), left: Box::new(Some(left)),
right: Box::new(right) right: Box::new(right)
}) }))
} }
fn parse_ptr_field_access(tokens: &mut Vec<Token>, left: Expr) -> Result<Expr> { fn parse_ptr_field_access(tokens: &mut Vec<Token>, left: ExprBox) -> Result<ExprBox> {
_ = utils::check_consume_or_err(tokens, TokenType::Punct(Punctuation::Arrow), "unreachable")?; 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 = if let Some(_) = utils::check_2_last(tokens, TokenType::Punct(Punctuation::Arrow)) {
let right = parse_path(tokens)?; let right = parse_path(tokens)?;
parse_ptr_field_access(tokens, right)? parse_ptr_field_access(tokens, right)?
@ -276,28 +272,28 @@ fn parse_ptr_field_access(tokens: &mut Vec<Token>, left: Expr) -> Result<Expr> {
} else { } else {
parse_path(tokens)? parse_path(tokens)?
}; };
Ok(Expr::PtrFieldAccess { Ok(ExprBox::new(start.loc(), Expr::PtrFieldAccess {
left: Box::new(Some(left)), left: Box::new(Some(left)),
right: Box::new(right) right: Box::new(right)
}) }))
} }
fn parse_literal(tokens: &mut Vec<Token>) -> Result<Expr> { fn parse_literal(tokens: &mut Vec<Token>) -> Result<ExprBox> {
if let Some(tkn) = utils::check_consume(tokens, TokenType::string("", false)) { if let Some(tkn) = utils::check_consume(tokens, TokenType::string("", false)) {
let TokenType::String(str) = tkn.tt() else {unreachable!()}; 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 } else
if let Some(tkn) = utils::check_consume(tokens, TokenType::number(0, 0, false)) { if let Some(tkn) = utils::check_consume(tokens, TokenType::number(0, 0, false)) {
let TokenType::Number(val) = tkn.tt() else {unreachable!()}; 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 } else
if let Some(tkn) = utils::check_consume(tokens, TokenType::char('\0')) { if let Some(tkn) = utils::check_consume(tokens, TokenType::char('\0')) {
let TokenType::Char(val) = tkn.tt() else {unreachable!()}; 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 } else
if let Some(start) = utils::check_consume(tokens, TokenType::Delim(Delimiter::SquareL)) { if let Some(start) = utils::check_consume(tokens, TokenType::Delim(Delimiter::SquareL)) {
if let Some(_) = utils::check_consume(tokens, TokenType::Delim(Delimiter::SquareR)) { 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) { if *tokens[tokens.len()-2].tt() == TokenType::Punct(Punctuation::Comma) {
let first = parse_expr(tokens, 0, false)?; let first = parse_expr(tokens, 0, false)?;
@ -314,15 +310,15 @@ fn parse_literal(tokens: &mut Vec<Token>) -> Result<Expr> {
} }
} }
utils::check_consume_or_err(tokens, TokenType::Delim(Delimiter::SquareR), "")?; 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) { } else if *tokens[tokens.len()-2].tt() == TokenType::Punct(Punctuation::Semi) {
let typ = parse_type(tokens)?; let typ = parse_type(tokens)?;
let count = parse_expr(tokens, 0, false)?.unwrap(); let count = parse_expr(tokens, 0, false)?.unwrap();
utils::check_consume_or_err(tokens, TokenType::Delim(Delimiter::SquareR), "")?; 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), typ: Box::new(typ),
count: Box::new(count) count: Box::new(count)
})); })));
} else { } else {
if let Some(curr) = tokens.last() { 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()); 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<Token>) -> Result<Expr> {
unreachable!() unreachable!()
} }
fn parse_struct_literal(tokens: &mut Vec<Token>, name: Path) -> Result<Expr> { fn parse_struct_literal(tokens: &mut Vec<Token>, name: Path) -> Result<ExprBox> {
_ = utils::check_consume_or_err(tokens, TokenType::Delim(Delimiter::CurlyL), "")?; let start = utils::check_consume_or_err(tokens, TokenType::Delim(Delimiter::CurlyL), "")?;
let mut fields = HashMap::new(); let mut fields = HashMap::new();
while !tokens.is_empty() { while !tokens.is_empty() {
if let Some(_) = utils::check_consume(tokens, TokenType::Delim(Delimiter::CurlyR)) { if let Some(_) = utils::check_consume(tokens, TokenType::Delim(Delimiter::CurlyR)) {
@ -352,21 +348,21 @@ fn parse_struct_literal(tokens: &mut Vec<Token>, name: Path) -> Result<Expr> {
break; break;
} }
} }
Ok(Expr::Struct { path: name, fields }) Ok(ExprBox::new(start.loc(), Expr::Struct { path: name, fields }))
} }
fn parse_group(tokens: &mut Vec<Token>) -> Result<Expr> { fn parse_group(tokens: &mut Vec<Token>) -> Result<ExprBox> {
let loc = utils::check_consume_or_err(tokens, TokenType::Delim(Delimiter::ParenL), "")?; let start = utils::check_consume_or_err(tokens, TokenType::Delim(Delimiter::ParenL), "")?;
let Some(expr) = parse_expr(tokens, 0, false)? else { let Some(expr) = parse_expr(tokens, 0, false)? else {
lerror!(loc.loc(), "Expected expr found nothing"); lerror!(start.loc(), "Expected expr found nothing");
bail!("") bail!("")
}; };
utils::check_consume_or_err(tokens, TokenType::Delim(Delimiter::ParenR), "")?; 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<Token>) -> Result<Expr> { fn parse_path(tokens: &mut Vec<Token>) -> Result<ExprBox> {
let mut buf = Vec::new(); let mut buf = Vec::new();
let part = utils::check_consume(tokens, TokenType::ident("")).unwrap(); let part = utils::check_consume(tokens, TokenType::ident("")).unwrap();
@ -379,10 +375,10 @@ fn parse_path(tokens: &mut Vec<Token>) -> Result<Expr> {
buf.push(part.tt().unwrap_ident()); 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<Token>) -> Result<Expr> { fn parse_unop(tokens: &mut Vec<Token>) -> Result<ExprBox> {
let typ = utils::check_consume_or_err_from_many(tokens, &[ let typ = utils::check_consume_or_err_from_many(tokens, &[
TokenType::Punct(Punctuation::Not), TokenType::Punct(Punctuation::Not),
TokenType::Punct(Punctuation::Plus), TokenType::Punct(Punctuation::Plus),
@ -397,18 +393,20 @@ fn parse_unop(tokens: &mut Vec<Token>) -> Result<Expr> {
lerror!(&loc, "Expected expression after unary token, found nothing"); lerror!(&loc, "Expected expression after unary token, found nothing");
bail!("") bail!("")
}; };
Ok(Expr::UnOp { Ok(ExprBox::new(&loc, Expr::UnOp {
typ, typ,
right: Box::new(right) right: Box::new(right)
}) }))
} }
fn parse_binop(tokens: &mut Vec<Token>, mut lhs: Expr, precedence: usize) -> Result<Expr> { fn parse_binop(tokens: &mut Vec<Token>, mut lhs: ExprBox, precedence: usize) -> Result<ExprBox> {
// TODO: https://en.wikipedia.org/wiki/Operator-precedence_parser#Pseudocode // TODO: https://en.wikipedia.org/wiki/Operator-precedence_parser#Pseudocode
loop { loop {
let op_loc;
let op = match tokens.last() { let op = match tokens.last() {
Some(op) if BINOP_LIST.contains(&op.tt()) => { Some(op) if BINOP_LIST.contains(&op.tt()) => {
op_loc = op.loc().clone();
let TokenType::Punct(op) = op.tt() else {unreachable!()}; let TokenType::Punct(op) = op.tt() else {unreachable!()};
op.clone() op.clone()
} }
@ -433,11 +431,11 @@ fn parse_binop(tokens: &mut Vec<Token>, mut lhs: Expr, precedence: usize) -> Res
_ = tokens.pop(); _ = tokens.pop();
let Some(rhs) = parse_expr(tokens, rp, false)? else {break;}; let Some(rhs) = parse_expr(tokens, rp, false)? else {break;};
lhs = Expr::BinOp { lhs = ExprBox::new(&op_loc, Expr::BinOp {
typ: op, typ: op,
left: Box::new(lhs), left: Box::new(lhs),
right: Box::new(rhs) right: Box::new(rhs)
}; });
} }

View File

@ -5,15 +5,15 @@ use crate::parser::ast::TokenType;
use crate::parser::expr::parse_expr; use crate::parser::expr::parse_expr;
use crate::parser::{Delimiter, Ident, Keyword, Punctuation}; use crate::parser::{Delimiter, Ident, Keyword, Punctuation};
use crate::tokeniser::Token; use crate::tokeniser::Token;
use super::ast::typ::Type; use super::ast::typ::{Type, TypeBox};
use super::expr::parse_block; use super::expr::parse_block;
use super::typ::parse_type; use super::typ::parse_type;
use super::utils; use super::utils;
use super::ast::statement::Statement; use super::ast::statement::{Enum, Function, Statement, StatementBox, Struct, TypeAlias};
type Result<T> = anyhow::Result<T>; type Result<T> = anyhow::Result<T>;
pub fn parse_statement(tokens: &mut Vec<Token>) -> Result<Option<Statement>> { pub fn parse_statement(tokens: &mut Vec<Token>) -> Result<Option<StatementBox>> {
if let Some(_) = utils::check(tokens, TokenType::Keyword(Keyword::Fn)) { if let Some(_) = utils::check(tokens, TokenType::Keyword(Keyword::Fn)) {
Ok(Some(parse_fn(tokens)?)) Ok(Some(parse_fn(tokens)?))
} else } else
@ -39,8 +39,8 @@ pub fn parse_statement(tokens: &mut Vec<Token>) -> Result<Option<Statement>> {
} }
} }
fn parse_enum(tokens: &mut Vec<Token>) -> Result<Statement> { fn parse_enum(tokens: &mut Vec<Token>) -> Result<StatementBox> {
_ = utils::check_consume(tokens, TokenType::Keyword(Keyword::Enum)); 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(); let name = utils::check_consume_or_err(tokens, TokenType::ident(""), "")?.tt().unwrap_ident();
_ = utils::check_consume(tokens, TokenType::Delim(Delimiter::CurlyL)); _ = utils::check_consume(tokens, TokenType::Delim(Delimiter::CurlyL));
let mut fields = Vec::new(); let mut fields = Vec::new();
@ -60,11 +60,11 @@ fn parse_enum(tokens: &mut Vec<Token>) -> Result<Statement> {
fields.push(field_name); 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<Token>) -> Result<Statement> { fn parse_struct(tokens: &mut Vec<Token>) -> Result<StatementBox> {
_ = utils::check_consume(tokens, TokenType::Keyword(Keyword::Struct)); 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(); let name = utils::check_consume_or_err(tokens, TokenType::ident(""), "")?.tt().unwrap_ident();
_ = utils::check_consume(tokens, TokenType::Delim(Delimiter::CurlyL)); _ = utils::check_consume(tokens, TokenType::Delim(Delimiter::CurlyL));
let mut fields = Vec::new(); let mut fields = Vec::new();
@ -86,11 +86,11 @@ fn parse_struct(tokens: &mut Vec<Token>) -> Result<Statement> {
fields.push((field_name, typ)); 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<Token>) -> Result<Statement> { fn parse_static(tokens: &mut Vec<Token>) -> Result<StatementBox> {
_ = utils::check_consume(tokens, TokenType::Keyword(Keyword::Static)); 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(); let name = utils::check_consume_or_err(tokens, TokenType::ident(""), "")?.tt().unwrap_ident();
_ = utils::check_consume_or_err(tokens, TokenType::Punct(Punctuation::Colon), "")?; _ = utils::check_consume_or_err(tokens, TokenType::Punct(Punctuation::Colon), "")?;
@ -101,11 +101,11 @@ fn parse_static(tokens: &mut Vec<Token>) -> Result<Statement> {
bail!("") bail!("")
}; };
_ = utils::check_consume_or_err(tokens, TokenType::Punct(Punctuation::Semi), "")?; _ = 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<Token>) -> Result<Statement> { fn parse_let(tokens: &mut Vec<Token>) -> Result<StatementBox> {
_ = utils::check_consume(tokens, TokenType::Keyword(Keyword::Let)); 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 name = utils::check_consume_or_err(tokens, TokenType::ident(""), "")?.tt().unwrap_ident();
let mut typ = None; let mut typ = None;
let mut val = None; let mut val = None;
@ -120,10 +120,10 @@ fn parse_let(tokens: &mut Vec<Token>) -> Result<Statement> {
val = Some(_val); val = Some(_val);
} }
_ = utils::check_consume_or_err(tokens, TokenType::Punct(Punctuation::Semi), "")?; _ = 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<Token>) -> Result<Statement> { fn parse_constant(tokens: &mut Vec<Token>) -> Result<StatementBox> {
_ = utils::check_consume(tokens, TokenType::Keyword(Keyword::Const)); let kw = utils::check_consume_or_err(tokens, TokenType::Keyword(Keyword::Const), "")?;
if let Some(_) = utils::check(tokens, TokenType::Keyword(Keyword::Fn)) { if let Some(_) = utils::check(tokens, TokenType::Keyword(Keyword::Fn)) {
unimplemented!() unimplemented!()
@ -137,22 +137,22 @@ fn parse_constant(tokens: &mut Vec<Token>) -> Result<Statement> {
bail!("") bail!("")
}; };
_ = utils::check_consume_or_err(tokens, TokenType::Punct(Punctuation::Semi), "")?; _ = 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<Token>) -> Result<Statement> { fn parse_type_alias(tokens: &mut Vec<Token>) -> Result<StatementBox> {
_ = utils::check_consume(tokens, TokenType::Keyword(Keyword::Type)); 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(); let name = utils::check_consume_or_err(tokens, TokenType::ident(""), "")?.tt().unwrap_ident();
_ = utils::check_consume_or_err(tokens, TokenType::Punct(Punctuation::Eq), "")?; _ = utils::check_consume_or_err(tokens, TokenType::Punct(Punctuation::Eq), "")?;
let typ = parse_type(tokens)?; let typ = parse_type(tokens)?;
_ = utils::check_consume_or_err(tokens, TokenType::Punct(Punctuation::Semi), "")?; _ = 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<Token>) -> Result<Statement> { fn parse_fn(tokens: &mut Vec<Token>) -> Result<StatementBox> {
// Just remove the kw since we checked it before // 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 struct_name = None;
let mut name = utils::check_consume_or_err(tokens, TokenType::ident(""), "")?.tt().unwrap_ident(); let mut name = utils::check_consume_or_err(tokens, TokenType::ident(""), "")?.tt().unwrap_ident();
@ -176,7 +176,8 @@ fn parse_fn(tokens: &mut Vec<Token>) -> Result<Statement> {
_ = utils::check_consume_or_err(tokens, TokenType::Punct(Punctuation::Semi), "")?; _ = utils::check_consume_or_err(tokens, TokenType::Punct(Punctuation::Semi), "")?;
body = None; body = None;
} }
Ok(Statement::Fn {
Ok(StatementBox::new(kw.loc(), Statement::Fn(Function{
struct_name, struct_name,
name, name,
params, params,
@ -184,12 +185,12 @@ fn parse_fn(tokens: &mut Vec<Token>) -> Result<Statement> {
qual_const: false, qual_const: false,
qual_extern: None, qual_extern: None,
body, body,
}) })))
} }
fn parse_fn_params(tokens: &mut Vec<Token>) -> Result<Vec<(Ident, Type)>> { fn parse_fn_params(tokens: &mut Vec<Token>) -> Result<Vec<(Ident, TypeBox)>> {
let mut args = Vec::new(); let mut args = Vec::new();
utils::check_consume_or_err(tokens, TokenType::Delim(Delimiter::ParenL), "")?; utils::check_consume_or_err(tokens, TokenType::Delim(Delimiter::ParenL), "")?;
while !tokens.is_empty() { while !tokens.is_empty() {

View File

@ -2,11 +2,15 @@ use anyhow::Result;
use crate::{parser::Delimiter, tokeniser::Token}; 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<Token>) -> Result<Type> { pub fn parse_type(tokens: &mut Vec<Token>) -> Result<TypeBox> {
let mut ref_cnt = Vec::new(); let mut ref_cnt = Vec::new();
let mut loc = None;
while let Some(tok) = utils::check_consume(tokens, TokenType::Punct(Punctuation::Ampersand)) { 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)) { if let Some(tok) = utils::check_consume(tokens, TokenType::Keyword(Keyword::Mut)) {
ref_cnt.push(tok.clone()); ref_cnt.push(tok.clone());
} else { } else {
@ -15,23 +19,29 @@ pub fn parse_type(tokens: &mut Vec<Token>) -> Result<Type> {
} }
let mut typ; 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)?; let itm_typ = parse_type(tokens)?;
if let Some(_) = utils::check_consume(tokens, TokenType::Punct(Punctuation::Semi)) { if let Some(_) = utils::check_consume(tokens, TokenType::Punct(Punctuation::Semi)) {
let count = parse_expr(tokens, 0, false)?.unwrap(); let count = parse_expr(tokens, 0, false)?.unwrap();
typ = Type::ArrayRepeat { typ = Type::ArrayRepeat {
inner: Box::new(itm_typ), inner: Box::new(itm_typ.inner().clone()),
count count
} }
} else { } else {
typ = Type::Array { 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), "")?; _ = utils::check_consume_or_err(tokens, TokenType::Delim(Delimiter::SquareR), "")?;
} else { } else {
let ident = utils::check_consume_or_err(tokens, TokenType::ident(""), "a")?; let ident = utils::check_consume_or_err(tokens, TokenType::ident(""), "a")?;
typ = Type::Owned(ident.tt().unwrap_ident()); typ = Type::Owned(ident.tt().unwrap_ident());
if let None = loc {
loc = Some(ident.loc().clone());
}
} }
while let Some(reft) = ref_cnt.pop() { while let Some(reft) = ref_cnt.pop() {
match reft.tt() { match reft.tt() {
@ -50,5 +60,5 @@ pub fn parse_type(tokens: &mut Vec<Token>) -> Result<Type> {
_ => unreachable!() _ => unreachable!()
} }
} }
Ok(typ) Ok(TypeBox::new(&loc.unwrap(), typ))
} }

View File

@ -2,29 +2,47 @@ Program {
ast: Block( ast: Block(
[ [
Statement( Statement(
Enum { StatementBox {
name: Ident( inner: Enum(
"Foo", Enum {
name: Ident(
"Foo",
),
fields: [],
},
), ),
fields: [], loc: Loc {
file: "parser/enumerations.mcl",
line: 1,
col: 5,
},
}, },
), ),
Statement( Statement(
Enum { StatementBox {
name: Ident( inner: Enum(
"Bar", Enum {
name: Ident(
"Bar",
),
fields: [
Ident(
"A",
),
Ident(
"B",
),
Ident(
"C",
),
],
},
), ),
fields: [ loc: Loc {
Ident( file: "parser/enumerations.mcl",
"A", line: 3,
), col: 5,
Ident( },
"B",
),
Ident(
"C",
),
],
}, },
), ),
], ],

View File

@ -1,53 +1,900 @@
Program { Program {
ast: Block( ast: Block(
[ [
Expr( Statement(
BinOp { StatementBox {
typ: Eq, inner: Let {
left: UnOp { name: Ident(
typ: Star, "a",
right: Path( ),
Path( typ: None,
[ val: Some(
Ident( ExprBox {
"a", 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 { loc: Loc {
typ: EqEq, file: "parser/expressions.mcl",
left: BinOp { line: 1,
typ: Star, col: 4,
left: Literal( },
Number( },
Number { ),
val: 1, Statement(
base: 10, StatementBox {
signed: false, inner: Let {
}, name: Ident(
), "b",
),
right: Literal(
Number(
Number {
val: 3,
base: 10,
signed: false,
},
),
),
},
right: Literal(
Number(
Number {
val: 4,
base: 10,
signed: false,
},
),
), ),
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,
}, },
}, },
), ),

View File

@ -1,8 +1,8 @@
*a = 1 * 3 == 4; let a = 1 * 3 == 4;
b.c = 3/4 == *a; let b = 3/4 == *a;
c->d = (a->b.c->d) / 2; let c = (a->b.c->d) / 2;
*d->e.f = 2 / a->b.c->d; let d = 2 / a->b.c->d;
e = a->b.c->d / 2; let e = a->b.c->d / 2;
f = a.b.c.d / 2; let f = a.b.c.d / 2;
g = a.b[*a.c] * 5; let g = a.b[*a.c] * 5;

View File

@ -2,187 +2,298 @@ Program {
ast: Block( ast: Block(
[ [
Statement( Statement(
Fn { StatementBox {
struct_name: None, inner: Fn(
name: Ident( Function {
"main", struct_name: None,
), name: Ident(
params: [ "main",
(
Ident(
"argc",
), ),
Owned( params: [
Ident( (
"i32", Ident(
), "argc",
),
),
(
Ident(
"argv",
),
Ref {
inner: Array {
inner: Owned(
Ident(
"Str",
),
), ),
}, TypeBox {
mutable: false, inner: Owned(
}, Ident(
), "i32",
],
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,
},
),
), ),
), ),
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( Statement(
Fn { StatementBox {
struct_name: Some( inner: Fn(
Ident( Function {
"Baz", struct_name: Some(
),
),
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(
Ident( 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, loc: Loc {
qual_extern: None, file: "parser/functions.mcl",
body: None, line: 4,
col: 3,
},
}, },
), ),
Statement( Statement(
Fn { StatementBox {
struct_name: Some( inner: Fn(
Ident( Function {
"Baz", struct_name: Some(
),
),
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(
Ident( 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, loc: Loc {
qual_extern: None, file: "parser/functions.mcl",
body: None, line: 5,
col: 3,
},
}, },
), ),
], ],

View File

@ -2,35 +2,63 @@ Program {
ast: Block( ast: Block(
[ [
Expr( Expr(
If( ExprBox {
IfExpr { inner: If(
test: BinOp { IfExpr {
typ: Gt, test: ExprBox {
left: Path( inner: BinOp {
Path( typ: Gt,
[ left: ExprBox {
Ident( inner: Path(
"i", Path(
[
Ident(
"i",
),
],
),
), ),
], loc: Loc {
), file: "parser/if-statements.mcl",
), line: 2,
right: Literal( col: 5,
Number( },
Number {
val: 3,
base: 10,
signed: false,
}, },
), 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( ),
[], loc: Loc {
), file: "parser/if-statements.mcl",
else_if: None, line: 2,
col: 3,
}, },
), },
), ),
], ],
), ),

View File

@ -2,106 +2,204 @@ Program {
ast: Block( ast: Block(
[ [
Expr( Expr(
ForLoop { ExprBox {
init: Statement( inner: ForLoop {
Let { init: Statement(
name: Ident( StatementBox {
"i", inner: Let {
), name: Ident(
typ: None, "i",
val: Some( ),
Literal( typ: None,
Number( val: Some(
Number { ExprBox {
val: 0, inner: Literal(
base: 10, Number(
signed: false, 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,
},
}, },
), on_loop: ExprBox {
test: BinOp { inner: BinOp {
typ: Lt, typ: AddEq,
left: Path( left: ExprBox {
Path( inner: Path(
[ Path(
Ident( [
"i", Ident(
"i",
),
],
),
), ),
], loc: Loc {
), file: "parser/loops.mcl",
), line: 1,
right: Literal( col: 25,
Number( },
Number {
val: 10,
base: 10,
signed: false,
}, },
), 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 { loc: Loc {
typ: AddEq, file: "parser/loops.mcl",
left: Path( line: 1,
Path( col: 4,
[
Ident(
"i",
),
],
),
),
right: Literal(
Number(
Number {
val: 1,
base: 10,
signed: false,
},
),
),
}, },
body: Block(
[],
),
}, },
), ),
Expr( Expr(
WhileLoop { ExprBox {
test: BinOp { inner: WhileLoop {
typ: Gt, test: ExprBox {
left: Path( inner: BinOp {
Path( typ: Gt,
[ left: ExprBox {
Ident( inner: Path(
"i", Path(
[
Ident(
"i",
),
],
),
), ),
], loc: Loc {
), file: "parser/loops.mcl",
), line: 2,
right: Literal( col: 8,
Number( },
Number {
val: 3,
base: 10,
signed: false,
}, },
), 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( Expr(
InfLoop { ExprBox {
body: Block( inner: InfLoop {
[], body: Block(
), [],
),
},
loc: Loc {
file: "parser/loops.mcl",
line: 3,
col: 5,
},
}, },
), ),
], ],

View File

@ -2,33 +2,58 @@ Program {
ast: Block( ast: Block(
[ [
Statement( Statement(
Struct { StatementBox {
name: Ident( inner: Struct(
"foo_t", Struct {
name: Ident(
"foo_t",
),
fields: [],
},
), ),
fields: [], loc: Loc {
file: "parser/structs.mcl",
line: 2,
col: 7,
},
}, },
), ),
Statement( Statement(
Struct { StatementBox {
name: Ident( inner: Struct(
"bar_t", Struct {
), name: Ident(
fields: [ "bar_t",
(
Ident(
"a",
), ),
Ref { fields: [
inner: Owned( (
Ident( 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,
},
}, },
), ),
], ],