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

268 lines
6.9 KiB
Rust
Raw Normal View History

2023-09-24 21:58:28 +00:00
//use bitflags::bitflags;
pub mod parser;
use parser::{Env as ParseEnv, Error as Perr, ErrorKind as Pek, Parse, Token, TokenKind as Tok};
#[derive(Clone, Debug)]
pub enum Pattern {
Ident(Box<str>),
Ignore,
}
/*
bitflags! {
#[repr(transparent)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct DefinFlags: u8 {
const PUBLIC = 0b00000001;
const MUTABLE = 0b00000010;
}
}
#[derive(Clone, Debug)]
pub struct Defin {
pub flags: DefinFlags,
pub value: Expr,
pub name: Box<str>,
}
#[derive(Clone, Debug)]
pub struct Block {
pub defs: Box<[Defin]>,
pub res: Box<Expr>,
}
*/
#[derive(Clone, Debug)]
pub struct Record {
pub fields: Vec<(Option<Box<str>>, Expr)>,
}
#[derive(Clone, Debug)]
pub enum Expr {
TyTy,
Lambda {
pat: Pattern,
pty: Option<Box<Expr>>,
exp: Box<Expr>,
},
SelfRecur {
pat: Pattern,
inner: Box<Expr>,
},
Apply {
lam: Box<Expr>,
args: Vec<Expr>,
},
Ref(usize),
Record(Record),
TyRecord(Record),
Select {
prim: Box<Expr>,
then: Vec<Box<str>>,
},
//Block(Block),
}
impl Pattern {
pub fn in_this<T>(&self, env: &mut ParseEnv<'_>, f: impl FnOnce(&mut ParseEnv<'_>) -> T) -> T {
match self {
Pattern::Ident(i) => env.names.push(i.clone()),
Pattern::Ignore => env.names.push("".to_string().into_boxed_str()),
}
let height = env.names.len();
let ret = f(env);
assert_eq!(env.names.len(), height);
env.names.pop();
ret
}
}
impl Parse for Pattern {
fn parse(env: &mut ParseEnv<'_>) -> Result<Self, Perr> {
let backup = env.lxr.clone();
let Token { offset, kind } = env.lxr.next().unwrap_or_else(|| {
Err(Perr {
offset: env.lxr.offset(),
kind: Pek::UnexpectedEof("pattern"),
})
})?;
Ok(match kind {
Tok::PatOut(i) => Pattern::Ident(i),
Tok::PatIgnore => Pattern::Ignore,
_ => {
env.lxr = backup;
return Err(Perr {
offset: offset.try_into().unwrap(),
kind: Pek::UnexpectedToken {
kind,
ctx: "pattern",
},
});
}
})
}
}
impl Parse for Record {
fn parse(env: &mut ParseEnv<'_>) -> Result<Self, Perr> {
env.lxr.expect(Tok::LBrace, "record")?;
let mut fields = Vec::new();
loop {
let lxrbak = env.lxr.clone();
let name = {
let Token { kind, .. } = env.lxr.next_in_noeof("record")?;
if let Tok::DotIdent(i) = kind {
if env.lxr.expect(Tok::Assign, "record").is_ok() {
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 = Expr::parse(env)?;
env.lxr.expect(Tok::SemiColon, "record")?;
fields.push((name, expr));
}
env.lxr.expect(Tok::RBrace, "record")?;
Ok(Record { fields })
}
}
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 => {
let pat = Pattern::parse(env)?;
let pty = if env.lxr.got(Tok::DubColon).is_some() {
Some(Box::new(Expr::parse(env)?))
} else {
None
};
env.lxr.expect(Tok::RArr, "lambda")?;
let exp = Box::new(pat.in_this(env, Expr::parse)?);
return Ok(Expr::Lambda { pat, pty, exp });
}
Tok::Mu => {
let pat = Pattern::parse(env)?;
env.lxr.expect(Tok::RArr, "mu")?;
let inner = Box::new(pat.in_this(env, Expr::parse)?);
return Ok(Expr::SelfRecur { pat, inner });
}
Tok::LParen => {
let inner = Expr::parse(env)?;
env.lxr.expect(Tok::RParen, "parens")?;
return Ok(inner);
}
Tok::Caret => {
return if let Ok(r) = Record::parse(env) {
Ok(Expr::TyRecord(r))
} else {
let Token { kind, offset } = env.lxr.next_in_noeof("expression")?;
Err(parser::unexpected_token(offset, kind, "expression"))
}
}
Tok::Dot => {
return if let Ok(r) = Record::parse(env) {
Ok(Expr::Record(r))
} else {
let Token { kind, offset } = env.lxr.next_in_noeof("expression")?;
Err(parser::unexpected_token(offset, kind, "expression"))
}
}
/*
Tok::LBrace => {
let inner = ;
env.lxr.expect(Tok::RBrace, "braces")?;
return Ok(inner);
}
*/
_ => return Err(parser::unexpected_token(fi_offset, fi_kind, "expression")),
};
loop {
let lxrbak = env.lxr.clone();
let Token { kind, .. } = match env.lxr.next() {
Some(Ok(x)) => x,
_ => {
env.lxr = lxrbak;
break;
}
};
match kind {
Tok::DotIdent(i) => {
if let Expr::Select { then, .. } = &mut ret {
then.push(i);
} else {
ret = Expr::Select {
prim: Box::new(ret),
then: vec![i],
};
}
}
_ => {
env.lxr = lxrbak;
break;
}
}
}
Ok(ret)
}
impl Parse for Expr {
fn parse(env: &mut ParseEnv<'_>) -> Result<Self, Perr> {
let base = parse_minexpr(env)?;
let mut args = Vec::new();
loop {
let mut nxtenv = env.clone();
args.push(match parse_minexpr(&mut nxtenv) {
Ok(x) => x,
Err(_) => break,
});
*env = nxtenv;
}
Ok(if args.is_empty() {
base
} else {
Expr::Apply {
lam: Box::new(base),
args,
}
})
}
}