use crate::{parser, span};
use flags::FlagSetConstructor;
use geo_aid_derive::CloneWithNode;
use geo_aid_figure::Style;
use num_traits::{One, Zero};
use std::any::Any;
use std::fmt::Formatter;
use std::mem;
use std::{
collections::{hash_map::Entry, HashMap},
fmt::{Debug, Display},
hash::Hash,
ops::{Deref, DerefMut},
rc::Rc,
write,
};
use crate::figure::SpannedMathString;
use crate::ty;
use library::macros::index;
use self::context::CompileContext;
use self::figure::{
AnyExprNode, CircleNode, CollectionNode, EmptyNode, FromExpr, HierarchyNode, LineNode,
LineType, MaybeUnset, Node, NumberNode, PCNode, PointNode,
};
use self::library::Library;
use super::parser::{
ExprBinop, ExprCall, FromProperty, InputStream, Name, PointCollectionConstructor, RefStatement,
};
use super::token::number::{CompExponent, ProcNum};
use super::token::NumberLit;
use super::{
parser::{
BinaryOperator, DisplayProperties, ExplicitIterator, Expression, ImplicitIterator,
LetStatement, Parse, PredefinedRuleOperator, PropertyValue, Punctuated, RuleOperator,
RuleStatement, SimpleExpression, SimpleExpressionKind, Statement, Type,
},
token::{self, Ident, NamedIdent, PointCollection as PCToken, Span},
unit, ComplexUnit, Error,
};
pub mod context;
pub mod figure;
pub mod flags;
pub mod library;
trait Unroll<T = AnyExpr> {
fn unroll(
&self,
context: &mut CompileContext,
library: &Library,
it_index: &HashMap<u8, usize>,
display: Properties,
) -> T;
}
#[derive(Debug)]
pub struct RuleOperatorDefinition {
pub name: String,
}
#[derive(Debug)]
pub struct Variable<T: Displayed> {
pub name: String,
pub definition_span: Span,
pub definition: Expr<T>,
}
#[derive(Debug)]
pub struct IterTree {
pub variants: Vec<IterNode>,
pub id: u8,
pub span: Span,
}
#[derive(Debug)]
pub struct IterNode(Vec<IterTree>);
impl Deref for IterNode {
type Target = Vec<IterTree>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for IterNode {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl<const ITER: bool> From<&Expression<ITER>> for IterNode {
fn from(value: &Expression<ITER>) -> Self {
match value {
Expression::ImplicitIterator(it) => it.into(),
Expression::Binop(binop) => Self::from2(binop.lhs.as_ref(), binop.rhs.as_ref()),
}
}
}
impl From<&SimpleExpressionKind> for IterNode {
fn from(value: &SimpleExpressionKind) -> Self {
match value {
SimpleExpressionKind::Number(_) => IterNode::new(Vec::new()),
SimpleExpressionKind::Name(name) => name.into(),
SimpleExpressionKind::ExplicitIterator(it) => IterNode::new(vec![it.into()]),
SimpleExpressionKind::PointCollection(col) => IterNode::new(
col.points
.iter()
.flat_map(|v| IterNode::from(v).0.into_iter())
.collect(),
),
}
}
}
impl From<&Name> for IterNode {
fn from(value: &Name) -> Self {
match value {
Name::Ident(_) => IterNode::new(Vec::new()),
Name::FieldIndex(f) => f.name.as_ref().into(),
Name::Call(expr) => IterNode::new(
IterNode::from(expr.name.as_ref())
.0
.into_iter()
.chain(
expr.params
.as_ref()
.into_iter()
.flat_map(|params| params.iter().flat_map(|v| IterNode::from(v).0)),
)
.collect(),
),
Name::Expression(expr) => expr.content.as_ref().into(),
}
}
}
impl<const ITER: bool> From<&ImplicitIterator<ITER>> for IterNode {
fn from(value: &ImplicitIterator<ITER>) -> Self {
if value.exprs.collection.is_empty() {
(&value.exprs.first.as_ref().kind).into()
} else {
IterNode::new(vec![value.into()])
}
}
}
impl<const ITER: bool> From<&ImplicitIterator<ITER>> for IterTree {
fn from(value: &ImplicitIterator<ITER>) -> Self {
Self {
id: 0, variants: value.exprs.iter().map(|v| (&v.kind).into()).collect(),
span: value.get_span(),
}
}
}
impl From<&ExplicitIterator> for IterTree {
fn from(value: &ExplicitIterator) -> Self {
Self {
id: value.id,
variants: value.exprs.iter().map(IterNode::from).collect(),
span: value.get_span(),
}
}
}
impl IterTree {
pub fn get_iter_lengths(
&self,
lengths: &mut HashMap<u8, (usize, Span, Option<Span>)>,
full_span: Span,
) -> Result<(), Error> {
for variant in &self.variants {
variant.get_iter_lengths(lengths, full_span)?;
}
Ok(())
}
}
impl IterNode {
#[must_use]
pub fn new(content: Vec<IterTree>) -> Self {
Self(content)
}
#[must_use]
pub fn from2<const ITER1: bool, const ITER2: bool>(
e1: &Expression<ITER1>,
e2: &Expression<ITER2>,
) -> Self {
let mut node = Self::from(e1);
node.extend(Self::from(e2).0);
node
}
pub fn get_iter_lengths(
&self,
lengths: &mut HashMap<u8, (usize, Span, Option<Span>)>,
full_span: Span,
) -> Result<(), Error> {
for iter in &self.0 {
match lengths.entry(iter.id) {
Entry::Vacant(entry) => {
entry.insert((iter.variants.len(), iter.span, Some(iter.span)));
}
Entry::Occupied(mut entry) => {
if entry.get().0 != iter.variants.len() {
return Err(Error::InconsistentIterators {
first_span: entry.get().1,
first_length: entry.get().0,
occurred_span: iter.span,
occurred_length: iter.variants.len(),
error_span: full_span,
});
} else if let Some(parent) = entry.get().2 {
return Err(Error::IteratorWithSameIdIterator {
error_span: full_span,
parent_span: parent,
contained_span: iter.span,
});
}
entry.get_mut().2 = Some(iter.span);
}
}
iter.get_iter_lengths(lengths, full_span)?;
lengths.get_mut(&iter.id).unwrap().2 = None;
}
Ok(())
}
}
#[derive(Debug)]
pub struct MultiRangeIterator {
maxes: Vec<usize>,
currents: Vec<usize>,
}
impl MultiRangeIterator {
#[must_use]
pub fn new(maxes: Vec<usize>) -> Self {
let l = maxes.len();
Self {
maxes,
currents: [0].repeat(l),
}
}
pub fn increment(&mut self) -> Option<&Vec<usize>> {
self.increment_place(self.currents.len() - 1)
}
fn increment_place(&mut self, at: usize) -> Option<&Vec<usize>> {
self.currents[at] += 1;
if self.currents[at] == self.maxes[at] {
self.currents[at] = 0;
if at == 0 {
None
} else {
self.increment_place(at - 1)
}
} else {
Some(&self.currents)
}
}
#[must_use]
pub fn get_currents(&self) -> &Vec<usize> {
&self.currents
}
}
#[derive(Debug)]
pub struct IterTreeIterator<'r> {
steps: Vec<(Vec<(&'r IterTree, usize)>, MultiRangeIterator)>,
currents: Option<HashMap<u8, usize>>,
}
impl<'r> IterTreeIterator<'r> {
#[must_use]
pub fn new(tree: &'r IterNode) -> Self {
let mut this = Self {
steps: Vec::new(),
currents: Some(HashMap::new()),
};
this.add_node(tree);
this
}
fn add_node(&mut self, node: &'r IterNode) {
if node.len() > 0 {
let mut visited = Vec::new();
let mut lengths = Vec::new();
for tree in node.iter() {
if !visited.contains(&tree.id) {
visited.push(tree.id);
lengths.push(tree.variants.len());
}
}
self.steps.push((
node.iter()
.map(|v| {
(
v,
visited
.iter()
.enumerate()
.find(|(_, x)| **x == v.id)
.unwrap()
.0,
)
})
.collect(),
MultiRangeIterator::new(lengths),
));
self.update_currents();
self.update_iterators();
}
}
fn update_iterators(&mut self) {
let nodes = if let Some(node) = self.steps.last() {
node.0
.iter()
.map(|iter| &iter.0.variants[node.1.get_currents()[iter.1]])
.collect()
} else {
Vec::new()
};
for node in nodes {
self.add_node(node);
}
}
fn update_currents(&mut self) {
let node = self.steps.last().unwrap();
let currents = node.1.get_currents();
for v in &node.0 {
self.currents
.as_mut()
.unwrap()
.entry(v.0.id)
.and_modify(|x| *x = currents[v.1])
.or_insert(currents[v.1]);
}
}
pub fn next(&mut self) {
while let Some(node) = self.steps.last_mut() {
if node.1.increment().is_some() {
self.update_currents();
self.update_iterators();
return;
}
self.steps.pop();
}
self.currents = None;
}
#[must_use]
pub fn get_currents(&self) -> Option<&HashMap<u8, usize>> {
self.currents.as_ref()
}
}
#[derive(Debug)]
pub enum UnrolledRuleKind {
PointEq(Expr<Point>, Expr<Point>),
NumberEq(Expr<Number>, Expr<Number>),
Gt(Expr<Number>, Expr<Number>),
Alternative(Vec<UnrolledRule>),
Bias(AnyExpr),
}
pub trait ConvertFrom<T>: Displayed {
fn convert_from(value: T, context: &CompileContext) -> Expr<Self>;
fn can_convert_from(value: &T) -> bool;
}
pub trait Convert
where
Self: Sized,
{
fn convert<T: ConvertFrom<Self>>(self, context: &CompileContext) -> Expr<T>;
fn can_convert<T: ConvertFrom<Self>>(&self) -> bool;
}
impl<T> Convert for T {
fn convert<U: ConvertFrom<Self>>(self, context: &CompileContext) -> Expr<U> {
U::convert_from(self, context)
}
fn can_convert<U: ConvertFrom<Self>>(&self) -> bool {
U::can_convert_from(self)
}
}
pub trait GetValueType {
fn get_value_type(&self) -> Type;
}
pub trait GeoType: From<Expr<Self::Target>> {
type Target: ConvertFrom<AnyExpr>;
fn get_type() -> Type;
}
macro_rules! impl_x_from_x {
($what:ident) => {
impl ConvertFrom<Expr<$what>> for $what {
fn convert_from(value: Expr<$what>, _context: &CompileContext) -> Expr<Self> {
value
}
fn can_convert_from(_value: &Expr<$what>) -> bool {
true
}
}
};
}
macro_rules! impl_from_any {
($what:ident) => {
impl ConvertFrom<AnyExpr> for $what {
fn convert_from(value: AnyExpr, context: &CompileContext) -> Expr<Self> {
match value {
AnyExpr::Point(v) => v.convert(context),
AnyExpr::Line(v) => v.convert(context),
AnyExpr::Number(v) => v.convert(context),
AnyExpr::Circle(v) => v.convert(context),
AnyExpr::PointCollection(v) => v.convert(context),
AnyExpr::Derived(v) => v.convert(context),
AnyExpr::Unknown(v) => v.convert(context),
}
}
fn can_convert_from(value: &AnyExpr) -> bool {
match value {
AnyExpr::Point(v) => Self::can_convert_from(v),
AnyExpr::Line(v) => Self::can_convert_from(v),
AnyExpr::Number(v) => Self::can_convert_from(v),
AnyExpr::Circle(v) => Self::can_convert_from(v),
AnyExpr::PointCollection(v) => Self::can_convert_from(v),
AnyExpr::Derived(v) => Self::can_convert_from(v),
AnyExpr::Unknown(v) => Self::can_convert_from(v),
}
}
}
};
}
macro_rules! convert_err {
($from:ident($v:expr) -> $to:ident with $context:ident) => {{
let v = $v;
$context.push_error(Error::ImplicitConversionDoesNotExist {
error_span: v.span,
from: v.data.get_value_type(),
to: Self::get_type(),
});
Expr {
span: v.span,
data: Rc::new($to::dummy()),
node: None,
}
}};
}
macro_rules! impl_convert_err {
($from:ident -> $to:ident) => {
impl ConvertFrom<Expr<$from>> for $to {
fn convert_from(value: Expr<$from>, context: &CompileContext) -> Expr<Self> {
convert_err!($from(value) -> $to with context)
}
fn can_convert_from(_value: &Expr<$from>) -> bool {
false
}
}
}
}
macro_rules! impl_from_unknown {
{$what:ident} => {
impl ConvertFrom<Expr<Unknown>> for $what {
fn convert_from(value: Expr<Unknown>, _context: &CompileContext) -> Expr<Self> {
Expr {
span: value.span,
data: Rc::new($what::dummy()),
node: None
}
}
fn can_convert_from(_value: &Expr<Unknown>) -> bool {
true
}
}
}
}
macro_rules! impl_make_variable {
($what:ident) => {
impl Expr<$what> {
#[must_use]
pub fn make_variable(self, name: String) -> Self {
let sp = self.span;
Expr {
span: sp,
data: Rc::new($what::Generic(Generic::VariableAccess(Rc::new(Variable {
name,
definition: self,
definition_span: sp,
})))),
node: None, }
}
}
};
($what:ident { other: $other:ident, data: $data:ident }) => {
impl Expr<$what> {
#[must_use]
pub fn make_variable(self, name: String) -> Self {
let sp = self.span;
Expr {
span: sp,
data: Rc::new($what {
$other: self.data.$other,
data: $data::Generic(Generic::VariableAccess(Rc::new(Variable {
name,
definition: self,
definition_span: sp,
}))),
}),
node: None, }
}
}
};
}
macro_rules! impl_any_from_x {
($what:ident) => {
impl From<Expr<$what>> for AnyExpr {
fn from(value: Expr<$what>) -> Self {
AnyExpr::$what(value)
}
}
};
}
#[derive(Debug, CloneWithNode)]
pub enum Generic<T>
where
T: Displayed,
{
VariableAccess(Rc<Variable<T>>),
Boxed(Expr<T>),
Dummy,
}
impl<T: Display + Displayed> Display for Generic<T> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Self::VariableAccess(name) => write!(f, "{}", name.name),
Self::Boxed(expr) => {
write!(f, "{expr}")
}
Self::Dummy => write!(f, "invalid (dummy)"),
}
}
}
#[derive(Debug, CloneWithNode)]
pub enum Point {
Generic(Generic<Self>),
Average(ClonedVec<Expr<Point>>),
LineLineIntersection(Expr<Line>, Expr<Line>),
CircleCenter(Expr<Circle>),
Free,
FromComplex(Expr<Number>),
}
impl Point {
#[must_use]
pub fn get_type() -> Type {
Type::Point
}
}
impl Dummy for Point {
fn dummy() -> Self {
Self::Generic(Generic::Dummy)
}
fn is_dummy(&self) -> bool {
matches!(self, Self::Generic(Generic::Dummy))
}
}
impl Displayed for Point {
type Node = PointNode;
}
impl GetData for Point {
fn get_data(&self) -> &Self {
match self {
Point::Generic(v) => match v {
Generic::Boxed(v) => v.get_data(),
Generic::VariableAccess(v) => v.definition.get_data(),
Generic::Dummy => self,
},
_ => self,
}
}
}
impl Expr<Point> {
#[must_use]
pub fn boxed(mut self, span: Span) -> Self {
let node = self.node.take();
Self {
span,
data: Rc::new(Point::Generic(Generic::Boxed(self))),
node,
}
}
#[must_use]
pub fn x(self, span: Span, display: Properties, context: &CompileContext) -> Expr<Number> {
let mut expr = Expr {
span,
node: None,
data: Rc::new(Number {
unit: Some(unit::DISTANCE),
data: NumberData::PointX(self),
}),
};
expr.node = Some(HierarchyNode::from_expr(&expr, display, context));
expr
}
#[must_use]
pub fn y(self, span: Span, display: Properties, context: &CompileContext) -> Expr<Number> {
let mut expr = Expr {
span,
node: None,
data: Rc::new(Number {
unit: Some(unit::DISTANCE),
data: NumberData::PointY(self),
}),
};
expr.node = Some(HierarchyNode::from_expr(&expr, display, context));
expr
}
}
impl GeoType for Expr<Point> {
type Target = Point;
fn get_type() -> Type {
ty::POINT
}
}
impl GetValueType for Point {
fn get_value_type(&self) -> Type {
ty::POINT
}
}
impl Display for Point {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Self::Generic(v) => write!(f, "{v}"),
Self::Average(exprs) => write!(
f,
"average({})",
exprs
.iter()
.map(|v| format!("{v}"))
.collect::<Vec<String>>()
.join(", ")
),
Self::LineLineIntersection(l1, l2) => {
write!(f, "intersection({l1}, {l2})")
}
Self::CircleCenter(circle) => {
write!(f, "{circle}.center")
}
Self::Free => write!(f, "Free point"),
Self::FromComplex(number) => write!(f, "to_point({number})"),
}
}
}
impl_x_from_x! {Point}
impl_from_any! {Point}
impl_from_unknown! {Point}
impl_convert_err! {Circle -> Point}
impl_convert_err! {Line -> Point}
impl_convert_err! {Derived -> Point}
impl_convert_err! {Number -> Point}
impl_make_variable! {Point}
impl ConvertFrom<Expr<PointCollection>> for Point {
fn convert_from(mut value: Expr<PointCollection>, context: &CompileContext) -> Expr<Self> {
if value.data.length == 1 {
let mut expr = index!(node value, 0);
if let Some(pc_node) = value.node {
if let Some(mut props) = pc_node.root.props {
if let Some(pt_node) = &mut expr.node {
pt_node.children = pc_node.children;
pt_node.root.display = pc_node.root.display;
pt_node.root.display_label = props.get("display_label").maybe_unset(true);
pt_node.root.label = props
.get("label")
.maybe_unset(SpannedMathString::new(span!(0, 0, 0, 0)));
pt_node.root.display_dot = props.get("display_dot").maybe_unset(true);
pt_node.root.default_label = props
.get("default-label")
.ok_or(SpannedMathString::new(span!(0, 0, 0, 0)));
}
props.ignore("default-label");
props.finish(context);
}
}
expr
} else {
convert_err!(PointCollection(value) -> Point with context)
}
}
fn can_convert_from(value: &Expr<PointCollection>) -> bool {
value.data.length == 1
}
}
#[derive(Debug, CloneWithNode)]
pub enum Circle {
Generic(Generic<Self>),
Circle(Expr<Point>, Expr<Number>),
}
impl_x_from_x! {Circle}
impl_from_any! {Circle}
impl_from_unknown! {Circle}
impl_convert_err! {Point -> Circle}
impl_convert_err! {Line -> Circle}
impl_convert_err! {Derived -> Circle}
impl_convert_err! {Number -> Circle}
impl_convert_err! {PointCollection -> Circle}
impl_make_variable! {Circle}
impl Circle {
#[must_use]
pub fn get_type() -> Type {
ty::CIRCLE
}
}
impl Dummy for Circle {
fn dummy() -> Self {
Self::Generic(Generic::Dummy)
}
fn is_dummy(&self) -> bool {
matches!(self, Self::Generic(Generic::Dummy))
}
}
impl Displayed for Circle {
type Node = CircleNode;
}
impl GetData for Circle {
fn get_data(&self) -> &Self {
match self {
Circle::Generic(v) => match v {
Generic::Boxed(v) => v.get_data(),
Generic::VariableAccess(v) => v.definition.get_data(),
Generic::Dummy => self,
},
Circle::Circle(..) => self,
}
}
}
impl Expr<Circle> {
#[must_use]
pub fn boxed(mut self, span: Span) -> Self {
let node = self.node.take();
Self {
span,
data: Rc::new(Circle::Generic(Generic::Boxed(self))),
node,
}
}
#[must_use]
pub fn center(self, span: Span, display: Properties, context: &CompileContext) -> Expr<Point> {
let mut expr = Expr {
span,
node: None,
data: Rc::new(Point::CircleCenter(self)),
};
expr.node = Some(HierarchyNode::from_expr(&expr, display, context));
expr
}
#[must_use]
pub fn radius(self, span: Span, display: Properties, context: &CompileContext) -> Expr<Number> {
let mut expr = Expr {
span,
node: None,
data: Rc::new(Number {
unit: Some(unit::DISTANCE),
data: NumberData::CircleRadius(self),
}),
};
expr.node = Some(HierarchyNode::from_expr(&expr, display, context));
expr
}
}
impl GetValueType for Circle {
fn get_value_type(&self) -> Type {
ty::CIRCLE
}
}
impl Display for Circle {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Self::Generic(v) => write!(f, "{v}"),
Self::Circle(center, radius) => {
write!(f, "circle({center}, {radius})")
}
}
}
}
impl GeoType for Expr<Circle> {
type Target = Circle;
fn get_type() -> Type {
ty::CIRCLE
}
}
#[derive(Debug, CloneWithNode)]
pub enum Line {
Generic(Generic<Self>),
LineFromPoints(Expr<Point>, Expr<Point>),
AngleBisector(Expr<Point>, Expr<Point>, Expr<Point>),
PerpendicularThrough(Expr<Line>, Expr<Point>),
ParallelThrough(Expr<Line>, Expr<Point>),
PointVector(Expr<Point>, Expr<Number>),
}
impl Line {
#[must_use]
pub fn get_type() -> Type {
ty::LINE
}
}
impl Dummy for Line {
fn dummy() -> Self {
Self::Generic(Generic::Dummy)
}
fn is_dummy(&self) -> bool {
matches!(self, Self::Generic(Generic::Dummy))
}
}
impl Displayed for Line {
type Node = LineNode;
}
impl GetData for Line {
fn get_data(&self) -> &Self {
match self {
Line::Generic(v) => match v {
Generic::Boxed(v) => v.get_data(),
Generic::VariableAccess(v) => v.definition.get_data(),
Generic::Dummy => self,
},
_ => self,
}
}
}
impl Expr<Line> {
#[must_use]
pub fn boxed(mut self, span: Span) -> Self {
let node = self.node.take();
Self {
span,
data: Rc::new(Line::Generic(Generic::Boxed(self))),
node,
}
}
}
impl_x_from_x! {Line}
impl_from_any! {Line}
impl_from_unknown! {Line}
impl_convert_err! {Derived -> Line}
impl_convert_err! {Circle -> Line}
impl_convert_err! {Point -> Line}
impl_convert_err! {Number -> Line}
impl_make_variable! {Line}
impl ConvertFrom<Expr<PointCollection>> for Line {
fn convert_from(mut value: Expr<PointCollection>, context: &CompileContext) -> Expr<Self> {
if value.data.length == 2 {
let mut expr = context.line(index!(node value, 0), index!(node value, 1));
if let Some(pc_node) = value.node {
if let Some(mut props) = pc_node.root.props {
if let Some(ln_node) = &mut expr.node {
ln_node.children = pc_node.children;
ln_node.root.display = pc_node.root.display;
ln_node.root.display_label = props.get("display_label").maybe_unset(true);
ln_node.root.label = props
.get("label")
.maybe_unset(SpannedMathString::new(span!(0, 0, 0, 0)));
ln_node.root.default_label = props
.get("default-label")
.get_or(SpannedMathString::new(span!(0, 0, 0, 0)));
ln_node.root.style = props.get("style").maybe_unset(Style::default());
ln_node.root.line_type = props.get("type").maybe_unset(LineType::default());
}
props.finish(context);
}
}
expr
} else {
convert_err!(PointCollection(value) -> Line with context)
}
}
fn can_convert_from(value: &Expr<PointCollection>) -> bool {
value.data.length == 2
}
}
impl GetValueType for Line {
fn get_value_type(&self) -> Type {
ty::LINE
}
}
impl Display for Line {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Self::Generic(v) => write!(f, "{v}"),
Self::LineFromPoints(e1, e2) => write!(f, "line({e1}, {e2})"),
Self::AngleBisector(e1, e2, e3) => {
write!(f, "angle-bisector({e1}, {e2}, {e3})")
}
Self::PerpendicularThrough(l, p) => {
write!(f, "perpendicular-through({l}, {p})")
}
Self::ParallelThrough(l, p) => {
write!(f, "parallel-through({l}, {p})")
}
Self::PointVector(p, v) => write!(f, "point-vector({p}, {v})"),
}
}
}
impl GeoType for Expr<Line> {
type Target = Line;
fn get_type() -> Type {
ty::LINE
}
}
#[derive(Debug, CloneWithNode)]
pub enum NumberData {
Generic(Generic<Number>),
Number(ProcNum),
DstLiteral(ProcNum),
SetUnit(Expr<Number>, ComplexUnit),
PointPointDistance(Expr<Point>, Expr<Point>),
PointLineDistance(Expr<Point>, Expr<Line>),
Negate(Expr<Number>),
Add(Expr<Number>, Expr<Number>),
Subtract(Expr<Number>, Expr<Number>),
Multiply(Expr<Number>, Expr<Number>),
Divide(Expr<Number>, Expr<Number>),
ThreePointAngle(Expr<Point>, Expr<Point>, Expr<Point>),
ThreePointAngleDir(Expr<Point>, Expr<Point>, Expr<Point>),
TwoLineAngle(Expr<Line>, Expr<Line>),
Average(ClonedVec<Expr<Number>>),
CircleRadius(Expr<Circle>),
Pow(Expr<Number>, CompExponent),
PointX(Expr<Point>),
PointY(Expr<Point>),
Free,
FromPoint(Expr<Point>),
Real(Expr<Number>),
Imaginary(Expr<Number>),
Log(Expr<Number>),
Exp(Expr<Number>),
Sin(Expr<Number>),
Cos(Expr<Number>),
Atan2(Expr<Number>, Expr<Number>),
Direction(Expr<Line>),
}
impl Display for NumberData {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Self::Generic(v) => write!(f, "{v}"),
Self::Average(exprs) => write!(
f,
"average({})",
exprs
.iter()
.map(|v| format!("{v}"))
.collect::<Vec<String>>()
.join(", ")
),
Self::Number(num) => write!(f, "{num}"),
Self::DstLiteral(dst) => write!(f, "={dst}"),
Self::SetUnit(expr, _) => {
write!(f, "{expr}")
}
Self::PointPointDistance(e1, e2) => write!(f, "dst({e1}, {e2})"),
Self::PointLineDistance(e1, e2) => write!(f, "dst({e1}, {e2})"),
Self::Negate(e) => write!(f, "-{e}"),
Self::Add(e1, e2) => write!(f, "{e1} + {e2}"),
Self::Multiply(e1, e2) => write!(f, "{e1} * {e2}"),
Self::Divide(e1, e2) => write!(f, "{e1} / {e2}"),
Self::Subtract(e1, e2) => write!(f, "{e1} - {e2}"),
Self::ThreePointAngle(e1, e2, e3) => {
write!(f, "angle({e1}, {e2}, {e3})")
}
Self::ThreePointAngleDir(e1, e2, e3) => {
write!(f, "dir_angle({e1}, {e2}, {e3})")
}
Self::TwoLineAngle(e1, e2) => write!(f, "angle({e1}, {e2})"),
Self::CircleRadius(circle) => {
write!(f, "{circle}.radius")
}
Self::Pow(base, exponent) => write!(f, "({base})^{exponent}"),
Self::PointX(expr) => write!(f, "{expr}.x"),
Self::PointY(expr) => write!(f, "{expr}.y"),
Self::Free => write!(f, "Free scalar"),
Self::FromPoint(point) => write!(f, "to_complex({point})"),
Self::Real(number) => write!(f, "Re({number})"),
Self::Imaginary(number) => write!(f, "Im({number})"),
Self::Log(number) => write!(f, "log({number})"),
Self::Exp(number) => write!(f, "exp({number})"),
Self::Sin(v) => write!(f, "sin({v})"),
Self::Cos(v) => write!(f, "cos({v})"),
Self::Atan2(y, x) => write!(f, "atan2({y}, {x})"),
Self::Direction(line) => write!(f, "dir({line})"),
}
}
}
#[derive(Debug, CloneWithNode)]
pub struct Number {
pub unit: Option<ComplexUnit>,
pub data: NumberData,
}
impl_x_from_x! {Number}
impl_from_any! {Number}
impl_from_unknown! {Number}
impl_convert_err! {Point -> Number}
impl_convert_err! {Circle -> Number}
impl_convert_err! {Line -> Number}
impl_convert_err! {Derived -> Number}
impl_make_variable! {Number {other: unit, data: NumberData}}
impl Dummy for Number {
fn dummy() -> Self {
Self {
unit: None,
data: NumberData::Generic(Generic::Dummy),
}
}
fn is_dummy(&self) -> bool {
matches!(self.data, NumberData::Generic(Generic::Dummy))
}
}
impl Displayed for Number {
type Node = NumberNode;
}
impl ConvertFrom<Expr<PointCollection>> for Number {
fn convert_from(mut value: Expr<PointCollection>, context: &CompileContext) -> Expr<Self> {
if value.data.length == 2 {
let display = value
.node
.as_mut()
.and_then(|x| x.root.props.take())
.unwrap_or_default();
let mut expr = library::dst::distance_function_pp(
index!(node value, 0),
index!(node value, 1),
context,
display,
);
if let Some(pc_node) = value.node {
if let Some(sc_node) = &mut expr.node {
sc_node.children = pc_node.children;
sc_node.root.display = pc_node.root.display;
}
}
expr.0
} else {
convert_err!(PointCollection(value) -> Number with context)
}
}
fn can_convert_from(value: &Expr<PointCollection>) -> bool {
value.data.length == 2
}
}
impl Number {
#[must_use]
pub fn get_type() -> Type {
ty::SCALAR
}
}
impl GetData for Number {
fn get_data(&self) -> &Self {
match &self.data {
NumberData::Generic(v) => match v {
Generic::Boxed(v) => v.get_data(),
Generic::VariableAccess(v) => v.definition.get_data(),
Generic::Dummy => self,
},
_ => self,
}
}
}
impl Expr<Number> {
#[must_use]
pub fn boxed(mut self, span: Span) -> Self {
let node = self.node.take();
Self {
span,
data: Rc::new(Number {
unit: self.data.unit,
data: NumberData::Generic(Generic::Boxed(self)),
}),
node,
}
}
#[must_use]
pub fn convert_unit(mut self, unit: Option<ComplexUnit>, context: &CompileContext) -> Self {
let err = Error::ImplicitConversionDoesNotExist {
error_span: self.span,
from: self.get_value_type(),
to: Type::Number(unit),
};
if self.data.unit == unit {
self
} else if unit.is_none() || self.data.unit.is_some() && self.data.unit != unit {
context.push_error(err);
Expr {
span: self.span,
data: Rc::new(Number {
unit,
data: self.data.data.clone_without_node(),
}),
node: self.node.take(),
}
} else {
Self {
data: Rc::new(Number {
unit,
data: match &self.data.data {
NumberData::Generic(generic) => match generic {
Generic::VariableAccess(_) => unreachable!(), Generic::Boxed(v) => NumberData::Generic(Generic::Boxed(
v.clone_without_node().convert_unit(unit, context),
)),
Generic::Dummy => NumberData::Generic(Generic::Dummy),
},
v @ NumberData::Number(_) => v.clone_without_node(),
NumberData::Free => {
NumberData::SetUnit(self.clone_without_node(), unit.unwrap_or_default())
}
NumberData::DstLiteral(_)
| NumberData::PointPointDistance(_, _)
| NumberData::PointLineDistance(_, _)
| NumberData::ThreePointAngle(_, _, _)
| NumberData::ThreePointAngleDir(_, _, _)
| NumberData::TwoLineAngle(_, _)
| NumberData::CircleRadius(_)
| NumberData::PointX(_)
| NumberData::PointY(_)
| NumberData::Log(_)
| NumberData::Exp(_)
| NumberData::Sin(_)
| NumberData::Cos(_)
| NumberData::Atan2(_, _)
| NumberData::Direction(_)
| NumberData::FromPoint(_)
| NumberData::SetUnit(_, _) => unreachable!(), NumberData::Negate(v) => {
NumberData::Negate(v.clone_without_node().convert_unit(unit, context))
}
NumberData::Add(a, b) => {
NumberData::Add(
a.clone_without_node().convert_unit(unit, context),
b.clone_without_node().convert_unit(unit, context),
)
}
NumberData::Subtract(a, b) => {
NumberData::Subtract(
a.clone_without_node().convert_unit(unit, context),
b.clone_without_node().convert_unit(unit, context),
)
}
NumberData::Multiply(a, b) => {
NumberData::Multiply(
a.clone_without_node().convert_unit(unit, context),
b.clone_without_node()
.convert_unit(Some(unit::SCALAR), context),
)
}
NumberData::Divide(a, b) => {
NumberData::Divide(
a.clone_without_node().convert_unit(unit, context),
b.clone_without_node()
.convert_unit(Some(unit::SCALAR), context),
)
}
NumberData::Average(exprs) => {
NumberData::Average(
exprs
.iter()
.map(|v| v.clone_without_node().convert_unit(unit, context))
.collect::<Vec<_>>()
.into(),
)
}
NumberData::Pow(base, exponent) => NumberData::Pow(
base.clone_without_node()
.convert_unit(unit.map(|x| x.pow(exponent.recip())), context),
*exponent,
),
NumberData::Real(number) => NumberData::Real(
number.clone_without_node().convert_unit(unit, context),
),
NumberData::Imaginary(number) => NumberData::Imaginary(
number.clone_without_node().convert_unit(unit, context),
),
},
}),
..self
}
}
}
#[must_use]
pub fn can_convert_unit(&self, unit: Option<ComplexUnit>) -> bool {
!(unit.is_none() || self.data.unit.is_some() && self.data.unit != unit)
}
#[must_use]
pub fn specify_unit(self, context: &CompileContext) -> Self {
if self.data.unit.is_none() {
self.convert_unit(Some(unit::SCALAR), context)
} else {
self
}
}
}
impl GetValueType for Number {
fn get_value_type(&self) -> Type {
Type::Number(self.unit)
}
}
impl Display for Number {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.data)
}
}
#[derive(Debug, CloneWithNode)]
pub enum PointCollectionData {
Generic(Generic<PointCollection>),
PointCollection(ClonedVec<Expr<Point>>),
}
impl PointCollectionData {
#[must_use]
pub fn as_collection(&self) -> Option<&ClonedVec<Expr<Point>>> {
match self {
PointCollectionData::PointCollection(v) => Some(v),
PointCollectionData::Generic(_) => None,
}
}
#[must_use]
pub fn as_collection_mut(&mut self) -> Option<&mut ClonedVec<Expr<Point>>> {
match self {
PointCollectionData::PointCollection(v) => Some(v),
PointCollectionData::Generic(_) => None,
}
}
#[must_use]
pub fn index(&self, index: usize) -> Expr<Point> {
match self {
PointCollectionData::Generic(generic) => match generic {
Generic::VariableAccess(var) => var.definition.index_without_node(index),
Generic::Boxed(expr) => expr.index_without_node(index),
Generic::Dummy => Expr::new_spanless(Point::Generic(Generic::Dummy)),
},
PointCollectionData::PointCollection(col) => col.get(index).map_or_else(
|| Expr::new_spanless(Point::dummy()),
CloneWithNode::clone_without_node,
),
}
}
}
impl Display for PointCollectionData {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Self::Generic(v) => write!(f, "{v}"),
Self::PointCollection(col) => write!(
f,
"col({})",
col.iter()
.map(|v| format!("{v}"))
.collect::<Vec<String>>()
.join(", ")
),
}
}
}
#[derive(Debug, CloneWithNode)]
pub struct PointCollection {
pub length: usize,
pub data: PointCollectionData,
}
impl_from_any! {PointCollection}
impl_from_unknown! {PointCollection}
impl_convert_err! {Circle -> PointCollection}
impl_convert_err! {Line -> PointCollection}
impl_convert_err! {Number -> PointCollection}
impl_convert_err! {Derived -> PointCollection}
impl_make_variable! {PointCollection {other: length, data: PointCollectionData}}
impl Displayed for PointCollection {
type Node = PCNode;
}
impl Dummy for PointCollection {
fn dummy() -> Self {
Self {
length: 0,
data: PointCollectionData::Generic(Generic::Dummy),
}
}
fn is_dummy(&self) -> bool {
matches!(self.data, PointCollectionData::Generic(Generic::Dummy))
}
}
impl GetData for PointCollection {
fn get_data(&self) -> &Self {
match &self.data {
PointCollectionData::Generic(v) => match v {
Generic::Boxed(v) => v.get_data(),
Generic::VariableAccess(v) => v.definition.get_data(),
Generic::Dummy => self,
},
PointCollectionData::PointCollection(_) => self,
}
}
}
impl ConvertFrom<Expr<Point>> for PointCollection {
fn convert_from(mut value: Expr<Point>, _context: &CompileContext) -> Expr<Self> {
let value_node = value.take_node();
let mut expr = Expr {
span: value.span,
data: Rc::new(PointCollection {
length: 1,
data: PointCollectionData::PointCollection(vec![value].into()),
}),
node: None,
};
let mut node = PCNode::new(expr.clone_without_node());
node.push(value_node);
expr.node = Some(HierarchyNode::new(node));
expr
}
fn can_convert_from(_value: &Expr<Point>) -> bool {
true
}
}
impl ConvertFrom<Expr<PointCollection>> for PointCollection {
fn convert_from(mut value: Expr<PointCollection>, context: &CompileContext) -> Expr<Self> {
if let Some(node) = &mut value.node {
if let Some(props) = node.root.props.take() {
props.finish(context);
}
}
value
}
fn can_convert_from(_value: &Expr<PointCollection>) -> bool {
true
}
}
impl PointCollection {
#[must_use]
pub fn get_type() -> Type {
ty::collection(0)
}
}
impl Expr<PointCollection> {
#[must_use]
pub fn boxed(mut self, span: Span) -> Self {
let node = self.node.take();
Self {
span,
data: Rc::new(PointCollection {
length: self.data.length,
data: PointCollectionData::Generic(Generic::Boxed(self)),
}),
node,
}
}
#[must_use]
pub fn check_len(self, length: usize, context: &CompileContext) -> Self {
if self.data.length == length
|| length == 0
|| matches!(self.data.data, PointCollectionData::Generic(Generic::Dummy))
{
self
} else {
context.push_error(Error::ImplicitConversionDoesNotExist {
error_span: self.span,
from: self.get_value_type(),
to: ty::collection(length),
});
Self {
data: Rc::new(PointCollection::dummy()),
..self
}
}
}
#[must_use]
pub fn index_without_node(&self, index: usize) -> Expr<Point> {
self.data.data.index(index)
}
#[must_use]
pub fn index_with_node(&mut self, index: usize) -> Expr<Point> {
let mut point = self.data.data.index(index);
point.node = self
.node
.as_mut()
.and_then(|x| x.root.children[index].take());
point
}
}
impl GetValueType for PointCollection {
fn get_value_type(&self) -> Type {
ty::collection(self.length)
}
}
impl Display for PointCollection {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.data)
}
}
#[derive(Debug, CloneWithNode)]
pub enum DerivedData {
Generic(Generic<Derived>),
Data(Rc<dyn DerivedType>),
}
impl Display for DerivedData {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Self::Generic(v) => write!(f, "{v}"),
Self::Data(v) => write!(f, "{v}"),
}
}
}
pub trait DerivedType: Debug + Display + 'static {
fn as_any(&self) -> &dyn Any;
}
#[derive(Debug, CloneWithNode)]
pub struct Derived {
pub name: &'static str,
pub data: DerivedData,
}
impl_x_from_x! {Derived}
impl_from_any! {Derived}
impl_from_unknown! {Derived}
impl_convert_err! {Point -> Derived}
impl_convert_err! {Line -> Derived}
impl_convert_err! {Circle -> Derived}
impl_convert_err! {Number -> Derived}
impl_convert_err! {PointCollection -> Derived}
impl_make_variable! {Derived {other: name, data: DerivedData}}
impl Derived {
#[must_use]
pub fn get_type() -> Type {
ty::derived("{}")
}
}
impl Displayed for Derived {
type Node = dyn Node;
}
impl Dummy for Derived {
fn dummy() -> Self {
Self {
name: "dummy",
data: DerivedData::Generic(Generic::Dummy),
}
}
fn is_dummy(&self) -> bool {
matches!(self.data, DerivedData::Generic(Generic::Dummy))
}
}
impl Expr<Derived> {
#[must_use]
pub fn boxed(mut self, span: Span) -> Self {
let node = self.node.take();
Self {
span,
data: Rc::new(Derived {
name: self.data.name,
data: DerivedData::Generic(Generic::Boxed(self)),
}),
node,
}
}
#[must_use]
pub fn check_name(self, name: &'static str, context: &CompileContext) -> Self {
if self.data.name == name || matches!(self.data.data, DerivedData::Generic(Generic::Dummy))
{
self
} else {
context.push_error(Error::ImplicitConversionDoesNotExist {
error_span: self.span,
from: self.get_value_type(),
to: ty::derived(name),
});
Self {
data: Rc::new(Derived::dummy()),
..self
}
}
}
}
impl GetData for Derived {
fn get_data(&self) -> &Self {
match &self.data {
DerivedData::Generic(v) => match v {
Generic::VariableAccess(var) => var.definition.get_data(),
Generic::Boxed(v) => v.get_data(),
Generic::Dummy => self,
},
_ => self,
}
}
}
impl GetValueType for Derived {
fn get_value_type(&self) -> Type {
ty::derived(self.name)
}
}
impl Display for Derived {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{} {}", self.name, self.data)
}
}
#[derive(Debug, CloneWithNode)]
pub enum Unknown {
Generic(Generic<Unknown>),
}
impl_make_variable! {Unknown}
impl Dummy for Unknown {
fn dummy() -> Self {
Self::Generic(Generic::Dummy)
}
fn is_dummy(&self) -> bool {
true
}
}
impl Display for Unknown {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Self::Generic(v) => write!(f, "{v}"),
}
}
}
impl Displayed for Unknown {
type Node = EmptyNode;
}
impl GetValueType for Unknown {
fn get_value_type(&self) -> Type {
Type::Unknown
}
}
impl Expr<Unknown> {
#[must_use]
pub fn boxed(mut self, span: Span) -> Self {
let node = self.take_node();
Self {
data: Rc::new(Unknown::Generic(Generic::Boxed(self))),
span,
node,
}
}
}
#[derive(Debug, CloneWithNode)]
pub enum AnyExpr {
Point(Expr<Point>),
Line(Expr<Line>),
Number(Expr<Number>),
Circle(Expr<Circle>),
PointCollection(Expr<PointCollection>),
Derived(Expr<Derived>),
Unknown(Expr<Unknown>),
}
impl_any_from_x! {Point}
impl_any_from_x! {Line}
impl_any_from_x! {Number}
impl_any_from_x! {Circle}
impl_any_from_x! {PointCollection}
impl_any_from_x! {Derived}
impl_any_from_x! {Unknown}
impl AnyExpr {
#[must_use]
pub fn get_span_mut(&mut self) -> &mut Span {
match self {
Self::Point(v) => &mut v.span,
Self::Line(v) => &mut v.span,
Self::Number(v) => &mut v.span,
Self::Circle(v) => &mut v.span,
Self::PointCollection(v) => &mut v.span,
Self::Derived(v) => &mut v.span,
Self::Unknown(v) => &mut v.span,
}
}
#[must_use]
pub fn get_span(&self) -> Span {
match self {
Self::Point(v) => v.span,
Self::Line(v) => v.span,
Self::Number(v) => v.span,
Self::Circle(v) => v.span,
Self::PointCollection(v) => v.span,
Self::Derived(v) => v.span,
Self::Unknown(v) => v.span,
}
}
pub fn replace_node(&mut self, with: Option<AnyExprNode>) -> Option<AnyExprNode> {
Some(match self {
Self::Point(v) => {
AnyExprNode::Point(mem::replace(&mut v.node, with.map(AnyExprNode::to_point))?)
}
Self::Line(v) => {
AnyExprNode::Line(mem::replace(&mut v.node, with.map(AnyExprNode::to_line))?)
}
Self::Number(v) => {
AnyExprNode::Number(mem::replace(&mut v.node, with.map(AnyExprNode::to_scalar))?)
}
Self::Circle(v) => {
AnyExprNode::Circle(mem::replace(&mut v.node, with.map(AnyExprNode::to_circle))?)
}
Self::PointCollection(v) => AnyExprNode::PointCollection(mem::replace(
&mut v.node,
with.map(AnyExprNode::to_point_collection),
)?),
Self::Derived(v) => AnyExprNode::Derived(mem::replace(
&mut v.node,
with.map(AnyExprNode::to_derived),
)?),
Self::Unknown(v) => AnyExprNode::Unknown(mem::replace(
&mut v.node,
with.map(AnyExprNode::to_unknown),
)?),
})
}
#[must_use]
pub fn get_node(&self) -> Option<&dyn Node> {
match self {
Self::Point(x) => x.node.as_ref().map(|c| c as &dyn Node),
Self::Line(x) => x.node.as_ref().map(|c| c as &dyn Node),
Self::Number(x) => x.node.as_ref().map(|c| c as &dyn Node),
Self::Circle(x) => x.node.as_ref().map(|c| c as &dyn Node),
Self::PointCollection(x) => x.node.as_ref().map(|c| c as &dyn Node),
Self::Derived(x) => x.node.as_ref().map(|c| c as &dyn Node),
Self::Unknown(x) => x.node.as_ref().map(|c| c as &dyn Node),
}
}
#[must_use]
pub fn to_scalar(self) -> Option<Expr<Number>> {
match self {
Self::Number(v) => Some(v),
_ => None,
}
}
#[must_use]
pub fn as_point(&self) -> Option<&Expr<Point>> {
match self {
Self::Point(v) => Some(v),
_ => None,
}
}
#[must_use]
pub fn get_type(&self) -> Type {
match self {
AnyExpr::Point(v) => v.get_value_type(),
AnyExpr::Line(v) => v.get_value_type(),
AnyExpr::Number(v) => v.get_value_type(),
AnyExpr::Circle(v) => v.get_value_type(),
AnyExpr::PointCollection(v) => v.get_value_type(),
AnyExpr::Derived(v) => v.get_value_type(),
AnyExpr::Unknown(v) => v.get_value_type(),
}
}
#[must_use]
pub fn convert_to(self, to: Type, context: &CompileContext) -> Self {
match to {
Type::Point => Self::Point(self.convert(context)),
Type::Line => Self::Line(self.convert(context)),
Type::Number(unit) => Self::Number(self.convert(context).convert_unit(unit, context)),
Type::PointCollection(len) => {
Self::PointCollection(self.convert(context).check_len(len, context))
}
Type::Circle => Self::Circle(self.convert(context)),
Type::Derived(name) => Self::Derived(self.convert(context).check_name(name, context)),
Type::Unknown => Self::Unknown(Expr::dummy()),
}
}
#[must_use]
pub fn can_convert_to(&self, to: Type) -> bool {
match to {
Type::Point => self.can_convert::<Point>(),
Type::Line => self.can_convert::<Line>(),
Type::Number(unit) => self.can_convert_to_scalar(unit).is_some(),
Type::PointCollection(len) => self.can_convert_to_collection(len).is_some(),
Type::Circle => self.can_convert::<Circle>(),
Type::Derived(name) => self.can_convert_to_derived(name),
Type::Unknown => true,
}
}
#[must_use]
pub fn can_convert_to_scalar(&self, unit: Option<ComplexUnit>) -> Option<Option<ComplexUnit>> {
match self {
Self::Line(_) | Self::Derived(_) | Self::Circle(_) | Self::Point(_) => None,
Self::PointCollection(v) => (v.data.length == 2
&& (unit == Some(unit::DISTANCE) || unit.is_none()))
.then_some(Some(unit::DISTANCE)),
Self::Number(u) => (u.data.unit == unit || u.data.unit.is_none() || unit.is_none())
.then_some(u.data.unit.or(unit)),
Self::Unknown(_) => Some(unit),
}
}
#[must_use]
pub fn can_convert_to_collection(&self, len: usize) -> Option<usize> {
match self {
Self::Line(_) | Self::Derived(_) | Self::Circle(_) | Self::Number(_) => None,
Self::PointCollection(v) => (v.data.length == len || len == 0).then_some(v.data.length),
Self::Point(_) => (len == 1 || len == 0).then_some(1),
Self::Unknown(_) => Some(0),
}
}
#[must_use]
pub fn can_convert_to_derived(&self, name: &str) -> bool {
match self {
Self::Derived(derived) => derived.data.name == name,
Self::Unknown(_) => true,
_ => false,
}
}
#[must_use]
pub fn boxed(self, span: Span) -> Self {
match self {
Self::Point(v) => Self::Point(v.boxed(span)),
Self::Line(v) => Self::Line(v.boxed(span)),
Self::Number(v) => Self::Number(v.boxed(span)),
Self::Circle(v) => Self::Circle(v.boxed(span)),
Self::PointCollection(v) => Self::PointCollection(v.boxed(span)),
Self::Derived(v) => Self::Derived(v.boxed(span)),
Self::Unknown(v) => Self::Unknown(v.boxed(span)),
}
}
#[must_use]
pub fn get_variable_span(&self) -> Span {
match self {
Self::Point(v) => match v.data.as_ref() {
Point::Generic(Generic::VariableAccess(var)) => var.definition_span,
_ => panic!("not a variable"),
},
Self::Line(v) => match v.data.as_ref() {
Line::Generic(Generic::VariableAccess(var)) => var.definition_span,
_ => panic!("not a variable"),
},
Self::Number(v) => match &v.data.data {
NumberData::Generic(Generic::VariableAccess(var)) => var.definition_span,
_ => panic!("not a variable"),
},
Self::Circle(v) => match v.data.as_ref() {
Circle::Generic(Generic::VariableAccess(var)) => var.definition_span,
_ => panic!("not a variable"),
},
Self::PointCollection(v) => match &v.data.data {
PointCollectionData::Generic(Generic::VariableAccess(var)) => var.definition_span,
_ => panic!("not a variable"),
},
Self::Derived(v) => match &v.data.data {
DerivedData::Generic(Generic::VariableAccess(var)) => var.definition_span,
_ => panic!("not a variable"),
},
Self::Unknown(v) => match v.data.as_ref() {
Unknown::Generic(Generic::VariableAccess(var)) => var.definition_span,
Unknown::Generic(_) => panic!("not a variable"),
},
}
}
#[must_use]
pub fn make_variable(self, name: String) -> Self {
match self {
Self::Point(v) => Self::Point(v.make_variable(name)),
Self::Line(v) => Self::Line(v.make_variable(name)),
Self::Number(v) => Self::Number(v.make_variable(name)),
Self::Circle(v) => Self::Circle(v.make_variable(name)),
Self::PointCollection(v) => Self::PointCollection(v.make_variable(name)),
Self::Derived(v) => Self::Derived(v.make_variable(name)),
Self::Unknown(v) => Self::Unknown(v.make_variable(name)),
}
}
#[must_use]
pub fn as_derived(&self) -> Option<&Expr<Derived>> {
if let Self::Derived(v) = self {
Some(v)
} else {
None
}
}
pub fn try_into_derived(self) -> Result<Expr<Derived>, Self> {
if let Self::Derived(v) = self {
Ok(v)
} else {
Err(self)
}
}
#[must_use]
pub fn as_number(&self) -> Option<&Expr<Number>> {
if let Self::Number(v) = self {
Some(v)
} else {
None
}
}
}
impl Dummy for AnyExpr {
fn dummy() -> Self {
Self::Unknown(Expr::dummy())
}
fn is_dummy(&self) -> bool {
match self {
Self::Point(v) => v.is_dummy(),
Self::Line(v) => v.is_dummy(),
Self::Number(v) => v.is_dummy(),
Self::Circle(v) => v.is_dummy(),
Self::PointCollection(v) => v.is_dummy(),
Self::Derived(v) => v.is_dummy(),
Self::Unknown(v) => v.is_dummy(),
}
}
}
impl Display for AnyExpr {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Self::Point(v) => write!(f, "{v}"),
Self::Line(v) => write!(f, "{v}"),
Self::Number(v) => write!(f, "{v}"),
Self::Circle(v) => write!(f, "{v}"),
Self::PointCollection(v) => write!(f, "{v}"),
Self::Derived(v) => write!(f, "{v}"),
Self::Unknown(v) => write!(f, "{v}"),
}
}
}
pub fn display_vec<T: Display>(v: &[T]) -> String {
v.iter()
.map(|x| format!("{x}"))
.collect::<Vec<String>>()
.join(", ")
}
pub trait Dummy {
#[must_use]
fn dummy() -> Self;
#[must_use]
fn is_dummy(&self) -> bool;
}
pub trait Displayed: Sized {
type Node: Node + ?Sized;
}
pub trait GetData {
#[must_use]
fn get_data(&self) -> &Self;
}
pub trait CloneWithNode {
#[must_use]
fn clone_with_node(&mut self) -> Self;
#[must_use]
fn clone_without_node(&self) -> Self;
}
#[derive(Debug)]
pub struct ClonedVec<T>(pub Vec<T>);
impl<T> From<Vec<T>> for ClonedVec<T> {
fn from(value: Vec<T>) -> Self {
Self(value)
}
}
impl<T> Deref for ClonedVec<T> {
type Target = Vec<T>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<T> DerefMut for ClonedVec<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
#[derive(Debug)]
pub struct ClonedMap<K, V>(pub HashMap<K, V>);
impl<K, V> From<HashMap<K, V>> for ClonedMap<K, V> {
fn from(value: HashMap<K, V>) -> Self {
Self(value)
}
}
impl<K, V> Deref for ClonedMap<K, V> {
type Target = HashMap<K, V>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<K, V> DerefMut for ClonedMap<K, V> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl<T: Clone> CloneWithNode for T {
fn clone_with_node(&mut self) -> Self {
self.clone()
}
fn clone_without_node(&self) -> Self {
self.clone()
}
}
impl<T: CloneWithNode> CloneWithNode for ClonedVec<T> {
fn clone_with_node(&mut self) -> Self {
self.iter_mut()
.map(CloneWithNode::clone_with_node)
.collect::<Vec<_>>()
.into()
}
fn clone_without_node(&self) -> Self {
self.iter()
.map(CloneWithNode::clone_without_node)
.collect::<Vec<_>>()
.into()
}
}
impl<K: Hash + CloneWithNode + Eq, V: CloneWithNode> CloneWithNode for ClonedMap<K, V> {
fn clone_with_node(&mut self) -> Self {
self.iter_mut()
.map(|(k, v)| (k.clone_without_node(), v.clone_with_node()))
.collect::<HashMap<_, _>>()
.into()
}
fn clone_without_node(&self) -> Self {
self.iter()
.map(|(k, v)| (k.clone_without_node(), v.clone_without_node()))
.collect::<HashMap<_, _>>()
.into()
}
}
#[derive(Debug)]
pub struct Expr<T: Displayed> {
pub data: Rc<T>,
pub span: Span,
pub node: Option<HierarchyNode<T::Node>>,
}
impl<T: GetData + Displayed> Expr<T> {
#[must_use]
pub fn get_data(&self) -> &T {
self.data.get_data()
}
}
impl<T: Displayed> CloneWithNode for Expr<T> {
fn clone_with_node(&mut self) -> Self {
Self {
data: Rc::clone(&self.data),
span: self.span,
node: self.node.take(),
}
}
fn clone_without_node(&self) -> Self {
Self {
data: Rc::clone(&self.data),
span: self.span,
node: None,
}
}
}
impl<T: GetValueType + Displayed> GetValueType for Expr<T> {
fn get_value_type(&self) -> Type {
self.data.get_value_type()
}
}
impl<T: Display + Displayed> Display for Expr<T> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.data)
}
}
impl<T: Displayed> Expr<T> {
#[must_use]
pub fn new_spanless(data: T) -> Self {
Self {
span: span!(0, 0, 0, 0),
data: Rc::new(data),
node: None,
}
}
pub fn take_node(&mut self) -> Option<HierarchyNode<T::Node>> {
self.node.take()
}
}
impl<T: Displayed + Dummy> Dummy for Expr<T> {
fn dummy() -> Self {
Self::new_spanless(T::dummy())
}
fn is_dummy(&self) -> bool {
self.data.is_dummy()
}
}
#[derive(Debug)]
pub struct UnrolledRule {
pub kind: UnrolledRuleKind,
pub inverted: bool,
pub weight: ProcNum,
}
impl Display for UnrolledRule {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
let inv = if self.inverted { "!" } else { "" };
match &self.kind {
UnrolledRuleKind::PointEq(a, b) => write!(f, "{a} {inv}= {b}"),
UnrolledRuleKind::NumberEq(a, b) => write!(f, "{a} {inv}= {b}"),
UnrolledRuleKind::Gt(a, b) => {
write!(f, "{a} {} {b}", if self.inverted { "<=" } else { ">" })
}
UnrolledRuleKind::Alternative(v) => {
write!(
f,
"{}",
v.iter()
.map(|x| format!("{x}"))
.collect::<Vec<String>>()
.join(" || ")
)
}
UnrolledRuleKind::Bias(v) => write!(f, "bias {v}"),
}
}
}
#[must_use]
pub fn construct_point_name(letter: char, primes: u8) -> String {
String::from(letter) + &"'".repeat(primes as usize)
}
fn fetch_variable(context: &CompileContext, name: &str, variable_span: Span) -> AnyExpr {
let mut var = if let Some(var) = context.variables.get(name) {
var.clone_without_node()
} else {
let suggested = most_similar(context.variables.keys(), name);
context.push_error(Error::UndefinedVariable {
error_span: variable_span,
variable_name: name.to_string(),
suggested: suggested.cloned(),
suggest_complex: name == "i",
});
Expr::new_spanless(Unknown::dummy())
.make_variable(name.to_string())
.into()
};
*var.get_span_mut() = variable_span;
var
}
impl Unroll for SimpleExpression {
fn unroll(
&self,
context: &mut CompileContext,
library: &Library,
it_index: &HashMap<u8, usize>,
display: Properties,
) -> AnyExpr {
let display = Properties::from(self.display.clone()).merge_with(display);
let unrolled = self.kind.unroll(context, library, it_index, display);
let unrolled = if let Some(exponent) = &self.exponent {
let mut unrolled: Expr<Number> = unrolled.convert(context);
let node = unrolled.node.take();
let exponent = match exponent.exponent.as_comp() {
Ok(v) => {
if self.minus.is_some() {
-v
} else {
v
}
}
Err(err) => {
context.push_error(err);
CompExponent::one()
}
};
AnyExpr::Number(Expr {
span: self.get_span(),
data: Rc::new(Number {
unit: unrolled.data.unit.map(|v| v.pow(exponent)),
data: NumberData::Pow(unrolled, exponent),
}),
node,
})
} else {
unrolled
};
if self.minus.is_some() {
let mut unrolled: Expr<Number> = unrolled.convert(context);
let node = unrolled.node.take();
AnyExpr::Number(Expr {
span: self.get_span(),
data: Rc::new(Number {
unit: unrolled.data.unit,
data: NumberData::Negate(unrolled),
}),
node,
})
} else {
unrolled
}
}
}
#[derive(Debug)]
pub enum FuncRef {
Function(String),
Method(String, AnyExpr),
Invalid,
}
impl Unroll for Ident {
fn unroll(
&self,
context: &mut CompileContext,
_library: &Library,
_it_index: &HashMap<u8, usize>,
display: Properties,
) -> AnyExpr {
match self {
Ident::Named(named) => {
display.finish(context);
fetch_variable(context, &named.ident, named.span)
}
Ident::Collection(col) => {
let mut display = display;
let display_pc = display.get("display").maybe_unset(true);
let mut pc_children = Vec::new();
pc_children.resize_with(col.collection.len(), || None);
let mut expr = Expr {
data: Rc::new(PointCollection {
length: col.collection.len(),
data: PointCollectionData::PointCollection(
col.collection
.iter()
.map(|item| {
fetch_variable(context, &format!("{item}"), col.span)
.convert::<Point>(context)
})
.collect::<Vec<_>>()
.into(),
),
}),
span: col.span,
node: None,
};
expr.node = Some(HierarchyNode::new(PCNode {
display: display_pc,
children: pc_children,
props: Some(display),
expr: expr.clone_without_node(),
}));
AnyExpr::PointCollection(expr)
}
}
}
}
impl Unroll for ExprCall {
fn unroll(
&self,
context: &mut CompileContext,
library: &Library,
it_index: &HashMap<u8, usize>,
mut display: Properties,
) -> AnyExpr {
let name = self
.name
.unroll(context, library, it_index, Properties::default());
let (func_name, self_param) = match name {
FuncRef::Function(x) => (x, None),
FuncRef::Method(x, y) => (x, Some(y)),
FuncRef::Invalid => {
display.ignore_all();
display.finish(context);
return AnyExpr::Unknown(Expr::new_spanless(Unknown::dummy()));
}
};
let self_type = self_param.as_ref().map(AnyExpr::get_type);
let mut params = Vec::new();
params.extend(self_param);
if let Some(parsed) = &self.params {
for p in parsed.iter() {
params.push(p.unroll(context, library, it_index, Properties::default()));
}
}
let func = match self_type {
Some(t) => library.get_method(t, &func_name),
None => library.get_function(&func_name),
};
let res = match func {
Ok(func) => {
if let Some(overload) = func.get_overload(¶ms) {
let ret = overload.unroll(params, context, display);
return ret.boxed(self.get_span());
}
context.push_error(Error::OverloadNotFound {
error_span: self.get_span(),
function_name: func_name.clone(),
params: params.iter().map(AnyExpr::get_type).collect(),
});
Expr {
data: Rc::new(Unknown::dummy()),
span: self.get_span(),
node: None,
}
.into()
}
Err(suggested) => {
if let Some(self_type) = self_type {
context.push_error(Error::UndefinedMethod {
error_span: self.name.get_span(),
function_name: func_name,
on_type: self_type,
suggested,
});
} else {
context.push_error(Error::UndefinedFunction {
error_span: self.name.get_span(),
function_name: func_name.clone(),
suggested,
});
}
Expr::new_spanless(Unknown::dummy()).into()
}
};
for mut param in params {
if let Some(AnyExprNode::PointCollection(mut pc)) = param.replace_node(None) {
if let Some(props) = pc.root.props.take() {
props.finish(context);
}
}
}
display.ignore_all();
display.finish(context);
res
}
}
impl Unroll for Name {
fn unroll(
&self,
context: &mut CompileContext,
library: &Library,
it_index: &HashMap<u8, usize>,
display: Properties,
) -> AnyExpr {
match self {
Self::Ident(i) => i.unroll(context, library, it_index, display),
Self::Call(expr) => expr.unroll(context, library, it_index, display),
Self::Expression(v) => v.content.unroll(context, library, it_index, display),
Self::FieldIndex(_) => {
context.push_error(Error::FieldAccess {
error_span: self.get_span(),
});
Expr::new_spanless(Unknown::dummy()).into()
}
}
}
}
impl Unroll<FuncRef> for Name {
fn unroll(
&self,
context: &mut CompileContext,
library: &Library,
it_index: &HashMap<u8, usize>,
display: Properties,
) -> FuncRef {
display.finish(context);
match self {
Self::Ident(Ident::Named(n)) => FuncRef::Function(n.ident.clone()),
Self::FieldIndex(f) => {
let self_param: AnyExpr =
f.name
.unroll(context, library, it_index, Properties::default());
let name = match &f.field {
Ident::Named(n) => n.ident.clone(),
Ident::Collection(_) => {
context.push_error(Error::ExpectedFunction {
error_span: self.get_span(),
});
return FuncRef::Invalid;
}
};
match self_param {
AnyExpr::Unknown(_) => FuncRef::Invalid,
self_param => FuncRef::Method(name, self_param),
}
}
_ => {
context.push_error(Error::ExpectedFunction {
error_span: self.get_span(),
});
FuncRef::Invalid
}
}
}
}
impl Unroll for NumberLit {
fn unroll(
&self,
context: &mut CompileContext,
_library: &Library,
_it_index: &HashMap<u8, usize>,
display: Properties,
) -> AnyExpr {
display.finish(context);
AnyExpr::Number(Expr {
data: Rc::new(Number {
unit: None,
data: NumberData::Number(self.into()),
}),
span: self.get_span(),
node: None,
})
}
}
impl Unroll for ExplicitIterator {
fn unroll(
&self,
context: &mut CompileContext,
library: &Library,
it_index: &HashMap<u8, usize>,
display: Properties,
) -> AnyExpr {
self.get(it_index[&self.id])
.unwrap()
.unroll(context, library, it_index, display)
}
}
impl Unroll for PointCollectionConstructor {
fn unroll(
&self,
context: &mut CompileContext,
library: &Library,
it_index: &HashMap<u8, usize>,
mut display: Properties,
) -> AnyExpr {
let display_pc = display.get("display").maybe_unset(true);
let mut pc_children = Vec::new();
pc_children.resize_with(self.points.len(), || None);
let mut expr = Expr {
span: self.get_span(),
data: Rc::new(PointCollection {
length: self.points.len(),
data: PointCollectionData::PointCollection({
let mut points = Vec::new();
for expr in self.points.iter() {
let mut unrolled =
expr.unroll(context, library, it_index, Properties::default());
if unrolled.can_convert_to(ty::POINT) {
points.push(unrolled.convert(context));
} else {
context.push_error(Error::NonPointInPointCollection {
error_span: self.get_span(),
received: (expr.get_span(), unrolled.get_type()), });
points.push(Expr {
span: unrolled.get_span(),
data: Rc::new(Point::dummy()),
node: unrolled.replace_node(None).map(AnyExprNode::to_point),
});
}
}
for pt in &mut points {
pc_children.push(pt.take_node());
}
points.into()
}),
}),
node: None,
};
expr.node = Some(HierarchyNode::new(PCNode {
display: display_pc,
children: pc_children,
props: Some(display),
expr: expr.clone_without_node(),
}));
AnyExpr::PointCollection(expr)
}
}
impl Unroll for SimpleExpressionKind {
fn unroll(
&self,
context: &mut CompileContext,
library: &Library,
it_index: &HashMap<u8, usize>,
display: Properties,
) -> AnyExpr {
match self {
Self::Name(name) => name.unroll(context, library, it_index, display),
Self::Number(num) => num.unroll(context, library, it_index, display),
Self::ExplicitIterator(it) => it.unroll(context, library, it_index, display),
Self::PointCollection(col) => col.unroll(context, library, it_index, display),
}
}
}
impl<const ITER: bool> Unroll for ExprBinop<ITER> {
fn unroll(
&self,
context: &mut CompileContext,
library: &Library,
it_index: &HashMap<u8, usize>,
display: Properties,
) -> AnyExpr {
let lhs = self
.lhs
.unroll(context, library, it_index, Properties::default());
let rhs = self
.rhs
.unroll(context, library, it_index, Properties::default());
let mut lhs = if lhs.can_convert_to(ty::SCALAR_UNKNOWN) {
lhs.convert::<Number>(context)
} else {
context.push_error(Error::InvalidOperandType {
error_span: Box::new(self.get_span()),
got: (lhs.get_type(), Box::new(lhs.get_span())),
op: self.operator.to_string(),
});
Expr {
span: lhs.get_span(),
data: Rc::new(Number::dummy()),
node: None,
}
};
let mut rhs = if rhs.can_convert_to(ty::SCALAR_UNKNOWN) {
rhs.convert::<Number>(context)
} else {
context.push_error(Error::InvalidOperandType {
error_span: Box::new(self.get_span()),
got: (rhs.get_type(), Box::new(rhs.get_span())),
op: self.operator.to_string(),
});
Expr {
span: rhs.get_span(),
data: Rc::new(Number::dummy()),
node: None,
}
};
let lhs_node = lhs.take_node();
let rhs_node = rhs.take_node();
match &self.operator {
BinaryOperator::Add(_) | BinaryOperator::Sub(_) => {
let lhs = if lhs.data.unit.is_none() {
lhs.convert_unit(rhs.data.unit, context)
} else {
lhs
};
let rhs = rhs.convert_unit(lhs.data.unit, context);
let mut expr = Expr {
span: self.get_span(),
data: Rc::new(Number {
unit: rhs.data.unit,
data: match &self.operator {
BinaryOperator::Add(_) => NumberData::Add(lhs, rhs),
BinaryOperator::Sub(_) => NumberData::Subtract(lhs, rhs),
_ => unreachable!(),
},
}),
node: None,
};
let mut node = HierarchyNode::new(NumberNode::from_expr(&expr, display, context));
node.extend_children(lhs_node);
node.extend_children(rhs_node);
expr.node = Some(node);
AnyExpr::Number(expr)
}
BinaryOperator::Mul(_) | BinaryOperator::Div(_) => {
let lhs = lhs.specify_unit(context);
let rhs = rhs.specify_unit(context);
let mut expr = Expr {
span: self.get_span(),
data: Rc::new(Number {
unit: Some(lhs.data.unit.unwrap() * rhs.data.unit.as_ref().unwrap()),
data: match &self.operator {
BinaryOperator::Mul(_) => NumberData::Multiply(lhs, rhs),
BinaryOperator::Div(_) => NumberData::Divide(lhs, rhs),
_ => unreachable!(),
},
}),
node: None,
};
let mut node = HierarchyNode::new(NumberNode::from_expr(&expr, display, context));
node.extend_children(lhs_node);
node.extend_children(rhs_node);
expr.node = Some(node);
AnyExpr::Number(expr)
}
}
}
}
impl<const ITER: bool> Unroll for ImplicitIterator<ITER> {
fn unroll(
&self,
context: &mut CompileContext,
library: &Library,
it_index: &HashMap<u8, usize>,
display: Properties,
) -> AnyExpr {
if self.exprs.collection.is_empty() {
self.exprs.first.as_ref()
} else {
self.get(it_index[&0]).unwrap()
}
.unroll(context, library, it_index, display)
}
}
impl<const ITER: bool> Unroll for Expression<ITER> {
fn unroll(
&self,
context: &mut CompileContext,
library: &Library,
it_index: &HashMap<u8, usize>,
display: Properties,
) -> AnyExpr {
match self {
Expression::ImplicitIterator(it) => it.unroll(context, library, it_index, display),
Expression::Binop(op) => op.unroll(context, library, it_index, display),
}
}
}
pub fn most_similar<'r, I: IntoIterator<Item = &'r T>, T: AsRef<str> + ?Sized + 'r>(
expected: I,
received: &str,
) -> Option<&'r T> {
#[allow(clippy::cast_possible_truncation)]
expected
.into_iter()
.map(|v| {
(
v,
(strsim::jaro(v.as_ref(), received) * 1000.0).floor() as i64,
)
})
.filter(|v| v.1 > 600)
.max_by_key(|v| v.1)
.map(|v| v.0)
}
#[derive(Debug)]
pub struct Properties {
props: HashMap<String, (Span, String, PropertyValue)>,
finished: bool,
errors: Vec<Error>,
expected: Vec<&'static str>,
}
impl Display for Properties {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "[")?;
for (k, v) in &self.props {
write!(f, "{k} = {}, ", v.1)?;
}
write!(f, "]")
}
}
impl Clone for Properties {
fn clone(&self) -> Self {
Self {
props: self.props.clone(),
finished: false,
errors: Vec::new(),
expected: Vec::new(),
}
}
}
#[allow(clippy::derivable_impls)]
impl Default for Properties {
fn default() -> Self {
Self {
props: HashMap::new(),
finished: false,
errors: Vec::new(),
expected: Vec::new(),
}
}
}
impl Properties {
fn normalize(property: &str) -> String {
property
.chars()
.filter(|c| *c != '_')
.map(|c| c.to_ascii_lowercase())
.collect()
}
pub fn finish(mut self, context: &CompileContext) {
self.finished = true;
let props = mem::take(&mut self.props);
let expected = mem::take(&mut self.expected);
self.errors.extend(props.into_values().map(|value| {
let suggested = most_similar(expected.iter().copied(), &value.1);
Error::UnexpectedDisplayOption {
error_span: value.0,
option: value.1,
suggested,
}
}));
context.extend_errors(mem::take(&mut self.errors));
}
#[must_use]
pub fn get<T: FromProperty>(&mut self, property: &'static str) -> Property<T> {
let norm = Self::normalize(property);
if let Some((_, _, prop)) = self.props.remove(&norm) {
let prop_span = prop.get_span();
Property {
value: match T::from_property(prop) {
Ok(v) => Some(v),
Err(err) => {
self.errors.push(err);
None
}
},
span: Some(prop_span),
}
} else {
self.expected.push(property);
Property {
value: None,
span: None,
}
}
}
pub fn ignore(&mut self, property: &'static str) {
self.props.remove(&Self::normalize(property));
}
pub fn add_if_not_present(
&mut self,
property: &'static str,
(key_span, value): (Span, PropertyValue),
) {
self.props.entry(Self::normalize(property)).or_insert((
key_span,
property.to_string(),
value,
));
}
#[must_use]
pub fn merge_with(mut self, mut other: Properties) -> Self {
self.errors.extend(mem::take(&mut other.errors));
for (k, v) in mem::take(&mut other.props) {
self.props.insert(k, v);
}
other.finished = true;
self
}
fn ignore_all(&mut self) {
self.props.clear();
}
}
impl From<Option<DisplayProperties>> for Properties {
fn from(value: Option<DisplayProperties>) -> Self {
Self {
props: value
.into_iter()
.flat_map(|x| x.properties.into_parsed_iter())
.map(|v| {
(
Self::normalize(&v.name.ident),
(v.name.span, v.name.ident.clone(), v.value.clone()),
)
})
.collect(),
finished: false,
errors: Vec::new(),
expected: Vec::new(),
}
}
}
impl Drop for Properties {
fn drop(&mut self) {
if !self.finished {
eprintln!(
"Properties dropped before finishing parsing: {:#?}. Please report this error.",
self.props
);
}
}
}
#[derive(Debug, Clone)]
pub struct Property<T> {
value: Option<T>,
span: Option<Span>,
}
impl<T> Property<T> {
#[must_use]
pub fn get(self) -> Option<T> {
self.value
}
#[must_use]
pub fn get_or(self, default: T) -> T {
self.value.unwrap_or(default)
}
#[must_use]
pub fn get_span(&self) -> Option<Span> {
self.span
}
#[must_use]
pub fn maybe_unset(self, default: T) -> MaybeUnset<T> {
let mut value = MaybeUnset::new(default);
value.try_set(self.get());
value
}
}
impl<T> Property<Result<T, Error>> {
#[must_use]
pub fn ok_or(self, default: T) -> T {
self.value.and_then(Result::ok).unwrap_or(default)
}
}
fn create_variable_named(
stat: &LetStatement,
context: &mut CompileContext,
named: &NamedIdent,
mut rhs_unrolled: AnyExpr,
variable_nodes: &mut Vec<Box<dyn Node>>,
) -> Result<(), Error> {
let convert = if let AnyExpr::PointCollection(pc) = &mut rhs_unrolled {
if pc.data.length == 1 {
true
} else {
if let Some(node) = &mut pc.node {
if let Some(mut props) = node.root.props.take() {
let _ = props.get::<Result<SpannedMathString, Error>>("default-label");
props.finish(context);
}
}
context.push_error(Error::InvalidPC {
error_span: stat.get_span(),
});
false
}
} else {
false
};
if convert {
rhs_unrolled = rhs_unrolled.convert_to(Type::Point, context);
}
match context.variables.entry(named.ident.clone()) {
Entry::Occupied(entry) => Err(Error::RedefinedVariable {
defined_at: entry.get().get_variable_span(),
error_span: stat.get_span(),
variable_name: entry.key().clone(),
}),
Entry::Vacant(entry) => {
variable_nodes.extend(rhs_unrolled.replace_node(None).map(AnyExprNode::to_dyn));
let var = rhs_unrolled.make_variable(entry.key().clone());
entry.insert(var);
Ok(())
}
}
}
fn create_variable_collection(
stat: &LetStatement,
context: &mut CompileContext,
col: &PCToken,
rhs_unrolled: AnyExpr,
variable_nodes: &mut Vec<Box<dyn Node>>,
) -> Result<(), Error> {
let maybe_error = Error::CannotUnpack {
error_span: rhs_unrolled.get_span(),
ty: rhs_unrolled.get_type(),
length: col.len(),
};
let mut rhs = rhs_unrolled.convert::<PointCollection>(context);
if rhs.data.length != col.len()
&& !matches!(rhs.data.data, PointCollectionData::Generic(Generic::Dummy))
{
return Err(maybe_error);
}
for (i, pt) in col.collection.iter().enumerate() {
let id = format!("{pt}");
let mut var = rhs.index_with_node(i);
let mut pt_node = var
.take_node()
.unwrap_or(HierarchyNode::new(PointNode::from_expr(
&var,
Properties::default(),
context,
)));
match context.variables.entry(id.clone()) {
Entry::Occupied(entry) => {
return Err(Error::RedefinedVariable {
defined_at: entry.get().get_variable_span(),
error_span: stat.get_span(),
variable_name: id,
})
}
Entry::Vacant(entry) => {
pt_node.root.default_label = SpannedMathString::from(pt.clone());
variable_nodes.push(Box::new(pt_node));
let var = var.make_variable(entry.key().clone());
let var = AnyExpr::Point(var);
entry.insert(var);
}
}
}
variable_nodes.extend(rhs.take_node().map(|n| Box::new(n) as Box<dyn Node>));
Ok(())
}
fn create_variables(
stat: &LetStatement,
context: &mut CompileContext,
library: &Library,
external: Option<DisplayProperties>,
) -> Result<Vec<Box<dyn Node>>, Error> {
let mut variable_nodes = Vec::new();
let tree = IterNode::from(&stat.expr);
let ind = if let Some(iter) = tree.first() {
if stat.ident.len() == 1 {
context.push_error(Error::LetStatUnexpectedIterator {
var_span: stat.ident.get_span(),
error_span: iter.span,
});
}
for it in tree.iter() {
if iter.id != it.id {
context.push_error(Error::LetStatMoreThanOneIterator {
error_span: stat.expr.get_span(),
first_span: iter.span,
second_span: it.span,
});
}
for variant in &it.variants {
if let Some(it2) = variant.first() {
context.push_error(Error::LetStatMoreThanOneIterator {
error_span: stat.expr.get_span(),
first_span: iter.span,
second_span: it2.span,
});
}
}
}
let mut lengths = HashMap::new();
tree.get_iter_lengths(&mut lengths, stat.expr.get_span())?;
let entry = lengths.get(&iter.id).unwrap();
if entry.0 != stat.ident.len() {
return Err(Error::InconsistentIterators {
first_span: stat.ident.get_span(),
first_length: stat.ident.len(),
occurred_span: entry.1,
occurred_length: entry.0,
error_span: stat.get_span(),
});
}
None
} else {
Some(HashMap::new())
};
let mut it_index = IterTreeIterator::new(&tree);
for def in stat.ident.iter() {
let mut external = Properties::from(external.clone());
if def.name.is_named() {
external.add_if_not_present(
"default-label",
(def.name.get_span(), PropertyValue::Ident(def.name.clone())),
);
}
let display = external.merge_with(Properties::from(def.display_properties.clone()));
let rhs_unrolled = stat.expr.unroll(
context,
library,
ind.as_ref()
.unwrap_or_else(|| it_index.get_currents().unwrap()),
display,
);
it_index.next();
match &def.name {
Ident::Named(named) => {
create_variable_named(stat, context, named, rhs_unrolled, &mut variable_nodes)?;
}
Ident::Collection(col) => {
create_variable_collection(stat, context, col, rhs_unrolled, &mut variable_nodes)?;
}
}
}
Ok(variable_nodes)
}
fn unroll_ref(
stat: &parser::Displayed<RefStatement>,
context: &mut CompileContext,
library: &Library,
) -> Result<Vec<Box<dyn Node>>, Error> {
let mut nodes = Vec::new();
let tree = IterNode::from(&stat.statement.operand);
tree.get_iter_lengths(&mut HashMap::new(), stat.get_span())?;
let mut index = IterTreeIterator::new(&tree);
while let Some(it_index) = index.get_currents() {
let mut display = Properties::from(stat.properties.clone());
let weight = display.get("weight").get_or(ProcNum::zero());
let mut expr = stat
.statement
.operand
.unroll(context, library, it_index, display);
if let AnyExpr::PointCollection(pc) = &mut expr {
if let Some(node) = pc.node.take() {
if let Some(props) = node.root.props {
props.finish(context);
}
}
context.push_error(Error::InvalidPC {
error_span: expr.get_span(),
});
}
let node = expr.replace_node(None).map(AnyExprNode::to_dyn);
nodes.extend(node);
if !weight.is_zero() {
context.push_rule(UnrolledRule {
kind: UnrolledRuleKind::Bias(expr),
inverted: false,
weight,
});
}
index.next();
}
Ok(nodes)
}
fn unroll_let(
stat: parser::Displayed<LetStatement>,
context: &mut CompileContext,
library: &Library,
) -> Result<Vec<Box<dyn Node>>, Error> {
let parser::Displayed {
properties,
statement: mut stat,
} = stat;
let lhs: Expression<true> = Expression::ImplicitIterator(ImplicitIterator {
exprs: Punctuated {
first: Box::new(SimpleExpression {
minus: None,
kind: SimpleExpressionKind::Name(Name::Ident(stat.ident.first.name.clone())),
exponent: None,
display: None,
}),
collection: stat
.ident
.collection
.iter()
.map(|(p, i)| {
(
*p,
SimpleExpression {
minus: None,
kind: SimpleExpressionKind::Name(Name::Ident(i.name.clone())),
exponent: None,
display: None,
},
)
})
.collect(),
},
});
let stat_span = stat.get_span();
let rule = mem::take(&mut stat.rule);
let mut nodes = create_variables(&stat, context, library, properties)?;
if let Some((rule, expr)) = rule {
let tree = IterNode::from2(&lhs, &expr);
tree.get_iter_lengths(&mut HashMap::new(), stat_span)?;
let mut index = IterTreeIterator::new(&tree);
while let Some(it_index) = index.get_currents() {
nodes.push(unroll_rule(
(
lhs.unroll(context, library, it_index, Properties::default()),
&rule,
expr.unroll(context, library, it_index, Properties::default()),
),
context,
library,
stat_span,
false,
Properties::from(None),
));
index.next();
}
}
Ok(nodes)
}
fn unroll_eq(
lhs: AnyExpr,
rhs: AnyExpr,
context: &mut CompileContext,
full_span: Span,
inverted: bool,
display: Properties,
) -> Box<dyn Node> {
let lhs_type = lhs.get_type();
let rhs_type = rhs.get_type();
if (lhs_type == ty::collection(2) && rhs_type == ty::collection(2))
|| (lhs_type == ty::collection(2) && rhs_type == ty::SCALAR_UNKNOWN)
|| (lhs_type == ty::SCALAR_UNKNOWN && rhs_type == ty::collection(2))
{
let lhs = lhs
.convert(context)
.convert_unit(Some(unit::DISTANCE), context);
let rhs = rhs
.convert(context)
.convert_unit(Some(unit::DISTANCE), context);
context.scalar_eq_display(lhs, rhs, inverted, display)
} else if lhs_type == ty::collection(1) && rhs_type == ty::collection(1) {
let lhs = lhs.convert(context);
let rhs = rhs.convert(context);
context.point_eq_display(lhs, rhs, inverted, display)
} else {
let (lhs, rhs, new_type) = if rhs.can_convert_to(lhs_type) {
(lhs, rhs.convert_to(lhs_type, context), lhs_type)
} else if lhs.can_convert_to(rhs_type) {
(lhs.convert_to(rhs_type, context), rhs, rhs_type)
} else {
context.push_error(Error::InconsistentTypes {
expected: (lhs_type, Box::new(lhs.get_span())),
got: (rhs_type, Box::new(rhs.get_span())),
error_span: Box::new(full_span),
});
(
lhs,
AnyExpr::Unknown(Expr {
span: rhs.get_span(),
data: Rc::new(Unknown::dummy()),
node: None,
})
.convert_to(lhs_type, context),
lhs_type,
)
};
match new_type {
Type::Point => {
let lhs = lhs.convert(context);
let rhs = rhs.convert(context);
context.point_eq_display(lhs, rhs, inverted, display)
}
Type::Number(_) => {
let lhs = lhs.convert(context);
let rhs = rhs.convert(context);
context.scalar_eq_display(lhs, rhs, inverted, display)
}
ty => {
if ty != Type::Unknown {
context.push_error(Error::ComparisonDoesNotExist {
error_span: full_span,
ty,
});
}
context.scalar_eq_display(
Expr::new_spanless(Number::dummy()),
Expr::new_spanless(Number::dummy()),
inverted,
display,
)
}
}
}
}
fn unroll_gt(
lhs: Expr<Number>,
rhs: Expr<Number>,
context: &mut CompileContext,
full_span: Span,
inverted: bool,
display: Properties,
) -> Box<dyn Node> {
if lhs.data.unit.is_some() {
let rhs = if rhs.can_convert_unit(lhs.data.unit) {
rhs.convert_unit(lhs.data.unit, context)
} else {
context.push_error(Error::InconsistentTypes {
expected: (lhs.get_value_type(), Box::new(lhs.span)),
got: (rhs.get_value_type(), Box::new(rhs.span)),
error_span: Box::new(full_span),
});
Expr {
span: rhs.span,
node: rhs.node,
data: Rc::new(Number::dummy()),
}
.convert_unit(lhs.data.unit, context)
};
context.gt_display(lhs, rhs, inverted, display)
} else if rhs.data.unit.is_some() {
let lhs = lhs.convert_unit(rhs.data.unit, context);
context.gt_display(lhs, rhs, inverted, display)
} else {
let lhs = lhs.convert_unit(Some(unit::SCALAR), context);
let rhs = rhs.convert_unit(Some(unit::SCALAR), context);
context.gt_display(lhs, rhs, inverted, display)
}
}
fn unroll_rule(
(lhs, op, rhs): (AnyExpr, &RuleOperator, AnyExpr),
context: &mut CompileContext,
library: &Library,
full_span: Span,
inverted: bool,
mut display: Properties,
) -> Box<dyn Node> {
match op {
RuleOperator::Predefined(pre) => match pre {
PredefinedRuleOperator::Eq(_) => {
unroll_eq(lhs, rhs, context, full_span, inverted, display)
}
PredefinedRuleOperator::Lt(_) => unroll_gt(
rhs.convert(context),
lhs.convert(context),
context,
full_span,
inverted,
display,
),
PredefinedRuleOperator::Gt(_) => unroll_gt(
lhs.convert(context),
rhs.convert(context),
context,
full_span,
inverted,
display,
),
PredefinedRuleOperator::Lteq(_) => unroll_gt(
lhs.convert(context),
rhs.convert(context),
context,
full_span,
!inverted,
display,
),
PredefinedRuleOperator::Gteq(_) => unroll_gt(
rhs.convert(context),
lhs.convert(context),
context,
full_span,
!inverted,
display,
),
},
RuleOperator::Defined(op) => {
let weight = display.get("weight").get_or(ProcNum::one());
let overload = match library.get_rule(op.ident.as_str()) {
Ok(func) => {
if let Some(overload) = func.get_overload(&lhs, &rhs) {
overload
} else {
context.push_error(Error::OverloadNotFound {
error_span: op.span,
function_name: op.ident.clone(),
params: vec![lhs.get_type(), rhs.get_type()],
});
display.finish(context);
return Box::new(EmptyNode);
}
}
Err(suggested) => {
context.push_error(Error::UndefinedFunction {
error_span: op.span,
function_name: op.ident.clone(),
suggested,
});
display.finish(context);
return Box::new(EmptyNode);
}
};
overload.unroll(lhs, rhs, context, display, inverted, weight)
}
RuleOperator::Inverted(op) => unroll_rule(
(lhs, &op.operator, rhs),
context,
library,
full_span,
!inverted,
display,
),
}
}
fn unroll_rule_statement(
rule: &parser::Displayed<RuleStatement>,
context: &mut CompileContext,
library: &Library,
) -> Result<Vec<Box<dyn Node>>, Error> {
let mut nodes = Vec::new();
let parser::Displayed {
properties,
statement: rule,
} = rule;
let firsts = Some(&rule.first)
.into_iter()
.chain(rule.rules.iter().map(|v| &v.1));
for (lhs, op, rhs) in firsts
.zip(rule.rules.iter())
.map(|(lhs, (op, rhs))| (lhs, op, rhs))
{
let tree = IterNode::from2(lhs, rhs);
let full_span = lhs.get_span().join(rhs.get_span());
tree.get_iter_lengths(&mut HashMap::new(), full_span)?;
let mut it_index = IterTreeIterator::new(&tree);
while let Some(index) = it_index.get_currents() {
nodes.push(unroll_rule(
(
lhs.unroll(context, library, index, Properties::default()),
op,
rhs.unroll(context, library, index, Properties::default()),
),
context,
library,
full_span,
false,
Properties::from(properties.clone()),
));
it_index.next();
}
}
Ok(nodes)
}
pub fn unroll(input: &str) -> Result<(CompileContext, CollectionNode), Vec<Error>> {
let mut context = CompileContext::new();
let library = Library::new();
let mut figure = CollectionNode::new();
let tokens = match token::tokenize(input) {
Ok(v) => v,
Err(err) => return Err(vec![err]),
};
let mut input = InputStream::new(&tokens);
let mut statements = Vec::new();
while !input.eof() {
statements.push(match input.parse() {
Ok(v) => v,
Err(err) => return Err(vec![err]),
});
}
let mut flags = FlagSetConstructor::new()
.add_set("optimizations", FlagSetConstructor::new())
.add_set(
"language",
FlagSetConstructor::new().add_bool_def("complex_numbers", false),
)
.add_bool_def("point_inequalities", true)
.finish();
for flag in statements.iter().filter_map(Statement::as_flag) {
flags::set_flag(&mut flags, flag, &context);
}
context.flags = flags;
let enable_complex = context.flags["language"].as_set().unwrap()["complex_numbers"]
.kind
.as_setting()
.unwrap();
if enable_complex.get_value().unwrap().as_bool().unwrap() {
context.variables.insert(
String::from("i"),
AnyExpr::Number(Expr {
span: enable_complex.get_span().unwrap(),
data: Rc::new(Number {
unit: Some(unit::SCALAR),
data: NumberData::Number(ProcNum::i()),
}),
node: None,
}),
);
}
for stat in statements {
match stat {
Statement::Noop(_) | Statement::Flag(_) => (),
Statement::Let(stat) => match unroll_let(stat, &mut context, &library) {
Ok(nodes) => {
for node in nodes {
figure.push_boxed(node);
}
}
Err(err) => context.push_error(err),
},
Statement::Rule(stat) => match unroll_rule_statement(&stat, &mut context, &library) {
Ok(nodes) => {
for node in nodes {
figure.push_boxed(node);
}
}
Err(err) => context.push_error(err),
},
Statement::Ref(stat) => match unroll_ref(&stat, &mut context, &library) {
Ok(nodes) => {
for node in nodes {
figure.push_boxed(node);
}
}
Err(err) => context.push_error(err),
},
}
}
if context.valid() {
Ok((context, figure))
} else {
Err(context.take_errors())
}
}