use crate::span::Span;
pub use crate::token::*;
use syan::error::ParseError;
use syan::parse::unparse::Emitter;
use syan::parse::{Parse, ParseStream, Unparse};
use syan::span::Spanned;
macro_rules! qualified_name_tokens {
($($(#[$doc:meta])* $name:ident => $variant:ident, $desc:literal;)*) => {
$(
$(#[$doc])*
#[derive(Clone, Debug, PartialEq)]
pub struct $name {
pub mods: Vec<String>,
pub name: String,
pub span: Span,
}
impl Parse<Atom> for $name {
type Error = ParseError<Span>;
fn parse_stream<S: ParseStream<Atom = Atom>>(
stream: &mut S,
) -> Result<Self, Self::Error> {
match stream.next() {
Some(Atom { slot: Token::$variant(mods, name), span }) => {
Ok($name { mods, name, span })
}
Some(atom) => {
let span = atom.span;
stream.push(atom);
Err(ParseError::expected(span, $desc))
}
None => Err(ParseError::eof(Span::default())),
}
}
}
impl Unparse<Atom> for $name {
fn unparse<S: Emitter<Atom>>(&self, sink: &mut S) -> Result<(), S::Error> {
sink.write_one(Atom {
slot: Token::$variant(self.mods.clone(), self.name.clone()),
span: self.span,
})
}
}
impl Spanned for $name {
type Span = Span;
fn span(&self) -> Span {
self.span
}
}
)*
};
}
qualified_name_tokens! {
VarInHorzTok => VarInHorz, "a variable reference in inline text";
VarInVertTok => VarInVert, "a variable reference in block text";
VarInMathTok => VarInMath, "a variable reference in math";
VarWithModTok => VarWithMod, "a qualified variable name";
LongUpperTok => LongUpper, "a qualified module path";
HorzCmdWithModTok => HorzCmdWithMod, "a qualified inline command";
VertCmdWithModTok => VertCmdWithMod, "a qualified block command";
MathCmdWithModTok => MathCmdWithMod, "a qualified math command";
}
#[derive(Parse, Unparse, Debug, Clone, PartialEq)]
pub enum AnyHorzCmdTok {
Plain(HorzCmdTok),
Mod(HorzCmdWithModTok),
}
#[derive(Parse, Unparse, Debug, Clone, PartialEq)]
pub enum AnyVertCmdTok {
Plain(VertCmdTok),
Mod(VertCmdWithModTok),
}
#[derive(Parse, Unparse, Debug, Clone, PartialEq)]
pub enum AnyMathCmdTok {
Plain(MathCmdTok),
Mod(MathCmdWithModTok),
}
#[derive(Clone, Debug, PartialEq)]
pub struct LengthTok {
pub value: f64,
pub unit: String,
pub span: Span,
}
impl Parse<Atom> for LengthTok {
type Error = ParseError<Span>;
fn parse_stream<S: ParseStream<Atom = Atom>>(
stream: &mut S,
) -> Result<Self, Self::Error> {
match stream.next() {
Some(Atom {
slot: Token::LengthConst(value, unit),
span,
}) => Ok(LengthTok { value, unit, span }),
Some(atom) => {
let span = atom.span;
stream.push(atom);
Err(ParseError::expected(span, "a length constant"))
}
None => Err(ParseError::eof(Span::default())),
}
}
}
impl Unparse<Atom> for LengthTok {
fn unparse<S: Emitter<Atom>>(&self, sink: &mut S) -> Result<(), S::Error> {
sink.write_one(Atom {
slot: Token::LengthConst(self.value, self.unit.clone()),
span: self.span,
})
}
}
impl Spanned for LengthTok {
type Span = Span;
fn span(&self) -> Span {
self.span
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct LiteralTok {
pub body: String,
pub omit_pre: bool,
pub omit_post: bool,
pub span: Span,
}
impl Parse<Atom> for LiteralTok {
type Error = ParseError<Span>;
fn parse_stream<S: ParseStream<Atom = Atom>>(
stream: &mut S,
) -> Result<Self, Self::Error> {
match stream.next() {
Some(Atom {
slot:
Token::Literal {
body,
omit_pre,
omit_post,
},
span,
}) => Ok(LiteralTok {
body,
omit_pre,
omit_post,
span,
}),
Some(atom) => {
let span = atom.span;
stream.push(atom);
Err(ParseError::expected(span, "a string literal"))
}
None => Err(ParseError::eof(Span::default())),
}
}
}
impl Unparse<Atom> for LiteralTok {
fn unparse<S: Emitter<Atom>>(&self, sink: &mut S) -> Result<(), S::Error> {
sink.write_one(Atom {
slot: Token::Literal {
body: self.body.clone(),
omit_pre: self.omit_pre,
omit_post: self.omit_post,
},
span: self.span,
})
}
}
impl Spanned for LiteralTok {
type Span = Span;
fn span(&self) -> Span {
self.span
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct ExactTimesTok {
pub span: Span,
}
impl Parse<Atom> for ExactTimesTok {
type Error = ParseError<Span>;
fn parse_stream<S: ParseStream<Atom = Atom>>(
stream: &mut S,
) -> Result<Self, Self::Error> {
match stream.next() {
Some(Atom {
slot: Token::ExactTimes,
span,
}) => Ok(ExactTimesTok { span }),
Some(atom) => {
let span = atom.span;
stream.push(atom);
Err(ParseError::expected(span, "'*'"))
}
None => Err(ParseError::eof(Span::default())),
}
}
}
impl Unparse<Atom> for ExactTimesTok {
fn unparse<S: Emitter<Atom>>(&self, sink: &mut S) -> Result<(), S::Error> {
sink.write_one(Atom {
slot: Token::ExactTimes,
span: self.span,
})
}
}
impl Spanned for ExactTimesTok {
type Span = Span;
fn span(&self) -> Span {
self.span
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct BinOpTok {
pub tok: Token,
pub span: Span,
}
impl Parse<Atom> for BinOpTok {
type Error = ParseError<Span>;
fn parse_stream<S: ParseStream<Atom = Atom>>(
stream: &mut S,
) -> Result<Self, Self::Error> {
match stream.next() {
Some(Atom { slot, span })
if matches!(
slot,
Token::BinopPlus(_)
| Token::BinopMinus(_)
| Token::BinopTimes(_)
| Token::BinopDivides(_)
| Token::BinopEq(_)
| Token::BinopLt(_)
| Token::BinopGt(_)
| Token::BinopAmp(_)
| Token::BinopBar(_)
| Token::BinopHat(_)
| Token::ExactMinus
| Token::ExactTimes
| Token::Mod
| Token::Cons
) =>
{
Ok(BinOpTok { tok: slot, span })
}
Some(atom) => {
let span = atom.span;
stream.push(atom);
Err(ParseError::expected(span, "a binary operator"))
}
None => Err(ParseError::eof(Span::default())),
}
}
}
impl Unparse<Atom> for BinOpTok {
fn unparse<S: Emitter<Atom>>(&self, sink: &mut S) -> Result<(), S::Error> {
sink.write_one(Atom {
slot: self.tok.clone(),
span: self.span,
})
}
}
impl Spanned for BinOpTok {
type Span = Span;
fn span(&self) -> Span {
self.span
}
}
impl BinOpTok {
pub fn op_text(&self) -> String {
match &self.tok {
Token::BinopPlus(s)
| Token::BinopMinus(s)
| Token::BinopTimes(s)
| Token::BinopDivides(s)
| Token::BinopEq(s)
| Token::BinopLt(s)
| Token::BinopGt(s)
| Token::BinopAmp(s)
| Token::BinopBar(s)
| Token::BinopHat(s) => s.clone(),
Token::ExactMinus => "-".to_string(),
Token::ExactTimes => "*".to_string(),
Token::Mod => "mod".to_string(),
Token::Cons => "::".to_string(),
_ => unreachable!("BinOpTok only ever holds one of the matched variants"),
}
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct NamingOpTok {
pub tok: Token,
pub span: Span,
}
impl Parse<Atom> for NamingOpTok {
type Error = ParseError<Span>;
fn parse_stream<S: ParseStream<Atom = Atom>>(
stream: &mut S,
) -> Result<Self, Self::Error> {
match stream.next() {
Some(Atom { slot, span })
if matches!(
slot,
Token::BinopPlus(_)
| Token::BinopMinus(_)
| Token::BinopTimes(_)
| Token::BinopDivides(_)
| Token::BinopEq(_)
| Token::BinopLt(_)
| Token::BinopGt(_)
| Token::BinopAmp(_)
| Token::BinopBar(_)
| Token::BinopHat(_)
| Token::ExactMinus
| Token::ExactTimes
| Token::Mod
| Token::Cons
| Token::UnopExclam(_)
| Token::Before
) =>
{
Ok(NamingOpTok { tok: slot, span })
}
Some(atom) => {
let span = atom.span;
stream.push(atom);
Err(ParseError::expected(
span,
"a binary operator, '!', or 'before'",
))
}
None => Err(ParseError::eof(Span::default())),
}
}
}
impl Unparse<Atom> for NamingOpTok {
fn unparse<S: Emitter<Atom>>(&self, sink: &mut S) -> Result<(), S::Error> {
sink.write_one(Atom {
slot: self.tok.clone(),
span: self.span,
})
}
}
impl Spanned for NamingOpTok {
type Span = Span;
fn span(&self) -> Span {
self.span
}
}
impl NamingOpTok {
pub fn op_text(&self) -> String {
match &self.tok {
Token::BinopPlus(s)
| Token::BinopMinus(s)
| Token::BinopTimes(s)
| Token::BinopDivides(s)
| Token::BinopEq(s)
| Token::BinopLt(s)
| Token::BinopGt(s)
| Token::BinopAmp(s)
| Token::BinopBar(s)
| Token::BinopHat(s)
| Token::UnopExclam(s) => s.clone(),
Token::ExactMinus => "-".to_string(),
Token::ExactTimes => "*".to_string(),
Token::Mod => "mod".to_string(),
Token::Cons => "::".to_string(),
Token::Before => "before".to_string(),
_ => unreachable!("NamingOpTok only ever holds one of the matched variants"),
}
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct OpNameTok {
pub name: String,
pub span: Span,
pub lparen: LParenTok,
pub op: NamingOpTok,
pub rparen: RParenTok,
}
impl Parse<Atom> for OpNameTok {
type Error = ParseError<Span>;
fn parse_stream<S: ParseStream<Atom = Atom>>(
stream: &mut S,
) -> Result<Self, Self::Error> {
let lparen = LParenTok::parse_stream(&mut *stream)?;
let op = NamingOpTok::parse_stream(&mut *stream)?;
let rparen = RParenTok::parse_stream(&mut *stream)?;
let name = op.op_text();
let span = lparen.span().unite(rparen.span());
Ok(OpNameTok {
name,
span,
lparen,
op,
rparen,
})
}
}
impl Unparse<Atom> for OpNameTok {
fn unparse<S: Emitter<Atom>>(&self, sink: &mut S) -> Result<(), S::Error> {
self.lparen.unparse(sink)?;
self.op.unparse(sink)?;
self.rparen.unparse(sink)
}
}
impl Spanned for OpNameTok {
type Span = Span;
fn span(&self) -> Span {
self.span
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct HeaderStageTok {
pub tok: Token,
pub span: Span,
}
impl Parse<Atom> for HeaderStageTok {
type Error = ParseError<Span>;
fn parse_stream<S: ParseStream<Atom = Atom>>(
stream: &mut S,
) -> Result<Self, Self::Error> {
match stream.next() {
Some(Atom { slot, span })
if matches!(
slot,
Token::HeaderStage0 | Token::HeaderStage1 | Token::HeaderPersistent0
) =>
{
Ok(HeaderStageTok { tok: slot, span })
}
Some(atom) => {
let span = atom.span;
stream.push(atom);
Err(ParseError::expected(span, "'@stage:'"))
}
None => Err(ParseError::eof(Span::default())),
}
}
}
impl Unparse<Atom> for HeaderStageTok {
fn unparse<S: Emitter<Atom>>(&self, sink: &mut S) -> Result<(), S::Error> {
sink.write_one(Atom {
slot: self.tok.clone(),
span: self.span,
})
}
}
impl Spanned for HeaderStageTok {
type Span = Span;
fn span(&self) -> Span {
self.span
}
}
pub type ParenGroup<T> = syan::nested::group::Group<T, LParenTok, RParenTok>;
pub type RecordGroup<T> = syan::nested::group::Group<T, BRecordTok, ERecordTok>;
pub type ListGroup<T> = syan::nested::group::Group<T, BListTok, EListTok>;
pub type InlineGroup<T> = syan::nested::group::Group<T, BHorzGrpTok, EHorzGrpTok>;
pub type BlockGroup<T> = syan::nested::group::Group<T, BVertGrpTok, EVertGrpTok>;
pub type MathGroup<T> = syan::nested::group::Group<T, BMathGrpTok, EMathGrpTok>;
pub type OpenModuleGroup<T> = syan::nested::group::Group<T, OpenModuleTok, RParenTok>;
#[derive(Parse, Unparse, Debug, Clone, PartialEq)]
pub struct UnitParen {
pub open: LParenTok,
pub close: RParenTok,
}
impl Spanned for UnitParen {
type Span = Span;
fn span(&self) -> Span {
self.open.span().unite(self.close.span())
}
}
macro_rules! leaf_eq {
(
span_only: $($unit:ident),* $(,)?;
with_fields: $($payload:ident { $($field:ident),* }),* $(,)?
) => {
$(
impl PartialEq for $unit {
fn eq(&self, other: &Self) -> bool {
self.0 == other.0
}
}
)*
$(
impl PartialEq for $payload {
fn eq(&self, other: &Self) -> bool {
$(self.$field == other.$field &&)* self.span == other.span
}
}
)*
};
}
leaf_eq! {
span_only:
KwLet, KwLetRec, KwLetHorz, KwLetVert, KwLetMath, KwAnd, KwIn, KwFun,
KwIf, KwThen, KwElse, KwTrue, KwFalse, ArrowTok, DefEqTok, ListPunctTok,
CommaTok, LParenTok, RParenTok, BRecordTok, ERecordTok, BListTok, EListTok,
BHorzGrpTok, EHorzGrpTok, BVertGrpTok, EVertGrpTok, SpaceTok, BreakTok,
EndActiveTok, EoiTok, KwMatch, KwWith, KwWhen, KwAs, KwType, KwOf, BarTok,
WildcardTok, ConsTok, ColonTok, ExactMinusTok, KwLetMutable, KwWhile, KwDo,
KwBefore, OverwriteEqTok, AccessTok, KwModule, KwStruct, KwSig, KwEnd,
KwOpen, KwVal, KwDirect, OptionalTok, OmissionTok, SuperscriptTok,
SubscriptTok, SepTok, BMathGrpTok, EMathGrpTok, HorzCmdTypeTok,
VertCmdTypeTok, MathCmdTypeTok, OptionalTypeTok, OptionalArrowTok,
ConstraintTok, CommandTok, KwRec, KwInline, KwBlock, KwMutable,
CoerceTok, KwSignature, KwInclude, KwUse, KwPackage, KwMath,
KwPersistent, ExactAmpTok, ExactTildeTok;
with_fields:
VarTok { name }, CtorTok { name }, IntTok { value }, FloatTok { value },
HorzCmdTok { name }, VertCmdTok { name }, CharTok { text }, ItemTok { depth },
CodeTextTok { text },
HeaderRequireTok { content }, HeaderImportTok { content }, TypeVarTok { name },
UnopExclamTok { text }, MathCharTok { text }, MathCmdTok { name },
PrimesTok { count }, OpenModuleTok { name }, RowVarTok { name }
}