use string_interner::{StringInterner, backend::StringBackend, symbol::SymbolU32};
use crate::{binding::Binding, context::Context, expr::Expr, ident::Ident};
pub(crate) type Interner = StringInterner<StringBackend>;
#[derive(Debug)]
pub struct CtxState {
contexts: Vec<Context>,
interner: Interner,
}
impl CtxState {
pub(crate) fn new() -> Self {
let mut interner = StringInterner::new();
Self {
contexts: vec![Context::root(&mut interner)],
interner,
}
}
pub(crate) fn place_ctx(&mut self, ctx_idx: usize, ctx: Context) {
if ctx_idx >= self.len() {
self.contexts.resize(ctx_idx + 1, Context::default());
}
self[ctx_idx] = ctx;
}
pub(crate) fn find_ctx_with_ident(
&self,
current_ctx_idx: usize,
ident: &Ident,
) -> Option<usize> {
let mut ctx_idx = current_ctx_idx;
loop {
let ctx = &self[ctx_idx];
if ctx.contains_key(ident) {
return Some(ctx_idx);
}
ctx_idx = ctx.parent_ctx_idx()?;
}
}
}
impl Default for CtxState {
fn default() -> Self {
Self::new()
}
}
impl std::ops::Deref for CtxState {
type Target = [Context];
fn deref(&self) -> &Self::Target {
&self.contexts
}
}
impl std::ops::DerefMut for CtxState {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.contexts
}
}
#[derive(Debug)]
pub struct ParseState<'ctx> {
active_ctx_idx: usize,
avail_ctx_idx: usize,
ctx_state: &'ctx mut CtxState,
}
impl<'ctx> ParseState<'ctx> {
pub(crate) fn new(ctx_state: &'ctx mut CtxState) -> Self {
let ctx_state_len = ctx_state.contexts.len();
Self {
active_ctx_idx: ctx_state_len - 1,
avail_ctx_idx: ctx_state_len,
ctx_state,
}
}
pub(crate) fn active_ctx_idx(&self) -> usize {
self.active_ctx_idx
}
pub(crate) fn set_active_ctx(&mut self, ctx_idx: usize) {
self.active_ctx_idx = ctx_idx;
}
pub(crate) fn avail_ctx_idx(&mut self) -> usize {
self.avail_ctx_idx
}
pub(crate) fn increment_avail_ctx_idx(&mut self) {
self.avail_ctx_idx += 1;
}
pub(crate) fn decrement_avail_ctx_idx(&mut self) {
self.avail_ctx_idx -= 1;
}
pub(crate) fn get_interned(&mut self, s: &str) -> SymbolU32 {
self.ctx_state.interner.get_or_intern(s)
}
}
impl std::ops::Deref for ParseState<'_> {
type Target = CtxState;
fn deref(&self) -> &Self::Target {
self.ctx_state
}
}
impl std::ops::DerefMut for ParseState<'_> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.ctx_state
}
}
#[derive(Debug)]
pub struct EvalState<'ctx> {
active_ctx_idx: usize,
ctx_state: &'ctx mut CtxState,
}
impl<'ctx> EvalState<'ctx> {
pub(crate) fn new(ctx_state: &'ctx mut CtxState) -> Self {
Self {
active_ctx_idx: 0,
ctx_state,
}
}
pub(crate) fn active_ctx_idx(&self) -> usize {
self.active_ctx_idx
}
pub(crate) fn set_active_ctx(&mut self, ctx_idx: usize) {
self.active_ctx_idx = ctx_idx;
}
pub(crate) fn find_ctx_with_ident(&self, ident: &Ident) -> Option<usize> {
self.ctx_state
.find_ctx_with_ident(self.active_ctx_idx, ident)
}
pub(crate) fn get_expr<'a>(&'a mut self, ident: &'a Ident) -> Option<&'a Expr> {
let ctx_idx = self.find_ctx_with_ident(ident)?;
if let Some(Binding::Expr(expr)) = self[ctx_idx].get(ident) {
return Some(expr);
}
None
}
}
impl std::ops::Deref for EvalState<'_> {
type Target = CtxState;
fn deref(&self) -> &Self::Target {
self.ctx_state
}
}
impl std::ops::DerefMut for EvalState<'_> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.ctx_state
}
}
#[derive(Debug, Clone, Copy)]
pub struct FmtState<'ctx> {
pretty: bool,
indent_level: usize,
ctx_state: &'ctx CtxState,
}
impl<'ctx> FmtState<'ctx> {
pub(crate) fn new(pretty: bool, ctx_state: &'ctx CtxState) -> Self {
Self {
pretty,
indent_level: 0,
ctx_state,
}
}
pub(crate) fn indented(&self) -> Self {
Self {
pretty: self.pretty,
indent_level: self.indent_level + 1,
ctx_state: self.ctx_state,
}
}
pub(crate) fn pretty(&self) -> bool {
self.pretty
}
pub(crate) fn indent_level(&self) -> usize {
self.indent_level
}
pub(crate) fn resolve_ident(&self, ident: &Ident) -> &str {
self.ctx_state
.interner
.resolve(ident.to_symbol())
.expect("Identifier not found in interner")
}
}
impl std::ops::Deref for FmtState<'_> {
type Target = CtxState;
fn deref(&self) -> &Self::Target {
self.ctx_state
}
}