use geo_aid_derive::Parse;
use num_traits::Zero;
use crate::script::builtins;
use std::{
fmt::{Debug, Display},
iter::Peekable,
marker::PhantomData,
};
use std::fmt::Formatter;
use crate::script::token::number::ProcNum;
use crate::span;
use super::{
token::{
number::CompExponent, Ampersant, Asterisk, At, Caret, Colon, Comma, Dollar, Dot, Eq,
Exclamation, Gt, Gteq, Ident, LBrace, LParen, LSquare, Let, Lt, Lteq, Minus, NamedIdent,
Number, Plus, Question, RBrace, RParen, RSquare, Semi, Slash, Span, StrLit, TokInteger,
Token,
},
unit, ComplexUnit, Error,
};
pub trait Parse {
type FirstToken: CheckParses;
fn parse<'t, I: Iterator<Item = &'t Token> + Clone>(
input: &mut InputStream<'t, I>,
) -> Result<Self, Error>
where
Self: Sized;
fn get_span(&self) -> Span;
}
pub trait CheckParses {
fn check_parses<'t, I: Iterator<Item = &'t Token> + Clone>(
input: &InputStream<'t, I>,
) -> Option<bool>;
}
impl<T: Parse> CheckParses for T {
fn check_parses<'t, I: Iterator<Item = &'t Token> + Clone>(
input: &InputStream<'t, I>,
) -> Option<bool> {
Some(input.clone().parse::<Self>().is_ok())
}
}
#[derive(Debug)]
pub struct TokenOr<T, U> {
phantom_t: PhantomData<T>,
phantom_u: PhantomData<U>,
}
impl<T: CheckParses, U: CheckParses> CheckParses for TokenOr<T, U> {
fn check_parses<'t, I: Iterator<Item = &'t Token> + Clone>(
input: &InputStream<'t, I>,
) -> Option<bool> {
T::check_parses(input).or_else(|| U::check_parses(input))
}
}
#[derive(Debug)]
pub struct Maybe<T> {
phantom_t: PhantomData<T>,
}
impl<T: CheckParses> CheckParses for Maybe<T> {
fn check_parses<'t, I: Iterator<Item = &'t Token> + Clone>(
input: &InputStream<'t, I>,
) -> Option<bool> {
T::check_parses(input).and_then(|x| if x { Some(x) } else { None })
}
}
impl<T: Parse> Parse for Vec<T> {
type FirstToken = Maybe<T::FirstToken>;
fn parse<'t, I: Iterator<Item = &'t Token> + Clone>(
input: &mut InputStream<'t, I>,
) -> Result<Self, Error>
where
Self: Sized,
{
let mut parsed = Self::new();
while let Ok(Some(v)) = input.parse() {
parsed.push(v);
}
Ok(parsed)
}
fn get_span(&self) -> Span {
self.first().map_or(Span::empty(), |x| {
x.get_span().join(self.last().unwrap().get_span())
})
}
}
impl<T: Parse, U: Parse> Parse for (T, U) {
type FirstToken = T::FirstToken;
fn parse<'t, I: Iterator<Item = &'t Token> + Clone>(
input: &mut InputStream<'t, I>,
) -> Result<Self, Error>
where
Self: Sized,
{
Ok((input.parse()?, input.parse()?))
}
fn get_span(&self) -> Span {
self.0.get_span().join(self.1.get_span())
}
}
impl<T: Parse> Parse for Option<T> {
type FirstToken = Maybe<T::FirstToken>;
fn parse<'t, I: Iterator<Item = &'t Token> + Clone>(
input: &mut InputStream<'t, I>,
) -> Result<Self, Error>
where
Self: Sized,
{
if T::FirstToken::check_parses(input) == Some(false) {
Ok(None)
} else {
Ok(Some(input.parse()?))
}
}
fn get_span(&self) -> Span {
match self {
Some(v) => v.get_span(),
None => span!(0, 0, 0, 0),
}
}
}
#[derive(Debug, Clone)]
pub struct InputStream<'t, I: Iterator<Item = &'t Token> + Clone> {
it: Peekable<I>,
}
impl<'t, I: Iterator<Item = &'t Token> + Clone> InputStream<'t, I> {
#[must_use]
pub fn new<It: IntoIterator<IntoIter = I>>(it: It) -> Self {
Self {
it: it.into_iter().peekable(),
}
}
pub fn parse<P: Parse>(&mut self) -> Result<P, Error> {
P::parse(self)
}
pub fn get_token(&mut self) -> Result<&'t Token, Error> {
self.it.next().ok_or(Error::EndOfInput)
}
pub fn expect_token(&mut self) -> Result<(), Error> {
if self.eof() {
Err(Error::EndOfInput)
} else {
Ok(())
}
}
#[must_use]
pub fn eof(&mut self) -> bool {
self.it.peek().is_none()
}
}
#[derive(Debug, Parse)]
pub enum BinaryOperator {
Add(Plus),
Sub(Minus),
Mul(Asterisk),
Div(Slash),
}
impl Display for BinaryOperator {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
BinaryOperator::Add(_) => write!(f, "+"),
BinaryOperator::Sub(_) => write!(f, "-"),
BinaryOperator::Mul(_) => write!(f, "*"),
BinaryOperator::Div(_) => write!(f, "/"),
}
}
}
#[derive(Debug, Parse)]
#[parse(first_token = Ampersant)]
pub struct PointCollectionConstructor {
pub ampersant: Ampersant,
pub left_paren: LParen,
pub points: Punctuated<Expression<false>, Comma>,
pub right_paren: RParen,
}
#[derive(Debug)]
pub struct ImplicitIterator<const ITER: bool> {
pub exprs: Punctuated<SimpleExpression, Comma>,
}
impl<const ITER: bool> ImplicitIterator<ITER> {
#[must_use]
pub fn get(&self, index: usize) -> Option<&SimpleExpression> {
if ITER {
self.exprs.get(index)
} else {
Some(&self.exprs.first)
}
}
}
impl<const ITER: bool> Parse for ImplicitIterator<ITER> {
type FirstToken = <SimpleExpression as Parse>::FirstToken;
fn parse<'t, I: Iterator<Item = &'t Token> + Clone>(
input: &mut InputStream<'t, I>,
) -> Result<Self, Error>
where
Self: Sized,
{
if ITER {
Ok(Self {
exprs: input.parse()?,
})
} else {
Ok(Self {
exprs: Punctuated {
first: input.parse()?,
collection: Vec::new(),
},
})
}
}
fn get_span(&self) -> Span {
self.exprs.get_span()
}
}
#[derive(Debug)]
pub struct ExplicitIterator {
pub dollar: Dollar,
pub id_token: TokInteger,
pub id: u8,
pub left_paren: LParen,
pub exprs: Punctuated<Expression<false>, Comma>,
pub right_paren: RParen,
}
impl ExplicitIterator {
#[must_use]
pub fn get(&self, index: usize) -> Option<&Expression<false>> {
self.exprs.get(index)
}
}
impl Parse for ExplicitIterator {
type FirstToken = Dollar;
fn parse<'r, I: Iterator<Item = &'r Token> + Clone>(
input: &mut InputStream<'r, I>,
) -> Result<Self, Error> {
let mut parsed = Self {
dollar: input.parse()?,
id_token: input.parse()?,
id: 0,
left_paren: input.parse()?,
exprs: input.parse()?,
right_paren: input.parse()?,
};
parsed.id = parsed
.id_token
.parsed
.parse()
.map_err(|_| Error::NumberTooLarge {
error_span: parsed.id_token.get_span(),
})?;
if parsed.exprs.len() == 1 {
return Err(Error::SingleVariantExplicitIterator {
error_span: parsed.dollar.span.join(parsed.right_paren.span),
});
}
Ok(parsed)
}
fn get_span(&self) -> Span {
self.dollar.span.join(self.right_paren.span)
}
}
#[derive(Debug)]
pub enum Expression<const ITER: bool> {
ImplicitIterator(ImplicitIterator<ITER>),
Binop(ExprBinop<ITER>),
}
impl<const ITER: bool> Parse for Expression<ITER> {
type FirstToken = <SimpleExpression as Parse>::FirstToken;
fn parse<'r, I: Iterator<Item = &'r Token> + Clone>(
input: &mut InputStream<'r, I>,
) -> Result<Self, Error> {
let mut expr = Expression::ImplicitIterator(input.parse()?);
while let Ok(Some(op)) = input.parse() {
let rhs = Expression::ImplicitIterator(input.parse()?);
expr = dispatch_order(expr, op, rhs);
}
Ok(expr)
}
fn get_span(&self) -> Span {
match self {
Expression::ImplicitIterator(it) => it.get_span(),
Expression::Binop(e) => e.lhs.get_span().join(e.rhs.get_span()),
}
}
}
#[derive(Debug)]
pub struct RationalExponent {
pub lparen: LParen,
pub nom: TokInteger,
pub slash: Slash,
pub denom: TokInteger,
pub rparen: RParen,
}
impl Parse for RationalExponent {
type FirstToken = LParen;
fn parse<'r, I: Iterator<Item = &'r Token> + Clone>(
input: &mut InputStream<'r, I>,
) -> Result<Self, Error> {
let parsed = Self {
lparen: input.parse()?,
nom: input.parse()?,
slash: input.parse()?,
denom: input.parse()?,
rparen: input.parse()?,
};
if parsed.denom.parsed.is_zero() {
return Err(Error::ZeroDenominator {
error_span: parsed.denom.span,
});
}
Ok(parsed)
}
fn get_span(&self) -> Span {
self.lparen.span.join(self.rparen.span)
}
}
#[derive(Debug, Parse)]
pub enum Exponent {
Simple(TokInteger),
Parenthesized(RationalExponent),
}
impl Exponent {
pub fn as_comp(&self) -> Result<CompExponent, Error> {
match self {
Self::Simple(i) => Ok(CompExponent::new(
i.parsed
.parse()
.map_err(|_| Error::NumberTooLarge { error_span: i.span })?,
1,
)),
Self::Parenthesized(exp) => Ok(CompExponent::new(
exp.nom.parsed.parse().map_err(|_| Error::NumberTooLarge {
error_span: exp.nom.span,
})?,
exp.denom
.parsed
.parse()
.map_err(|_| Error::NumberTooLarge {
error_span: exp.denom.span,
})?,
)),
}
}
}
#[derive(Debug, Parse)]
pub struct Exponentiation {
pub caret: Caret,
pub minus: Option<Minus>,
pub exponent: Exponent,
}
#[derive(Debug, Parse)]
pub struct FieldIndex {
pub name: Box<Name>,
pub dot: Dot,
pub field: Ident,
}
#[derive(Debug)]
pub enum Name {
Call(ExprCall),
FieldIndex(FieldIndex),
Ident(Ident),
Expression(ExprParenthesised),
}
impl Parse for Name {
type FirstToken = TokenOr<Maybe<Ident>, LParen>;
fn parse<'t, I: Iterator<Item = &'t Token> + Clone>(
input: &mut InputStream<'t, I>,
) -> Result<Self, Error>
where
Self: Sized,
{
let mut name = if let Some(expr) = input.parse()? {
Self::Expression(expr)
} else {
Self::Ident(input.parse()?)
};
loop {
name = if let Some(dot) = input.parse::<Option<Dot>>()? {
Self::FieldIndex(FieldIndex {
name: Box::new(name),
dot,
field: input.parse()?,
})
} else if let Some(lparen) = input.parse::<Option<LParen>>()? {
Self::Call(ExprCall {
name: Box::new(name),
lparen,
params: input.parse()?,
rparen: input.parse()?,
})
} else {
break Ok(name);
};
}
}
fn get_span(&self) -> Span {
match self {
Self::Call(v) => v.get_span(),
Self::FieldIndex(v) => v.get_span(),
Self::Expression(v) => v.get_span(),
Self::Ident(v) => v.get_span(),
}
}
}
#[derive(Debug, Parse)]
pub struct SimpleExpression {
pub minus: Option<Minus>,
pub kind: SimpleExpressionKind,
pub exponent: Option<Exponentiation>,
pub display: Option<DisplayProperties>,
}
#[derive(Debug, Parse)]
pub enum SimpleExpressionKind {
Name(Name),
Number(Number),
ExplicitIterator(ExplicitIterator),
PointCollection(PointCollectionConstructor),
}
#[derive(Debug, Parse)]
pub struct ExprCall {
pub name: Box<Name>,
pub lparen: LParen,
pub params: Option<Punctuated<Expression<false>, Comma>>,
pub rparen: RParen,
}
#[derive(Debug, Parse)]
pub struct ExprParenthesised {
pub lparen: LParen,
pub content: Box<Expression<true>>,
pub rparen: RParen,
}
#[derive(Debug, Parse)]
pub struct ExprBinop<const ITER: bool> {
pub lhs: Box<Expression<ITER>>,
pub operator: BinaryOperator,
pub rhs: Box<Expression<ITER>>,
}
impl BinaryOperator {
fn index(&self) -> u8 {
match self {
BinaryOperator::Add(_) | BinaryOperator::Sub(_) => 1,
BinaryOperator::Mul(_) | BinaryOperator::Div(_) => 2,
}
}
}
fn dispatch_order<const ITER: bool>(
lhs: Expression<ITER>,
op: BinaryOperator,
rhs: Expression<ITER>, ) -> Expression<ITER> {
match lhs {
lhs @ Expression::ImplicitIterator(_) => Expression::Binop(ExprBinop {
lhs: Box::new(lhs),
operator: op,
rhs: Box::new(rhs),
}),
Expression::Binop(lhs) => {
if op.index() > lhs.operator.index() {
Expression::Binop(ExprBinop {
lhs: lhs.lhs,
operator: lhs.operator,
rhs: Box::new(dispatch_order(*lhs.rhs, op, rhs)),
})
} else {
Expression::Binop(ExprBinop {
lhs: Box::new(Expression::Binop(lhs)),
operator: op,
rhs: Box::new(rhs),
})
}
}
}
}
#[derive(Debug, Parse)]
pub enum PredefinedRuleOperator {
Eq(Eq),
Lt(Lt),
Gt(Gt),
Lteq(Lteq),
Gteq(Gteq),
}
#[derive(Debug, Parse)]
pub enum RuleOperator {
Inverted(InvertedRuleOperator),
Predefined(PredefinedRuleOperator),
Defined(NamedIdent),
}
#[derive(Debug, Parse)]
#[parse(first_token = Exclamation)]
pub struct InvertedRuleOperator {
pub exclamation: Exclamation,
pub operator: Box<RuleOperator>,
}
#[derive(Debug, Parse)]
pub struct FlagName {
pub at: At,
pub name: Punctuated<NamedIdent, Dot>,
pub colon: Colon,
}
#[derive(Debug, Parse)]
#[parse(first_token = LBrace)]
pub struct FlagSet {
pub lbrace: LBrace,
pub flags: Vec<FlagStatement>,
pub rbrace: RBrace,
}
#[derive(Debug, Parse)]
pub enum FlagValue {
Ident(NamedIdent),
Set(FlagSet),
Number(Number),
}
#[derive(Debug, Parse)]
pub struct FlagStatement {
pub name: FlagName,
pub value: FlagValue,
}
#[derive(Debug, Clone, Parse)]
pub struct VariableDefinition {
pub name: Ident,
pub display_properties: Option<DisplayProperties>,
}
#[derive(Debug, Parse)]
pub struct LetStatement {
pub let_token: Let,
pub ident: Punctuated<VariableDefinition, Comma>,
pub eq: Eq,
pub expr: Expression<true>,
pub rules: Vec<(RuleOperator, Expression<true>)>,
pub semi: Semi,
}
#[derive(Debug, Parse)]
pub struct RuleStatement {
pub display: Option<DisplayProperties>,
pub lhs: Expression<true>,
pub op: RuleOperator,
pub rhs: Expression<true>,
pub semi: Semi,
}
#[derive(Debug, Parse)]
pub struct RefStatement {
pub display: Option<DisplayProperties>,
pub question: Question,
pub operand: Expression<true>,
pub semi: Semi,
}
#[derive(Debug, Parse)]
pub enum Statement {
Noop(Semi),
Let(LetStatement),
Flag(FlagStatement),
Ref(RefStatement),
Rule(RuleStatement),
}
impl Statement {
#[must_use]
pub fn as_flag(&self) -> Option<&FlagStatement> {
if let Self::Flag(v) = self {
Some(v)
} else {
None
}
}
}
#[derive(Debug, Clone, Parse)]
pub struct Punctuated<T: Parse, P: Parse> {
pub first: Box<T>,
pub collection: Vec<(P, T)>,
}
impl<T: Parse, P: Parse> Punctuated<T, P> {
#[must_use]
pub fn new(first: T) -> Punctuated<T, P> {
Self {
first: Box::new(first),
collection: Vec::new(),
}
}
pub fn iter(&self) -> impl Iterator<Item = &T> {
vec![self.first.as_ref()]
.into_iter()
.chain(self.collection.iter().map(|x| &x.1))
}
pub fn into_parsed_iter(self) -> impl Iterator<Item = T> {
vec![*self.first]
.into_iter()
.chain(self.collection.into_iter().map(|x| x.1))
}
#[must_use]
pub fn len(&self) -> usize {
self.collection.len() + 1
}
#[must_use]
pub fn is_empty(&self) -> bool {
false
}
#[must_use]
pub fn get(&self, index: usize) -> Option<&T> {
match index {
0 => Some(&self.first),
_ => self.collection.get(index - 1).map(|x| &x.1),
}
}
}
impl Parse for TokInteger {
type FirstToken = Number;
fn parse<'r, I: Iterator<Item = &'r Token> + Clone>(
input: &mut InputStream<'r, I>,
) -> Result<Self, Error> {
match input.get_token()? {
Token::Number(Number::Integer(tok)) => Ok(tok.clone()),
t => Err(Error::InvalidToken { token: t.clone() }),
}
}
fn get_span(&self) -> Span {
self.span
}
}
impl Parse for NamedIdent {
type FirstToken = Ident;
fn parse<'r, I: Iterator<Item = &'r Token> + Clone>(
input: &mut InputStream<'r, I>,
) -> Result<Self, Error> {
match input.get_token()? {
Token::Ident(Ident::Named(named)) => Ok(named.clone()),
t => Err(Error::InvalidToken { token: t.clone() }),
}
}
fn get_span(&self) -> Span {
self.span
}
}
impl<T: Parse> Parse for Box<T> {
type FirstToken = T::FirstToken;
fn parse<'r, I: Iterator<Item = &'r Token> + Clone>(
input: &mut InputStream<'r, I>,
) -> Result<Self, Error> {
Ok(Box::new(input.parse()?))
}
fn get_span(&self) -> Span {
(**self).get_span()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Type {
Point,
Line,
Scalar(Option<ComplexUnit>),
PointCollection(usize),
Circle,
Bundle(&'static str),
Unknown,
}
impl Type {
#[must_use]
pub fn as_scalar(&self) -> Option<&Option<ComplexUnit>> {
if let Self::Scalar(v) = self {
Some(v)
} else {
None
}
}
}
pub struct DefinedType {
pub name: String,
}
impl Display for Type {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Point => write!(f, "Point"),
Self::Line => write!(f, "Line"),
Self::Scalar(unit) => match unit {
Some(unit) => write!(f, "Scalar ({unit})"),
None => write!(f, "Scalar (no unit)"),
},
Self::PointCollection(l) => write!(f, "Point collection ({l})"),
Self::Circle => write!(f, "Circle"),
Self::Bundle(name) => write!(f, "{name}"),
Type::Unknown => write!(f, "undefined"),
}
}
}
impl Type {
#[must_use]
pub fn can_cast(&self, into: &Type) -> bool {
match self {
Type::Point => matches!(into, Type::Point | Type::PointCollection(1)),
Type::Line => matches!(into, Type::Line),
Type::Scalar(Some(unit1)) => {
if let Type::Scalar(Some(unit2)) = into {
unit1 == unit2
} else {
false
}
}
Type::Scalar(None) => match into {
Type::Scalar(unit) => match unit {
Some(unit) => unit.0[1].is_zero(), None => true,
},
_ => false,
},
Type::PointCollection(l) => match into {
Type::Point => *l == 1,
Type::Line => *l == 2,
Type::Scalar(Some(u)) => *u == unit::DISTANCE && *l == 2,
Type::PointCollection(v) => v == l || *v == 0,
_ => false,
},
Type::Circle => matches!(into, Type::Circle),
Type::Bundle(name) => {
if into == self {
true
} else if let Type::PointCollection(count) = into {
builtins::get_bundle_pc(name) == *count
} else {
false
}
}
Type::Unknown => false,
}
}
}
#[derive(Debug, Clone, Parse)]
pub struct Property {
pub name: NamedIdent,
pub eq: Eq,
pub value: PropertyValue,
}
#[derive(Debug, Clone, Parse)]
pub enum PropertyValue {
Number(Number),
Ident(Ident),
RawString(RawString),
String(StrLit),
}
impl Display for PropertyValue {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Number(n) => write!(f, "{n}"),
Self::Ident(i) => write!(f, "{i}"),
Self::RawString(s) => write!(f, "!{}", s.lit),
Self::String(s) => write!(f, "{s}"),
}
}
}
#[derive(Debug, Clone, Parse)]
pub struct RawString {
pub excl: Exclamation,
pub lit: StrLit,
}
pub trait FromProperty: Sized {
fn from_property(property: PropertyValue) -> Result<Self, Error>;
}
impl<T: FromProperty> FromProperty for Result<T, Error> {
fn from_property(property: PropertyValue) -> Result<Self, Error> {
Ok(T::from_property(property))
}
}
impl FromProperty for bool {
fn from_property(property: PropertyValue) -> Result<Self, Error> {
match property {
PropertyValue::Ident(ident) => match ident {
Ident::Named(ident) => match ident.ident.as_str() {
"enabled" | "on" | "true" | "yes" => Ok(true),
"disabled" | "off" | "false" | "no" => Ok(false),
_ => Err(Error::BooleanExpected {
error_span: ident.get_span(),
}),
},
Ident::Collection(_) => Err(Error::BooleanExpected {
error_span: ident.get_span(),
}),
},
PropertyValue::Number(num) => match num {
Number::Integer(i) => match i.parsed.parse::<u8>() {
Ok(0) => Ok(false),
Ok(1) => Ok(true),
_ => Err(Error::BooleanExpected { error_span: i.span }),
},
Number::Float(f) => Err(Error::BooleanExpected { error_span: f.span }),
},
PropertyValue::String(s) => match s.content.as_str() {
"enabled" | "on" | "true" | "yes" => Ok(true),
"disabled" | "off" | "false" | "no" => Ok(false),
_ => Err(Error::BooleanExpected {
error_span: s.get_span(),
}),
},
PropertyValue::RawString(s) => Err(Error::BooleanExpected {
error_span: s.get_span(),
}),
}
}
}
impl FromProperty for String {
fn from_property(property: PropertyValue) -> Result<String, Error> {
match property {
PropertyValue::Ident(ident) => Ok(ident.to_string()),
PropertyValue::Number(num) => Err(Error::StringExpected {
error_span: num.get_span(),
}),
PropertyValue::RawString(s) => Ok(s.lit.content),
PropertyValue::String(s) => Ok(s.content),
}
}
}
impl FromProperty for ProcNum {
fn from_property(property: PropertyValue) -> Result<Self, Error> {
match property {
PropertyValue::Number(num) => Ok(ProcNum::from(&num)),
PropertyValue::RawString(s) => Err(Error::NumberExpected {
error_span: s.get_span(),
}),
PropertyValue::String(s) => Err(Error::NumberExpected {
error_span: s.get_span(),
}),
PropertyValue::Ident(ident) => Err(Error::NumberExpected {
error_span: ident.get_span(),
})
}
}
}
#[derive(Debug, Clone, Parse)]
pub struct DisplayProperties {
pub lsquare: LSquare,
pub properties: Punctuated<Property, Semi>,
pub rsquare: RSquare,
}