holey-bytes/hblang/src/parser.rs

1681 lines
52 KiB
Rust
Raw Normal View History

2024-07-08 00:22:53 -05:00
use {
crate::{
ident::{self, Ident},
2024-09-01 14:15:29 -05:00
lexer::{self, Lexer, Token, TokenKind},
2024-07-08 00:22:53 -05:00
},
2024-09-30 12:09:17 -05:00
alloc::{boxed::Box, string::String, vec::Vec},
core::{
cell::UnsafeCell,
2024-10-01 08:28:18 -05:00
fmt::{self},
marker::PhantomData,
ops::Deref,
2024-07-08 00:22:53 -05:00
ptr::NonNull,
sync::atomic::AtomicUsize,
},
2024-10-01 08:28:18 -05:00
std::intrinsics::unlikely,
2024-05-12 04:52:58 -05:00
};
2024-05-12 16:19:45 -05:00
pub type Pos = u32;
pub type IdentFlags = u32;
2024-05-17 12:53:59 -05:00
pub type Symbols = Vec<Symbol>;
pub type FileId = u32;
2024-07-08 00:22:53 -05:00
pub type IdentIndex = u16;
2024-09-30 12:09:17 -05:00
pub type LoaderError = String;
pub type Loader<'a> = &'a (dyn Fn(&str, &str) -> Result<FileId, LoaderError> + 'a);
2024-05-20 07:11:58 -05:00
pub mod idfl {
use super::*;
2024-05-17 12:53:59 -05:00
2024-05-20 07:11:58 -05:00
macro_rules! flags {
($($name:ident,)*) => {
2024-09-30 12:09:17 -05:00
$(pub const $name: IdentFlags = 1 << (core::mem::size_of::<IdentFlags>() * 8 - 1 - ${index(0)});)*
2024-05-20 07:11:58 -05:00
pub const ALL: IdentFlags = 0 $(| $name)*;
};
2024-05-17 12:53:59 -05:00
}
2024-05-20 07:11:58 -05:00
flags! {
MUTABLE,
REFERENCED,
2024-06-01 13:30:07 -05:00
COMPTIME,
2024-05-17 12:53:59 -05:00
}
}
2024-09-30 12:09:17 -05:00
pub fn no_loader(_: &str, _: &str) -> Result<FileId, LoaderError> {
Err(String::new())
2024-05-17 12:53:59 -05:00
}
2024-05-19 11:20:42 -05:00
#[derive(Debug)]
2024-05-17 12:53:59 -05:00
pub struct Symbol {
2024-07-08 00:22:53 -05:00
pub name: Ident,
2024-05-17 12:53:59 -05:00
pub flags: IdentFlags,
}
2024-06-01 13:30:07 -05:00
#[derive(Clone, Copy)]
2024-05-17 12:53:59 -05:00
struct ScopeIdent {
2024-07-08 00:22:53 -05:00
ident: Ident,
2024-05-12 04:52:58 -05:00
declared: bool,
2024-07-08 00:22:53 -05:00
flags: IdentFlags,
2024-05-12 04:52:58 -05:00
}
2024-05-09 16:41:59 -05:00
pub struct Parser<'a, 'b> {
2024-07-08 00:22:53 -05:00
path: &'b str,
loader: Loader<'b>,
2024-10-01 08:28:18 -05:00
lexer: Lexer<'a>,
2024-07-08 00:22:53 -05:00
arena: &'b Arena<'a>,
token: Token,
symbols: &'b mut Symbols,
2024-10-01 08:28:18 -05:00
stack: &'b mut StackAlloc,
2024-07-08 00:22:53 -05:00
ns_bound: usize,
2024-06-25 14:41:12 -05:00
trailing_sep: bool,
2024-09-22 11:17:30 -05:00
packed: bool,
2024-07-08 00:22:53 -05:00
idents: Vec<ScopeIdent>,
captured: Vec<Ident>,
2024-05-09 16:41:59 -05:00
}
impl<'a, 'b> Parser<'a, 'b> {
2024-10-01 08:28:18 -05:00
pub fn new(
arena: &'b Arena<'a>,
symbols: &'b mut Symbols,
stack: &'b mut StackAlloc,
loader: Loader<'b>,
) -> Self {
2024-05-13 02:38:33 -05:00
let mut lexer = Lexer::new("");
Self {
2024-05-17 12:53:59 -05:00
loader,
token: lexer.next(),
lexer,
2024-05-13 02:38:33 -05:00
path: "",
arena,
2024-05-17 12:53:59 -05:00
symbols,
2024-10-01 08:28:18 -05:00
stack,
2024-05-20 07:11:58 -05:00
ns_bound: 0,
2024-06-25 14:41:12 -05:00
trailing_sep: false,
2024-09-22 11:17:30 -05:00
packed: false,
2024-06-01 13:30:07 -05:00
idents: Vec::new(),
2024-05-20 07:11:58 -05:00
captured: Vec::new(),
}
2024-05-09 16:41:59 -05:00
}
2024-10-01 08:28:18 -05:00
pub fn file(&mut self, input: &'a str, path: &'b str) -> &'a [Expr<'a>] {
2024-05-13 02:38:33 -05:00
self.path = path;
self.lexer = Lexer::new(input);
self.token = self.lexer.next();
2024-07-08 00:22:53 -05:00
let f = self.collect_list(TokenKind::Semi, TokenKind::Eof, |s| s.expr_low(true));
2024-05-17 12:53:59 -05:00
2024-05-12 04:52:58 -05:00
self.pop_scope(0);
2024-09-18 02:47:52 -05:00
let mut errors = String::new();
2024-05-12 04:52:58 -05:00
for id in self.idents.drain(..) {
2024-09-18 02:47:52 -05:00
report_to(
self.lexer.source(),
2024-05-12 17:02:32 -05:00
self.path,
2024-09-20 04:01:10 -05:00
ident::pos(id.ident),
2024-09-18 02:47:52 -05:00
format_args!("undeclared identifier: {}", self.lexer.slice(ident::range(id.ident))),
&mut errors,
2024-05-12 04:52:58 -05:00
);
}
2024-09-18 02:47:52 -05:00
if !errors.is_empty() {
2024-05-17 12:53:59 -05:00
// TODO: we need error recovery
2024-09-30 12:27:00 -05:00
log::error!("{errors}");
2024-05-12 04:52:58 -05:00
unreachable!();
}
f
2024-05-09 16:41:59 -05:00
}
fn next(&mut self) -> Token {
2024-09-30 12:09:17 -05:00
core::mem::replace(&mut self.token, self.lexer.next())
2024-05-09 16:41:59 -05:00
}
fn ptr_expr(&mut self) -> &'a Expr<'a> {
self.arena.alloc(self.expr())
2024-05-09 16:41:59 -05:00
}
2024-07-08 00:22:53 -05:00
fn expr_low(&mut self, top_level: bool) -> Expr<'a> {
2024-05-10 15:54:12 -05:00
let left = self.unit_expr();
2024-07-08 00:22:53 -05:00
self.bin_expr(left, 0, top_level)
}
fn expr(&mut self) -> Expr<'a> {
self.expr_low(false)
2024-05-10 15:54:12 -05:00
}
2024-07-08 00:22:53 -05:00
fn bin_expr(&mut self, mut fold: Expr<'a>, min_prec: u8, top_level: bool) -> Expr<'a> {
2024-05-10 15:54:12 -05:00
loop {
let Some(prec) = self.token.kind.precedence() else {
break;
};
2024-05-13 06:36:29 -05:00
if prec <= min_prec {
2024-05-10 15:54:12 -05:00
break;
}
2024-06-24 10:26:00 -05:00
let checkpoint = self.token.start;
2024-05-10 15:54:12 -05:00
let op = self.next().kind;
2024-06-01 13:30:07 -05:00
2024-07-08 00:22:53 -05:00
if op == TokenKind::Decl {
self.declare_rec(&fold, top_level);
}
let op_ass = op.ass_op().map(|op| {
2024-06-24 10:26:00 -05:00
// this abomination reparses the left side, so that the desubaring adheres to the
// parser invariants.
let source = self.lexer.slice(0..checkpoint as usize);
let prev_lexer =
2024-09-30 12:09:17 -05:00
core::mem::replace(&mut self.lexer, Lexer::restore(source, fold.pos()));
let prev_token = core::mem::replace(&mut self.token, self.lexer.next());
2024-06-24 10:26:00 -05:00
let clone = self.expr();
self.lexer = prev_lexer;
self.token = prev_token;
(op, clone)
});
2024-05-10 15:54:12 -05:00
let right = self.unit_expr();
2024-07-08 00:22:53 -05:00
let right = self.bin_expr(right, prec, false);
2024-06-01 13:30:07 -05:00
let right = self.arena.alloc(right);
let left = self.arena.alloc(fold);
2024-05-15 03:37:39 -05:00
2024-06-24 10:26:00 -05:00
if let Some((op, clone)) = op_ass {
2024-05-20 07:11:58 -05:00
self.flag_idents(*left, idfl::MUTABLE);
2024-06-24 10:26:00 -05:00
2024-07-08 00:22:53 -05:00
let right = Expr::BinOp { left: self.arena.alloc(clone), op, right };
fold = Expr::BinOp { left, op: TokenKind::Assign, right: self.arena.alloc(right) };
2024-05-15 03:37:39 -05:00
} else {
fold = Expr::BinOp { left, right, op };
if op == TokenKind::Assign {
2024-05-20 07:11:58 -05:00
self.flag_idents(*left, idfl::MUTABLE);
}
2024-05-15 03:37:39 -05:00
}
2024-05-10 15:54:12 -05:00
}
2024-05-15 03:37:39 -05:00
fold
2024-05-10 15:54:12 -05:00
}
2024-07-08 00:22:53 -05:00
fn declare_rec(&mut self, expr: &Expr, top_level: bool) {
match *expr {
2024-09-20 09:37:51 -05:00
Expr::Ident { pos, id, is_first, .. } => self.declare(pos, id, is_first || top_level),
2024-07-08 00:22:53 -05:00
Expr::Ctor { fields, .. } => {
for CtorField { value, .. } in fields {
self.declare_rec(value, top_level)
}
}
2024-09-18 02:47:52 -05:00
_ => self.report(expr.pos(), "cant declare this shit (yet)"),
2024-07-08 00:22:53 -05:00
}
}
2024-09-20 09:37:51 -05:00
fn declare(&mut self, pos: Pos, id: Ident, valid_order: bool) {
if !valid_order {
2024-09-18 02:47:52 -05:00
self.report(
2024-07-08 00:22:53 -05:00
pos,
format_args!(
"out of order declaration not allowed: {}",
self.lexer.slice(ident::range(id))
),
);
}
let index = self.idents.binary_search_by_key(&id, |s| s.ident).expect("fck up");
2024-09-30 12:09:17 -05:00
if core::mem::replace(&mut self.idents[index].declared, true) {
2024-09-18 02:47:52 -05:00
self.report(
2024-07-08 00:22:53 -05:00
pos,
format_args!("redeclaration of identifier: {}", self.lexer.slice(ident::range(id))),
)
}
}
2024-09-20 09:37:51 -05:00
fn resolve_ident(&mut self, token: Token) -> (Ident, bool) {
2024-06-24 10:26:00 -05:00
let is_ct = token.kind == TokenKind::CtIdent;
2024-05-12 04:52:58 -05:00
let name = self.lexer.slice(token.range());
if let Some(builtin) = crate::ty::from_str(name) {
2024-09-20 09:37:51 -05:00
return (builtin, false);
2024-05-12 04:52:58 -05:00
}
2024-09-20 09:37:51 -05:00
let (i, id, bl) = match self
2024-05-12 04:52:58 -05:00
.idents
.iter_mut()
2024-05-20 07:11:58 -05:00
.enumerate()
.rfind(|(_, elem)| self.lexer.slice(ident::range(elem.ident)) == name)
2024-05-12 04:52:58 -05:00
{
2024-09-20 09:37:51 -05:00
Some((i, elem)) => (i, elem, false),
2024-05-12 04:52:58 -05:00
None => {
let id = ident::new(token.start, name.len() as _);
2024-07-08 00:22:53 -05:00
self.idents.push(ScopeIdent { ident: id, declared: false, flags: 0 });
2024-09-20 09:37:51 -05:00
(self.idents.len() - 1, self.idents.last_mut().unwrap(), true)
2024-05-12 04:52:58 -05:00
}
};
2024-06-01 13:30:07 -05:00
id.flags |= idfl::COMPTIME * is_ct as u32;
if id.declared && self.ns_bound > i {
id.flags |= idfl::COMPTIME;
2024-05-20 07:11:58 -05:00
self.captured.push(id.ident);
}
2024-05-12 04:52:58 -05:00
2024-09-20 09:37:51 -05:00
(id.ident, bl)
2024-05-17 12:53:59 -05:00
}
2024-10-01 08:28:18 -05:00
fn tok_str(&mut self, range: Token) -> &'a str {
self.lexer.slice(range.range())
2024-05-12 04:52:58 -05:00
}
2024-05-10 15:54:12 -05:00
fn unit_expr(&mut self) -> Expr<'a> {
2024-05-11 15:22:08 -05:00
use {Expr as E, TokenKind as T};
2024-05-12 04:52:58 -05:00
let frame = self.idents.len();
let token @ Token { start: pos, .. } = self.next();
2024-05-20 07:11:58 -05:00
let prev_boundary = self.ns_bound;
let prev_captured = self.captured.len();
2024-05-11 09:04:13 -05:00
let mut expr = match token.kind {
T::Ct => E::Ct { pos, value: self.ptr_expr() },
2024-06-25 11:39:59 -05:00
T::Directive if self.lexer.slice(token.range()) == "use" => {
2024-05-19 11:20:42 -05:00
self.expect_advance(TokenKind::LParen);
2024-07-06 08:05:56 -05:00
let str = self.expect_advance(TokenKind::DQuote);
2024-05-19 11:20:42 -05:00
self.expect_advance(TokenKind::RParen);
let path = self.lexer.slice(str.range()).trim_matches('"');
E::Mod {
pos,
2024-05-19 11:20:42 -05:00
path: self.arena.alloc_str(path),
2024-07-08 00:22:53 -05:00
id: match (self.loader)(path, self.path) {
2024-05-19 11:20:42 -05:00
Ok(id) => id,
2024-09-18 02:47:52 -05:00
Err(e) => {
self.report(str.start, format_args!("error loading dependency: {e:#}"))
}
2024-05-19 11:20:42 -05:00
},
}
}
2024-06-25 11:39:59 -05:00
T::Directive => E::Directive {
2024-09-15 13:14:56 -05:00
pos: pos - 1, // need to undo the directive shift
2024-10-01 08:28:18 -05:00
name: self.tok_str(token),
2024-05-14 16:07:32 -05:00
args: {
self.expect_advance(T::LParen);
self.collect_list(T::Comma, T::RParen, Self::expr)
},
},
T::True => E::Bool { pos, value: true },
T::False => E::Bool { pos, value: false },
T::Idk => E::Idk { pos },
2024-10-01 08:28:18 -05:00
T::DQuote => E::String { pos, literal: self.tok_str(token) },
2024-09-22 11:17:30 -05:00
T::Packed => {
self.packed = true;
let expr = self.unit_expr();
if self.packed {
self.report(
expr.pos(),
"this can not be packed \
(unlike your mom that gets packed every day by me)",
);
}
expr
}
2024-05-12 05:16:40 -05:00
T::Struct => E::Struct {
2024-09-30 12:09:17 -05:00
packed: core::mem::take(&mut self.packed),
2024-07-08 00:22:53 -05:00
fields: {
2024-05-20 07:11:58 -05:00
self.ns_bound = self.idents.len();
2024-05-12 05:16:40 -05:00
self.expect_advance(T::LBrace);
self.collect_list(T::Comma, T::RBrace, |s| {
let tok = s.token;
if s.advance_if(T::Comment) {
2024-10-01 08:28:18 -05:00
CommentOr::Comment { literal: s.tok_str(tok), pos: tok.start }
} else {
let name = s.expect_advance(T::Ident);
s.expect_advance(T::Colon);
CommentOr::Or(StructField {
pos: name.start,
2024-10-01 08:28:18 -05:00
name: s.tok_str(name),
ty: s.expr(),
})
}
2024-05-12 05:16:40 -05:00
})
},
2024-05-20 07:11:58 -05:00
captured: {
self.ns_bound = prev_boundary;
self.captured[prev_captured..].sort_unstable();
let preserved = self.captured[prev_captured..].partition_dedup().0.len();
self.captured.truncate(prev_captured + preserved);
self.arena.alloc_slice(&self.captured[prev_captured..])
},
2024-07-08 00:22:53 -05:00
pos: {
2024-05-20 07:11:58 -05:00
if self.ns_bound == 0 {
// we might save some memory
self.captured.clear();
}
pos
2024-05-20 07:11:58 -05:00
},
2024-09-30 12:09:17 -05:00
trailing_comma: core::mem::take(&mut self.trailing_sep),
2024-05-12 05:16:40 -05:00
},
2024-06-01 13:30:07 -05:00
T::Ident | T::CtIdent => {
2024-09-20 09:37:51 -05:00
let (id, is_first) = self.resolve_ident(token);
2024-10-01 08:28:18 -05:00
let name = self.tok_str(token);
2024-09-20 09:37:51 -05:00
E::Ident { pos, is_ct: token.kind == T::CtIdent, name, id, is_first }
2024-05-12 04:52:58 -05:00
}
2024-05-11 15:22:08 -05:00
T::If => E::If {
pos,
2024-07-08 00:22:53 -05:00
cond: self.ptr_expr(),
then: self.ptr_expr(),
2024-05-11 15:22:08 -05:00
else_: self.advance_if(T::Else).then(|| self.ptr_expr()),
},
T::Loop => E::Loop { pos, body: self.ptr_expr() },
T::Break => E::Break { pos },
T::Continue => E::Continue { pos },
2024-05-11 15:22:08 -05:00
T::Return => E::Return {
pos,
2024-07-19 06:44:35 -05:00
val: (!matches!(
self.token.kind,
T::Semi | T::RBrace | T::RBrack | T::RParen | T::Comma
))
.then(|| self.ptr_expr()),
2024-05-09 16:41:59 -05:00
},
2024-05-11 15:22:08 -05:00
T::Fn => E::Closure {
pos,
2024-05-11 15:22:08 -05:00
args: {
self.expect_advance(T::LParen);
self.collect_list(T::Comma, T::RParen, |s| {
2024-06-01 13:30:07 -05:00
let name = s.advance_ident();
2024-09-20 09:37:51 -05:00
let (id, _) = s.resolve_ident(name);
s.declare(name.start, id, true);
2024-05-11 15:22:08 -05:00
s.expect_advance(T::Colon);
2024-07-19 14:04:22 -05:00
Arg {
pos: name.start,
2024-10-01 08:28:18 -05:00
name: s.tok_str(name),
2024-07-19 14:04:22 -05:00
is_ct: name.kind == T::CtIdent,
id,
ty: s.expr(),
}
2024-05-11 09:04:13 -05:00
})
2024-05-11 15:22:08 -05:00
},
2024-07-08 00:22:53 -05:00
ret: {
2024-05-11 15:22:08 -05:00
self.expect_advance(T::Colon);
self.ptr_expr()
},
body: self.ptr_expr(),
},
T::Ctor => self.ctor(pos, None),
T::Tupl => self.tupl(pos, None),
2024-07-08 11:08:58 -05:00
T::LBrack => E::Slice {
item: self.ptr_unit_expr(),
size: self.advance_if(T::Semi).then(|| self.ptr_expr()),
pos: {
self.expect_advance(T::RBrack);
pos
2024-07-08 11:08:58 -05:00
},
},
2024-09-14 04:26:54 -05:00
T::Band | T::Mul | T::Xor | T::Sub => E::UnOp {
pos,
2024-07-08 00:22:53 -05:00
op: token.kind,
2024-05-17 12:53:59 -05:00
val: {
2024-07-08 11:08:58 -05:00
let expr = self.ptr_unit_expr();
2024-05-19 11:20:42 -05:00
if token.kind == T::Band {
2024-05-20 07:11:58 -05:00
self.flag_idents(*expr, idfl::REFERENCED);
2024-05-19 11:20:42 -05:00
}
2024-05-17 12:53:59 -05:00
expr
},
2024-05-12 04:52:58 -05:00
},
T::LBrace => E::Block { pos, stmts: self.collect_list(T::Semi, T::RBrace, Self::expr) },
T::Number => {
let slice = self.lexer.slice(token.range());
let (slice, radix) = match &slice.get(0..2) {
Some("0x") => (slice.trim_start_matches("0x"), Radix::Hex),
Some("0b") => (slice.trim_start_matches("0b"), Radix::Binary),
Some("0o") => (slice.trim_start_matches("0o"), Radix::Octal),
_ => (slice, Radix::Decimal),
};
E::Number {
pos,
2024-09-04 10:13:43 -05:00
value: match u64::from_str_radix(slice, radix as u32) {
2024-09-01 12:42:04 -05:00
Ok(value) => value,
2024-09-18 02:47:52 -05:00
Err(e) => self.report(token.start, format_args!("invalid number: {e}")),
2024-09-04 10:13:43 -05:00
} as i64,
radix,
}
}
2024-05-11 15:22:08 -05:00
T::LParen => {
2024-05-10 15:54:12 -05:00
let expr = self.expr();
2024-05-11 15:22:08 -05:00
self.expect_advance(T::RParen);
2024-05-10 15:54:12 -05:00
expr
}
2024-10-01 08:28:18 -05:00
T::Comment => Expr::Comment { pos, literal: self.tok_str(token) },
2024-09-18 02:47:52 -05:00
tok => self.report(token.start, format_args!("unexpected token: {tok:?}")),
2024-05-09 16:41:59 -05:00
};
2024-05-11 09:04:13 -05:00
loop {
2024-05-14 05:17:39 -05:00
let token = self.token;
2024-07-08 11:08:58 -05:00
if matches!(token.kind, T::LParen | T::Ctor | T::Dot | T::Tupl | T::LBrack) {
2024-05-12 05:16:40 -05:00
self.next();
}
2024-05-14 05:17:39 -05:00
expr = match token.kind {
2024-05-12 05:16:40 -05:00
T::LParen => Expr::Call {
func: self.arena.alloc(expr),
2024-05-17 12:53:59 -05:00
args: self.collect_list(T::Comma, T::RParen, Self::expr),
2024-09-30 12:09:17 -05:00
trailing_comma: core::mem::take(&mut self.trailing_sep),
2024-05-12 05:16:40 -05:00
},
2024-07-07 12:16:15 -05:00
T::Ctor => self.ctor(token.start, Some(expr)),
T::Tupl => self.tupl(token.start, Some(expr)),
2024-07-08 11:08:58 -05:00
T::LBrack => E::Index {
base: self.arena.alloc(expr),
index: {
let index = self.expr();
self.expect_advance(T::RBrack);
self.arena.alloc(index)
},
},
2024-05-12 05:16:40 -05:00
T::Dot => E::Field {
2024-05-12 06:13:36 -05:00
target: self.arena.alloc(expr),
2024-09-30 12:09:17 -05:00
pos: token.start,
2024-07-08 00:22:53 -05:00
name: {
2024-05-12 05:16:40 -05:00
let token = self.expect_advance(T::Ident);
2024-10-01 08:28:18 -05:00
self.tok_str(token)
2024-05-12 05:16:40 -05:00
},
},
2024-05-11 09:04:13 -05:00
_ => break,
}
}
2024-05-12 04:52:58 -05:00
if matches!(token.kind, T::Loop | T::LBrace | T::Fn) {
self.pop_scope(frame);
}
2024-05-09 16:41:59 -05:00
expr
}
2024-07-07 12:16:15 -05:00
fn tupl(&mut self, pos: Pos, ty: Option<Expr<'a>>) -> Expr<'a> {
Expr::Tupl {
pos,
ty: ty.map(|ty| self.arena.alloc(ty)),
fields: self.collect_list(TokenKind::Comma, TokenKind::RParen, Self::expr),
2024-09-30 12:09:17 -05:00
trailing_comma: core::mem::take(&mut self.trailing_sep),
2024-07-07 12:16:15 -05:00
}
}
fn ctor(&mut self, pos: Pos, ty: Option<Expr<'a>>) -> Expr<'a> {
Expr::Ctor {
pos,
ty: ty.map(|ty| self.arena.alloc(ty)),
fields: self.collect_list(TokenKind::Comma, TokenKind::RBrace, |s| {
2024-07-08 00:22:53 -05:00
let name_tok = s.advance_ident();
2024-10-01 08:28:18 -05:00
let name = s.tok_str(name_tok);
2024-07-08 00:22:53 -05:00
CtorField {
pos: name_tok.start,
name,
value: if s.advance_if(TokenKind::Colon) {
s.expr()
} else {
2024-09-20 09:37:51 -05:00
let (id, is_first) = s.resolve_ident(name_tok);
Expr::Ident { pos: name_tok.start, is_ct: false, id, name, is_first }
2024-07-08 00:22:53 -05:00
},
}
2024-07-07 12:16:15 -05:00
}),
2024-09-30 12:09:17 -05:00
trailing_comma: core::mem::take(&mut self.trailing_sep),
2024-07-07 12:16:15 -05:00
}
}
2024-06-01 13:30:07 -05:00
fn advance_ident(&mut self) -> Token {
if matches!(self.token.kind, TokenKind::Ident | TokenKind::CtIdent) {
self.next()
} else {
2024-09-18 02:47:52 -05:00
self.report(
self.token.start,
format_args!("expected identifier, found {:?}", self.token.kind),
)
2024-06-01 13:30:07 -05:00
}
}
2024-05-12 04:52:58 -05:00
fn pop_scope(&mut self, frame: usize) {
let mut undeclared_count = frame;
for i in frame..self.idents.len() {
2024-06-01 13:30:07 -05:00
if !&self.idents[i].declared {
2024-05-12 04:52:58 -05:00
self.idents.swap(i, undeclared_count);
undeclared_count += 1;
}
}
2024-05-17 12:53:59 -05:00
self.idents
.drain(undeclared_count..)
2024-07-08 00:22:53 -05:00
.map(|ident| Symbol { name: ident.ident, flags: ident.flags })
2024-05-17 12:53:59 -05:00
.collect_into(self.symbols);
2024-05-12 04:52:58 -05:00
}
fn ptr_unit_expr(&mut self) -> &'a Expr<'a> {
self.arena.alloc(self.unit_expr())
}
2024-05-11 15:22:08 -05:00
fn collect_list<T: Copy>(
&mut self,
delim: TokenKind,
end: TokenKind,
mut f: impl FnMut(&mut Self) -> T,
) -> &'a [T] {
2024-10-01 08:28:18 -05:00
let mut view = self.stack.view();
while !self.advance_if(end) {
let val = f(self);
self.trailing_sep = self.advance_if(delim);
unsafe { self.stack.push(&mut view, val) };
}
self.arena.alloc_slice(unsafe { self.stack.finalize(view) })
}
2024-05-09 16:41:59 -05:00
fn advance_if(&mut self, kind: TokenKind) -> bool {
if self.token.kind == kind {
self.next();
true
} else {
false
}
}
2024-05-11 09:04:13 -05:00
fn expect_advance(&mut self, kind: TokenKind) -> Token {
2024-05-09 16:41:59 -05:00
if self.token.kind != kind {
2024-09-18 02:47:52 -05:00
self.report(
self.token.start,
format_args!("expected {:?}, found {:?}", kind, self.token.kind),
);
2024-05-09 16:41:59 -05:00
}
2024-05-11 09:04:13 -05:00
self.next()
2024-05-09 16:41:59 -05:00
}
2024-06-01 13:30:07 -05:00
#[track_caller]
2024-09-18 02:47:52 -05:00
fn report(&self, pos: Pos, msg: impl fmt::Display) -> ! {
let mut str = String::new();
report_to(self.lexer.source(), self.path, pos, msg, &mut str);
2024-09-30 12:27:00 -05:00
log::error!("{str}");
2024-05-09 16:41:59 -05:00
unreachable!();
}
2024-05-17 12:53:59 -05:00
fn flag_idents(&mut self, e: Expr<'a>, flags: IdentFlags) {
match e {
Expr::Ident { id, .. } => find_ident(&mut self.idents, id).flags |= flags,
Expr::Field { target, .. } => self.flag_idents(*target, flags),
_ => {}
}
}
2024-05-09 16:41:59 -05:00
}
2024-05-17 12:53:59 -05:00
fn find_ident(idents: &mut [ScopeIdent], id: Ident) -> &mut ScopeIdent {
2024-07-08 00:22:53 -05:00
idents.binary_search_by_key(&id, |si| si.ident).map(|i| &mut idents[i]).unwrap()
2024-05-17 12:53:59 -05:00
}
pub fn find_symbol(symbols: &[Symbol], id: Ident) -> &Symbol {
2024-07-08 00:22:53 -05:00
symbols.binary_search_by_key(&id, |s| s.name).map(|i| &symbols[i]).unwrap()
2024-05-17 12:53:59 -05:00
}
2024-05-12 04:52:58 -05:00
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Arg<'a> {
pub pos: u32,
2024-07-08 00:22:53 -05:00
pub name: &'a str,
pub id: Ident,
2024-07-19 14:04:22 -05:00
pub is_ct: bool,
2024-07-08 00:22:53 -05:00
pub ty: Expr<'a>,
2024-05-12 04:52:58 -05:00
}
impl Poser for Arg<'_> {
fn posi(&self) -> Pos {
self.pos
}
}
2024-06-01 13:30:07 -05:00
macro_rules! generate_expr {
($(#[$meta:meta])* $vis:vis enum $name:ident<$lt:lifetime> {$(
$(#[$field_meta:meta])*
$variant:ident {
2024-09-03 10:51:28 -05:00
2024-06-01 13:30:07 -05:00
$($field:ident: $ty:ty,)*
},
)*}) => {
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
$vis enum $name<$lt> {$(
2024-09-03 10:51:28 -05:00
$(#[$field_meta])*
2024-06-01 13:30:07 -05:00
$variant {
$($field: $ty,)*
},
)*}
impl<$lt> $name<$lt> {
pub fn pos(&self) -> Pos {
#[allow(unused_variables)]
match self {
2024-06-24 10:26:00 -05:00
$(Self::$variant { $($field),* } => generate_expr!(@first $(($field),)*).posi(),)*
2024-06-01 13:30:07 -05:00
}
}
2024-07-19 14:04:22 -05:00
pub fn used_bytes(&self) -> usize {
match self {$(
Self::$variant { $($field,)* } => {
#[allow(clippy::size_of_ref)]
2024-09-30 12:09:17 -05:00
let fields = [$(($field as *const _ as usize - self as *const _ as usize, core::mem::size_of_val($field)),)*];
2024-07-19 14:04:22 -05:00
let (last, size) = fields.iter().copied().max().unwrap();
last + size
},
)*}
}
2024-06-01 13:30:07 -05:00
}
};
2024-07-19 14:04:22 -05:00
(@filed_names $variant:ident $ident1:ident) => { Self::$variant { $ident1: a } };
2024-06-01 13:30:07 -05:00
(@first ($($first:tt)*), $($rest:tt)*) => { $($first)* };
(@last ($($ign:tt)*), $($rest:tt)*) => { $($rest)* };
(@last ($($last:tt)*),) => { $($last)* };
}
#[repr(u32)]
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum Radix {
Hex = 16,
Octal = 8,
Binary = 2,
Decimal = 10,
}
2024-06-01 13:30:07 -05:00
generate_expr! {
2024-09-03 10:51:28 -05:00
/// `LIST(start, sep, end, elem) => start { elem sep } [elem] end`
/// `OP := grep for `#define OP:`
2024-06-01 13:30:07 -05:00
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Expr<'a> {
2024-09-03 10:51:28 -05:00
/// `'ct' Expr`
Ct {
pos: Pos,
2024-07-19 14:04:22 -05:00
value: &'a Self,
},
2024-09-03 10:51:28 -05:00
/// `'"([^"]|\\")"'`
2024-07-02 07:49:05 -05:00
String {
pos: Pos,
literal: &'a str,
},
2024-09-03 10:51:28 -05:00
/// `'//[^\n]' | '/*' { '([^/*]|*/)*' | Comment } '*/'
2024-06-25 12:55:25 -05:00
Comment {
pos: Pos,
literal: &'a str,
},
2024-09-03 10:51:28 -05:00
/// `'break'`
2024-06-01 13:30:07 -05:00
Break {
pos: Pos,
},
2024-09-03 10:51:28 -05:00
/// `'continue'`
2024-06-01 13:30:07 -05:00
Continue {
pos: Pos,
},
2024-09-03 10:51:28 -05:00
/// `'fn' LIST('(', ',', ')', Ident ':' Expr) ':' Expr Expr`
2024-06-01 13:30:07 -05:00
Closure {
pos: Pos,
args: &'a [Arg<'a>],
ret: &'a Self,
body: &'a Self,
},
2024-09-03 10:51:28 -05:00
/// `Expr LIST('(', ',', ')', Expr)`
2024-06-01 13:30:07 -05:00
Call {
func: &'a Self,
args: &'a [Self],
2024-06-25 14:41:12 -05:00
trailing_comma: bool,
2024-06-01 13:30:07 -05:00
},
2024-09-03 10:51:28 -05:00
/// `'return' [Expr]`
2024-06-01 13:30:07 -05:00
Return {
pos: Pos,
val: Option<&'a Self>,
},
2024-09-03 10:51:28 -05:00
/// note: ':unicode:' is any utf-8 character except ascii
/// `'[a-zA-Z_:unicode:][a-zA-Z0-9_:unicode:]*'`
2024-06-01 13:30:07 -05:00
Ident {
2024-09-20 09:37:51 -05:00
pos: Pos,
2024-07-19 14:04:22 -05:00
is_ct: bool,
2024-09-20 09:37:51 -05:00
is_first: bool,
id: Ident,
name: &'a str,
2024-06-01 13:30:07 -05:00
},
2024-09-03 10:51:28 -05:00
/// `LIST('{', [';'], '}', Expr)`
2024-06-01 13:30:07 -05:00
Block {
pos: Pos,
stmts: &'a [Self],
},
2024-09-03 10:51:28 -05:00
/// `'0b[01]+' | '0o[0-7]+' | '[0-9]+' | '0b[01]+'`
2024-06-01 13:30:07 -05:00
Number {
pos: Pos,
2024-09-03 10:51:28 -05:00
value: i64,
radix: Radix,
2024-06-01 13:30:07 -05:00
},
2024-09-03 10:51:28 -05:00
/// node: precedence defined in `OP` applies
/// `Expr OP Expr`
2024-06-01 13:30:07 -05:00
BinOp {
left: &'a Self,
op: TokenKind,
right: &'a Self,
},
2024-09-03 10:51:28 -05:00
/// `'if' Expr Expr [else Expr]`
2024-06-01 13:30:07 -05:00
If {
pos: Pos,
cond: &'a Self,
then: &'a Self,
else_: Option<&'a Self>,
},
2024-09-03 10:51:28 -05:00
/// `'loop' Expr`
2024-06-01 13:30:07 -05:00
Loop {
pos: Pos,
body: &'a Self,
},
2024-09-03 10:51:28 -05:00
/// `('&' | '*' | '^') Expr`
2024-06-01 13:30:07 -05:00
UnOp {
pos: Pos,
op: TokenKind,
val: &'a Self,
},
2024-09-03 10:51:28 -05:00
/// `'struct' LIST('{', ',', '}', Ident ':' Expr)`
2024-06-01 13:30:07 -05:00
Struct {
pos: Pos,
fields: &'a [CommentOr<'a, StructField<'a>>],
2024-06-01 13:30:07 -05:00
captured: &'a [Ident],
2024-07-19 14:04:22 -05:00
trailing_comma: bool,
2024-09-22 11:17:30 -05:00
packed: bool,
2024-06-01 13:30:07 -05:00
},
2024-09-03 10:51:28 -05:00
/// `[Expr] LIST('.{', ',', '}', Ident [':' Expr])`
2024-06-01 13:30:07 -05:00
Ctor {
pos: Pos,
ty: Option<&'a Self>,
2024-07-08 00:22:53 -05:00
fields: &'a [CtorField<'a>],
2024-07-07 12:16:15 -05:00
trailing_comma: bool,
},
2024-09-03 10:51:28 -05:00
/// `[Expr] LIST('.(', ',', ')', Ident [':' Expr])`
2024-07-07 12:16:15 -05:00
Tupl {
pos: Pos,
ty: Option<&'a Self>,
fields: &'a [Self],
2024-06-25 14:51:41 -05:00
trailing_comma: bool,
2024-06-01 13:30:07 -05:00
},
2024-09-03 10:51:28 -05:00
/// `'[' Expr [';' Expr] ']'`
2024-07-08 11:08:58 -05:00
Slice {
pos: Pos,
size: Option<&'a Self>,
item: &'a Self,
},
2024-09-03 10:51:28 -05:00
/// `Expr '[' Expr ']'`
2024-07-08 11:08:58 -05:00
Index {
base: &'a Self,
index: &'a Self,
},
2024-09-03 10:51:28 -05:00
/// `Expr '.' Ident`
2024-06-01 13:30:07 -05:00
Field {
target: &'a Self,
2024-09-30 12:09:17 -05:00
pos: Pos,
2024-07-08 00:22:53 -05:00
name: &'a str,
2024-06-01 13:30:07 -05:00
},
2024-09-03 10:51:28 -05:00
/// `'true' | 'false'`
2024-06-01 13:30:07 -05:00
Bool {
pos: Pos,
value: bool,
},
/// `'idk'`
Idk {
pos: Pos,
},
2024-09-03 10:51:28 -05:00
/// `'@' Ident List('(', ',', ')', Expr)`
2024-06-01 13:30:07 -05:00
Directive {
pos: u32,
name: &'a str,
args: &'a [Self],
},
2024-09-03 10:51:28 -05:00
/// `'@use' '(' String ')'`
2024-06-01 13:30:07 -05:00
Mod {
pos: Pos,
id: FileId,
path: &'a str,
},
}
}
2024-07-08 00:22:53 -05:00
impl<'a> Expr<'a> {
pub fn declares(&self, iden: Result<Ident, &str>) -> Option<Ident> {
match *self {
Self::Ident { id, name, .. } if iden == Ok(id) || iden == Err(name) => Some(id),
Self::Ctor { fields, .. } => fields.iter().find_map(|f| f.value.declares(iden)),
_ => None,
}
}
pub fn has_ct(&self, symbols: &[Symbol]) -> bool {
match *self {
Self::Ident { id, .. } => find_symbol(symbols, id).flags & idfl::COMPTIME != 0,
Self::Ctor { fields, .. } => fields.iter().any(|f| f.value.has_ct(symbols)),
_ => false,
}
}
2024-07-08 00:22:53 -05:00
pub fn find_pattern_path<F: FnOnce(&Expr)>(
&self,
ident: Ident,
target: &Expr,
mut with_final: F,
) -> Result<(), F> {
match *self {
Self::Ident { id, .. } if id == ident => {
with_final(target);
Ok(())
}
Self::Ctor { fields, .. } => {
2024-09-30 12:09:17 -05:00
for &CtorField { name, value, pos } in fields {
match value.find_pattern_path(
ident,
&Expr::Field { pos, target, name },
with_final,
) {
2024-07-08 00:22:53 -05:00
Ok(()) => return Ok(()),
Err(e) => with_final = e,
}
}
Err(with_final)
}
_ => Err(with_final),
}
}
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct StructField<'a> {
pub pos: Pos,
pub name: &'a str,
pub ty: Expr<'a>,
}
impl Poser for StructField<'_> {
fn posi(&self) -> Pos {
self.pos
}
}
2024-07-08 00:22:53 -05:00
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct CtorField<'a> {
pub pos: Pos,
pub name: &'a str,
pub value: Expr<'a>,
}
impl Poser for CtorField<'_> {
fn posi(&self) -> Pos {
self.pos
}
}
2024-06-01 13:30:07 -05:00
trait Poser {
fn posi(&self) -> Pos;
2024-05-09 16:41:59 -05:00
}
2024-06-01 13:30:07 -05:00
impl Poser for Pos {
fn posi(&self) -> Pos {
*self
2024-05-12 16:19:45 -05:00
}
}
impl<'a> Poser for Expr<'a> {
fn posi(&self) -> Pos {
2024-06-01 13:30:07 -05:00
self.pos()
}
}
impl<'a, T: Poser> Poser for CommentOr<'a, T> {
fn posi(&self) -> Pos {
match self {
CommentOr::Or(expr) => expr.posi(),
CommentOr::Comment { pos, .. } => *pos,
}
}
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum CommentOr<'a, T> {
Or(T),
Comment { literal: &'a str, pos: Pos },
}
impl<'a, T: Copy> CommentOr<'a, T> {
pub fn or(&self) -> Option<T> {
match *self {
CommentOr::Or(v) => Some(v),
CommentOr::Comment { .. } => None,
}
}
}
2024-10-01 08:28:18 -05:00
pub struct Display<'a> {
source: &'a str,
expr: &'a Expr<'a>,
}
impl<'a> Display<'a> {
pub fn new(source: &'a str, expr: &'a Expr<'a>) -> Self {
Self { source, expr }
}
}
impl core::fmt::Display for Display<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
Formatter::new(self.source).fmt(self.expr, f)
}
}
2024-09-30 12:09:17 -05:00
pub struct Formatter<'a> {
source: &'a str,
depth: usize,
disp_buff: String,
2024-06-25 14:41:12 -05:00
}
2024-09-30 12:09:17 -05:00
impl<'a> Formatter<'a> {
pub fn new(source: &'a str) -> Self {
Self { source, depth: 0, disp_buff: Default::default() }
}
2024-05-09 16:41:59 -05:00
2024-10-01 08:28:18 -05:00
fn fmt_list<T: Poser, F: core::fmt::Write>(
2024-09-30 12:09:17 -05:00
&mut self,
2024-10-01 08:28:18 -05:00
f: &mut F,
2024-09-30 12:09:17 -05:00
trailing: bool,
end: &str,
sep: &str,
list: &[T],
2024-10-01 08:28:18 -05:00
fmt: impl Fn(&mut Self, &T, &mut F) -> fmt::Result,
2024-09-30 12:09:17 -05:00
) -> fmt::Result {
self.fmt_list_low(f, trailing, end, sep, list, |s, v, f| {
fmt(s, v, f)?;
Ok(true)
})
}
2024-10-01 08:28:18 -05:00
fn fmt_list_low<T: Poser, F: core::fmt::Write>(
2024-09-30 12:09:17 -05:00
&mut self,
2024-10-01 08:28:18 -05:00
f: &mut F,
2024-09-30 12:09:17 -05:00
trailing: bool,
end: &str,
sep: &str,
list: &[T],
2024-10-01 08:28:18 -05:00
fmt: impl Fn(&mut Self, &T, &mut F) -> Result<bool, fmt::Error>,
2024-09-30 12:09:17 -05:00
) -> fmt::Result {
if !trailing {
let mut first = true;
for expr in list {
if !core::mem::take(&mut first) {
write!(f, "{sep} ")?;
2024-05-14 16:07:32 -05:00
}
2024-09-30 12:09:17 -05:00
first = !fmt(self, expr, f)?;
2024-05-14 16:07:32 -05:00
}
2024-09-30 12:09:17 -05:00
return write!(f, "{end}");
}
2024-05-14 16:07:32 -05:00
2024-09-30 12:09:17 -05:00
writeln!(f)?;
self.depth += 1;
let res = (|| {
for (i, stmt) in list.iter().enumerate() {
for _ in 0..self.depth {
write!(f, "\t")?;
}
let add_sep = fmt(self, stmt, f)?;
if add_sep {
write!(f, "{sep}")?;
}
if let Some(expr) = list.get(i + 1)
&& let Some(rest) = self.source.get(expr.posi() as usize..)
{
if insert_needed_semicolon(rest) {
write!(f, ";")?;
}
2024-09-30 12:09:17 -05:00
if preserve_newlines(&self.source[..expr.posi() as usize]) > 1 {
writeln!(f)?;
}
2024-06-25 14:41:12 -05:00
}
2024-09-30 12:09:17 -05:00
if add_sep {
writeln!(f)?;
}
2024-06-25 14:41:12 -05:00
}
2024-09-30 12:09:17 -05:00
Ok(())
})();
self.depth -= 1;
for _ in 0..self.depth {
write!(f, "\t")?;
2024-06-25 14:41:12 -05:00
}
2024-09-30 12:09:17 -05:00
write!(f, "{end}")?;
res
}
2024-10-01 08:28:18 -05:00
fn fmt_paren<F: core::fmt::Write>(
2024-09-30 12:09:17 -05:00
&mut self,
expr: &Expr,
2024-10-01 08:28:18 -05:00
f: &mut F,
2024-09-30 12:09:17 -05:00
cond: impl FnOnce(&Expr) -> bool,
) -> fmt::Result {
if cond(expr) {
write!(f, "(")?;
self.fmt(expr, f)?;
write!(f, ")")
} else {
self.fmt(expr, f)
}
}
2024-06-25 14:41:12 -05:00
2024-10-01 08:28:18 -05:00
pub fn fmt<F: core::fmt::Write>(&mut self, expr: &Expr, f: &mut F) -> fmt::Result {
macro_rules! impl_parenter {
($($name:ident => $pat:pat,)*) => {
$(
2024-09-30 12:09:17 -05:00
let $name = |e: &Expr| matches!(e, $pat);
)*
};
}
impl_parenter! {
2024-09-30 12:09:17 -05:00
unary => Expr::BinOp { .. },
postfix => Expr::UnOp { .. } | Expr::BinOp { .. },
consecutive => Expr::UnOp { .. },
}
2024-09-30 12:09:17 -05:00
match *expr {
Expr::Ct { value, .. } => {
write!(f, "$: ")?;
self.fmt(value, f)
}
Expr::String { literal, .. } => write!(f, "{literal}"),
Expr::Comment { literal, .. } => write!(f, "{}", literal.trim_end()),
Expr::Mod { path, .. } => write!(f, "@use(\"{path}\")"),
Expr::Field { target, name: field, .. } => {
self.fmt_paren(target, f, postfix)?;
write!(f, ".{field}")
}
Expr::Directive { name, args, .. } => {
2024-05-14 16:07:32 -05:00
write!(f, "@{name}(")?;
2024-09-30 12:09:17 -05:00
self.fmt_list(f, false, ")", ",", args, Self::fmt)
2024-05-14 16:07:32 -05:00
}
2024-09-30 12:09:17 -05:00
Expr::Struct { fields, trailing_comma, packed, .. } => {
2024-09-22 11:17:30 -05:00
if packed {
write!(f, "packed ")?;
}
2024-05-12 05:16:40 -05:00
write!(f, "struct {{")?;
2024-09-30 12:09:17 -05:00
self.fmt_list_low(f, trailing_comma, "}", ",", fields, |s, field, f| {
match field {
2024-09-30 12:09:17 -05:00
CommentOr::Or(StructField { name, ty, .. }) => {
write!(f, "{name}: ")?;
s.fmt(ty, f)?
}
CommentOr::Comment { literal, .. } => write!(f, "{literal}")?,
}
Ok(field.or().is_some())
2024-07-19 14:04:22 -05:00
})
2024-05-12 05:16:40 -05:00
}
2024-09-30 12:09:17 -05:00
Expr::Ctor { ty, fields, trailing_comma, .. } => {
2024-05-14 05:17:39 -05:00
if let Some(ty) = ty {
2024-09-30 12:09:17 -05:00
self.fmt_paren(ty, f, unary)?;
2024-05-14 05:17:39 -05:00
}
2024-07-07 12:16:15 -05:00
write!(f, ".{{")?;
2024-09-30 12:09:17 -05:00
self.fmt_list(
f,
trailing_comma,
"}",
",",
fields,
|s: &mut Self, CtorField { name, value, .. }: &_, f| {
if matches!(value, Expr::Ident { name: n, .. } if name == n) {
write!(f, "{name}")
} else {
write!(f, "{name}: ")?;
s.fmt(value, f)
}
},
)
2024-07-07 12:16:15 -05:00
}
2024-09-30 12:09:17 -05:00
Expr::Tupl { ty, fields, trailing_comma, .. } => {
2024-07-07 12:16:15 -05:00
if let Some(ty) = ty {
2024-09-30 12:09:17 -05:00
self.fmt_paren(ty, f, unary)?;
2024-05-12 05:16:40 -05:00
}
2024-07-07 12:16:15 -05:00
write!(f, ".(")?;
2024-09-30 12:09:17 -05:00
self.fmt_list(f, trailing_comma, ")", ",", fields, Self::fmt)
2024-05-12 05:16:40 -05:00
}
2024-09-30 12:09:17 -05:00
Expr::Slice { item, size, .. } => {
write!(f, "[")?;
self.fmt(item, f)?;
if let Some(size) = size {
write!(f, "; ")?;
self.fmt(size, f)?;
}
write!(f, "]")
}
Expr::Index { base, index } => {
self.fmt(base, f)?;
write!(f, "[")?;
self.fmt(index, f)?;
write!(f, "]")
}
Expr::UnOp { op, val, .. } => {
write!(f, "{op}")?;
self.fmt_paren(val, f, unary)
}
Expr::Break { .. } => write!(f, "break"),
Expr::Continue { .. } => write!(f, "continue"),
Expr::If { cond, then, else_, .. } => {
write!(f, "if ")?;
self.fmt(cond, f)?;
write!(f, " ")?;
self.fmt_paren(then, f, consecutive)?;
if let Some(e) = else_ {
write!(f, " else ")?;
self.fmt(e, f)?;
2024-05-11 11:16:27 -05:00
}
Ok(())
}
2024-09-30 12:09:17 -05:00
Expr::Loop { body, .. } => {
write!(f, "loop ")?;
self.fmt(body, f)
}
Expr::Closure { ret, body, args, .. } => {
2024-05-14 16:07:32 -05:00
write!(f, "fn(")?;
2024-09-30 12:09:17 -05:00
self.fmt_list(f, false, "", ",", args, |s, arg, f| {
2024-07-19 14:04:22 -05:00
if arg.is_ct {
write!(f, "$")?;
}
2024-09-30 12:09:17 -05:00
write!(f, "{}: ", arg.name)?;
s.fmt(&arg.ty, f)
2024-07-19 14:04:22 -05:00
})?;
2024-09-30 12:09:17 -05:00
write!(f, "): ")?;
self.fmt(ret, f)?;
write!(f, " ")?;
self.fmt_paren(body, f, consecutive)?;
2024-07-07 11:21:07 -05:00
Ok(())
2024-05-11 09:04:13 -05:00
}
2024-09-30 12:09:17 -05:00
Expr::Call { func, args, trailing_comma } => {
self.fmt_paren(func, f, postfix)?;
write!(f, "(")?;
self.fmt_list(f, trailing_comma, ")", ",", args, Self::fmt)
2024-05-11 09:04:13 -05:00
}
2024-09-30 12:09:17 -05:00
Expr::Return { val: Some(val), .. } => {
write!(f, "return ")?;
self.fmt(val, f)
}
Expr::Return { val: None, .. } => write!(f, "return"),
Expr::Ident { name, is_ct: true, .. } => write!(f, "${name}"),
Expr::Ident { name, is_ct: false, .. } => write!(f, "{name}"),
Expr::Block { stmts, .. } => {
2024-06-25 14:41:12 -05:00
write!(f, "{{")?;
2024-09-30 12:09:17 -05:00
self.fmt_list(f, true, "}", "", stmts, Self::fmt)
2024-05-09 16:41:59 -05:00
}
2024-09-30 12:09:17 -05:00
Expr::Number { value, radix, .. } => match radix {
Radix::Decimal => write!(f, "{value}"),
Radix::Hex => write!(f, "{value:#X}"),
Radix::Octal => write!(f, "{value:#o}"),
Radix::Binary => write!(f, "{value:#b}"),
},
2024-09-30 12:09:17 -05:00
Expr::Bool { value, .. } => write!(f, "{value}"),
Expr::Idk { .. } => write!(f, "idk"),
Expr::BinOp {
2024-07-19 14:04:22 -05:00
left,
2024-07-19 07:39:30 -05:00
op: TokenKind::Assign,
2024-09-30 12:09:17 -05:00
right: Expr::BinOp { left: lleft, op, right },
} if {
let mut b = core::mem::take(&mut self.disp_buff);
self.fmt(lleft, &mut b)?;
2024-07-19 14:04:22 -05:00
let len = b.len();
2024-09-30 12:09:17 -05:00
self.fmt(left, &mut b)?;
2024-07-19 14:04:22 -05:00
let (lleft, left) = b.split_at(len);
let res = lleft == left;
b.clear();
2024-09-30 12:09:17 -05:00
self.disp_buff = b;
2024-07-19 14:04:22 -05:00
res
2024-09-30 12:09:17 -05:00
} =>
2024-07-19 14:04:22 -05:00
{
2024-09-30 12:09:17 -05:00
self.fmt(left, f)?;
write!(f, " {op}= ")?;
self.fmt(right, f)
2024-07-19 07:39:30 -05:00
}
2024-09-30 12:09:17 -05:00
Expr::BinOp { right, op, left } => {
let pec_miss = |e: &Expr| {
matches!(
e, Expr::BinOp { op: lop, .. } if op.precedence() > lop.precedence()
)
2024-05-10 15:54:12 -05:00
};
2024-09-30 12:09:17 -05:00
self.fmt_paren(left, f, pec_miss)?;
if let Some(mut prev) = self.source.get(..right.pos() as usize) {
2024-07-19 14:04:22 -05:00
prev = prev.trim_end();
let estimate_bound =
prev.rfind(|c: char| c.is_ascii_whitespace()).map_or(prev.len(), |i| i + 1);
let exact_bound = lexer::Lexer::new(&prev[estimate_bound..]).last().start;
prev = &prev[..exact_bound as usize + estimate_bound];
if preserve_newlines(prev) > 0 {
writeln!(f)?;
2024-09-30 12:09:17 -05:00
for _ in 0..self.depth + 1 {
2024-07-19 14:04:22 -05:00
write!(f, "\t")?;
}
write!(f, "{op} ")?;
} else {
write!(f, " {op} ")?;
}
} else {
write!(f, " {op} ")?;
}
2024-09-30 12:09:17 -05:00
self.fmt_paren(right, f, pec_miss)
2024-05-10 15:54:12 -05:00
}
2024-05-09 16:41:59 -05:00
}
}
}
2024-07-19 08:51:02 -05:00
pub fn preserve_newlines(source: &str) -> usize {
2024-07-19 14:04:22 -05:00
source[source.trim_end().len()..].chars().filter(|&c| c == '\n').count()
2024-07-19 08:51:02 -05:00
}
2024-07-19 07:17:45 -05:00
pub fn insert_needed_semicolon(source: &str) -> bool {
let kind = lexer::Lexer::new(source).next().kind;
2024-07-19 07:24:58 -05:00
kind.precedence().is_some() || matches!(kind, TokenKind::Ctor | TokenKind::Tupl)
2024-07-19 07:17:45 -05:00
}
2024-05-17 12:53:59 -05:00
#[repr(C)]
2024-05-19 11:20:42 -05:00
pub struct AstInner<T: ?Sized> {
2024-05-17 12:53:59 -05:00
ref_count: AtomicUsize,
2024-07-08 00:22:53 -05:00
mem: ArenaChunk,
exprs: *const [Expr<'static>],
2024-05-19 11:20:42 -05:00
2024-07-08 00:22:53 -05:00
pub path: Box<str>,
2024-09-01 14:15:29 -05:00
pub file: Box<str>,
2024-05-19 11:20:42 -05:00
pub symbols: T,
2024-05-17 12:53:59 -05:00
}
impl AstInner<[Symbol]> {
2024-09-30 12:09:17 -05:00
fn layout(syms: usize) -> core::alloc::Layout {
core::alloc::Layout::new::<AstInner<()>>()
.extend(core::alloc::Layout::array::<Symbol>(syms).unwrap())
2024-05-17 12:53:59 -05:00
.unwrap()
.0
}
2024-10-01 08:28:18 -05:00
fn new(file: Box<str>, path: &str, stack: &mut StackAlloc, loader: Loader) -> NonNull<Self> {
2024-05-17 12:53:59 -05:00
let arena = Arena::default();
let mut syms = Vec::new();
2024-10-01 08:28:18 -05:00
let mut parser = Parser::new(&arena, &mut syms, stack, loader);
let exprs =
parser.file(unsafe { &*(&*file as *const _) }, path) as *const [Expr<'static>];
drop(parser);
2024-05-17 12:53:59 -05:00
syms.sort_unstable_by_key(|s| s.name);
let layout = Self::layout(syms.len());
unsafe {
2024-09-30 12:09:17 -05:00
let ptr = alloc::alloc::alloc(layout);
let inner: *mut Self = core::ptr::from_raw_parts_mut(ptr as *mut _, syms.len());
2024-05-19 11:20:42 -05:00
2024-09-30 12:09:17 -05:00
core::ptr::write(inner as *mut AstInner<()>, AstInner {
2024-07-08 00:22:53 -05:00
ref_count: AtomicUsize::new(1),
mem: arena.chunk.into_inner(),
exprs,
path: path.into(),
2024-10-01 08:28:18 -05:00
file,
2024-07-08 00:22:53 -05:00
symbols: (),
});
2024-09-30 12:09:17 -05:00
core::ptr::addr_of_mut!((*inner).symbols)
2024-05-17 12:53:59 -05:00
.as_mut_ptr()
.copy_from_nonoverlapping(syms.as_ptr(), syms.len());
2024-05-19 11:20:42 -05:00
2024-05-17 12:53:59 -05:00
NonNull::new_unchecked(inner)
}
}
2024-09-13 08:12:20 -05:00
pub fn report_to(&self, pos: Pos, msg: impl fmt::Display, out: &mut impl fmt::Write) {
2024-09-18 02:47:52 -05:00
report_to(&self.file, &self.path, pos, msg, out);
2024-09-13 08:12:20 -05:00
}
2024-05-17 12:53:59 -05:00
}
2024-09-18 02:47:52 -05:00
pub fn report_to(
file: &str,
path: &str,
pos: Pos,
msg: impl fmt::Display,
out: &mut impl fmt::Write,
) {
let (line, mut col) = lexer::line_col(file.as_bytes(), pos);
2024-09-30 12:09:17 -05:00
#[cfg(feature = "std")]
let disp = crate::fs::display_rel_path(path);
#[cfg(not(feature = "std"))]
let disp = path;
_ = writeln!(out, "{}:{}:{}: {}", disp, line, col, msg);
2024-09-18 02:47:52 -05:00
let line = &file[file[..pos as usize].rfind('\n').map_or(0, |i| i + 1)
..file[pos as usize..].find('\n').unwrap_or(file.len()) + pos as usize];
col += line.matches('\t').count() * 3;
_ = writeln!(out, "{}", line.replace("\t", " "));
_ = writeln!(out, "{}^", " ".repeat(col - 1));
}
2024-05-17 12:53:59 -05:00
#[derive(PartialEq, Eq, Hash)]
pub struct Ast(NonNull<AstInner<[Symbol]>>);
impl Ast {
2024-10-01 08:28:18 -05:00
pub fn new(path: &str, content: String, stack: &mut StackAlloc, loader: Loader) -> Self {
Self(AstInner::new(content.into(), path, stack, loader))
2024-05-17 12:53:59 -05:00
}
pub fn exprs(&self) -> &[Expr] {
unsafe { &*self.inner().exprs }
}
2024-05-19 11:20:42 -05:00
fn inner(&self) -> &AstInner<[Symbol]> {
unsafe { self.0.as_ref() }
2024-05-17 12:53:59 -05:00
}
2024-05-20 07:11:58 -05:00
pub fn find_decl(&self, id: Result<Ident, &str>) -> Option<(&Expr, Ident)> {
2024-05-19 11:20:42 -05:00
self.exprs().iter().find_map(|expr| match expr {
2024-07-08 00:22:53 -05:00
Expr::BinOp { left, op: TokenKind::Decl, .. } => left.declares(id).map(|id| (expr, id)),
2024-05-19 11:20:42 -05:00
_ => None,
})
2024-05-17 12:53:59 -05:00
}
2024-09-03 10:51:28 -05:00
pub fn ident_str(&self, ident: Ident) -> &str {
&self.file[ident::range(ident)]
}
2024-05-19 11:20:42 -05:00
}
2024-05-17 12:53:59 -05:00
2024-05-19 11:20:42 -05:00
impl Default for Ast {
fn default() -> Self {
2024-10-01 08:28:18 -05:00
Self(AstInner::new("".into(), "", &mut StackAlloc::default(), &no_loader))
2024-05-19 11:20:42 -05:00
}
}
#[derive(Clone, Copy)]
#[repr(packed)]
pub struct ExprRef(NonNull<Expr<'static>>);
impl ExprRef {
pub fn new(expr: &Expr) -> Self {
Self(NonNull::from(expr).cast())
}
pub fn get<'a>(&self, from: &'a Ast) -> Option<&'a Expr<'a>> {
2024-06-21 16:07:32 -05:00
ArenaChunk::contains(from.mem.base, self.0.as_ptr() as _).then_some(())?;
2024-05-19 11:20:42 -05:00
// SAFETY: the pointer is or was a valid reference in the past, if it points within one of
// arenas regions, it muts be walid, since arena does not give invalid pointers to its
// allocations
2024-06-21 16:07:32 -05:00
Some(unsafe { { self.0 }.as_ref() })
2024-05-17 12:53:59 -05:00
}
2024-09-04 09:54:34 -05:00
pub fn dangling() -> Self {
Self(NonNull::dangling())
}
}
impl Default for ExprRef {
fn default() -> Self {
Self::dangling()
}
2024-05-17 12:53:59 -05:00
}
unsafe impl Send for Ast {}
unsafe impl Sync for Ast {}
impl Clone for Ast {
fn clone(&self) -> Self {
2024-09-30 12:09:17 -05:00
unsafe { self.0.as_ref() }.ref_count.fetch_add(1, core::sync::atomic::Ordering::Relaxed);
2024-05-17 12:53:59 -05:00
Self(self.0)
}
}
impl Drop for Ast {
fn drop(&mut self) {
let inner = unsafe { self.0.as_ref() };
2024-09-30 12:09:17 -05:00
if inner.ref_count.fetch_sub(1, core::sync::atomic::Ordering::Relaxed) == 1 {
2024-10-01 08:28:18 -05:00
let inner = unsafe { self.0.as_mut() };
let len = inner.symbols.len();
unsafe { core::ptr::drop_in_place(inner) };
let layout = AstInner::layout(len);
2024-05-17 12:53:59 -05:00
unsafe {
2024-09-30 12:09:17 -05:00
alloc::alloc::dealloc(self.0.as_ptr() as _, layout);
2024-05-17 12:53:59 -05:00
}
}
}
}
2024-05-19 11:20:42 -05:00
impl Deref for Ast {
type Target = AstInner<[Symbol]>;
fn deref(&self) -> &Self::Target {
self.inner()
}
}
2024-10-01 08:28:18 -05:00
pub struct StackAllocView<T> {
prev: usize,
base: usize,
_ph: PhantomData<T>,
}
pub struct StackAlloc {
data: *mut u8,
len: usize,
cap: usize,
}
impl StackAlloc {
const MAX_ALIGN: usize = 16;
fn view<T: Copy>(&mut self) -> StackAllocView<T> {
let prev = self.len;
let align = core::mem::align_of::<T>();
assert!(align <= Self::MAX_ALIGN);
self.len = (self.len + align - 1) & !(align - 1);
StackAllocView { base: self.len, prev, _ph: PhantomData }
}
unsafe fn push<T: Copy>(&mut self, _view: &mut StackAllocView<T>, value: T) {
if unlikely(self.len + core::mem::size_of::<T>() > self.cap) {
let next_cap = self.cap.max(16 * 32).max(std::mem::size_of::<T>()) * 2;
if self.cap == 0 {
let layout =
core::alloc::Layout::from_size_align_unchecked(next_cap, Self::MAX_ALIGN);
self.data = alloc::alloc::alloc(layout);
} else {
let old_layout =
core::alloc::Layout::from_size_align_unchecked(self.cap, Self::MAX_ALIGN);
self.data = alloc::alloc::realloc(self.data, old_layout, next_cap);
}
self.cap = next_cap;
}
let dst = self.data.add(self.len) as *mut T;
debug_assert!(
dst.is_aligned(),
"{:?} {:?} {} {} {}",
dst,
std::mem::size_of::<T>(),
std::mem::align_of::<T>(),
self.len,
self.cap
);
self.len += core::mem::size_of::<T>();
core::ptr::write(dst, value);
}
unsafe fn finalize<T: Copy>(&mut self, view: StackAllocView<T>) -> &[T] {
if unlikely(self.cap == 0) {
return &[];
}
let slice = core::slice::from_ptr_range(
self.data.add(view.base) as *const T..self.data.add(self.len) as *const T,
);
self.len = view.prev;
slice
}
}
impl Default for StackAlloc {
fn default() -> Self {
Self { data: core::ptr::null_mut(), len: 0, cap: 0 }
}
}
impl Drop for StackAlloc {
fn drop(&mut self) {
let layout =
unsafe { core::alloc::Layout::from_size_align_unchecked(self.cap, Self::MAX_ALIGN) };
unsafe { alloc::alloc::dealloc(self.data, layout) };
}
}
#[derive(Default)]
pub struct Arena<'a> {
2024-05-17 12:53:59 -05:00
chunk: UnsafeCell<ArenaChunk>,
2024-09-30 12:09:17 -05:00
ph: core::marker::PhantomData<&'a ()>,
}
impl<'a> Arena<'a> {
pub fn alloc_str(&self, token: &str) -> &'a str {
let ptr = self.alloc_slice(token.as_bytes());
2024-09-30 12:09:17 -05:00
unsafe { core::str::from_utf8_unchecked(ptr) }
}
2024-06-01 13:30:07 -05:00
pub fn alloc(&self, expr: Expr<'a>) -> &'a Expr<'a> {
2024-09-30 12:09:17 -05:00
let align = core::mem::align_of::<Expr<'a>>();
2024-06-01 13:30:07 -05:00
let size = expr.used_bytes();
2024-09-30 12:09:17 -05:00
let layout = unsafe { core::alloc::Layout::from_size_align_unchecked(size, align) };
let ptr = self.alloc_low(layout);
2024-06-01 13:30:07 -05:00
unsafe {
2024-07-08 00:22:53 -05:00
ptr.cast::<u64>().copy_from_nonoverlapping(NonNull::from(&expr).cast(), size / 8)
2024-06-01 13:30:07 -05:00
};
unsafe { ptr.cast::<Expr<'a>>().as_ref() }
}
2024-06-01 13:30:07 -05:00
pub fn alloc_slice<T: Copy>(&self, slice: &[T]) -> &'a [T] {
2024-09-30 12:09:17 -05:00
if slice.is_empty() || core::mem::size_of::<T>() == 0 {
2024-05-19 11:20:42 -05:00
return &mut [];
}
2024-09-30 12:09:17 -05:00
let layout = core::alloc::Layout::array::<T>(slice.len()).unwrap();
let ptr = self.alloc_low(layout);
2024-07-08 00:22:53 -05:00
unsafe { ptr.as_ptr().cast::<T>().copy_from_nonoverlapping(slice.as_ptr(), slice.len()) };
2024-09-30 12:09:17 -05:00
unsafe { core::slice::from_raw_parts(ptr.as_ptr() as _, slice.len()) }
}
2024-09-30 12:09:17 -05:00
fn alloc_low(&self, layout: core::alloc::Layout) -> NonNull<u8> {
assert!(layout.align() <= ArenaChunk::ALIGN);
assert!(layout.size() <= ArenaChunk::CHUNK_SIZE);
2024-05-17 12:53:59 -05:00
let chunk = unsafe { &mut *self.chunk.get() };
2024-05-17 12:53:59 -05:00
if let Some(ptr) = chunk.alloc(layout) {
return ptr;
}
2024-05-19 11:20:42 -05:00
unsafe {
2024-09-30 12:09:17 -05:00
core::ptr::write(chunk, ArenaChunk::new(chunk.base));
}
2024-05-17 12:53:59 -05:00
chunk.alloc(layout).unwrap()
}
}
struct ArenaChunk {
base: *mut u8,
2024-07-08 00:22:53 -05:00
end: *mut u8,
}
impl Default for ArenaChunk {
fn default() -> Self {
2024-09-30 12:09:17 -05:00
Self { base: core::ptr::null_mut(), end: core::ptr::null_mut() }
}
}
impl ArenaChunk {
2024-09-30 12:09:17 -05:00
const ALIGN: usize = core::mem::align_of::<Self>();
2024-07-08 00:22:53 -05:00
const CHUNK_SIZE: usize = 1 << 16;
2024-09-30 12:09:17 -05:00
const LAYOUT: core::alloc::Layout =
unsafe { core::alloc::Layout::from_size_align_unchecked(Self::CHUNK_SIZE, Self::ALIGN) };
const NEXT_OFFSET: usize = Self::CHUNK_SIZE - core::mem::size_of::<*mut u8>();
fn new(next: *mut u8) -> Self {
2024-09-30 12:09:17 -05:00
let base = unsafe { alloc::alloc::alloc(Self::LAYOUT) };
2024-05-19 11:20:42 -05:00
let end = unsafe { base.add(Self::NEXT_OFFSET) };
Self::set_next(base, next);
Self { base, end }
}
fn set_next(curr: *mut u8, next: *mut u8) {
2024-09-30 12:09:17 -05:00
unsafe { core::ptr::write(curr.add(Self::NEXT_OFFSET) as *mut _, next) };
}
fn next(curr: *mut u8) -> *mut u8 {
2024-09-30 12:09:17 -05:00
unsafe { core::ptr::read(curr.add(Self::NEXT_OFFSET) as *mut _) }
}
2024-09-30 12:09:17 -05:00
fn alloc(&mut self, layout: core::alloc::Layout) -> Option<NonNull<u8>> {
let padding = self.end as usize - (self.end as usize & !(layout.align() - 1));
let size = layout.size() + padding;
if size > self.end as usize - self.base as usize {
return None;
}
unsafe { self.end = self.end.sub(size) };
unsafe { Some(NonNull::new_unchecked(self.end)) }
}
2024-05-19 11:20:42 -05:00
fn contains(base: *mut u8, arg: *mut u8) -> bool {
!base.is_null()
&& ((unsafe { base.add(Self::CHUNK_SIZE) } > arg && base <= arg)
|| Self::contains(Self::next(base), arg))
}
}
2024-05-17 12:53:59 -05:00
impl Drop for ArenaChunk {
fn drop(&mut self) {
2024-09-02 17:27:50 -05:00
//log::inf!(
// "dropping chunk of size: {}",
// (Self::LAYOUT.size() - (self.end as usize - self.base as usize))
// * !self.end.is_null() as usize
//);
2024-05-17 12:53:59 -05:00
let mut current = self.base;
while !current.is_null() {
let next = Self::next(current);
2024-09-30 12:09:17 -05:00
unsafe { alloc::alloc::dealloc(current, Self::LAYOUT) };
2024-05-17 12:53:59 -05:00
current = next;
2024-09-02 17:27:50 -05:00
//log::dbg!("deallocating full chunk");
2024-05-17 12:53:59 -05:00
}
}
}
2024-06-25 14:41:12 -05:00
#[cfg(test)]
2024-07-19 14:04:22 -05:00
pub mod test {
2024-10-01 08:28:18 -05:00
use {crate::parser::StackAlloc, alloc::borrow::ToOwned, std::string::String};
2024-09-30 12:09:17 -05:00
2024-07-19 14:04:22 -05:00
pub fn format(ident: &str, input: &str) {
2024-10-01 08:28:18 -05:00
let ast =
super::Ast::new(ident, input.to_owned(), &mut StackAlloc::default(), &|_, _| Ok(0));
2024-09-30 12:09:17 -05:00
let mut output = String::new();
crate::fs::format_to(&ast, input, &mut output).unwrap();
2024-06-25 14:41:12 -05:00
let input_path = format!("formatter_{ident}.expected");
let output_path = format!("formatter_{ident}.actual");
std::fs::write(&input_path, input).unwrap();
std::fs::write(&output_path, output).unwrap();
let success = std::process::Command::new("diff")
.arg("-u")
.arg("--color")
.arg(&input_path)
.arg(&output_path)
.status()
.unwrap()
.success();
std::fs::remove_file(&input_path).unwrap();
std::fs::remove_file(&output_path).unwrap();
assert!(success, "test failed");
}
macro_rules! test {
($($name:ident => $input:expr;)*) => {$(
#[test]
fn $name() {
format(stringify!($name), $input);
}
)*};
}
test! {
comments => "// comment\n// comment\n\n// comment\n\n\
2024-07-19 14:04:22 -05:00
/* comment */\n/* comment */\n\n/* comment */";
some_ordinary_code => "loft := fn(): int return loft(1, 2, 3)";
2024-06-25 14:41:12 -05:00
some_arg_per_line_code => "loft := fn(): int return loft(\
2024-07-19 14:04:22 -05:00
\n\t1,\n\t2,\n\t3,\n)";
some_ordinary_struct => "loft := fn(): int return loft.{a: 1, b: 2}";
2024-06-25 14:51:41 -05:00
some_ordinary_fild_per_lin_struct => "loft := fn(): int return loft.{\
2024-07-19 14:04:22 -05:00
\n\ta: 1,\n\tb: 2,\n}";
code_block => "loft := fn(): int {\n\tloft()\n\treturn 1\n}";
2024-06-25 14:41:12 -05:00
}
}