335 lines
8.8 KiB
Rust
335 lines
8.8 KiB
Rust
//use bitflags::bitflags;
|
|
pub mod parser;
|
|
use parser::{
|
|
Env as ParseEnv, Error as Perr, ErrorKind as Pek, MaybeParse, 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 struct FullPattern {
|
|
pub pat: Pattern,
|
|
pub pty: Option<Box<Expr>>,
|
|
}
|
|
|
|
#[derive(Clone, Debug)]
|
|
pub enum Expr {
|
|
TyTy,
|
|
|
|
Lambda {
|
|
pat: FullPattern,
|
|
exp: Box<Expr>,
|
|
},
|
|
|
|
SelfRecur {
|
|
pat: Pattern,
|
|
inner: Box<Expr>,
|
|
},
|
|
|
|
LetBind {
|
|
kvs: Vec<(FullPattern, Expr)>,
|
|
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 push_to(&self, env: &mut ParseEnv<'_>) {
|
|
match self {
|
|
Pattern::Ident(i) => env.names.push(i.clone()),
|
|
Pattern::Ignore => {}
|
|
}
|
|
}
|
|
|
|
pub fn pop_from(&self, env: &mut ParseEnv<'_>) {
|
|
match self {
|
|
Pattern::Ident(_) => {
|
|
env.names.pop();
|
|
}
|
|
Pattern::Ignore => {}
|
|
}
|
|
}
|
|
|
|
pub fn in_this<T>(&self, env: &mut ParseEnv<'_>, f: impl FnOnce(&mut ParseEnv<'_>) -> T) -> T {
|
|
self.push_to(env);
|
|
let height = env.names.len();
|
|
let ret = f(env);
|
|
assert_eq!(env.names.len(), height);
|
|
self.pop_from(env);
|
|
ret
|
|
}
|
|
}
|
|
|
|
impl MaybeParse for Pattern {
|
|
const DFL_CTX: &'static str = "pattern";
|
|
|
|
fn maybe_parse(env: &mut ParseEnv<'_>) -> Result<Option<Self>, Perr> {
|
|
let backup = env.lxr.clone();
|
|
let Token { kind, .. } = match env.lxr.next().transpose()? {
|
|
None => return Ok(None),
|
|
Some(x) => x,
|
|
};
|
|
Ok(match kind {
|
|
Tok::PatOut(i) => Some(Pattern::Ident(i)),
|
|
Tok::PatIgnore => Some(Pattern::Ignore),
|
|
_ => {
|
|
env.lxr = backup;
|
|
None
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
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,
|
|
};
|
|
|
|
let pty = if env.lxr.got(Tok::DubColon).is_some() {
|
|
Some(Box::new(Expr::parse(env)?))
|
|
} else {
|
|
None
|
|
};
|
|
|
|
Ok(Some(FullPattern { pat, pty }))
|
|
}
|
|
}
|
|
|
|
impl MaybeParse for Record {
|
|
const DFL_CTX: &'static str = "record";
|
|
|
|
fn maybe_parse(env: &mut ParseEnv<'_>) -> Result<Option<Self>, Perr> {
|
|
if env.lxr.got(Tok::LBrace).is_none() {
|
|
return Ok(None);
|
|
}
|
|
|
|
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(Some(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 = FullPattern::parse(env)?;
|
|
env.lxr.expect(Tok::RArr, "lambda")?;
|
|
let exp = Box::new(pat.pat.in_this(env, Expr::parse)?);
|
|
return Ok(Expr::Lambda { pat, 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 Some(r) = Record::maybe_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 Some(r) = Record::maybe_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,
|
|
Some(Err(e)) => return Err(e),
|
|
None => 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> {
|
|
fn parse_env_inner(env: &mut ParseEnv<'_>) -> Result<Expr, Perr> {
|
|
let mut letbinds = Vec::new();
|
|
|
|
while env.lxr.got(Tok::Let).is_some() {
|
|
let key = FullPattern::parse(env)?;
|
|
env.lxr.expect(Tok::Assign, "let expression =")?;
|
|
let value = Expr::parse(env)?;
|
|
key.pat.push_to(env);
|
|
letbinds.push((key, value));
|
|
env.lxr.expect(Tok::SemiColon, "let expression ;")?;
|
|
}
|
|
|
|
let mut args = Vec::new();
|
|
let mut base = parse_minexpr(env)?;
|
|
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;
|
|
}
|
|
});
|
|
}
|
|
|
|
if !args.is_empty() {
|
|
base = Expr::Apply {
|
|
lam: Box::new(base),
|
|
args,
|
|
};
|
|
}
|
|
|
|
if !letbinds.is_empty() {
|
|
base = Expr::LetBind {
|
|
kvs: letbinds,
|
|
inner: Box::new(base),
|
|
};
|
|
}
|
|
|
|
Ok(base)
|
|
}
|
|
|
|
// 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
|
|
}
|
|
}
|