1use std::{
6 fmt::Display,
7 ops::{Deref, DerefMut, Div, Mul},
8};
9
10use crate::cli::{AnnotationKind, Change, DiagnosticData, Fix};
11use geo_aid_figure::math_string::SPECIAL_MATH;
12use num_traits::{One, Zero};
13use serde::Serialize;
14
15use self::parser::Type;
16use self::token::{number::CompExponent, NamedIdent, Span, Token};
17
18pub mod cli;
19pub mod figure;
20pub mod geometry;
21pub mod math;
22pub mod parser;
23pub mod token;
24pub mod unroll;
25
26#[derive(Debug)]
28pub enum Error {
29 InvalidToken {
31 token: Token,
33 },
34 UnexpectedProperties {
36 error_span: Span,
38 },
39 InvalidCharacter {
41 character: char,
43 error_span: Span,
45 },
46 NewLineInString {
48 error_span: Span,
50 },
51 NumberTooLarge {
53 error_span: Span,
55 },
56 SingleVariantExplicitIterator {
58 error_span: Span,
60 },
61 EndOfInput,
63 UndefinedRuleOperator {
65 operator: NamedIdent,
67 },
68 InconsistentIterators {
70 first_span: Span,
72 first_length: usize,
74 occurred_span: Span,
76 occurred_length: usize,
78 error_span: Span,
80 },
81 IteratorWithSameIdIterator {
83 error_span: Span,
85 parent_span: Span,
87 contained_span: Span,
89 },
90 InconsistentTypes {
92 expected: (Type, Box<Span>),
95 got: (Type, Box<Span>),
97 error_span: Box<Span>,
99 },
100 RedefinedVariable {
102 defined_at: Span,
104 error_span: Span,
106 variable_name: String,
108 },
109 UndefinedTypeVariable {
111 definition: Span,
113 },
114 UndefinedVariable {
116 error_span: Span,
118 variable_name: String,
120 suggested: Option<String>,
122 suggest_complex: bool,
124 },
125 UndefinedFunction {
127 error_span: Span,
129 function_name: String,
131 suggested: Option<&'static str>,
133 },
134 UndefinedMethod {
136 error_span: Span,
138 function_name: String,
140 suggested: Option<&'static str>,
142 on_type: Type,
144 },
145 FieldAccess {
147 error_span: Span,
149 },
150 FeatureNotSupported {
152 error_span: Span,
154 feature_name: &'static str,
156 },
157 InvalidArgumentCount {
159 error_span: Span,
161 expected: &'static [u8],
163 got: u8,
165 },
166 OverloadNotFound {
168 error_span: Span,
170 params: Vec<Type>,
172 function_name: String,
174 },
175 CannotUnpack {
177 error_span: Span,
179 ty: Type,
181 length: usize,
183 },
184 ImplicitConversionDoesNotExist {
186 error_span: Span,
188 from: Type,
190 to: Type,
192 },
193 InvalidOperandType {
195 error_span: Box<Span>,
197 got: (Type, Box<Span>),
199 op: String,
201 },
202 LetStatUnexpectedIterator {
204 var_span: Span,
206 error_span: Span,
208 },
209 LetStatMoreThanOneIterator {
211 error_span: Span,
213 first_span: Span,
215 second_span: Span,
217 },
218 NonPointInPointCollection {
220 error_span: Span,
222 received: (Span, Type),
224 },
225 FlagDoesNotExist {
227 flag_name: String,
229 flag_span: Span,
231 error_span: Span,
233 suggested: Option<&'static str>,
235 },
236 FlagSetExpected {
238 error_span: Span,
240 },
241 StringExpected { error_span: Span },
243 StringOrIdentExpected { error_span: Span },
245 NonRawStringOrIdentExpected { error_span: Span },
247 BooleanExpected { error_span: Span },
249 NumberExpected { error_span: Span },
251 InvalidIdentMathString { error_span: Span },
253 RedefinedFlag {
255 error_span: Span,
257 first_defined: Span,
259 flag_name: &'static str,
261 },
262 EnumInvalidValue {
264 error_span: Span,
266 available_values: &'static [&'static str],
268 received_value: String,
270 },
271 RequiredFlagNotSet {
273 flag_name: &'static str,
275 required_because: Span,
277 definition_span: Option<Span>,
279 available_values: &'static [&'static str],
281 },
282 ComparisonDoesNotExist {
284 error_span: Span,
285 ty: Type,
287 },
288 EmptyLabel { error_span: Span },
290 UnclosedSpecial {
292 error_span: Span,
293 parsed_special: String,
295 },
296 SpecialNotRecognised {
298 error_span: Span,
299 code: String,
301 suggested: Option<String>,
303 },
304 UnclosedString { error_span: Span },
306 LabelIndexInsideIndex { error_span: Span },
308 UnexpectedDisplayOption {
310 error_span: Span,
311 option: String,
313 suggested: Option<&'static str>,
315 },
316 RepeatedDisplayOption {
318 error_span: Span,
320 first_span: Span,
322 option: String,
324 },
325 InvalidPC { error_span: Span },
327 ZeroDenominator { error_span: Span },
329 ExpectedFunction { error_span: Span },
331}
332
333impl Error {
334 #[must_use]
336 pub fn as_implicit_does_not_exist(&self) -> Option<(&Span, &Type, &Type)> {
337 match self {
338 Self::ImplicitConversionDoesNotExist {
339 error_span,
340 from,
341 to,
342 } => Some((error_span, from, to)),
343 _ => None,
344 }
345 }
346
347 #[must_use]
349 #[allow(clippy::too_many_lines)]
350 pub fn diagnostic(self) -> DiagnosticData {
351 match self {
352 Self::InvalidToken { token } => {
353 DiagnosticData::new(&format!("invalid token: `{token}`")).add_span(token.get_span())
354 }
355 Self::UnexpectedProperties { error_span } => {
356 DiagnosticData::new(&"unexpected properties (display options)").add_span(error_span)
357 }
358 Self::InvalidCharacter {
359 character,
360 error_span,
361 } => DiagnosticData::new(&format!("invalid character: `{character}`"))
362 .add_span(error_span),
363 Self::NewLineInString {
364 error_span,
365 } => DiagnosticData::new(&"newline in string")
366 .add_span(error_span),
367 Self::EndOfInput => DiagnosticData::new("unexpected end of input"),
368 Self::UndefinedRuleOperator { operator } => {
369 DiagnosticData::new(&format!("undefined rule operator: `{}`", operator.ident))
370 .add_span(operator.span)
371 }
372 Self::InconsistentIterators {
373 first_span,
374 first_length,
375 occurred_span,
376 occurred_length,
377 error_span,
378 } => DiagnosticData::new(&"inconsistent iterator lengths")
379 .add_span(error_span)
380 .add_annotation(
381 first_span,
382 AnnotationKind::Note,
383 &format!("First iterator with length {first_length} here."),
384 )
385 .add_annotation(
386 occurred_span,
387 AnnotationKind::Note,
388 &format!("Inconsistency (iterator with length {occurred_length}) here."),
389 ),
390 Self::InconsistentTypes {
391 expected,
392 got,
393 error_span,
394 } => DiagnosticData::new("inconsistent types")
395 .add_span(*error_span)
396 .add_annotation(
397 *expected.1,
398 AnnotationKind::Note,
399 &format!("This expression is of type {}", expected.0),
400 )
401 .add_annotation(
402 *got.1,
403 AnnotationKind::Note,
404 &format!("This expression is of type {}", got.0),
405 ),
406 Self::RedefinedVariable {
407 defined_at,
408 error_span,
409 variable_name,
410 } => DiagnosticData::new(&format!("redefined variable: `{variable_name}`"))
411 .add_span(error_span)
412 .add_annotation(defined_at, AnnotationKind::Note, "First defined here."),
413 Self::UndefinedTypeVariable { definition } => {
414 DiagnosticData::new("variable of undefined type")
415 .add_span(definition)
416 .add_annotation(definition, AnnotationKind::Note, "Defined here.")
417 }
418 Self::UndefinedVariable {
419 error_span,
420 variable_name,
421 suggested,
422 suggest_complex
423 } => {
424 let message = suggested.map(|v| format!("did you mean: `{v}`?"));
425 let data = DiagnosticData::new(&format!("undefined variable: `{variable_name}`"))
426 .add_span(error_span)
427 .add_annotation_opt_msg(error_span, AnnotationKind::Help, message.as_ref());
428
429 if suggest_complex {
430 data.add_fix(Fix {
431 changes: vec![Change {
432 span: span!(1, 1, 1, 1),
433 new_content: vec![String::from("@language.complex_numbers: true;"), String::new()]
434 }],
435 message: String::from("Did you want to use a complex unit? If so, declare it with a flag.")
436 })
437 } else {
438 data
439 }
440 }
441 Self::UndefinedFunction {
442 error_span,
443 function_name,
444 suggested
445 } => {
446 let message = suggested.map(|v| format!("did you mean: `{v}`?"));
447 DiagnosticData::new(&format!("function `{function_name}` not found"))
448 .add_span(error_span)
449 .add_annotation_opt_msg(error_span, AnnotationKind::Help, message.as_ref())
450 }
451 Self::UndefinedMethod {
452 error_span,
453 function_name,
454 suggested,
455 on_type
456 } => {
457 let message = suggested.map(|v| format!("did you mean: `{v}`?"));
458 DiagnosticData::new(&format!("method `{function_name}` not found on type {on_type}"))
459 .add_span(error_span)
460 .add_annotation_opt_msg(error_span, AnnotationKind::Help, message.as_ref())
461 }
462 Self::FieldAccess { error_span } => {
463 DiagnosticData::new("GeoScript has no fields. Did you mean to call a method?")
464 .add_span(error_span)
465 }
466 Self::FeatureNotSupported {
467 error_span,
468 feature_name,
469 } => {
470 DiagnosticData::new(&format!("feature `{feature_name}` not supported"))
471 .add_span(error_span)
472 }
473 Self::InvalidArgumentCount {
474 error_span,
475 expected,
476 got,
477 } => {
478 DiagnosticData::new(&format!("invalid argument count. Expected one of `{expected:?}`, got {got}"))
479 .add_span(error_span)
480 }
481 Self::OverloadNotFound {
482 error_span,
483 params,
484 function_name,
485 } => {
486 DiagnosticData::new(&format!("overload for function `{function_name}` with params `({})` not found", params.into_iter().map(|x| format!("{x}")).collect::<Vec<String>>().join(", ")))
487 .add_span(error_span)
488 },
489 Self::CannotUnpack { error_span, ty, length } => {
490 DiagnosticData::new(&format!("could not unpack `{ty}` onto a point collection of length {length}"))
491 .add_span(error_span)
492 }
493 Self::ImplicitConversionDoesNotExist {
494 error_span,
495 from,
496 to,
497 } => {
498 DiagnosticData::new(&format!("implicit conversion from `{from}` to `{to}` does not exist."))
499 .add_span(error_span)
500 }
501 Self::InvalidOperandType {
502 error_span,
503 got,
504 op,
505 } => {
506 DiagnosticData::new(&format!("invalid operand type `{}` for operator `{op}`", got.0))
507 .add_span(*error_span)
508 .add_annotation(*got.1, AnnotationKind::Note, "this is of invalid type")
509 }
510 Self::LetStatUnexpectedIterator {
511 var_span,
512 error_span,
513 } => {
514 DiagnosticData::new(&"unexpected iterator in right-hand side of `let` statement")
515 .add_span(error_span)
516 .add_annotation(var_span, AnnotationKind::Note, "there was no iterator of left-hand side, so the same is expected for the right")
517 }
518 Self::IteratorWithSameIdIterator { error_span, parent_span, contained_span } => {
519 DiagnosticData::new(&"an iterator with an id of `x` must not contain an iterator with an id of `x`")
520 .add_span(error_span)
521 .add_annotation(parent_span, AnnotationKind::Note, "parent iterator here")
522 .add_annotation(contained_span, AnnotationKind::Note, "child iterator here")
523 }
524 Self::LetStatMoreThanOneIterator { error_span, first_span, second_span } => {
525 DiagnosticData::new(&"right hand side of a let statement must contain at most a single level of iteration")
526 .add_span(error_span)
527 .add_annotation(first_span, AnnotationKind::Note, "first iterator here")
528 .add_annotation(second_span, AnnotationKind::Note, "second iterator here")
529 }
530 Self::NumberTooLarge { error_span } => {
531 DiagnosticData::new(&"number too large")
532 .add_span(error_span)
533 }
534 Self::SingleVariantExplicitIterator { error_span } => {
535 DiagnosticData::new(&"explicit iterators must have at least two variants")
536 .add_span(error_span)
537 }
538 Self::NonPointInPointCollection { error_span, received } => {
539 DiagnosticData::new(&"all values in a point collection constructor must be points")
540 .add_span(error_span)
541 .add_annotation(received.0, AnnotationKind::Note, &format!("value should be a point, received {}", received.1))
542 }
543 Self::FlagDoesNotExist { flag_name, flag_span, error_span, suggested } => {
544 let message = suggested.map(|v| format!("Did you mean: `{v}`?"));
545 DiagnosticData::new(&format!("compiler flag `{flag_name}` does not exist"))
546 .add_span(error_span)
547 .add_annotation(flag_span, AnnotationKind::Note, &"This does not exist.")
548 .add_annotation_opt_msg(flag_span, AnnotationKind::Help, message.as_ref())
549 }
550 Self::FlagSetExpected { error_span } => {
551 DiagnosticData::new(&"expected a flag set ({...})")
552 .add_span(error_span)
553 }
554 Self::StringExpected { error_span } => {
555 DiagnosticData::new(&"expected a string")
556 .add_span(error_span)
557 }
558 Self::StringOrIdentExpected { error_span } => {
559 DiagnosticData::new(&"expected a string or an identifier")
560 .add_span(error_span)
561 }
562 Self::NonRawStringOrIdentExpected { error_span } => {
563 DiagnosticData::new(&"expected a non-raw string or an identifier")
564 .add_span(error_span)
565 }
566 Self::BooleanExpected { error_span } => {
567 DiagnosticData::new(&"expected a boolean value (enabled, disabled, on, off, true, false, 1 or 0)")
568 .add_span(error_span)
569 }
570 Self::NumberExpected { error_span } => {
571 DiagnosticData::new(&"expected a number value")
572 .add_span(error_span)
573 }
574 Self::InvalidIdentMathString { error_span } => {
575 DiagnosticData::new(&"invalid ident for a math string")
576 .add_span(error_span)
577 }
578 Self::RedefinedFlag {
579 first_defined,
580 error_span,
581 flag_name,
582 } => DiagnosticData::new(&format!("redefined flag: `{flag_name}`"))
583 .add_span(error_span)
584 .add_annotation(first_defined, AnnotationKind::Note, "first defined here"),
585 Self::EnumInvalidValue { error_span, available_values, received_value } => {
586 DiagnosticData::new(&format!("invalid value for an enum flag or property: `{received_value}`"))
587 .add_span(error_span)
588 .add_annotation(error_span, AnnotationKind::Help, &format!("supported values: {}", available_values.iter().map(
589 |v| format!("`{v}`")
590 ).collect::<Vec<String>>().join(", ")))
591 }
592 Self::RequiredFlagNotSet { flag_name, required_because, definition_span: flagdef_span, available_values } => {
593 DiagnosticData::new(&format!("you must set a value for flag `{flag_name}`."))
594 .add_annotation(required_because, AnnotationKind::Note, &"Required because of this line.")
595 .add_annotation(required_because, AnnotationKind::Help, &format!("Possible values: {}", available_values.iter().map(
596 |v| format!("`{v}`")
597 ).collect::<Vec<String>>().join(", ")))
598 .add_annotation_opt_span(flagdef_span, AnnotationKind::Note, &"Flag defined here")
599 .add_fix(Fix {
600 message: String::from("Consider defining this flag at the top of the file."),
601 changes: vec![
602 Change {
603 span: span!(1, 1, 1, 1),
604 new_content: vec![
605 format!("@{flag_name}: {};", available_values[0]),
606 String::new()
607 ]
608 }
609 ]
610 })
611 }
612 Self::ComparisonDoesNotExist { error_span, ty } => {
613 DiagnosticData::new(&format!("comparison between values of type {ty} does not exist."))
614 .add_span(error_span)
615 }
616 Self::EmptyLabel { error_span } => {
617 DiagnosticData::new(&"labels cannot be empty.")
618 .add_span(error_span)
619 }
620 Self::UnclosedSpecial { error_span, parsed_special } => {
621 let found = SPECIAL_MATH.iter().find(|x| parsed_special.starts_with(*x));
623
624 let d = DiagnosticData::new(&"there's a missing ']' somewhere here. Braces denote special characters To escape a brace, use \\[.")
625 .add_span(error_span);
626
627 if let Some(found) = found {
628 d.add_fix(Fix {
629 message: String::from("You may have forgotten to put a `]` here."),
630 changes: vec![
631 Change {
632 span: span!(
633 error_span.start.line, error_span.start.column + found.len() + 1,
634 error_span.start.line, error_span.start.column + found.len() + 1
635 ),
636 new_content: vec![
637 String::from("]")
638 ]
639 }
640 ]
641 })
642 } else {
643 d
644 }
645 }
646 Self::SpecialNotRecognised {
647 error_span,
648 code,
649 suggested
650 } => {
651 let message = suggested.map(|v| format!("Did you mean: `{v}`?"));
652 DiagnosticData::new(&format!("special code not recognised: `{code}`"))
653 .add_span(error_span)
654 .add_annotation_opt_msg(error_span, AnnotationKind::Help, message.as_ref())
655 }
656 Self::UnclosedString { error_span } => {
657 DiagnosticData::new(&"unclosed special tag")
658 .add_span(error_span)
659 }
660 Self::LabelIndexInsideIndex { error_span } => {
661 DiagnosticData::new(&"lower index cannot be used inside another lower index")
662 .add_span(error_span)
663 }
664 Self::UnexpectedDisplayOption { error_span, option, suggested } => {
665 let message = suggested.map(|v| format!("did you mean: `{v}`?"));
666 DiagnosticData::new(&format!("unexpected display option: `{option}`"))
667 .add_span(error_span)
668 .add_annotation_opt_msg(error_span, AnnotationKind::Help, message.as_ref())
669 }
670 Self::RepeatedDisplayOption { error_span, first_span, option } => {
671 DiagnosticData::new(&format!("repeated display option: `{option}`"))
672 .add_span(error_span)
673 .add_annotation(first_span, AnnotationKind::Help, &"first defined here")
674 }
675 Self::InvalidPC { error_span } => {
676 DiagnosticData::new(&"point collections in this place are ambiguous and therefore not valid")
677 .add_span(error_span)
678 }
679 Self::ZeroDenominator { error_span } => {
680 DiagnosticData::new(&"denominator in a fraction cannot be equal to zero")
681 .add_span(error_span)
682 }
683 Self::ExpectedFunction { error_span } => {
684 DiagnosticData::new(&"expected function, found, value")
685 .add_span(error_span)
686 }
687 }
688 }
689}
690
691#[derive(Clone, Copy, PartialEq, Eq, Debug)]
693pub enum SimpleUnit {
694 Distance,
695 Angle,
696 Unitless,
697}
698
699impl Mul for SimpleUnit {
700 type Output = ComplexUnit;
701
702 fn mul(self, rhs: Self) -> Self::Output {
703 let complex = ComplexUnit::new(self);
704
705 complex * rhs
706 }
707}
708
709const fn unit_count() -> usize {
711 SimpleUnit::Unitless as usize
712}
713
714#[derive(Clone, Copy, PartialEq, Eq, Debug, Serialize, Default, Hash)]
716pub struct ComplexUnit([CompExponent; unit_count()]);
717
718pub mod unit {
720 use super::{ComplexUnit, SimpleUnit};
721
722 pub const DISTANCE: ComplexUnit = ComplexUnit::new(SimpleUnit::Distance);
724 pub const ANGLE: ComplexUnit = ComplexUnit::new(SimpleUnit::Angle);
726 pub const SCALAR: ComplexUnit = ComplexUnit::new(SimpleUnit::Unitless);
728}
729
730pub mod ty {
732 use super::{parser::Type, ComplexUnit, SimpleUnit};
733
734 pub const DISTANCE: Type = Type::Number(Some(ComplexUnit::new(SimpleUnit::Distance)));
736 pub const POINT: Type = Type::Point;
738 pub const ANGLE: Type = Type::Number(Some(ComplexUnit::new(SimpleUnit::Angle)));
740 pub const LINE: Type = Type::Line;
742 pub const CIRCLE: Type = Type::Circle;
744 pub const SCALAR: Type = Type::Number(Some(ComplexUnit::new(SimpleUnit::Unitless)));
746 pub const SCALAR_UNKNOWN: Type = Type::Number(None);
748
749 #[must_use]
751 pub const fn collection(length: usize) -> Type {
752 Type::PointCollection(length)
753 }
754
755 #[must_use]
757 pub const fn derived(t: &'static str) -> Type {
758 Type::Derived(t)
759 }
760}
761
762impl ComplexUnit {
763 #[must_use]
765 pub const fn new(simple: SimpleUnit) -> Self {
766 let mut arr = [CompExponent::new_raw(0, 1); unit_count()];
767
768 match simple {
769 SimpleUnit::Unitless => (),
770 _ => arr[simple as usize] = CompExponent::new_raw(1, 1),
771 }
772
773 Self(arr)
774 }
775
776 #[must_use]
778 pub fn pow(mut self, exp: CompExponent) -> Self {
779 for v in &mut self.0 {
780 *v *= exp;
781 }
782
783 self
784 }
785}
786
787impl Display for ComplexUnit {
788 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
789 let mut s = String::new();
790
791 for i in 0..(SimpleUnit::Unitless as usize) {
792 if !self.0[i].is_zero() {
793 let name = match i {
794 0 => "Distance",
795 1 => "Point",
796 2 => "Angle",
797 3 => "Line",
798 _ => unreachable!(),
799 };
800
801 if self.0[i].is_one() {
802 s += name;
803 } else {
804 s += &format!("{name}^{}", self.0[i]);
805 };
806
807 s += " * ";
808 }
809 }
810
811 if s.is_empty() {
812 write!(f, "no unit")
813 } else {
814 write!(
815 f,
816 "{}",
817 String::from_utf8(s.as_bytes()[0..(s.len() - 3)].to_vec()).unwrap()
818 )
819 }
820 }
821}
822
823impl Mul<SimpleUnit> for ComplexUnit {
824 type Output = ComplexUnit;
825
826 fn mul(mut self, rhs: SimpleUnit) -> Self::Output {
827 match rhs {
828 SimpleUnit::Unitless => (),
829 #[allow(clippy::suspicious_arithmetic_impl)]
831 _ => self[rhs as usize] += 1,
832 }
833 self
834 }
835}
836
837impl Mul<&ComplexUnit> for ComplexUnit {
838 type Output = ComplexUnit;
839
840 fn mul(mut self, rhs: &Self) -> Self::Output {
841 self.iter_mut()
842 .enumerate()
843 .map(|(i, x)| *x += rhs[i])
844 .for_each(drop);
845 self
846 }
847}
848
849impl Div<SimpleUnit> for ComplexUnit {
850 type Output = ComplexUnit;
851
852 fn div(mut self, rhs: SimpleUnit) -> Self::Output {
853 match rhs {
854 SimpleUnit::Unitless => (),
855 #[allow(clippy::suspicious_arithmetic_impl)]
857 _ => self[rhs as usize] -= 1,
858 }
859 self
860 }
861}
862
863impl Div<&ComplexUnit> for ComplexUnit {
864 type Output = ComplexUnit;
865
866 fn div(mut self, rhs: &Self) -> Self::Output {
867 self.iter_mut()
868 .enumerate()
869 .map(|(i, x)| *x -= rhs[i])
870 .for_each(drop);
871 self
872 }
873}
874
875impl Deref for ComplexUnit {
876 type Target = [CompExponent; unit_count()];
877
878 fn deref(&self) -> &Self::Target {
879 &self.0
880 }
881}
882
883impl DerefMut for ComplexUnit {
884 fn deref_mut(&mut self) -> &mut Self::Target {
885 &mut self.0
886 }
887}