move pattern stuff into separate file
This commit is contained in:
parent
c63329d59d
commit
38b8b54104
|
@ -10,6 +10,9 @@ use parser::{
|
|||
Env as ParseEnv, Error as Perr, ErrorKind as Pek, MaybeParse, Parse, Token, TokenKind as Tok,
|
||||
};
|
||||
|
||||
mod pat;
|
||||
pub use pat::{FullPattern, Pattern};
|
||||
|
||||
mod typeck;
|
||||
pub use typeck::Error as TypeckError;
|
||||
|
||||
|
@ -17,39 +20,6 @@ use miette::SourceSpan;
|
|||
|
||||
use std::collections::VecDeque;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum Pattern {
|
||||
Ident(Box<str>, parser::Offset),
|
||||
Record(Record<Pattern>),
|
||||
TyRecord(Record<Pattern>),
|
||||
Ignore,
|
||||
}
|
||||
|
||||
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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Record<V> {
|
||||
pub span: SourceSpan,
|
||||
|
@ -65,35 +35,6 @@ impl<V: core::cmp::PartialEq> core::cmp::PartialEq for Record<V> {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct FullPattern {
|
||||
pub pat: Pattern,
|
||||
pub pty: Option<Box<(SourceSpan, Expr)>>,
|
||||
}
|
||||
|
||||
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)]
|
||||
pub enum Expr {
|
||||
TyTy,
|
||||
|
@ -140,130 +81,6 @@ pub enum Expr {
|
|||
},
|
||||
}
|
||||
|
||||
impl Pattern {
|
||||
pub fn push_to_penv(&self, env: &mut ParseEnv<'_>) {
|
||||
match self {
|
||||
Pattern::Ident(i, _) => env.names.push(i.clone()),
|
||||
Pattern::Record(xs) | Pattern::TyRecord(xs) => {
|
||||
xs.fields[..].iter().for_each(|i| i.1.push_to_penv(env));
|
||||
}
|
||||
Pattern::Ignore => {}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn pop_from_penv(&self, env: &mut ParseEnv<'_>) {
|
||||
match self {
|
||||
Pattern::Ident(..) => {
|
||||
env.names.pop();
|
||||
}
|
||||
Pattern::Record(xs) | Pattern::TyRecord(xs) => {
|
||||
xs.fields[..].iter().for_each(|i| i.1.pop_from_penv(env));
|
||||
}
|
||||
Pattern::Ignore => {}
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
self.push_to_penv(env);
|
||||
let height = env.names.len();
|
||||
let ret = f(env);
|
||||
assert_eq!(env.names.len(), height);
|
||||
self.pop_from_penv(env);
|
||||
assert_eq!(env.names.len(), orig_height);
|
||||
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,
|
||||
offset: tok_start,
|
||||
} = match env.lxr.next().transpose()? {
|
||||
None => return Ok(None),
|
||||
Some(x) => x,
|
||||
};
|
||||
Ok(Some(match kind {
|
||||
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"));
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
env.lxr = backup;
|
||||
return Ok(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,
|
||||
};
|
||||
|
||||
// check for name collisions
|
||||
{
|
||||
let mut exports = Vec::new();
|
||||
pat.extract_exports(&mut exports)?;
|
||||
}
|
||||
|
||||
let pty = if env.lxr.got(Tok::DubColon).is_some() {
|
||||
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)))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
Ok(Some(FullPattern { pat, pty }))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Parse> MaybeParse for Record<T> {
|
||||
const DFL_CTX: &'static str = "record";
|
||||
|
||||
|
|
198
crates/yn-qgy4hbz-core/src/pat.rs
Normal file
198
crates/yn-qgy4hbz-core/src/pat.rs
Normal file
|
@ -0,0 +1,198 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Alain Zscheile <fogti+devel@ytrizja.de>
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
use super::parser::{
|
||||
self, Env as ParseEnv, Error as Perr, ErrorKind as Pek, MaybeParse, Parse, Token,
|
||||
TokenKind as Tok,
|
||||
};
|
||||
use super::{Expr, Record};
|
||||
use miette::SourceSpan;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum Pattern {
|
||||
Ident(Box<str>, parser::Offset),
|
||||
Record(Record<Pattern>),
|
||||
TyRecord(Record<Pattern>),
|
||||
Ignore,
|
||||
}
|
||||
|
||||
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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct FullPattern {
|
||||
pub pat: Pattern,
|
||||
pub pty: Option<Box<(SourceSpan, Expr)>>,
|
||||
}
|
||||
|
||||
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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Pattern {
|
||||
pub fn push_to_penv(&self, env: &mut ParseEnv<'_>) {
|
||||
match self {
|
||||
Pattern::Ident(i, _) => env.names.push(i.clone()),
|
||||
Pattern::Record(xs) | Pattern::TyRecord(xs) => {
|
||||
xs.fields[..].iter().for_each(|i| i.1.push_to_penv(env));
|
||||
}
|
||||
Pattern::Ignore => {}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn pop_from_penv(&self, env: &mut ParseEnv<'_>) {
|
||||
match self {
|
||||
Pattern::Ident(..) => {
|
||||
env.names.pop();
|
||||
}
|
||||
Pattern::Record(xs) | Pattern::TyRecord(xs) => {
|
||||
xs.fields[..].iter().for_each(|i| i.1.pop_from_penv(env));
|
||||
}
|
||||
Pattern::Ignore => {}
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
self.push_to_penv(env);
|
||||
let height = env.names.len();
|
||||
let ret = f(env);
|
||||
assert_eq!(env.names.len(), height);
|
||||
self.pop_from_penv(env);
|
||||
assert_eq!(env.names.len(), orig_height);
|
||||
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,
|
||||
offset: tok_start,
|
||||
} = match env.lxr.next().transpose()? {
|
||||
None => return Ok(None),
|
||||
Some(x) => x,
|
||||
};
|
||||
Ok(Some(match kind {
|
||||
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"));
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
env.lxr = backup;
|
||||
return Ok(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,
|
||||
};
|
||||
|
||||
// check for name collisions
|
||||
{
|
||||
let mut exports = Vec::new();
|
||||
pat.extract_exports(&mut exports)?;
|
||||
}
|
||||
|
||||
let pty = if env.lxr.got(Tok::DubColon).is_some() {
|
||||
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)))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
Ok(Some(FullPattern { pat, pty }))
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue