2023-09-25 14:23:03 +00:00
|
|
|
/*
|
|
|
|
* 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-25 21:27:58 +00:00
|
|
|
use std::collections::VecDeque;
|
|
|
|
|
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),
|
2023-09-25 14:23:03 +00:00
|
|
|
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)]
|
2023-09-25 14:23:03 +00:00
|
|
|
pub struct Record<V> {
|
2023-09-25 20:26:15 +00:00
|
|
|
pub span: SourceSpan,
|
2023-09-25 14:23:03 +00:00
|
|
|
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>,
|
2023-09-25 21:27:58 +00:00
|
|
|
args: Vec<(SourceSpan, Expr)>,
|
2023-09-24 21:58:28 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
Ref(usize),
|
|
|
|
|
2023-09-25 14:23:03 +00:00
|
|
|
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 21:27:58 +00:00
|
|
|
then: VecDeque<(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()),
|
2023-09-25 14:23:03 +00:00
|
|
|
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 14:23:03 +00:00
|
|
|
}
|
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();
|
|
|
|
}
|
2023-09-25 14:23:03 +00:00
|
|
|
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 14:23:03 +00:00
|
|
|
}
|
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 {
|
2023-09-25 14:23:03 +00:00
|
|
|
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);
|
2023-09-25 14:23:03 +00:00
|
|
|
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,
|
|
|
|
};
|
2023-09-25 14:23:03 +00:00
|
|
|
Ok(Some(match kind {
|
2023-09-25 20:26:15 +00:00
|
|
|
Tok::PatOut(i) => Pattern::Ident(i, tok_start),
|
2023-09-25 14:23:03 +00:00
|
|
|
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;
|
2023-09-25 14:23:03 +00:00
|
|
|
return Ok(None);
|
2023-09-24 21:58:28 +00:00
|
|
|
}
|
2023-09-25 14:23:03 +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 }))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-09-25 14:23:03 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2023-09-25 14:23:03 +00:00
|
|
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-09-25 21:27:58 +00:00
|
|
|
pub enum RecordEntry<'a> {
|
|
|
|
Name(&'a str),
|
|
|
|
Ref(usize),
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T> Record<T> {
|
|
|
|
pub fn lookup_mut(&mut self, name: RecordEntry<'_>) -> Option<&mut T> {
|
|
|
|
match name {
|
|
|
|
RecordEntry::Name(name) => self
|
|
|
|
.fields
|
|
|
|
.iter_mut()
|
|
|
|
.find(|(j, _)| j.as_ref().map(|x| &**x) == Some(name)),
|
|
|
|
RecordEntry::Ref(i) => self.fields.get_mut(i),
|
|
|
|
}
|
|
|
|
.map(|x| &mut x.1)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn lookup(&self, name: RecordEntry<'_>) -> Option<&T> {
|
|
|
|
match name {
|
|
|
|
RecordEntry::Name(name) => self
|
|
|
|
.fields
|
|
|
|
.iter()
|
|
|
|
.find(|(j, _)| j.as_ref().map(|x| &**x) == Some(name)),
|
|
|
|
RecordEntry::Ref(i) => self.fields.get(i),
|
|
|
|
}
|
|
|
|
.map(|x| &x.1)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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 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
|
|
|
}
|
|
|
|
}
|