diff --git a/Cargo.lock b/Cargo.lock index 356074d..3736c24 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -159,9 +159,7 @@ dependencies = [ "chumsky", "clap", "eyre", - "id-arena", "im", - "index_vec", "itertools", "lasso", "logos", @@ -523,12 +521,6 @@ dependencies = [ "serde", ] -[[package]] -name = "id-arena" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25a2bc672d1148e28034f176e01fffebb08b35768468cc954630da77a1449005" - [[package]] name = "im" version = "15.1.0" @@ -549,12 +541,6 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" -[[package]] -name = "index_vec" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74086667896a940438f2118212f313abba4aff3831fef6f4b17d02add5c8bb60" - [[package]] name = "indexmap" version = "1.9.3" diff --git a/Cargo.toml b/Cargo.toml index d661b5f..4cd50ed 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,8 +31,6 @@ lasso = { version = "0.6.0", features = ["multi-threaded"] } logos = "0.12.1" itertools = "0.10.5" chumsky = { git = "https://github.com/zesterer/chumsky.git", features = ["pratt", "label"] } -id-arena = "2.2.1" -index_vec = "0.1.3" im = "15.1.0" pretty = "0.12.3" diff --git a/src/arena.rs b/src/arena.rs new file mode 100644 index 0000000..8049fda --- /dev/null +++ b/src/arena.rs @@ -0,0 +1,48 @@ +use std::{marker::PhantomData, ops::Index}; + +#[derive(Debug)] +pub struct Arena { + inner: Vec, + _phantom: PhantomData, +} + +impl Arena { + pub fn new() -> Self { + Self { + inner: vec![], + _phantom: PhantomData, + } + } + + pub fn len(&self) -> usize { + self.inner.len() + } + + pub fn is_empty(&self) -> bool { + self.inner.is_empty() + } + + pub fn push(&mut self, x: T) -> Id { + self.inner.push(x); + Id::from_raw(self.inner.len() - 1) + } +} + +impl Default for Arena { + fn default() -> Self { + Self::new() + } +} + +impl Index for Arena { + type Output = T; + + fn index(&self, index: Id) -> &Self::Output { + &self.inner[index.into_raw()] + } +} + +pub trait IdLike { + fn from_raw(index: usize) -> Self; + fn into_raw(self) -> usize; +} diff --git a/src/ast/mod.rs b/src/ast/mod.rs index b641802..8d81a92 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -4,41 +4,65 @@ use std::{ fmt::{self, Display}, }; -use id_arena::{Arena, Id}; - use crate::{ + arena::{Arena, IdLike}, ctxt::GlobalCtxt, parse::Span, symbol::{Ident, Symbol}, }; -pub const DUMMY_AST_ID: AstId = AstId { _raw: 0 }; +pub const DUMMY_AST_ID: AstId = AstId(0); + +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[repr(transparent)] +pub struct AstId(u32); + +impl AstId { + pub fn from_raw(id: u32) -> AstId { + AstId(id) + } -index_vec::define_index_type! { - pub struct AstId = u32; + pub fn into_raw(self) -> u32 { + self.0 + } +} - DISABLE_MAX_INDEX_CHECK = cfg!(not(debug_assertions)); - DEBUG_FORMAT = "AstId({})"; - DISPLAY_FORMAT = "{}"; - IMPL_RAW_CONVERSIONS = true; +impl Display for AstId { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.0) + } +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[repr(transparent)] +pub struct Expr(usize); + +impl IdLike for Expr { + fn from_raw(index: usize) -> Self { + Self(index) + } + + fn into_raw(self) -> usize { + self.0 + } } #[derive(Clone, Debug)] -pub struct Expr { +pub struct ExprData { pub id: AstId, pub kind: ExprKind, pub span: Span, } impl Expr { - pub fn new(gcx: &GlobalCtxt, kind: ExprKind, span: Span) -> Id { + pub fn new(gcx: &GlobalCtxt, kind: ExprKind, span: Span) -> Expr { let id = gcx.arenas.ast.next_ast_id(); let expr = gcx .arenas .ast .expr .borrow_mut() - .alloc(Expr { id, kind, span }); + .push(ExprData { id, kind, span }); gcx.arenas.ast.insert_node(id, Node::Expr(expr)); expr } @@ -47,20 +71,18 @@ impl Expr { #[derive(Clone, Debug)] pub enum ExprKind { Let { - is_mut: bool, - varlist: im::Vector<(Ident, Option>, Id)>, - in_block: im::Vector>, + varlist: im::Vector<(bool, Ident, Option, Expr)>, + in_block: im::Vector, }, BinaryOp { - left: Id, + left: Expr, kind: BinOpKind, - right: Id, + right: Expr, }, - UnaryMinus(Id), - UnaryNot(Id), - //Paren(Id), + UnaryMinus(Expr), + UnaryNot(Expr), Do { - exprs: im::Vector>, + exprs: im::Vector, }, Numeral(Numeral), Ident(Ident), @@ -68,17 +90,36 @@ pub enum ExprKind { Error, } +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[repr(transparent)] +pub struct Ty(usize); + +impl IdLike for Ty { + fn from_raw(index: usize) -> Self { + Self(index) + } + + fn into_raw(self) -> usize { + self.0 + } +} + #[derive(Clone, Debug)] -pub struct Ty { +pub struct TyData { pub id: AstId, pub kind: TyKind, pub span: Span, } impl Ty { - pub fn new(gcx: &GlobalCtxt, kind: TyKind, span: Span) -> Id { + pub fn new(gcx: &GlobalCtxt, kind: TyKind, span: Span) -> Ty { let id = gcx.arenas.ast.next_ast_id(); - let ty = gcx.arenas.ast.ty.borrow_mut().alloc(Ty { id, kind, span }); + let ty = gcx + .arenas + .ast + .ty + .borrow_mut() + .push(TyData { id, kind, span }); gcx.arenas.ast.insert_node(id, Node::Ty(ty)); ty } @@ -125,8 +166,8 @@ pub struct Parentage { #[derive(Debug)] pub struct AstArenas { - pub expr: RefCell>, - pub ty: RefCell>, + pub expr: RefCell>, + pub ty: RefCell>, pub parentage: RefCell, next_ast_id: Cell, ast_id_to_node: RefCell>, @@ -139,11 +180,11 @@ impl AstArenas { self.parentage.borrow_mut().map.clear(); } - pub fn expr(&self, id: Id) -> Expr { + pub fn expr(&self, id: Expr) -> ExprData { self.expr.borrow()[id].clone() } - pub fn ty(&self, id: Id) -> Ty { + pub fn ty(&self, id: Ty) -> TyData { self.ty.borrow()[id].clone() } @@ -182,8 +223,8 @@ impl Default for AstArenas { #[derive(Copy, Clone, Debug)] pub enum Node { - Expr(Id), - Ty(Id), + Expr(Expr), + Ty(Ty), } #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] diff --git a/src/lib.rs b/src/lib.rs index 6de4e54..63fefae 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,4 @@ +pub mod arena; pub mod ast; pub mod ctxt; pub mod diagnostic; diff --git a/src/parse/parser.rs b/src/parse/parser.rs index c95174d..f0b8f1e 100644 --- a/src/parse/parser.rs +++ b/src/parse/parser.rs @@ -9,7 +9,6 @@ use chumsky::{ prelude::*, util::MaybeRef, }; -use id_arena::Id; use crate::{ ast::{self, BinOpKind, Expr, ExprKind, Numeral, Radix, Ty, TyKind}, @@ -57,7 +56,7 @@ fn maybe_nls<'src>() -> impl Parser<'src, CalInput<'src>, (), Extra<'src>> + Clo just(Token::Nl).ignored().repeated() } -fn numeral<'src>() -> impl Parser<'src, CalInput<'src>, Id, Extra<'src>> + Clone + 'src { +fn numeral<'src>() -> impl Parser<'src, CalInput<'src>, Expr, Extra<'src>> + Clone + 'src { any().try_map_with(|tok, extra| { let span = extra.span(); if let Token::Numeral(num) = tok { @@ -76,7 +75,7 @@ fn numeral<'src>() -> impl Parser<'src, CalInput<'src>, Id, Extra<'src>> + }) } -fn binop(lhs: Id, op: Token, rhs: Id, span: Span, gcx: &GlobalCtxt) -> Id { +fn binop(lhs: Expr, op: Token, rhs: Expr, span: Span, gcx: &GlobalCtxt) -> Expr { Expr::new( gcx, ExprKind::BinaryOp { @@ -111,7 +110,7 @@ fn binop(lhs: Id, op: Token, rhs: Id, span: Span, gcx: &GlobalCtxt) // TODO: check for where recovery should be done -pub fn ty<'src>() -> impl Parser<'src, CalInput<'src>, Id, Extra<'src>> + Clone + 'src { +pub fn ty<'src>() -> impl Parser<'src, CalInput<'src>, Ty, Extra<'src>> + Clone + 'src { select! { Token::IdentLike(IdentLike::Primitive(Primitive::Uint)) => TyKind::Primitive(ast::Primitive::Uint), Token::IdentLike(IdentLike::Primitive(Primitive::Bool)) => TyKind::Primitive(ast::Primitive::Bool), @@ -121,7 +120,7 @@ pub fn ty<'src>() -> impl Parser<'src, CalInput<'src>, Id, Extra<'src>> + Cl }) } -pub fn expr<'src>() -> impl Parser<'src, CalInput<'src>, Id, Extra<'src>> + Clone + 'src { +pub fn expr<'src>() -> impl Parser<'src, CalInput<'src>, Expr, Extra<'src>> + Clone + 'src { let expr = recursive(|expr| { let exprs_block = expr .clone() @@ -130,7 +129,7 @@ pub fn expr<'src>() -> impl Parser<'src, CalInput<'src>, Id, Extra<'src>> just(Token::Nl).repeated().at_least(1).ignored(), ))) .allow_trailing() - .collect::>>() + .collect::>() .map(im::Vector::from); let primary = choice(( @@ -275,11 +274,8 @@ pub fn expr<'src>() -> impl Parser<'src, CalInput<'src>, Id, Extra<'src>> just(keyword(Keyword::Mut)) .then_ignore(maybe_nls()) .or_not() - .map(|x| x.is_some()), - ) - .then( - ident() - .or(under_ident()) + .map(|x| x.is_some()) + .then(ident().or(under_ident())) .then_ignore(maybe_nls()) .then( just(Token::Colon) @@ -293,7 +289,7 @@ pub fn expr<'src>() -> impl Parser<'src, CalInput<'src>, Id, Extra<'src>> // TODO: should this be `pratt`? .then(expr) .then_ignore(maybe_nls()) - .map(|((ident, ty), expr)| (ident, ty, expr)) + .map(|(((is_mut, ident), ty), expr)| (is_mut, ident, ty, expr)) .separated_by(just(Token::Comma).then_ignore(maybe_nls())) .at_least(1) .allow_trailing() @@ -305,17 +301,9 @@ pub fn expr<'src>() -> impl Parser<'src, CalInput<'src>, Id, Extra<'src>> .then_ignore(maybe_nls()) .then(exprs_block) .then_ignore(just(keyword(Keyword::End))) - .map_with(|((is_mut, varlist), in_block), extra| { + .map_with(|(varlist, in_block), extra| { let span = extra.span(); - Expr::new( - extra.state(), - ExprKind::Let { - is_mut, - varlist, - in_block, - }, - span, - ) + Expr::new(extra.state(), ExprKind::Let { varlist, in_block }, span) }) .or(pratt); diff --git a/src/parse/pretty/ast.rs b/src/parse/pretty/ast.rs index 932aa1f..b123854 100644 --- a/src/parse/pretty/ast.rs +++ b/src/parse/pretty/ast.rs @@ -1,4 +1,3 @@ -use id_arena::Id; use pretty::BoxDoc; use crate::ast::{BinOpKind, Expr, ExprKind, Numeral, Primitive, Ty, TyKind}; @@ -6,42 +5,44 @@ use crate::ast::{BinOpKind, Expr, ExprKind, Numeral, Primitive, Ty, TyKind}; use super::Printer; impl<'gcx> Printer<'gcx> { - pub fn print_expr(&self, expr: Id) -> BoxDoc { + pub fn print_expr(&self, expr: Expr) -> BoxDoc { let arena = &self.gcx.arenas.ast; match arena.expr(expr).kind { - ExprKind::Let { - is_mut, - varlist, - in_block, - } => BoxDoc::text("(") - .append(if is_mut { - BoxDoc::text("let-mut") - } else { - BoxDoc::text("let") - }) + ExprKind::Let { varlist, in_block } => BoxDoc::text("(") + .append("let") .append(BoxDoc::space()) .append(BoxDoc::text("[")) .append( BoxDoc::intersperse( - varlist.into_iter().map(|(var, ty, expr)| { - BoxDoc::text(var.as_str()) - .append(if let Some(ty) = ty { - BoxDoc::space() - .append(self.print_ty(ty)) - .nest((var.as_str().len() + 1) as isize) - } else { - BoxDoc::nil() - }) - .append( - BoxDoc::space() - .append(self.print_expr(expr)) - .nest((var.as_str().len() + 1) as isize), - ) - .group() + varlist.into_iter().map(|(is_mut, var, ty, expr)| { + if is_mut { + BoxDoc::text("(mut").append(BoxDoc::space()) + } else { + BoxDoc::nil() + } + .append(BoxDoc::text(var.as_str())) + .append(if is_mut { + BoxDoc::text(")") + } else { + BoxDoc::nil() + }) + .append(if let Some(ty) = ty { + BoxDoc::space() + .append(self.print_ty(ty)) + .nest((var.as_str().len() + 1) as isize) + } else { + BoxDoc::nil() + }) + .append( + BoxDoc::space() + .append(self.print_expr(expr)) + .nest((var.as_str().len() + 1) as isize), + ) + .group() }), BoxDoc::line(), ) - .nest(if is_mut { 10 } else { 6 }), + .nest(6), ) .append(BoxDoc::text("]")) .append( @@ -55,7 +56,7 @@ impl<'gcx> Printer<'gcx> { ) .append(BoxDoc::text(")")), ) - .nest(if is_mut { 9 } else { 5 }), + .nest(5), ), ExprKind::BinaryOp { left, kind, right } => { BoxDoc::text(format!("({}", self.print_binopkind(kind))) @@ -119,7 +120,7 @@ impl<'gcx> Printer<'gcx> { } } - pub fn print_ty(&self, ty: Id) -> BoxDoc { + pub fn print_ty(&self, ty: Ty) -> BoxDoc { let arena = &self.gcx.arenas.ast; match arena.ty(ty).kind { TyKind::Primitive(Primitive::Bool) => BoxDoc::text("bool"),