use std::{
fmt::Display,
hash::Hash,
ops::{Deref, DerefMut, Div, Mul},
rc::Rc,
sync::Arc,
};
use crate::cli::{AnnotationKind, DiagnosticData};
use self::parser::Type;
use self::token::{NamedIdent, Span, Token};
mod builtins;
pub mod compile;
pub mod figure;
pub mod parser;
pub mod token;
pub mod unroll;
#[derive(Debug)]
pub enum Error {
InvalidToken {
token: Token,
},
InvalidCharacter {
character: char,
error_span: Span,
},
EndOfInput,
UndefinedRuleOperator {
operator: NamedIdent,
},
InconsistentIterators {
first_span: Span,
first_length: usize,
occured_span: Span,
occured_length: usize,
error_span: Span,
},
InconsistentTypes {
expected: (Type, Box<Span>),
got: (Type, Box<Span>),
error_span: Box<Span>,
},
InvalidType {
expected: Type,
got: (Type, Span),
},
RedefinedVariable {
defined_at: Span,
error_span: Span,
variable_name: String,
},
UndefinedTypeVariable {
definition: Span,
},
UndefinedVariable {
error_span: Span,
variable_name: String,
},
UndefinedFunction {
error_span: Span,
function_name: String,
},
FetureNotSupported {
error_span: Span,
feature_name: &'static str,
},
InvalidArgumentCount {
error_span: Span,
expected: &'static [u8],
got: u8,
},
OverloadNotFound {
error_span: Span,
params: Vec<Type>,
function_name: String,
},
CannotUnpack {
error_span: Span,
ty: Type,
},
ImplicitConversionDoesNotExist {
error_span: Span,
from: Type,
to: Type,
},
InvalidOperandType {
error_span: Span,
got: (Type, Span),
op: String,
},
LetStatUnexpectedIterator {
var_span: Span,
error_span: Span,
},
}
impl Error {
#[must_use]
pub fn inconsistent_iterators_get_span(&self) -> Option<Span> {
match self {
Self::InconsistentIterators {
first_span: _,
first_length: _,
occured_span,
occured_length: _,
error_span: _,
} => Some(*occured_span),
_ => None,
}
}
#[must_use]
pub fn invalid_token(token: Token) -> Self {
Self::InvalidToken { token }
}
#[must_use]
pub fn invalid_character(character: char, error_span: Span) -> Self {
Self::InvalidCharacter {
character,
error_span,
}
}
#[must_use]
pub fn end_of_input() -> Self {
Self::EndOfInput
}
#[must_use]
pub fn undefined_rule_operator(name: NamedIdent) -> Self {
Self::UndefinedRuleOperator { operator: name }
}
#[must_use]
pub fn redefined_variable(defined_at: Span, error_span: Span, variable_name: String) -> Self {
Self::RedefinedVariable {
defined_at,
error_span,
variable_name,
}
}
#[must_use]
pub fn undefined_type_variable(definition: Span) -> Self {
Self::UndefinedTypeVariable { definition }
}
#[must_use]
pub fn undefined_function(error_span: Span, function_name: String) -> Self {
Self::UndefinedFunction {
error_span,
function_name,
}
}
#[must_use]
pub fn feature_not_supported(error_span: Span, feature_name: &'static str) -> Self {
Self::FetureNotSupported {
error_span,
feature_name,
}
}
#[must_use]
pub fn invalid_argument_count(error_span: Span, expected: &'static [u8], got: u8) -> Self {
Self::InvalidArgumentCount {
error_span,
expected,
got,
}
}
#[must_use]
pub fn overload_not_found(error_span: Span, function_name: String, params: Vec<Type>) -> Self {
Self::OverloadNotFound {
error_span,
params,
function_name,
}
}
#[must_use]
pub fn cannot_unpack(error_span: Span, ty: Type) -> Self {
Self::CannotUnpack { error_span, ty }
}
#[must_use]
pub fn implicit_conversion_does_not_exist(error_span: Span, from: Type, to: Type) -> Self {
Self::ImplicitConversionDoesNotExist {
error_span,
from,
to,
}
}
#[must_use]
#[allow(clippy::too_many_lines)]
pub fn diagnostic(self) -> DiagnosticData {
match self {
Self::InvalidToken { token } => {
DiagnosticData::new(&format!("invalid token: `{token}`")).add_span(token.get_span())
}
Self::InvalidCharacter {
character,
error_span,
} => DiagnosticData::new(&format!("invalid character: `{character}`"))
.add_span(error_span),
Self::EndOfInput => DiagnosticData::new("unexpected end of input"),
Self::UndefinedRuleOperator { operator } => {
DiagnosticData::new(&format!("undefined rule operator: `{}`", operator.ident))
.add_span(operator.span)
}
Self::InconsistentIterators {
first_span,
first_length,
occured_span,
occured_length,
error_span,
} => DiagnosticData::new(&"inconsitent iterator lengths")
.add_span(error_span)
.add_annotation(
first_span,
AnnotationKind::Note,
&format!("First iterator with length {first_length} here."),
)
.add_annotation(
occured_span,
AnnotationKind::Note,
&format!("Inconsistensy (iterator with length {occured_length}) here."),
),
Self::InconsistentTypes {
expected,
got,
error_span,
} => DiagnosticData::new("inconsistent types")
.add_span(*error_span)
.add_annotation(
*expected.1,
AnnotationKind::Note,
&format!("This expression is of type {}", expected.0),
)
.add_annotation(
*got.1,
AnnotationKind::Note,
&format!("This expression is of type {}", got.0),
),
Self::InvalidType { expected, got } => DiagnosticData::new(&format!(
"invalid type: `{expected}` expected, got `{}`",
got.0
))
.add_span(got.1),
Self::RedefinedVariable {
defined_at,
error_span,
variable_name,
} => DiagnosticData::new(&format!("redefined variable: `{variable_name}`"))
.add_span(error_span)
.add_annotation(defined_at, AnnotationKind::Note, "First defined here.")
.add_annotation(error_span, AnnotationKind::Note, "Then redefined here."),
Self::UndefinedTypeVariable { definition } => {
DiagnosticData::new("variable of undefined type")
.add_span(definition)
.add_annotation(definition, AnnotationKind::Note, "Defined here.")
}
Self::UndefinedVariable {
error_span,
variable_name,
} => DiagnosticData::new(&format!("undefined variable: `{variable_name}`"))
.add_span(error_span),
Self::UndefinedFunction {
error_span,
function_name,
} => DiagnosticData::new(&format!("undefined function: `{function_name}`"))
.add_span(error_span),
Self::FetureNotSupported {
error_span,
feature_name,
} => {
DiagnosticData::new(&format!("feature `{feature_name}` of undefined type"))
.add_span(error_span)
}
Self::InvalidArgumentCount {
error_span,
expected,
got,
} => {
DiagnosticData::new(&format!("invalid argument count. Expected one of `{expected:?}`, got {got}"))
.add_span(error_span)
}
Self::OverloadNotFound {
error_span,
params,
function_name,
} => {
DiagnosticData::new(&format!("overload for function `{function_name}` with params `({})` not found", params.into_iter().map(|x| format!("{x}")).collect::<Vec<String>>().join(", ")))
.add_span(error_span)
},
Self::CannotUnpack { error_span, ty } => {
DiagnosticData::new(&format!("could not unpack `{ty}` onto a point collection"))
.add_span(error_span)
}
Self::ImplicitConversionDoesNotExist {
error_span,
from,
to,
} => {
DiagnosticData::new(&format!("implicit conversion from `{from}` to `{to}` does not exist."))
.add_span(error_span)
}
Self::InvalidOperandType {
error_span,
got,
op,
} => {
DiagnosticData::new(&format!("invalid operand type `{}` for operator `{op}`", got.0))
.add_span(error_span)
.add_annotation(got.1, AnnotationKind::Note, "This is of invalid type.")
}
Self::LetStatUnexpectedIterator {
var_span,
error_span,
} => {
DiagnosticData::new(&"unexpected iterator in right-hand side of `let` statement")
.add_span(error_span)
.add_annotation(var_span, AnnotationKind::Note, "There was no iterator of left-hand side, so the same is expected for the right.")
}
}
}
}
#[derive(Debug)]
pub struct Weighed<T> {
pub object: T,
pub weight: f64,
}
impl<T> Weighed<T> {
pub fn one(object: T) -> Self {
Self {
object,
weight: 1.0,
}
}
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum SimpleUnit {
Distance,
Point,
Angle,
Line,
Scalar,
}
impl Mul for SimpleUnit {
type Output = ComplexUnit;
fn mul(self, rhs: Self) -> Self::Output {
let complex = ComplexUnit::new(self);
complex * rhs
}
}
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct ComplexUnit([i8; SimpleUnit::Scalar as usize]);
impl ComplexUnit {
#[must_use]
pub fn new(simple: SimpleUnit) -> Self {
let mut arr = [0; SimpleUnit::Scalar as usize];
match simple {
SimpleUnit::Scalar => (),
_ => arr[simple as usize] = 1,
}
Self(arr)
}
}
impl Display for ComplexUnit {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut s = String::new();
for i in 0..(SimpleUnit::Scalar as usize) {
if self.0[i] > 0 {
let name = match i {
0 => "Distance",
1 => "Point",
2 => "Angle",
3 => "Line",
_ => unreachable!(),
};
if self.0[i] == 1 {
s += name;
} else {
s += &format!("{name}^{}", self.0[i]);
};
s += " * ";
}
}
if s.is_empty() {
write!(f, "no unit")
} else {
write!(
f,
"{}",
String::from_utf8(s.as_bytes()[0..(s.len() - 3)].to_vec()).unwrap()
)
}
}
}
impl Mul<SimpleUnit> for ComplexUnit {
type Output = ComplexUnit;
fn mul(mut self, rhs: SimpleUnit) -> Self::Output {
match rhs {
SimpleUnit::Scalar => (),
#[allow(clippy::suspicious_arithmetic_impl)]
_ => self[rhs as usize] += 1,
}
self
}
}
impl Mul for ComplexUnit {
type Output = ComplexUnit;
fn mul(mut self, rhs: Self) -> Self::Output {
self.iter_mut()
.enumerate()
.map(|(i, x)| *x += rhs[i])
.for_each(drop);
self
}
}
impl Div<SimpleUnit> for ComplexUnit {
type Output = ComplexUnit;
fn div(mut self, rhs: SimpleUnit) -> Self::Output {
match rhs {
SimpleUnit::Scalar => (),
#[allow(clippy::suspicious_arithmetic_impl)]
_ => self[rhs as usize] -= 1,
}
self
}
}
impl Div for ComplexUnit {
type Output = ComplexUnit;
fn div(mut self, rhs: Self) -> Self::Output {
self.iter_mut()
.enumerate()
.map(|(i, x)| *x -= rhs[i])
.for_each(drop);
self
}
}
impl Deref for ComplexUnit {
type Target = [i8; SimpleUnit::Scalar as usize];
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for ComplexUnit {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
#[derive(Debug)]
pub enum Expression {
PointPointDistance(Arc<Weighed<Expression>>, Arc<Weighed<Expression>>),
PointLineDistance(Arc<Weighed<Expression>>, Arc<Weighed<Expression>>),
AnglePoint(
Arc<Weighed<Expression>>,
Arc<Weighed<Expression>>,
Arc<Weighed<Expression>>,
),
AngleLine(Arc<Weighed<Expression>>, Arc<Weighed<Expression>>),
Literal(f64, ComplexUnit),
FreePoint(usize),
Line(Arc<Weighed<Expression>>, Arc<Weighed<Expression>>),
LineCrossing(Box<Weighed<Expression>>, Box<Weighed<Expression>>),
SetUnit(Arc<Weighed<Expression>>, ComplexUnit),
Sum(Arc<Weighed<Expression>>, Arc<Weighed<Expression>>),
Difference(Arc<Weighed<Expression>>, Arc<Weighed<Expression>>),
Product(Arc<Weighed<Expression>>, Arc<Weighed<Expression>>),
Quotient(Arc<Weighed<Expression>>, Arc<Weighed<Expression>>),
Negation(Arc<Weighed<Expression>>),
}
#[derive(Debug)]
pub enum CriteriaKind {
Equal(Arc<Weighed<Expression>>, Arc<Weighed<Expression>>),
Less(Arc<Weighed<Expression>>, Arc<Weighed<Expression>>),
Greater(Arc<Weighed<Expression>>, Arc<Weighed<Expression>>),
Inverse(Box<CriteriaKind>),
}
pub type Criteria = Weighed<CriteriaKind>;
pub struct HashableArc<T>(Arc<T>);
impl<T> HashableArc<T> {
#[must_use]
pub fn new(content: Arc<T>) -> Self {
Self(content)
}
}
impl<T> Hash for HashableArc<T> {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
Arc::as_ptr(&self.0).hash(state);
}
}
impl<T> PartialEq for HashableArc<T> {
fn eq(&self, other: &Self) -> bool {
Arc::as_ptr(&self.0) == Arc::as_ptr(&other.0)
}
}
impl<T> Eq for HashableArc<T> {
fn assert_receiver_is_total_eq(&self) {}
}
pub struct HashableRc<T: ?Sized>(Rc<T>);
impl<T: ?Sized> HashableRc<T> {
#[must_use]
pub fn new(content: Rc<T>) -> Self {
Self(content)
}
}
impl<T: ?Sized> Hash for HashableRc<T> {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
Rc::as_ptr(&self.0).hash(state);
}
}
impl<T: ?Sized> PartialEq for HashableRc<T> {
fn eq(&self, other: &Self) -> bool {
Rc::as_ptr(&self.0) == Rc::as_ptr(&other.0)
}
}
impl<T: ?Sized> Eq for HashableRc<T> {
fn assert_receiver_is_total_eq(&self) {}
}
impl<T: ?Sized> Deref for HashableRc<T> {
type Target = Rc<T>;
fn deref(&self) -> &Self::Target {
&self.0
}
}