2023-09-25 14:23:03 +00:00
|
|
|
/*
|
|
|
|
* SPDX-FileCopyrightText: 2023 Alain Zscheile <fogti+devel@ytrizja.de>
|
|
|
|
*
|
|
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
|
|
*/
|
|
|
|
|
2023-09-24 21:58:28 +00:00
|
|
|
//use bitflags::bitflags;
|
|
|
|
pub mod parser;
|
2023-09-25 12:33:56 +00:00
|
|
|
use parser::{
|
|
|
|
Env as ParseEnv, Error as Perr, ErrorKind as Pek, MaybeParse, Parse, Token, TokenKind as Tok,
|
|
|
|
};
|
2023-09-24 21:58:28 +00:00
|
|
|
|
2023-09-26 09:40:05 +00:00
|
|
|
mod pat;
|
|
|
|
pub use pat::{FullPattern, Pattern};
|
|
|
|
|
2023-09-26 09:45:07 +00:00
|
|
|
pub mod typeck;
|
2023-09-25 20:26:15 +00:00
|
|
|
|
2023-09-26 10:04:09 +00:00
|
|
|
use core::cmp;
|
2023-09-25 20:26:15 +00:00
|
|
|
use miette::SourceSpan;
|
2023-09-25 21:27:58 +00:00
|
|
|
use std::collections::VecDeque;
|
|
|
|
|
2023-09-26 10:04:09 +00:00
|
|
|
/// A SourceSpan which is always equal to all other SourceSpans
|
|
|
|
/// (to be used to ignore span differences in expression comparisons)
|
|
|
|
#[derive(Clone, Copy, Debug)]
|
|
|
|
pub struct EvEqSourceSpan(pub SourceSpan);
|
|
|
|
|
|
|
|
impl cmp::PartialEq for EvEqSourceSpan {
|
|
|
|
#[inline(always)]
|
|
|
|
fn eq(&self, _: &Self) -> bool {
|
|
|
|
true
|
|
|
|
}
|
|
|
|
#[inline(always)]
|
|
|
|
fn ne(&self, _: &Self) -> bool {
|
|
|
|
false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<(usize, usize)> for EvEqSourceSpan {
|
|
|
|
#[inline]
|
|
|
|
fn from(x: (usize, usize)) -> Self {
|
|
|
|
Self(x.into())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<core::ops::Range<usize>> for EvEqSourceSpan {
|
|
|
|
#[inline]
|
|
|
|
fn from(x: core::ops::Range<usize>) -> Self {
|
|
|
|
Self(x.into())
|
|
|
|
}
|
2023-09-24 21:58:28 +00:00
|
|
|
}
|
|
|
|
|
2023-09-26 10:04:09 +00:00
|
|
|
impl From<EvEqSourceSpan> for SourceSpan {
|
|
|
|
#[inline(always)]
|
|
|
|
fn from(x: EvEqSourceSpan) -> SourceSpan {
|
|
|
|
x.0
|
2023-09-25 20:26:15 +00:00
|
|
|
}
|
2023-09-26 10:04:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> From<&'a EvEqSourceSpan> for SourceSpan {
|
|
|
|
#[inline(always)]
|
|
|
|
fn from(x: &'a EvEqSourceSpan) -> SourceSpan {
|
|
|
|
x.0
|
2023-09-25 20:26:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-09-26 10:04:09 +00:00
|
|
|
#[derive(Clone, Debug, PartialEq)]
|
|
|
|
pub struct Record<V> {
|
|
|
|
pub span: EvEqSourceSpan,
|
|
|
|
pub fields: Vec<(Option<Box<str>>, V)>,
|
|
|
|
}
|
|
|
|
|
2023-09-25 20:26:15 +00:00
|
|
|
#[derive(Clone, Debug, PartialEq)]
|
2023-09-24 21:58:28 +00:00
|
|
|
pub enum Expr {
|
|
|
|
TyTy,
|
2023-09-25 20:26:15 +00:00
|
|
|
Tbool,
|
|
|
|
Tu32,
|
|
|
|
Tusize,
|
2023-09-24 21:58:28 +00:00
|
|
|
|
|
|
|
Lambda {
|
2023-09-25 13:08:48 +00:00
|
|
|
pat: FullPattern,
|
2023-09-24 21:58:28 +00:00
|
|
|
exp: Box<Expr>,
|
|
|
|
},
|
|
|
|
|
2023-09-25 20:26:15 +00:00
|
|
|
TyLambda {
|
|
|
|
pat: FullPattern,
|
2023-09-26 10:04:09 +00:00
|
|
|
body_span: EvEqSourceSpan,
|
2023-09-25 20:26:15 +00:00
|
|
|
exp: Box<Expr>,
|
|
|
|
},
|
|
|
|
|
2023-09-24 21:58:28 +00:00
|
|
|
SelfRecur {
|
2023-09-25 20:26:15 +00:00
|
|
|
pat: FullPattern,
|
2023-09-26 10:04:09 +00:00
|
|
|
inner_span: EvEqSourceSpan,
|
2023-09-24 21:58:28 +00:00
|
|
|
inner: Box<Expr>,
|
|
|
|
},
|
|
|
|
|
2023-09-25 13:08:48 +00:00
|
|
|
LetBind {
|
2023-09-25 20:26:15 +00:00
|
|
|
kvs: Vec<(FullPattern, usize, Expr)>,
|
2023-09-25 13:08:48 +00:00
|
|
|
inner: Box<Expr>,
|
|
|
|
},
|
|
|
|
|
2023-09-24 21:58:28 +00:00
|
|
|
Apply {
|
|
|
|
lam: Box<Expr>,
|
2023-09-26 10:04:09 +00:00
|
|
|
args: Vec<(EvEqSourceSpan, Expr)>,
|
2023-09-24 21:58:28 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
Ref(usize),
|
|
|
|
|
2023-09-25 14:23:03 +00:00
|
|
|
Record(Record<Expr>),
|
|
|
|
TyRecord(Record<Expr>),
|
2023-09-24 21:58:28 +00:00
|
|
|
|
|
|
|
Select {
|
2023-09-26 10:04:09 +00:00
|
|
|
prim_span: EvEqSourceSpan,
|
2023-09-24 21:58:28 +00:00
|
|
|
prim: Box<Expr>,
|
2023-09-26 10:04:09 +00:00
|
|
|
then: VecDeque<(EvEqSourceSpan, Box<str>)>,
|
2023-09-24 21:58:28 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2023-09-25 14:23:03 +00:00
|
|
|
impl<T: Parse> MaybeParse for Record<T> {
|
2023-09-25 12:33:56 +00:00
|
|
|
const DFL_CTX: &'static str = "record";
|
|
|
|
|
|
|
|
fn maybe_parse(env: &mut ParseEnv<'_>) -> Result<Option<Self>, Perr> {
|
2023-09-25 20:26:15 +00:00
|
|
|
let start_offset = match env.lxr.got(Tok::LBrace) {
|
|
|
|
None => return Ok(None),
|
|
|
|
Some(x) => x,
|
|
|
|
};
|
2023-09-24 21:58:28 +00:00
|
|
|
|
2023-09-25 20:26:15 +00:00
|
|
|
let mut fields: Vec<(Option<Box<str>>, _)> = Vec::new();
|
2023-09-24 21:58:28 +00:00
|
|
|
|
|
|
|
loop {
|
|
|
|
let lxrbak = env.lxr.clone();
|
|
|
|
let name = {
|
2023-09-25 20:26:15 +00:00
|
|
|
let Token { kind, offset } = env.lxr.next_in_noeof("record")?;
|
2023-09-24 21:58:28 +00:00
|
|
|
|
|
|
|
if let Tok::DotIdent(i) = kind {
|
2023-09-25 12:33:56 +00:00
|
|
|
if env.lxr.expect(Tok::Assign, "record =").is_ok() {
|
2023-09-25 20:26:15 +00:00
|
|
|
if fields
|
|
|
|
.iter()
|
|
|
|
.find(|(j, _)| j.as_ref() == Some(&i))
|
|
|
|
.is_some()
|
|
|
|
{
|
|
|
|
env.lxr = lxrbak;
|
|
|
|
return Err(Perr {
|
|
|
|
offset: usize::try_from(offset).unwrap(),
|
|
|
|
kind: Pek::RcdDupIdent(i),
|
|
|
|
});
|
|
|
|
}
|
2023-09-24 21:58:28 +00:00
|
|
|
Some(i)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
} else if let Tok::RBrace = kind {
|
|
|
|
env.lxr = lxrbak;
|
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
};
|
|
|
|
if name.is_none() {
|
|
|
|
// backtrack
|
|
|
|
env.lxr = lxrbak;
|
|
|
|
}
|
|
|
|
|
2023-09-25 14:23:03 +00:00
|
|
|
let expr = T::parse(env)?;
|
2023-09-25 12:33:56 +00:00
|
|
|
env.lxr.expect(Tok::SemiColon, "record ;")?;
|
2023-09-24 21:58:28 +00:00
|
|
|
fields.push((name, expr));
|
|
|
|
}
|
|
|
|
|
2023-09-25 20:26:15 +00:00
|
|
|
let end_offset = env.lxr.expect(Tok::RBrace, "record")?;
|
|
|
|
Ok(Some(Record {
|
|
|
|
span: (usize::try_from(start_offset).unwrap()..usize::try_from(end_offset).unwrap())
|
|
|
|
.into(),
|
|
|
|
fields,
|
|
|
|
}))
|
2023-09-24 21:58:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-09-25 21:27:58 +00:00
|
|
|
pub enum RecordEntry<'a> {
|
|
|
|
Name(&'a str),
|
|
|
|
Ref(usize),
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T> Record<T> {
|
|
|
|
pub fn lookup_mut(&mut self, name: RecordEntry<'_>) -> Option<&mut T> {
|
|
|
|
match name {
|
|
|
|
RecordEntry::Name(name) => self
|
|
|
|
.fields
|
|
|
|
.iter_mut()
|
|
|
|
.find(|(j, _)| j.as_ref().map(|x| &**x) == Some(name)),
|
|
|
|
RecordEntry::Ref(i) => self.fields.get_mut(i),
|
|
|
|
}
|
|
|
|
.map(|x| &mut x.1)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn lookup(&self, name: RecordEntry<'_>) -> Option<&T> {
|
|
|
|
match name {
|
|
|
|
RecordEntry::Name(name) => self
|
|
|
|
.fields
|
|
|
|
.iter()
|
|
|
|
.find(|(j, _)| j.as_ref().map(|x| &**x) == Some(name)),
|
|
|
|
RecordEntry::Ref(i) => self.fields.get(i),
|
|
|
|
}
|
|
|
|
.map(|x| &x.1)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-09-24 21:58:28 +00:00
|
|
|
fn parse_minexpr(env: &mut ParseEnv<'_>) -> Result<Expr, Perr> {
|
|
|
|
let Token {
|
|
|
|
offset: fi_offset,
|
|
|
|
kind: fi_kind,
|
|
|
|
} = env.lxr.next_in_noeof("expression")?;
|
|
|
|
let mut ret = match fi_kind {
|
|
|
|
Tok::Ident(i) => {
|
|
|
|
if let Some(x) = env.lookup(&i) {
|
|
|
|
Expr::Ref(x)
|
|
|
|
} else {
|
|
|
|
return Err(Perr {
|
|
|
|
offset: fi_offset.try_into().unwrap(),
|
|
|
|
kind: Pek::UnknownIdent(i),
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Tok::Lambda => {
|
2023-09-25 13:08:48 +00:00
|
|
|
let pat = FullPattern::parse(env)?;
|
2023-09-24 21:58:28 +00:00
|
|
|
env.lxr.expect(Tok::RArr, "lambda")?;
|
2023-09-25 20:26:15 +00:00
|
|
|
let exp = Box::new(pat.pat.in_this_penv(env, Expr::parse)?);
|
2023-09-25 13:08:48 +00:00
|
|
|
return Ok(Expr::Lambda { pat, exp });
|
2023-09-24 21:58:28 +00:00
|
|
|
}
|
2023-09-25 20:26:15 +00:00
|
|
|
Tok::TyLambda => {
|
|
|
|
let pat = FullPattern::parse(env)?;
|
|
|
|
env.lxr.expect(Tok::RArr, "tylambda")?;
|
|
|
|
let body_start = env.lxr.offset();
|
|
|
|
let exp = Box::new(pat.pat.in_this_penv(env, Expr::parse)?);
|
|
|
|
let body_end = env.lxr.offset();
|
|
|
|
return Ok(Expr::TyLambda {
|
|
|
|
pat,
|
|
|
|
body_span: (body_start..body_end).into(),
|
|
|
|
exp,
|
|
|
|
});
|
|
|
|
}
|
2023-09-24 21:58:28 +00:00
|
|
|
Tok::Mu => {
|
2023-09-25 20:26:15 +00:00
|
|
|
let pat = FullPattern::parse(env)?;
|
2023-09-24 21:58:28 +00:00
|
|
|
env.lxr.expect(Tok::RArr, "mu")?;
|
2023-09-25 20:26:15 +00:00
|
|
|
let inner_start = usize::try_from(env.lxr.offset()).unwrap();
|
|
|
|
let inner = Box::new(pat.pat.in_this_penv(env, Expr::parse)?);
|
|
|
|
let inner_end = usize::try_from(env.lxr.offset()).unwrap();
|
|
|
|
return Ok(Expr::SelfRecur {
|
|
|
|
pat,
|
|
|
|
inner_span: (inner_start..inner_end).into(),
|
|
|
|
inner,
|
|
|
|
});
|
2023-09-24 21:58:28 +00:00
|
|
|
}
|
|
|
|
Tok::LParen => {
|
|
|
|
let inner = Expr::parse(env)?;
|
|
|
|
env.lxr.expect(Tok::RParen, "parens")?;
|
|
|
|
return Ok(inner);
|
|
|
|
}
|
|
|
|
Tok::Caret => {
|
2023-09-25 12:33:56 +00:00
|
|
|
return if let Some(r) = Record::maybe_parse(env)? {
|
2023-09-24 21:58:28 +00:00
|
|
|
Ok(Expr::TyRecord(r))
|
|
|
|
} else {
|
2023-09-25 12:33:56 +00:00
|
|
|
let Token { kind, offset } = env.lxr.next_in_noeof("^expression")?;
|
2023-09-25 20:26:15 +00:00
|
|
|
match kind {
|
|
|
|
Tok::Symbol(x) => match &*x {
|
|
|
|
"bool" => Ok(Expr::Tbool),
|
|
|
|
"type" => Ok(Expr::TyTy),
|
|
|
|
"u32" => Ok(Expr::Tu32),
|
|
|
|
"usize" => Ok(Expr::Tusize),
|
|
|
|
_ => Err(parser::unexpected_token(
|
|
|
|
offset,
|
|
|
|
Tok::Symbol(x),
|
|
|
|
"^expression",
|
|
|
|
)),
|
|
|
|
},
|
|
|
|
_ => Err(parser::unexpected_token(offset, kind, "^expression")),
|
|
|
|
}
|
2023-09-24 21:58:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
Tok::Dot => {
|
2023-09-25 12:33:56 +00:00
|
|
|
return if let Some(r) = Record::maybe_parse(env)? {
|
2023-09-24 21:58:28 +00:00
|
|
|
Ok(Expr::Record(r))
|
|
|
|
} else {
|
2023-09-25 12:33:56 +00:00
|
|
|
let Token { kind, offset } = env.lxr.next_in_noeof(".expression")?;
|
|
|
|
Err(parser::unexpected_token(offset, kind, ".expression"))
|
2023-09-24 21:58:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
Tok::LBrace => {
|
|
|
|
let inner = ;
|
|
|
|
env.lxr.expect(Tok::RBrace, "braces")?;
|
|
|
|
return Ok(inner);
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
_ => return Err(parser::unexpected_token(fi_offset, fi_kind, "expression")),
|
|
|
|
};
|
|
|
|
|
2023-09-25 20:26:15 +00:00
|
|
|
let prim_end = env.lxr.offset();
|
|
|
|
|
2023-09-24 21:58:28 +00:00
|
|
|
loop {
|
|
|
|
let lxrbak = env.lxr.clone();
|
2023-09-25 20:26:15 +00:00
|
|
|
let Token { kind, offset } = match env.lxr.next() {
|
2023-09-24 21:58:28 +00:00
|
|
|
Some(Ok(x)) => x,
|
2023-09-25 12:33:56 +00:00
|
|
|
Some(Err(e)) => return Err(e),
|
|
|
|
None => break,
|
2023-09-24 21:58:28 +00:00
|
|
|
};
|
|
|
|
match kind {
|
|
|
|
Tok::DotIdent(i) => {
|
2023-09-25 20:26:15 +00:00
|
|
|
let ioffset_end = env.lxr.offset();
|
2023-09-26 10:04:09 +00:00
|
|
|
let span: EvEqSourceSpan = (usize::try_from(offset).unwrap()..ioffset_end).into();
|
2023-09-24 21:58:28 +00:00
|
|
|
if let Expr::Select { then, .. } = &mut ret {
|
2023-09-25 21:27:58 +00:00
|
|
|
then.push_back((span, i));
|
2023-09-24 21:58:28 +00:00
|
|
|
} else {
|
2023-09-25 21:27:58 +00:00
|
|
|
let mut then = VecDeque::new();
|
|
|
|
then.push_back((span, i));
|
2023-09-24 21:58:28 +00:00
|
|
|
ret = Expr::Select {
|
2023-09-25 20:26:15 +00:00
|
|
|
prim_span: (usize::try_from(fi_offset).unwrap()..prim_end).into(),
|
2023-09-24 21:58:28 +00:00
|
|
|
prim: Box::new(ret),
|
2023-09-25 21:27:58 +00:00
|
|
|
then,
|
2023-09-24 21:58:28 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
env.lxr = lxrbak;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Ok(ret)
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Parse for Expr {
|
|
|
|
fn parse(env: &mut ParseEnv<'_>) -> Result<Self, Perr> {
|
2023-09-25 12:33:56 +00:00
|
|
|
fn parse_env_inner(env: &mut ParseEnv<'_>) -> Result<Expr, Perr> {
|
2023-09-25 13:08:48 +00:00
|
|
|
let mut letbinds = Vec::new();
|
2023-09-24 21:58:28 +00:00
|
|
|
|
2023-09-25 12:33:56 +00:00
|
|
|
while env.lxr.got(Tok::Let).is_some() {
|
2023-09-25 13:08:48 +00:00
|
|
|
let key = FullPattern::parse(env)?;
|
2023-09-25 20:26:15 +00:00
|
|
|
let middle = env.lxr.offset();
|
2023-09-25 12:33:56 +00:00
|
|
|
env.lxr.expect(Tok::Assign, "let expression =")?;
|
2023-09-25 13:08:48 +00:00
|
|
|
let value = Expr::parse(env)?;
|
2023-09-25 20:26:15 +00:00
|
|
|
key.pat.push_to_penv(env);
|
|
|
|
letbinds.push((key, middle, value));
|
2023-09-25 12:33:56 +00:00
|
|
|
env.lxr.expect(Tok::SemiColon, "let expression ;")?;
|
|
|
|
}
|
2023-09-24 21:58:28 +00:00
|
|
|
|
2023-09-25 12:33:56 +00:00
|
|
|
let mut args = Vec::new();
|
2023-09-25 13:08:48 +00:00
|
|
|
let mut base = parse_minexpr(env)?;
|
2023-09-25 12:33:56 +00:00
|
|
|
let reside_knamcnt = env.names.len();
|
|
|
|
loop {
|
|
|
|
let lxrbak = env.lxr.clone();
|
2023-09-25 21:27:58 +00:00
|
|
|
let arg_start = env.lxr.offset();
|
2023-09-25 12:33:56 +00:00
|
|
|
let arg = parse_minexpr(env);
|
2023-09-25 21:27:58 +00:00
|
|
|
let arg_end = env.lxr.offset();
|
2023-09-25 12:33:56 +00:00
|
|
|
assert_eq!(env.names.len(), reside_knamcnt);
|
2023-09-25 21:27:58 +00:00
|
|
|
match arg {
|
|
|
|
Ok(x) => args.push(((arg_start..arg_end).into(), x)),
|
2023-09-25 12:33:56 +00:00
|
|
|
Err(_) => {
|
|
|
|
// do not eat errors without backtracking the lexer
|
|
|
|
env.lxr = lxrbak;
|
|
|
|
break;
|
|
|
|
}
|
2023-09-25 21:27:58 +00:00
|
|
|
}
|
2023-09-24 21:58:28 +00:00
|
|
|
}
|
2023-09-25 12:33:56 +00:00
|
|
|
|
2023-09-25 13:08:48 +00:00
|
|
|
if !args.is_empty() {
|
|
|
|
base = Expr::Apply {
|
2023-09-25 12:33:56 +00:00
|
|
|
lam: Box::new(base),
|
|
|
|
args,
|
2023-09-25 13:08:48 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
if !letbinds.is_empty() {
|
|
|
|
base = Expr::LetBind {
|
|
|
|
kvs: letbinds,
|
|
|
|
inner: Box::new(base),
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(base)
|
2023-09-25 12:33:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// make sure we don't leak names
|
|
|
|
// (the assert_eq checks serve the same purpose)
|
|
|
|
let knamcnt = env.names.len();
|
|
|
|
let res = parse_env_inner(env);
|
|
|
|
assert!(env.names.len() >= knamcnt);
|
|
|
|
env.names.truncate(knamcnt);
|
|
|
|
res
|
2023-09-24 21:58:28 +00:00
|
|
|
}
|
|
|
|
}
|
2023-09-26 09:45:07 +00:00
|
|
|
|
|
|
|
impl Expr {
|
|
|
|
pub fn weak_is_type(&self) -> Option<bool> {
|
|
|
|
Some(match self {
|
|
|
|
Expr::TyTy | Expr::Tbool | Expr::Tu32 | Expr::Tusize => true,
|
|
|
|
Expr::Lambda { .. } | Expr::Record(_) => false,
|
|
|
|
Expr::TyLambda { .. } | Expr::TyRecord(_) => true,
|
|
|
|
Expr::SelfRecur { inner, .. }
|
|
|
|
| Expr::LetBind { inner, .. }
|
|
|
|
| Expr::Apply { lam: inner, .. } => return inner.weak_is_type(),
|
|
|
|
Expr::Ref(_) | Expr::Select { .. } => return None,
|
|
|
|
})
|
|
|
|
}
|
2023-09-26 11:11:46 +00:00
|
|
|
|
|
|
|
pub fn incr_refs(&mut self, mut keep: usize, offset: usize) {
|
|
|
|
// this pattern prevents too deep recursion
|
|
|
|
let mut this = Some(self);
|
|
|
|
while let Some(cur) = this.take() {
|
|
|
|
match cur {
|
|
|
|
Expr::TyTy | Expr::Tbool | Expr::Tu32 | Expr::Tusize => {}
|
|
|
|
|
|
|
|
Expr::Lambda { pat, exp }
|
|
|
|
| Expr::TyLambda { pat, exp, .. }
|
|
|
|
| Expr::SelfRecur {
|
|
|
|
pat, inner: exp, ..
|
|
|
|
} => {
|
|
|
|
pat.incr_refs(keep, offset);
|
|
|
|
keep += pat.count_exports();
|
|
|
|
this = Some(exp);
|
|
|
|
}
|
|
|
|
|
|
|
|
Expr::LetBind { kvs, inner } => {
|
|
|
|
for (pat, _, value) in kvs {
|
|
|
|
pat.incr_refs(keep, offset);
|
|
|
|
value.incr_refs(keep, offset);
|
|
|
|
keep += pat.count_exports();
|
|
|
|
}
|
|
|
|
this = Some(inner);
|
|
|
|
}
|
|
|
|
|
|
|
|
Expr::Apply { lam, args } => {
|
|
|
|
lam.incr_refs(keep, offset);
|
|
|
|
for (_, i) in args {
|
|
|
|
i.incr_refs(keep, offset);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Expr::Ref(i) => {
|
|
|
|
if *i >= keep {
|
|
|
|
*i += offset;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Expr::Record(rcd) | Expr::TyRecord(rcd) => {
|
|
|
|
for (_, i) in &mut rcd.fields {
|
|
|
|
i.incr_refs(keep, offset);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Expr::Select { prim, .. } => this = Some(prim),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn subst(&mut self, mut bnest: usize, with_e: &Expr) {
|
|
|
|
match self {
|
|
|
|
Expr::TyTy | Expr::Tbool | Expr::Tu32 | Expr::Tusize => {}
|
|
|
|
|
|
|
|
Expr::Lambda { pat, exp }
|
|
|
|
| Expr::TyLambda { pat, exp, .. }
|
|
|
|
| Expr::SelfRecur {
|
|
|
|
pat, inner: exp, ..
|
|
|
|
} => {
|
|
|
|
pat.subst(bnest, with_e);
|
|
|
|
let mut with_e2 = with_e.clone();
|
|
|
|
let patexps = pat.count_exports();
|
|
|
|
with_e2.incr_refs(0, patexps);
|
|
|
|
exp.subst(bnest + patexps, &with_e2);
|
|
|
|
}
|
|
|
|
|
|
|
|
Expr::LetBind { kvs, inner } => {
|
|
|
|
let mut with_e2 = with_e.clone();
|
|
|
|
for (pat, _, value) in kvs {
|
|
|
|
pat.subst(bnest, &with_e2);
|
|
|
|
value.subst(bnest, &with_e2);
|
|
|
|
let patexps = pat.count_exports();
|
|
|
|
with_e2.incr_refs(0, patexps);
|
|
|
|
bnest += patexps;
|
|
|
|
}
|
|
|
|
inner.subst(bnest, &with_e2);
|
|
|
|
}
|
|
|
|
|
|
|
|
Expr::Apply { lam, args } => {
|
|
|
|
lam.subst(bnest, with_e);
|
|
|
|
for (_, i) in args {
|
|
|
|
i.subst(bnest, with_e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Expr::Ref(i) => {
|
|
|
|
if *i == bnest {
|
|
|
|
*self = with_e.clone();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Expr::Record(rcd) | Expr::TyRecord(rcd) => {
|
|
|
|
for (_, i) in &mut rcd.fields {
|
|
|
|
i.subst(bnest, with_e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Expr::Select { prim, .. } => prim.subst(bnest, with_e),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
#[test]
|
|
|
|
fn subst00() {
|
|
|
|
use crate::*;
|
|
|
|
let mut a = Expr::Lambda {
|
|
|
|
pat: FullPattern {
|
|
|
|
pat: Pattern::Ident("x".to_string().into_boxed_str(), 0),
|
|
|
|
pty: None,
|
|
|
|
},
|
|
|
|
exp: Box::new(Expr::Ref(0)),
|
|
|
|
};
|
|
|
|
a.subst(0, &Expr::Ref(1));
|
|
|
|
assert_eq!(&a, &Expr::Lambda {
|
|
|
|
pat: FullPattern {
|
|
|
|
pat: Pattern::Ident("x".to_string().into_boxed_str(), 0),
|
|
|
|
pty: None,
|
|
|
|
},
|
|
|
|
exp: Box::new(Expr::Ref(0)),
|
|
|
|
});
|
|
|
|
if let Expr::Lambda { exp, .. } = &mut a {
|
|
|
|
**exp = Expr::Ref(1);
|
|
|
|
}
|
|
|
|
a.subst(0, &Expr::Ref(1));
|
|
|
|
assert_eq!(&a, &Expr::Lambda {
|
|
|
|
pat: FullPattern {
|
|
|
|
pat: Pattern::Ident("x".to_string().into_boxed_str(), 0),
|
|
|
|
pty: None,
|
|
|
|
},
|
|
|
|
exp: Box::new(Expr::Ref(2)),
|
|
|
|
});
|
|
|
|
}
|
2023-09-26 09:45:07 +00:00
|
|
|
}
|