yanais/crates/yn-qgy4hbz-core/src/lib.rs

448 lines
13 KiB
Rust
Raw Normal View History

/*
* 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 12:12:43 +00:00
mod record;
pub use record::{Record, RecordEntry};
2023-09-26 09:45:07 +00:00
pub mod typeck;
2023-09-25 20:26:15 +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;
/// 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
}
impl From<EvEqSourceSpan> for SourceSpan {
#[inline(always)]
fn from(x: EvEqSourceSpan) -> SourceSpan {
x.0
2023-09-25 20:26:15 +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
}
}
#[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,
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,
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>,
args: Vec<(EvEqSourceSpan, Expr)>,
2023-09-24 21:58:28 +00:00
},
Ref(usize),
Record(Record<Expr>),
TyRecord(Record<Expr>),
2023-09-24 21:58:28 +00:00
Select {
prim_span: EvEqSourceSpan,
2023-09-24 21:58:28 +00:00
prim: Box<Expr>,
then: VecDeque<(EvEqSourceSpan, Box<str>)>,
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();
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
}