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

504 lines
15 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-25 20:26:15 +00:00
mod typeck;
pub use typeck::Error as TypeckError;
use miette::SourceSpan;
2023-09-24 21:58:28 +00:00
#[derive(Clone, Debug)]
pub enum Pattern {
2023-09-25 20:26:15 +00:00
Ident(Box<str>, parser::Offset),
Record(Record<Pattern>),
TyRecord(Record<Pattern>),
2023-09-24 21:58:28 +00:00
Ignore,
}
2023-09-25 20:26:15 +00:00
impl core::cmp::PartialEq for Pattern {
fn eq(&self, rhs: &Self) -> bool {
match (self, rhs) {
(Pattern::Ident(_, _), Pattern::Ident(_, _)) => true,
(Pattern::Ignore, Pattern::Ignore) => true,
(Pattern::Record(lxs), Pattern::Record(rxs)) => lxs == rxs,
(Pattern::TyRecord(lxs), Pattern::TyRecord(rxs)) => lxs == rxs,
// TODO: should Ident(_) be = Ignore?
(_, _) => false,
}
}
fn ne(&self, rhs: &Self) -> bool {
match (self, rhs) {
(Pattern::Ident(_, _), Pattern::Ident(_, _)) => false,
(Pattern::Ignore, Pattern::Ignore) => false,
(Pattern::Record(lxs), Pattern::Record(rxs)) => lxs != rxs,
(Pattern::TyRecord(lxs), Pattern::TyRecord(rxs)) => lxs != rxs,
(Pattern::Ident(_, _), Pattern::Ignore) | (Pattern::Ignore, Pattern::Ident(_, _)) => {
false
}
(_, _) => true,
}
}
}
2023-09-24 21:58:28 +00:00
#[derive(Clone, Debug)]
pub struct Record<V> {
2023-09-25 20:26:15 +00:00
pub span: SourceSpan,
pub fields: Vec<(Option<Box<str>>, V)>,
2023-09-24 21:58:28 +00:00
}
2023-09-25 20:26:15 +00:00
impl<V: core::cmp::PartialEq> core::cmp::PartialEq for Record<V> {
fn eq(&self, rhs: &Self) -> bool {
self.fields == rhs.fields
}
fn ne(&self, rhs: &Self) -> bool {
self.fields != rhs.fields
}
}
2023-09-25 13:08:48 +00:00
#[derive(Clone, Debug)]
pub struct FullPattern {
pub pat: Pattern,
2023-09-25 20:26:15 +00:00
pub pty: Option<Box<(SourceSpan, Expr)>>,
2023-09-25 13:08:48 +00:00
}
2023-09-25 20:26:15 +00:00
impl core::cmp::PartialEq for FullPattern {
fn eq(&self, rhs: &Self) -> bool {
if self.pat != rhs.pat {
return false;
}
match (&self.pty, &rhs.pty) {
(None, None) => true,
(Some(_), None) | (None, Some(_)) => false,
(Some(lt), Some(rt)) => lt.1 == rt.1,
}
}
fn ne(&self, rhs: &Self) -> bool {
if self.pat == rhs.pat {
return false;
}
match (&self.pty, &rhs.pty) {
(None, None) => false,
(Some(_), None) | (None, Some(_)) => true,
(Some(lt), Some(rt)) => lt.1 != rt.1,
}
}
}
#[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: SourceSpan,
exp: Box<Expr>,
},
2023-09-24 21:58:28 +00:00
SelfRecur {
2023-09-25 20:26:15 +00:00
pat: FullPattern,
inner_span: SourceSpan,
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<Expr>,
},
Ref(usize),
Record(Record<Expr>),
TyRecord(Record<Expr>),
2023-09-24 21:58:28 +00:00
Select {
2023-09-25 20:26:15 +00:00
prim_span: SourceSpan,
2023-09-24 21:58:28 +00:00
prim: Box<Expr>,
2023-09-25 20:26:15 +00:00
then: Vec<(SourceSpan, Box<str>)>,
2023-09-24 21:58:28 +00:00
},
}
impl Pattern {
2023-09-25 20:26:15 +00:00
pub fn push_to_penv(&self, env: &mut ParseEnv<'_>) {
2023-09-24 21:58:28 +00:00
match self {
2023-09-25 20:26:15 +00:00
Pattern::Ident(i, _) => env.names.push(i.clone()),
Pattern::Record(xs) | Pattern::TyRecord(xs) => {
2023-09-25 20:26:15 +00:00
xs.fields[..].iter().for_each(|i| i.1.push_to_penv(env));
}
2023-09-25 13:08:48 +00:00
Pattern::Ignore => {}
}
}
2023-09-25 20:26:15 +00:00
pub fn pop_from_penv(&self, env: &mut ParseEnv<'_>) {
2023-09-25 13:08:48 +00:00
match self {
2023-09-25 20:26:15 +00:00
Pattern::Ident(..) => {
2023-09-25 13:08:48 +00:00
env.names.pop();
}
Pattern::Record(xs) | Pattern::TyRecord(xs) => {
2023-09-25 20:26:15 +00:00
xs.fields[..].iter().for_each(|i| i.1.pop_from_penv(env));
}
2023-09-25 13:08:48 +00:00
Pattern::Ignore => {}
2023-09-24 21:58:28 +00:00
}
2023-09-25 13:08:48 +00:00
}
2023-09-25 20:26:15 +00:00
pub fn extract_exports(&self, outp: &mut Vec<Box<str>>) -> Result<(), Perr> {
match self {
Pattern::Ident(i, loc) => {
let i2 = i.clone();
if outp.iter().find(|j| i == *j).is_some() {
Err(Perr {
offset: usize::try_from(*loc).unwrap(),
kind: Pek::PatDupIdent(i2),
})
} else {
outp.push(i2);
Ok(())
}
}
Pattern::Record(xs) | Pattern::TyRecord(xs) => xs.fields[..]
.iter()
.try_for_each(|i| i.1.extract_exports(outp)),
Pattern::Ignore => Ok(()),
}
}
pub fn in_this_penv<T>(
&self,
env: &mut ParseEnv<'_>,
f: impl FnOnce(&mut ParseEnv<'_>) -> T,
) -> T {
let orig_height = env.names.len();
2023-09-25 20:26:15 +00:00
self.push_to_penv(env);
2023-09-24 21:58:28 +00:00
let height = env.names.len();
let ret = f(env);
assert_eq!(env.names.len(), height);
2023-09-25 20:26:15 +00:00
self.pop_from_penv(env);
assert_eq!(env.names.len(), orig_height);
2023-09-24 21:58:28 +00:00
ret
}
}
2023-09-25 12:33:56 +00:00
impl MaybeParse for Pattern {
const DFL_CTX: &'static str = "pattern";
fn maybe_parse(env: &mut ParseEnv<'_>) -> Result<Option<Self>, Perr> {
2023-09-24 21:58:28 +00:00
let backup = env.lxr.clone();
2023-09-25 20:26:15 +00:00
let Token {
kind,
offset: tok_start,
} = match env.lxr.next().transpose()? {
2023-09-25 12:33:56 +00:00
None => return Ok(None),
Some(x) => x,
};
Ok(Some(match kind {
2023-09-25 20:26:15 +00:00
Tok::PatOut(i) => Pattern::Ident(i, tok_start),
Tok::PatIgnore => Pattern::Ignore,
Tok::Caret | Tok::Dot => {
let is_tylvl = kind == Tok::Caret;
if let Some(r) = Record::<Pattern>::maybe_parse(env)? {
if is_tylvl {
Pattern::TyRecord(r)
} else {
Pattern::Record(r)
}
} else {
let Token { kind, offset } = env.lxr.next_in_noeof("[^.]pattern")?;
return Err(parser::unexpected_token(offset, kind, "[^.]pattern"));
}
}
2023-09-24 21:58:28 +00:00
_ => {
env.lxr = backup;
return Ok(None);
2023-09-24 21:58:28 +00:00
}
}))
2023-09-24 21:58:28 +00:00
}
}
2023-09-25 13:08:48 +00:00
impl MaybeParse for FullPattern {
const DFL_CTX: &'static str = "pattern";
fn maybe_parse(env: &mut ParseEnv<'_>) -> Result<Option<Self>, Perr> {
let pat = match Pattern::maybe_parse(env)? {
None => return Ok(None),
Some(x) => x,
};
2023-09-25 20:26:15 +00:00
// check for name collisions
{
let mut exports = Vec::new();
pat.extract_exports(&mut exports)?;
}
2023-09-25 13:08:48 +00:00
let pty = if env.lxr.got(Tok::DubColon).is_some() {
2023-09-25 20:26:15 +00:00
let start_loc = usize::try_from(env.lxr.offset()).unwrap();
let ptyx = Expr::parse(env)?;
let end_loc = usize::try_from(env.lxr.offset()).unwrap();
Some(Box::new(((start_loc..end_loc).into(), ptyx)))
2023-09-25 13:08:48 +00:00
} else {
None
};
Ok(Some(FullPattern { pat, pty }))
}
}
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;
}
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
}
}
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: SourceSpan = (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 20:26:15 +00:00
then.push((span, i));
2023-09-24 21:58:28 +00:00
} else {
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 20:26:15 +00:00
then: vec![(span, i)],
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();
let arg = parse_minexpr(env);
assert_eq!(env.names.len(), reside_knamcnt);
args.push(match arg {
Ok(x) => x,
Err(_) => {
// do not eat errors without backtracking the lexer
env.lxr = lxrbak;
break;
}
});
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
}
}