268 lines
6.9 KiB
Rust
268 lines
6.9 KiB
Rust
|
//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,
|
||
|
}
|
||
|
})
|
||
|
}
|
||
|
}
|