Fork of daniellemaywood.uk/gleam — Wasm codegen work
2

Configure Feed

Select the types of activity you want to include in your feed.

gleam / compiler-core / src / ast.rs
70 kB 2334 lines
1mod constant; 2mod typed; 3mod untyped; 4 5#[cfg(test)] 6mod tests; 7pub mod visit; 8 9pub use self::typed::TypedExpr; 10pub use self::untyped::{FunctionLiteralKind, UntypedExpr, Use}; 11 12pub use self::constant::{Constant, TypedConstant, UntypedConstant}; 13 14use crate::analyse::Inferred; 15use crate::build::{Located, Target}; 16use crate::parse::SpannedString; 17use crate::type_::expression::Implementations; 18use crate::type_::printer::Names; 19use crate::type_::{ 20 self, Deprecation, ModuleValueConstructor, PatternConstructor, Type, ValueConstructor, 21}; 22use std::sync::Arc; 23 24use ecow::EcoString; 25use num_bigint::BigInt; 26#[cfg(test)] 27use pretty_assertions::assert_eq; 28use vec1::Vec1; 29 30pub const TRY_VARIABLE: &str = "_try"; 31pub const PIPE_VARIABLE: &str = "_pipe"; 32pub const USE_ASSIGNMENT_VARIABLE: &str = "_use"; 33pub const ASSERT_FAIL_VARIABLE: &str = "_assert_fail"; 34pub const ASSERT_SUBJECT_VARIABLE: &str = "_assert_subject"; 35pub const CAPTURE_VARIABLE: &str = "_capture"; 36 37pub trait HasLocation { 38 fn location(&self) -> SrcSpan; 39} 40 41pub type TypedModule = Module<type_::ModuleInterface, TypedDefinition>; 42 43pub type UntypedModule = Module<(), TargetedDefinition>; 44 45#[derive(Debug, Clone, PartialEq, Eq)] 46pub struct Module<Info, Statements> { 47 pub name: EcoString, 48 pub documentation: Vec<EcoString>, 49 pub type_info: Info, 50 pub definitions: Vec<Statements>, 51 pub names: Names, 52} 53 54impl TypedModule { 55 pub fn find_node(&self, byte_index: u32) -> Option<Located<'_>> { 56 self.definitions 57 .iter() 58 .find_map(|statement| statement.find_node(byte_index)) 59 } 60} 61 62/// The `@target(erlang)` and `@target(javascript)` attributes can be used to 63/// mark a definition as only being for a specific target. 64/// 65/// ```gleam 66/// const x: Int = 1 67/// 68/// @target(erlang) 69/// pub fn main(a) { ...} 70/// ``` 71/// 72#[derive(Debug, Clone, PartialEq, Eq)] 73pub struct TargetedDefinition { 74 pub definition: UntypedDefinition, 75 pub target: Option<Target>, 76} 77 78impl TargetedDefinition { 79 pub fn is_for(&self, target: Target) -> bool { 80 self.target.map(|t| t == target).unwrap_or(true) 81 } 82} 83 84impl UntypedModule { 85 pub fn dependencies(&self, target: Target) -> Vec<(EcoString, SrcSpan)> { 86 self.iter_statements(target) 87 .flat_map(|s| match s { 88 Definition::Import(Import { 89 module, location, .. 90 }) => Some((module.clone(), *location)), 91 _ => None, 92 }) 93 .collect() 94 } 95 96 pub fn iter_statements(&self, target: Target) -> impl Iterator<Item = &UntypedDefinition> { 97 self.definitions 98 .iter() 99 .filter(move |def| def.is_for(target)) 100 .map(|def| &def.definition) 101 } 102 103 pub fn into_iter_statements(self, target: Target) -> impl Iterator<Item = UntypedDefinition> { 104 self.definitions 105 .into_iter() 106 .filter(move |def| def.is_for(target)) 107 .map(|def| def.definition) 108 } 109} 110 111#[test] 112fn module_dependencies_test() { 113 let parsed = crate::parse::parse_module( 114 camino::Utf8PathBuf::from("test/path"), 115 "import one 116 @target(erlang) 117 import two 118 119 @target(javascript) 120 import three 121 122 import four", 123 &crate::warning::WarningEmitter::null(), 124 ) 125 .expect("syntax error"); 126 let module = parsed.module; 127 128 assert_eq!( 129 vec![ 130 ("one".into(), SrcSpan::new(0, 10)), 131 ("two".into(), SrcSpan::new(45, 55)), 132 ("four".into(), SrcSpan::new(118, 129)), 133 ], 134 module.dependencies(Target::Erlang) 135 ); 136} 137 138pub type TypedArg = Arg<Arc<Type>>; 139pub type UntypedArg = Arg<()>; 140 141#[derive(Debug, Clone, PartialEq, Eq)] 142pub struct Arg<T> { 143 pub names: ArgNames, 144 pub location: SrcSpan, 145 pub annotation: Option<TypeAst>, 146 pub type_: T, 147} 148 149impl<A> Arg<A> { 150 pub fn set_type<B>(self, t: B) -> Arg<B> { 151 Arg { 152 type_: t, 153 names: self.names, 154 location: self.location, 155 annotation: self.annotation, 156 } 157 } 158 159 pub fn get_variable_name(&self) -> Option<&EcoString> { 160 self.names.get_variable_name() 161 } 162 163 pub fn is_capture_hole(&self) -> bool { 164 match &self.names { 165 ArgNames::Named { name, .. } if name == CAPTURE_VARIABLE => true, 166 _ => false, 167 } 168 } 169} 170 171impl TypedArg { 172 pub fn find_node(&self, byte_index: u32) -> Option<Located<'_>> { 173 if self.location.contains(byte_index) { 174 if let Some(annotation) = &self.annotation { 175 return annotation 176 .find_node(byte_index, self.type_.clone()) 177 .or(Some(Located::Arg(self))); 178 } 179 Some(Located::Arg(self)) 180 } else { 181 None 182 } 183 } 184} 185 186#[derive(Debug, Clone, PartialEq, Eq)] 187pub enum ArgNames { 188 Discard { 189 name: EcoString, 190 location: SrcSpan, 191 }, 192 LabelledDiscard { 193 label: EcoString, 194 label_location: SrcSpan, 195 name: EcoString, 196 name_location: SrcSpan, 197 }, 198 Named { 199 name: EcoString, 200 location: SrcSpan, 201 }, 202 NamedLabelled { 203 label: EcoString, 204 label_location: SrcSpan, 205 name: EcoString, 206 name_location: SrcSpan, 207 }, 208} 209 210impl ArgNames { 211 pub fn get_label(&self) -> Option<&EcoString> { 212 match self { 213 ArgNames::Discard { .. } | ArgNames::Named { .. } => None, 214 ArgNames::LabelledDiscard { label, .. } | ArgNames::NamedLabelled { label, .. } => { 215 Some(label) 216 } 217 } 218 } 219 pub fn get_variable_name(&self) -> Option<&EcoString> { 220 match self { 221 ArgNames::Discard { .. } | ArgNames::LabelledDiscard { .. } => None, 222 ArgNames::NamedLabelled { name, .. } | ArgNames::Named { name, .. } => Some(name), 223 } 224 } 225} 226 227pub type TypedRecordConstructor = RecordConstructor<Arc<Type>>; 228 229#[derive(Debug, Clone, PartialEq, Eq)] 230pub struct RecordConstructor<T> { 231 pub location: SrcSpan, 232 pub name_location: SrcSpan, 233 pub name: EcoString, 234 pub arguments: Vec<RecordConstructorArg<T>>, 235 pub documentation: Option<(u32, EcoString)>, 236} 237 238impl<A> RecordConstructor<A> { 239 pub fn put_doc(&mut self, new_doc: (u32, EcoString)) { 240 self.documentation = Some(new_doc); 241 } 242} 243 244pub type TypedRecordConstructorArg = RecordConstructorArg<Arc<Type>>; 245 246#[derive(Debug, Clone, PartialEq, Eq)] 247pub struct RecordConstructorArg<T> { 248 pub label: Option<SpannedString>, 249 pub ast: TypeAst, 250 pub location: SrcSpan, 251 pub type_: T, 252 pub doc: Option<(u32, EcoString)>, 253} 254 255impl<T: PartialEq> RecordConstructorArg<T> { 256 pub fn put_doc(&mut self, new_doc: (u32, EcoString)) { 257 self.doc = Some(new_doc); 258 } 259} 260 261#[derive(Debug, Clone, PartialEq, Eq)] 262pub struct TypeAstConstructor { 263 pub location: SrcSpan, 264 pub module: Option<(EcoString, SrcSpan)>, 265 pub name: EcoString, 266 pub arguments: Vec<TypeAst>, 267} 268 269#[derive(Debug, Clone, PartialEq, Eq)] 270pub struct TypeAstFn { 271 pub location: SrcSpan, 272 pub arguments: Vec<TypeAst>, 273 pub return_: Box<TypeAst>, 274} 275 276#[derive(Debug, Clone, PartialEq, Eq)] 277pub struct TypeAstVar { 278 pub location: SrcSpan, 279 pub name: EcoString, 280} 281 282#[derive(Debug, Clone, PartialEq, Eq)] 283pub struct TypeAstTuple { 284 pub location: SrcSpan, 285 pub elems: Vec<TypeAst>, 286} 287 288#[derive(Debug, Clone, PartialEq, Eq)] 289pub struct TypeAstHole { 290 pub location: SrcSpan, 291 pub name: EcoString, 292} 293 294#[derive(Debug, Clone, PartialEq, Eq)] 295pub enum TypeAst { 296 Constructor(TypeAstConstructor), 297 Fn(TypeAstFn), 298 Var(TypeAstVar), 299 Tuple(TypeAstTuple), 300 Hole(TypeAstHole), 301} 302 303impl TypeAst { 304 pub fn location(&self) -> SrcSpan { 305 match self { 306 TypeAst::Fn(TypeAstFn { location, .. }) 307 | TypeAst::Var(TypeAstVar { location, .. }) 308 | TypeAst::Hole(TypeAstHole { location, .. }) 309 | TypeAst::Tuple(TypeAstTuple { location, .. }) 310 | TypeAst::Constructor(TypeAstConstructor { location, .. }) => *location, 311 } 312 } 313 314 pub fn is_logically_equal(&self, other: &TypeAst) -> bool { 315 match self { 316 TypeAst::Constructor(TypeAstConstructor { 317 module, 318 name, 319 arguments, 320 location: _, 321 }) => match other { 322 TypeAst::Constructor(TypeAstConstructor { 323 module: o_module, 324 name: o_name, 325 arguments: o_arguments, 326 location: _, 327 }) => { 328 let module_name = 329 |m: &Option<(EcoString, _)>| m.as_ref().map(|(m, _)| m.clone()); 330 module_name(module) == module_name(o_module) 331 && name == o_name 332 && arguments.len() == o_arguments.len() 333 && arguments 334 .iter() 335 .zip(o_arguments) 336 .all(|a| a.0.is_logically_equal(a.1)) 337 } 338 _ => false, 339 }, 340 TypeAst::Fn(TypeAstFn { 341 arguments, 342 return_, 343 location: _, 344 }) => match other { 345 TypeAst::Fn(TypeAstFn { 346 arguments: o_arguments, 347 return_: o_return_, 348 location: _, 349 }) => { 350 arguments.len() == o_arguments.len() 351 && arguments 352 .iter() 353 .zip(o_arguments) 354 .all(|a| a.0.is_logically_equal(a.1)) 355 && return_.is_logically_equal(o_return_) 356 } 357 _ => false, 358 }, 359 TypeAst::Var(TypeAstVar { name, location: _ }) => match other { 360 TypeAst::Var(TypeAstVar { 361 name: o_name, 362 location: _, 363 }) => name == o_name, 364 _ => false, 365 }, 366 TypeAst::Tuple(TypeAstTuple { elems, location: _ }) => match other { 367 TypeAst::Tuple(TypeAstTuple { 368 elems: o_elems, 369 location: _, 370 }) => { 371 elems.len() == o_elems.len() 372 && elems 373 .iter() 374 .zip(o_elems) 375 .all(|a| a.0.is_logically_equal(a.1)) 376 } 377 _ => false, 378 }, 379 TypeAst::Hole(TypeAstHole { name, location: _ }) => match other { 380 TypeAst::Hole(TypeAstHole { 381 name: o_name, 382 location: _, 383 }) => name == o_name, 384 _ => false, 385 }, 386 } 387 } 388 389 pub fn find_node(&self, byte_index: u32, type_: Arc<Type>) -> Option<Located<'_>> { 390 if !self.location().contains(byte_index) { 391 return None; 392 } 393 394 match self { 395 TypeAst::Fn(TypeAstFn { 396 arguments, return_, .. 397 }) => type_ 398 .fn_types() 399 .and_then(|(arg_types, ret_type)| { 400 if let Some(arg) = arguments 401 .iter() 402 .zip(arg_types) 403 .find_map(|(arg, arg_type)| arg.find_node(byte_index, arg_type.clone())) 404 { 405 return Some(arg); 406 } 407 if let Some(ret) = return_.find_node(byte_index, ret_type) { 408 return Some(ret); 409 } 410 411 None 412 }) 413 .or(Some(Located::Annotation(self.location(), type_))), 414 TypeAst::Constructor(TypeAstConstructor { arguments, .. }) => type_ 415 .constructor_types() 416 .and_then(|arg_types| { 417 if let Some(arg) = arguments 418 .iter() 419 .zip(arg_types) 420 .find_map(|(arg, arg_type)| arg.find_node(byte_index, arg_type.clone())) 421 { 422 return Some(arg); 423 } 424 425 None 426 }) 427 .or(Some(Located::Annotation(self.location(), type_))), 428 TypeAst::Tuple(TypeAstTuple { elems, .. }) => type_ 429 .tuple_types() 430 .and_then(|elem_types| { 431 if let Some(e) = elems 432 .iter() 433 .zip(elem_types) 434 .find_map(|(e, e_type)| e.find_node(byte_index, e_type.clone())) 435 { 436 return Some(e); 437 } 438 439 None 440 }) 441 .or(Some(Located::Annotation(self.location(), type_))), 442 TypeAst::Var(_) | TypeAst::Hole(_) => Some(Located::Annotation(self.location(), type_)), 443 } 444 } 445 446 /// Generates an annotation corresponding to the type. 447 pub fn print(&self, buffer: &mut EcoString) { 448 match &self { 449 TypeAst::Var(var) => buffer.push_str(&var.name), 450 TypeAst::Hole(hole) => buffer.push_str(&hole.name), 451 TypeAst::Tuple(tuple) => { 452 buffer.push_str("#("); 453 for (i, elem) in tuple.elems.iter().enumerate() { 454 elem.print(buffer); 455 if i < tuple.elems.len() - 1 { 456 buffer.push_str(", "); 457 } 458 } 459 buffer.push(')') 460 } 461 TypeAst::Fn(func) => { 462 buffer.push_str("fn("); 463 for (i, argument) in func.arguments.iter().enumerate() { 464 argument.print(buffer); 465 if i < func.arguments.len() - 1 { 466 buffer.push_str(", "); 467 } 468 } 469 buffer.push(')'); 470 buffer.push_str(" -> "); 471 func.return_.print(buffer); 472 } 473 TypeAst::Constructor(constructor) => { 474 if let Some((module, _)) = &constructor.module { 475 buffer.push_str(module); 476 buffer.push('.'); 477 } 478 buffer.push_str(&constructor.name); 479 if !constructor.arguments.is_empty() { 480 buffer.push('('); 481 for (i, argument) in constructor.arguments.iter().enumerate() { 482 argument.print(buffer); 483 if i < constructor.arguments.len() - 1 { 484 buffer.push_str(", "); 485 } 486 } 487 buffer.push(')'); 488 } 489 } 490 } 491 } 492} 493 494#[test] 495fn type_ast_print_fn() { 496 let mut buffer = EcoString::new(); 497 let ast = TypeAst::Fn(TypeAstFn { 498 location: SrcSpan { start: 1, end: 1 }, 499 arguments: vec![ 500 TypeAst::Var(TypeAstVar { 501 location: SrcSpan { start: 1, end: 1 }, 502 name: "String".into(), 503 }), 504 TypeAst::Var(TypeAstVar { 505 location: SrcSpan { start: 1, end: 1 }, 506 name: "Bool".into(), 507 }), 508 ], 509 return_: Box::new(TypeAst::Var(TypeAstVar { 510 location: SrcSpan { start: 1, end: 1 }, 511 name: "Int".into(), 512 })), 513 }); 514 ast.print(&mut buffer); 515 assert_eq!(&buffer, "fn(String, Bool) -> Int") 516} 517 518#[test] 519fn type_ast_print_constructor() { 520 let mut buffer = EcoString::new(); 521 let ast = TypeAst::Constructor(TypeAstConstructor { 522 name: "SomeType".into(), 523 module: Some(("some_module".into(), SrcSpan { start: 1, end: 1 })), 524 location: SrcSpan { start: 1, end: 1 }, 525 arguments: vec![ 526 TypeAst::Var(TypeAstVar { 527 location: SrcSpan { start: 1, end: 1 }, 528 name: "String".into(), 529 }), 530 TypeAst::Var(TypeAstVar { 531 location: SrcSpan { start: 1, end: 1 }, 532 name: "Bool".into(), 533 }), 534 ], 535 }); 536 ast.print(&mut buffer); 537 assert_eq!(&buffer, "some_module.SomeType(String, Bool)") 538} 539 540#[test] 541fn type_ast_print_tuple() { 542 let mut buffer = EcoString::new(); 543 let ast = TypeAst::Tuple(TypeAstTuple { 544 location: SrcSpan { start: 1, end: 1 }, 545 elems: vec![ 546 TypeAst::Constructor(TypeAstConstructor { 547 name: "SomeType".into(), 548 module: Some(("some_module".into(), SrcSpan { start: 1, end: 1 })), 549 location: SrcSpan { start: 1, end: 1 }, 550 arguments: vec![ 551 TypeAst::Var(TypeAstVar { 552 location: SrcSpan { start: 1, end: 1 }, 553 name: "String".into(), 554 }), 555 TypeAst::Var(TypeAstVar { 556 location: SrcSpan { start: 1, end: 1 }, 557 name: "Bool".into(), 558 }), 559 ], 560 }), 561 TypeAst::Fn(TypeAstFn { 562 location: SrcSpan { start: 1, end: 1 }, 563 arguments: vec![ 564 TypeAst::Var(TypeAstVar { 565 location: SrcSpan { start: 1, end: 1 }, 566 name: "String".into(), 567 }), 568 TypeAst::Var(TypeAstVar { 569 location: SrcSpan { start: 1, end: 1 }, 570 name: "Bool".into(), 571 }), 572 ], 573 return_: Box::new(TypeAst::Var(TypeAstVar { 574 location: SrcSpan { start: 1, end: 1 }, 575 name: "Int".into(), 576 })), 577 }), 578 ], 579 }); 580 ast.print(&mut buffer); 581 assert_eq!( 582 &buffer, 583 "#(some_module.SomeType(String, Bool), fn(String, Bool) -> Int)" 584 ) 585} 586 587#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)] 588pub enum Publicity { 589 Public, 590 Private, 591 Internal { attribute_location: Option<SrcSpan> }, 592} 593 594impl Publicity { 595 pub fn is_private(&self) -> bool { 596 match self { 597 Self::Private => true, 598 Self::Public | Self::Internal { .. } => false, 599 } 600 } 601 602 pub fn is_internal(&self) -> bool { 603 match self { 604 Self::Internal { .. } => true, 605 Self::Public | Self::Private => false, 606 } 607 } 608 609 pub fn is_public(&self) -> bool { 610 match self { 611 Self::Public => true, 612 Self::Internal { .. } | Self::Private => false, 613 } 614 } 615 616 pub fn is_importable(&self) -> bool { 617 match self { 618 Self::Internal { .. } | Self::Public => true, 619 Self::Private => false, 620 } 621 } 622} 623 624#[derive(Debug, Clone, PartialEq, Eq)] 625/// A function definition 626/// 627/// Note that an anonymous function will have `None` as the name field, while a 628/// named function will have `Some`. 629/// 630/// # Example(s) 631/// 632/// ```gleam 633/// // Public function 634/// pub fn wobble() -> String { ... } 635/// // Private function 636/// fn wibble(x: Int) -> Int { ... } 637/// // Anonymous function 638/// fn(x: Int) { ... } 639/// ``` 640pub struct Function<T, Expr> { 641 pub location: SrcSpan, 642 pub end_position: u32, 643 pub name: Option<SpannedString>, 644 pub arguments: Vec<Arg<T>>, 645 pub body: Vec1<Statement<T, Expr>>, 646 pub publicity: Publicity, 647 pub deprecation: Deprecation, 648 pub return_annotation: Option<TypeAst>, 649 pub return_type: T, 650 pub documentation: Option<(u32, EcoString)>, 651 pub external_erlang: Option<(EcoString, EcoString, SrcSpan)>, 652 pub external_javascript: Option<(EcoString, EcoString, SrcSpan)>, 653 pub implementations: Implementations, 654} 655 656pub type TypedFunction = Function<Arc<Type>, TypedExpr>; 657pub type UntypedFunction = Function<(), UntypedExpr>; 658 659impl<T, E> Function<T, E> { 660 pub fn full_location(&self) -> SrcSpan { 661 SrcSpan::new(self.location.start, self.end_position) 662 } 663} 664 665pub type UntypedImport = Import<()>; 666 667#[derive(Debug, Clone, PartialEq, Eq)] 668/// Import another Gleam module so the current module can use the types and 669/// values it defines. 670/// 671/// # Example(s) 672/// 673/// ```gleam 674/// import unix/cat 675/// // Import with alias 676/// import animal/cat as kitty 677/// ``` 678pub struct Import<PackageName> { 679 pub documentation: Option<EcoString>, 680 pub location: SrcSpan, 681 pub module: EcoString, 682 pub as_name: Option<(AssignName, SrcSpan)>, 683 pub unqualified_values: Vec<UnqualifiedImport>, 684 pub unqualified_types: Vec<UnqualifiedImport>, 685 pub package: PackageName, 686} 687 688impl<T> Import<T> { 689 pub(crate) fn used_name(&self) -> Option<EcoString> { 690 match self.as_name.as_ref() { 691 Some((AssignName::Variable(name), _)) => Some(name.clone()), 692 Some((AssignName::Discard(_), _)) => None, 693 None => self.module.split('/').last().map(EcoString::from), 694 } 695 } 696 697 pub(crate) fn alias_location(&self) -> Option<SrcSpan> { 698 self.as_name.as_ref().map(|(_, location)| *location) 699 } 700} 701 702pub type UntypedModuleConstant = ModuleConstant<(), ()>; 703pub type TypedModuleConstant = ModuleConstant<Arc<Type>, EcoString>; 704 705#[derive(Debug, Clone, PartialEq, Eq)] 706/// A certain fixed value that can be used in multiple places 707/// 708/// # Example(s) 709/// 710/// ```gleam 711/// pub const start_year = 2101 712/// pub const end_year = 2111 713/// ``` 714pub struct ModuleConstant<T, ConstantRecordTag> { 715 pub documentation: Option<(u32, EcoString)>, 716 /// The location of the constant, starting at the "(pub) const" keywords and 717 /// ending after the ": Type" annotation, or (without an annotation) after its name. 718 pub location: SrcSpan, 719 pub publicity: Publicity, 720 pub name: EcoString, 721 pub name_location: SrcSpan, 722 pub annotation: Option<TypeAst>, 723 pub value: Box<Constant<T, ConstantRecordTag>>, 724 pub type_: T, 725 pub deprecation: Deprecation, 726 pub implementations: Implementations, 727} 728 729pub type UntypedCustomType = CustomType<()>; 730 731#[derive(Debug, Clone, PartialEq, Eq)] 732/// A newly defined type with one or more constructors. 733/// Each variant of the custom type can contain different types, so the type is 734/// the product of the types contained by each variant. 735/// 736/// This might be called an algebraic data type (ADT) or tagged union in other 737/// languages and type systems. 738/// 739/// 740/// # Example(s) 741/// 742/// ```gleam 743/// pub type Cat { 744/// Cat(name: String, cuteness: Int) 745/// } 746/// ``` 747pub struct CustomType<T> { 748 pub location: SrcSpan, 749 pub end_position: u32, 750 pub name: EcoString, 751 pub name_location: SrcSpan, 752 pub publicity: Publicity, 753 pub constructors: Vec<RecordConstructor<T>>, 754 pub documentation: Option<(u32, EcoString)>, 755 pub deprecation: Deprecation, 756 pub opaque: bool, 757 /// The names of the type parameters. 758 pub parameters: Vec<SpannedString>, 759 /// Once type checked this field will contain the type information for the 760 /// type parameters. 761 pub typed_parameters: Vec<T>, 762} 763 764impl<T> CustomType<T> { 765 /// The `location` field of a `CustomType` is only the location of `pub type 766 /// TheName`. This method returns a `SrcSpan` that includes the entire type 767 /// definition. 768 pub fn full_location(&self) -> SrcSpan { 769 SrcSpan::new(self.location.start, self.end_position) 770 } 771} 772 773pub type UntypedTypeAlias = TypeAlias<()>; 774 775#[derive(Debug, Clone, PartialEq, Eq)] 776/// A new name for an existing type 777/// 778/// # Example(s) 779/// 780/// ```gleam 781/// pub type Headers = 782/// List(#(String, String)) 783/// ``` 784pub struct TypeAlias<T> { 785 pub location: SrcSpan, 786 pub alias: EcoString, 787 pub name_location: SrcSpan, 788 pub parameters: Vec<SpannedString>, 789 pub type_ast: TypeAst, 790 pub type_: T, 791 pub publicity: Publicity, 792 pub documentation: Option<(u32, EcoString)>, 793 pub deprecation: Deprecation, 794} 795 796pub type TypedDefinition = Definition<Arc<Type>, TypedExpr, EcoString, EcoString>; 797pub type UntypedDefinition = Definition<(), UntypedExpr, (), ()>; 798 799#[derive(Debug, Clone, PartialEq, Eq)] 800pub enum Definition<T, Expr, ConstantRecordTag, PackageName> { 801 Function(Function<T, Expr>), 802 803 TypeAlias(TypeAlias<T>), 804 805 CustomType(CustomType<T>), 806 807 Import(Import<PackageName>), 808 809 ModuleConstant(ModuleConstant<T, ConstantRecordTag>), 810} 811 812impl TypedDefinition { 813 pub fn main_function(&self) -> Option<&TypedFunction> { 814 match self { 815 Definition::Function(f) if f.name.as_ref().is_some_and(|(_, name)| name == "main") => { 816 Some(f) 817 } 818 _ => None, 819 } 820 } 821 822 pub fn find_node(&self, byte_index: u32) -> Option<Located<'_>> { 823 match self { 824 Definition::Function(function) => { 825 // Search for the corresponding node inside the function 826 // only if the index falls within the function's full location. 827 if !function.full_location().contains(byte_index) { 828 return None; 829 } 830 831 if let Some(found) = function.body.iter().find_map(|s| s.find_node(byte_index)) { 832 return Some(found); 833 } 834 835 if let Some(found_arg) = function 836 .arguments 837 .iter() 838 .find_map(|arg| arg.find_node(byte_index)) 839 { 840 return Some(found_arg); 841 }; 842 843 if let Some(found_statement) = function 844 .body 845 .iter() 846 .find(|statement| statement.location().contains(byte_index)) 847 { 848 return Some(Located::Statement(found_statement)); 849 }; 850 851 // Check if location is within the return annotation. 852 if let Some(l) = function 853 .return_annotation 854 .iter() 855 .find_map(|a| a.find_node(byte_index, function.return_type.clone())) 856 { 857 return Some(l); 858 }; 859 860 // Note that the fn `.location` covers the function head, not 861 // the entire statement. 862 if function.location.contains(byte_index) { 863 Some(Located::ModuleStatement(self)) 864 } else if function.full_location().contains(byte_index) { 865 Some(Located::FunctionBody(function)) 866 } else { 867 None 868 } 869 } 870 871 Definition::CustomType(custom) => { 872 // Check if location is within the type of one of the arguments of a constructor. 873 if let Some(annotation) = custom 874 .constructors 875 .iter() 876 .find(|constructor| constructor.location.contains(byte_index)) 877 .and_then(|constructor| { 878 constructor 879 .arguments 880 .iter() 881 .find(|arg| arg.location.contains(byte_index)) 882 }) 883 .filter(|arg| arg.location.contains(byte_index)) 884 .and_then(|arg| arg.ast.find_node(byte_index, arg.type_.clone())) 885 { 886 return Some(annotation); 887 } 888 889 // Note that the custom type `.location` covers the function 890 // head, not the entire statement. 891 if custom.full_location().contains(byte_index) { 892 Some(Located::ModuleStatement(self)) 893 } else { 894 None 895 } 896 } 897 898 Definition::TypeAlias(alias) => { 899 // Check if location is within the type being aliased. 900 if let Some(l) = alias.type_ast.find_node(byte_index, alias.type_.clone()) { 901 return Some(l); 902 } 903 904 if alias.location.contains(byte_index) { 905 Some(Located::ModuleStatement(self)) 906 } else { 907 None 908 } 909 } 910 911 Definition::ModuleConstant(constant) => { 912 // Check if location is within the annotation. 913 if let Some(annotation) = &constant.annotation { 914 if let Some(l) = annotation.find_node(byte_index, constant.type_.clone()) { 915 return Some(l); 916 } 917 } 918 919 if constant.location.contains(byte_index) { 920 Some(Located::ModuleStatement(self)) 921 } else { 922 None 923 } 924 } 925 926 Definition::Import(import) => { 927 if self.location().contains(byte_index) { 928 if let Some(unqualified) = import 929 .unqualified_values 930 .iter() 931 .find(|i| i.location.contains(byte_index)) 932 { 933 return Some(Located::UnqualifiedImport( 934 crate::build::UnqualifiedImport { 935 name: &unqualified.name, 936 module: &import.module, 937 is_type: false, 938 location: &unqualified.location, 939 }, 940 )); 941 } 942 943 if let Some(unqualified) = import 944 .unqualified_types 945 .iter() 946 .find(|i| i.location.contains(byte_index)) 947 { 948 return Some(Located::UnqualifiedImport( 949 crate::build::UnqualifiedImport { 950 name: &unqualified.name, 951 module: &import.module, 952 is_type: true, 953 location: &unqualified.location, 954 }, 955 )); 956 } 957 958 Some(Located::ModuleStatement(self)) 959 } else { 960 None 961 } 962 } 963 } 964 } 965} 966 967impl<A, B, C, E> Definition<A, B, C, E> { 968 pub fn location(&self) -> SrcSpan { 969 match self { 970 Definition::Function(Function { location, .. }) 971 | Definition::Import(Import { location, .. }) 972 | Definition::TypeAlias(TypeAlias { location, .. }) 973 | Definition::CustomType(CustomType { location, .. }) 974 | Definition::ModuleConstant(ModuleConstant { location, .. }) => *location, 975 } 976 } 977 978 /// Returns `true` if the definition is [`Import`]. 979 /// 980 /// [`Import`]: Definition::Import 981 #[must_use] 982 pub fn is_import(&self) -> bool { 983 matches!(self, Self::Import(..)) 984 } 985 986 /// Returns `true` if the module statement is [`Function`]. 987 /// 988 /// [`Function`]: ModuleStatement::Function 989 #[must_use] 990 pub fn is_function(&self) -> bool { 991 matches!(self, Self::Function(..)) 992 } 993 994 pub fn put_doc(&mut self, new_doc: (u32, EcoString)) { 995 match self { 996 Definition::Import(Import { .. }) => (), 997 998 Definition::Function(Function { documentation, .. }) 999 | Definition::TypeAlias(TypeAlias { documentation, .. }) 1000 | Definition::CustomType(CustomType { documentation, .. }) 1001 | Definition::ModuleConstant(ModuleConstant { documentation, .. }) => { 1002 let _ = std::mem::replace(documentation, Some(new_doc)); 1003 } 1004 } 1005 } 1006 1007 pub fn get_doc(&self) -> Option<EcoString> { 1008 match self { 1009 Definition::Import(Import { .. }) => None, 1010 1011 Definition::Function(Function { 1012 documentation: doc, .. 1013 }) 1014 | Definition::TypeAlias(TypeAlias { 1015 documentation: doc, .. 1016 }) 1017 | Definition::CustomType(CustomType { 1018 documentation: doc, .. 1019 }) 1020 | Definition::ModuleConstant(ModuleConstant { 1021 documentation: doc, .. 1022 }) => doc.as_ref().map(|(_, doc)| doc.clone()), 1023 } 1024 } 1025 1026 pub fn is_internal(&self) -> bool { 1027 match self { 1028 Definition::Function(Function { publicity, .. }) 1029 | Definition::CustomType(CustomType { publicity, .. }) 1030 | Definition::ModuleConstant(ModuleConstant { publicity, .. }) 1031 | Definition::TypeAlias(TypeAlias { publicity, .. }) => publicity.is_internal(), 1032 1033 Definition::Import(_) => false, 1034 } 1035 } 1036} 1037 1038#[derive(Debug, Clone, PartialEq, Eq)] 1039pub struct UnqualifiedImport { 1040 pub location: SrcSpan, 1041 pub name: EcoString, 1042 pub as_name: Option<EcoString>, 1043} 1044 1045impl UnqualifiedImport { 1046 pub fn used_name(&self) -> &EcoString { 1047 self.as_name.as_ref().unwrap_or(&self.name) 1048 } 1049} 1050 1051#[derive(Debug, Clone, PartialEq, Eq, Copy, Default, serde::Serialize, serde::Deserialize)] 1052pub enum Layer { 1053 #[default] 1054 Value, 1055 Type, 1056} 1057 1058impl Layer { 1059 /// Returns `true` if the layer is [`Value`]. 1060 pub fn is_value(&self) -> bool { 1061 matches!(self, Self::Value) 1062 } 1063} 1064 1065#[derive(Debug, Clone, Copy, PartialEq, Eq)] 1066pub enum BinOp { 1067 // Boolean logic 1068 And, 1069 Or, 1070 1071 // Equality 1072 Eq, 1073 NotEq, 1074 1075 // Order comparison 1076 LtInt, 1077 LtEqInt, 1078 LtFloat, 1079 LtEqFloat, 1080 GtEqInt, 1081 GtInt, 1082 GtEqFloat, 1083 GtFloat, 1084 1085 // Maths 1086 AddInt, 1087 AddFloat, 1088 SubInt, 1089 SubFloat, 1090 MultInt, 1091 MultFloat, 1092 DivInt, 1093 DivFloat, 1094 RemainderInt, 1095 1096 // Strings 1097 Concatenate, 1098} 1099 1100#[derive(Clone, Copy, Debug, PartialEq)] 1101pub enum OperatorKind { 1102 BooleanLogic, 1103 Equality, 1104 IntComparison, 1105 FLoatComparison, 1106 IntMath, 1107 FloatMath, 1108 StringConcatenation, 1109} 1110 1111impl BinOp { 1112 pub fn precedence(&self) -> u8 { 1113 // Ensure that this matches the other precedence function for guards 1114 match self { 1115 Self::Or => 1, 1116 1117 Self::And => 2, 1118 1119 Self::Eq | Self::NotEq => 3, 1120 1121 Self::LtInt 1122 | Self::LtEqInt 1123 | Self::LtFloat 1124 | Self::LtEqFloat 1125 | Self::GtEqInt 1126 | Self::GtInt 1127 | Self::GtEqFloat 1128 | Self::GtFloat => 4, 1129 1130 Self::Concatenate => 5, 1131 1132 // Pipe is 6 1133 Self::AddInt | Self::AddFloat | Self::SubInt | Self::SubFloat => 7, 1134 1135 Self::MultInt 1136 | Self::MultFloat 1137 | Self::DivInt 1138 | Self::DivFloat 1139 | Self::RemainderInt => 8, 1140 } 1141 } 1142 1143 pub fn name(&self) -> &'static str { 1144 match self { 1145 Self::And => "&&", 1146 Self::Or => "||", 1147 Self::LtInt => "<", 1148 Self::LtEqInt => "<=", 1149 Self::LtFloat => "<.", 1150 Self::LtEqFloat => "<=.", 1151 Self::Eq => "==", 1152 Self::NotEq => "!=", 1153 Self::GtEqInt => ">=", 1154 Self::GtInt => ">", 1155 Self::GtEqFloat => ">=.", 1156 Self::GtFloat => ">.", 1157 Self::AddInt => "+", 1158 Self::AddFloat => "+.", 1159 Self::SubInt => "-", 1160 Self::SubFloat => "-.", 1161 Self::MultInt => "*", 1162 Self::MultFloat => "*.", 1163 Self::DivInt => "/", 1164 Self::DivFloat => "/.", 1165 Self::RemainderInt => "%", 1166 Self::Concatenate => "<>", 1167 } 1168 } 1169 1170 pub fn operator_kind(&self) -> OperatorKind { 1171 match self { 1172 Self::Concatenate => OperatorKind::StringConcatenation, 1173 Self::Eq | Self::NotEq => OperatorKind::Equality, 1174 Self::And | Self::Or => OperatorKind::BooleanLogic, 1175 Self::LtInt | Self::LtEqInt | Self::GtEqInt | Self::GtInt => { 1176 OperatorKind::IntComparison 1177 } 1178 Self::LtFloat | Self::LtEqFloat | Self::GtEqFloat | Self::GtFloat => { 1179 OperatorKind::FLoatComparison 1180 } 1181 Self::AddInt | Self::SubInt | Self::MultInt | Self::RemainderInt | Self::DivInt => { 1182 OperatorKind::IntMath 1183 } 1184 Self::AddFloat | Self::SubFloat | Self::MultFloat | Self::DivFloat => { 1185 OperatorKind::FloatMath 1186 } 1187 } 1188 } 1189 1190 pub fn can_be_grouped_with(&self, other: &BinOp) -> bool { 1191 self.operator_kind() == other.operator_kind() 1192 } 1193} 1194 1195#[derive(Debug, PartialEq, Eq, Clone)] 1196pub struct CallArg<A> { 1197 pub label: Option<EcoString>, 1198 pub location: SrcSpan, 1199 pub value: A, 1200 pub implicit: Option<ImplicitCallArgOrigin>, 1201} 1202 1203#[derive(Debug, PartialEq, Eq, Clone, Copy)] 1204pub enum ImplicitCallArgOrigin { 1205 /// The implicit callback argument passed as the last argument to the 1206 /// function on the right hand side of `use`. 1207 /// 1208 Use, 1209 /// An argument added by the compiler when rewriting a pipe `left |> right`. 1210 /// 1211 Pipe, 1212 /// An argument added by the compiler to fill in all the missing fields of a 1213 /// record that are being ignored with the `..` syntax. 1214 /// 1215 PatternFieldSpread, 1216 /// An argument used to fill in the missing args when a function on the 1217 /// right hand side of `use` is being called with the wrong arity. 1218 /// 1219 IncorrectArityUse, 1220} 1221 1222impl<A> CallArg<A> { 1223 #[must_use] 1224 pub fn is_implicit(&self) -> bool { 1225 self.implicit.is_some() 1226 } 1227} 1228 1229impl CallArg<TypedExpr> { 1230 pub fn find_node(&self, byte_index: u32) -> Option<Located<'_>> { 1231 match (self.implicit, &self.value) { 1232 // If a call argument is the implicit use callback then we don't 1233 // want to look at its arguments and body but we don't want to 1234 // return the whole anonymous function if anything else doesn't 1235 // match. 1236 // 1237 // In addition, if the callback is invalid because it couldn't be 1238 // typed, we don't want to return it as it would make it hard for 1239 // the LSP to give any suggestions on the use function being typed. 1240 // 1241 (Some(ImplicitCallArgOrigin::Use), TypedExpr::Invalid { .. }) => None, 1242 // So the code below is exactly the same as 1243 // `TypedExpr::Fn{}.find_node()` except we do not return self as a 1244 // fallback. 1245 // 1246 (Some(ImplicitCallArgOrigin::Use), TypedExpr::Fn { args, body, .. }) => args 1247 .iter() 1248 .find_map(|arg| arg.find_node(byte_index)) 1249 .or_else(|| body.iter().find_map(|s| s.find_node(byte_index))), 1250 // In all other cases we're happy with the default behaviour. 1251 // 1252 _ => self.value.find_node(byte_index), 1253 } 1254 } 1255} 1256 1257impl CallArg<TypedPattern> { 1258 pub fn find_node(&self, byte_index: u32) -> Option<Located<'_>> { 1259 self.value.find_node(byte_index) 1260 } 1261} 1262 1263impl CallArg<UntypedExpr> { 1264 pub fn is_capture_hole(&self) -> bool { 1265 match &self.value { 1266 UntypedExpr::Var { ref name, .. } => name == CAPTURE_VARIABLE, 1267 _ => false, 1268 } 1269 } 1270} 1271 1272impl<T> CallArg<T> 1273where 1274 T: HasLocation, 1275{ 1276 #[must_use] 1277 pub fn uses_label_shorthand(&self) -> bool { 1278 self.label.is_some() && self.location == self.value.location() 1279 } 1280} 1281 1282impl<T> HasLocation for CallArg<T> { 1283 fn location(&self) -> SrcSpan { 1284 self.location 1285 } 1286} 1287 1288#[derive(Debug, Clone, PartialEq, Eq)] 1289pub struct RecordBeingUpdated { 1290 pub base: Box<UntypedExpr>, 1291 pub location: SrcSpan, 1292} 1293 1294#[derive(Debug, Clone, PartialEq, Eq)] 1295pub struct UntypedRecordUpdateArg { 1296 pub label: EcoString, 1297 pub location: SrcSpan, 1298 pub value: UntypedExpr, 1299} 1300 1301impl UntypedRecordUpdateArg { 1302 #[must_use] 1303 pub fn uses_label_shorthand(&self) -> bool { 1304 self.value.location() == self.location 1305 } 1306} 1307 1308#[derive(Debug, Clone, PartialEq, Eq)] 1309pub struct TypedRecordUpdateArg { 1310 pub label: EcoString, 1311 pub location: SrcSpan, 1312 pub value: TypedExpr, 1313 pub index: u32, 1314} 1315 1316impl TypedRecordUpdateArg { 1317 pub fn find_node(&self, byte_index: u32) -> Option<Located<'_>> { 1318 self.value.find_node(byte_index) 1319 } 1320 1321 #[must_use] 1322 pub fn uses_label_shorthand(&self) -> bool { 1323 self.value.location() == self.location 1324 } 1325} 1326 1327pub type MultiPattern<Type> = Vec<Pattern<Type>>; 1328 1329pub type UntypedMultiPattern = MultiPattern<()>; 1330pub type TypedMultiPattern = MultiPattern<Arc<Type>>; 1331 1332pub type TypedClause = Clause<TypedExpr, Arc<Type>, EcoString>; 1333 1334pub type UntypedClause = Clause<UntypedExpr, (), ()>; 1335 1336#[derive(Debug, Clone, PartialEq, Eq)] 1337pub struct Clause<Expr, Type, RecordTag> { 1338 pub location: SrcSpan, 1339 pub pattern: MultiPattern<Type>, 1340 pub alternative_patterns: Vec<MultiPattern<Type>>, 1341 pub guard: Option<ClauseGuard<Type, RecordTag>>, 1342 pub then: Expr, 1343} 1344 1345impl<A, B, C> Clause<A, B, C> { 1346 pub fn pattern_count(&self) -> usize { 1347 1 + self.alternative_patterns.len() 1348 } 1349} 1350 1351impl TypedClause { 1352 pub fn location(&self) -> SrcSpan { 1353 SrcSpan { 1354 start: self 1355 .pattern 1356 .first() 1357 .map(|p| p.location().start) 1358 .unwrap_or_default(), 1359 end: self.then.location().end, 1360 } 1361 } 1362 1363 pub fn find_node(&self, byte_index: u32) -> Option<Located<'_>> { 1364 self.pattern 1365 .iter() 1366 .find_map(|p| p.find_node(byte_index)) 1367 .or_else(|| self.then.find_node(byte_index)) 1368 } 1369} 1370 1371pub type UntypedClauseGuard = ClauseGuard<(), ()>; 1372pub type TypedClauseGuard = ClauseGuard<Arc<Type>, EcoString>; 1373 1374#[derive(Debug, Clone, PartialEq, Eq)] 1375pub enum ClauseGuard<Type, RecordTag> { 1376 Equals { 1377 location: SrcSpan, 1378 left: Box<Self>, 1379 right: Box<Self>, 1380 }, 1381 1382 NotEquals { 1383 location: SrcSpan, 1384 left: Box<Self>, 1385 right: Box<Self>, 1386 }, 1387 1388 GtInt { 1389 location: SrcSpan, 1390 left: Box<Self>, 1391 right: Box<Self>, 1392 }, 1393 1394 GtEqInt { 1395 location: SrcSpan, 1396 left: Box<Self>, 1397 right: Box<Self>, 1398 }, 1399 1400 LtInt { 1401 location: SrcSpan, 1402 left: Box<Self>, 1403 right: Box<Self>, 1404 }, 1405 1406 LtEqInt { 1407 location: SrcSpan, 1408 left: Box<Self>, 1409 right: Box<Self>, 1410 }, 1411 1412 GtFloat { 1413 location: SrcSpan, 1414 left: Box<Self>, 1415 right: Box<Self>, 1416 }, 1417 1418 GtEqFloat { 1419 location: SrcSpan, 1420 left: Box<Self>, 1421 right: Box<Self>, 1422 }, 1423 1424 LtFloat { 1425 location: SrcSpan, 1426 left: Box<Self>, 1427 right: Box<Self>, 1428 }, 1429 1430 LtEqFloat { 1431 location: SrcSpan, 1432 left: Box<Self>, 1433 right: Box<Self>, 1434 }, 1435 1436 AddInt { 1437 location: SrcSpan, 1438 left: Box<Self>, 1439 right: Box<Self>, 1440 }, 1441 1442 AddFloat { 1443 location: SrcSpan, 1444 left: Box<Self>, 1445 right: Box<Self>, 1446 }, 1447 1448 SubInt { 1449 location: SrcSpan, 1450 left: Box<Self>, 1451 right: Box<Self>, 1452 }, 1453 1454 SubFloat { 1455 location: SrcSpan, 1456 left: Box<Self>, 1457 right: Box<Self>, 1458 }, 1459 1460 MultInt { 1461 location: SrcSpan, 1462 left: Box<Self>, 1463 right: Box<Self>, 1464 }, 1465 1466 MultFloat { 1467 location: SrcSpan, 1468 left: Box<Self>, 1469 right: Box<Self>, 1470 }, 1471 1472 DivInt { 1473 location: SrcSpan, 1474 left: Box<Self>, 1475 right: Box<Self>, 1476 }, 1477 1478 DivFloat { 1479 location: SrcSpan, 1480 left: Box<Self>, 1481 right: Box<Self>, 1482 }, 1483 1484 RemainderInt { 1485 location: SrcSpan, 1486 left: Box<Self>, 1487 right: Box<Self>, 1488 }, 1489 1490 Or { 1491 location: SrcSpan, 1492 left: Box<Self>, 1493 right: Box<Self>, 1494 }, 1495 1496 And { 1497 location: SrcSpan, 1498 left: Box<Self>, 1499 right: Box<Self>, 1500 }, 1501 1502 Not { 1503 location: SrcSpan, 1504 expression: Box<Self>, 1505 }, 1506 1507 Var { 1508 location: SrcSpan, 1509 type_: Type, 1510 name: EcoString, 1511 }, 1512 1513 TupleIndex { 1514 location: SrcSpan, 1515 index: u64, 1516 type_: Type, 1517 tuple: Box<Self>, 1518 }, 1519 1520 FieldAccess { 1521 location: SrcSpan, 1522 index: Option<u64>, 1523 label: EcoString, 1524 type_: Type, 1525 container: Box<Self>, 1526 }, 1527 1528 ModuleSelect { 1529 location: SrcSpan, 1530 type_: Type, 1531 label: EcoString, 1532 module_name: EcoString, 1533 module_alias: EcoString, 1534 literal: Constant<Type, RecordTag>, 1535 }, 1536 1537 Constant(Constant<Type, RecordTag>), 1538} 1539 1540impl<A, B> ClauseGuard<A, B> { 1541 pub fn location(&self) -> SrcSpan { 1542 match self { 1543 ClauseGuard::Constant(constant) => constant.location(), 1544 ClauseGuard::Or { location, .. } 1545 | ClauseGuard::And { location, .. } 1546 | ClauseGuard::Not { location, .. } 1547 | ClauseGuard::Var { location, .. } 1548 | ClauseGuard::TupleIndex { location, .. } 1549 | ClauseGuard::Equals { location, .. } 1550 | ClauseGuard::NotEquals { location, .. } 1551 | ClauseGuard::GtInt { location, .. } 1552 | ClauseGuard::GtEqInt { location, .. } 1553 | ClauseGuard::LtInt { location, .. } 1554 | ClauseGuard::LtEqInt { location, .. } 1555 | ClauseGuard::GtFloat { location, .. } 1556 | ClauseGuard::GtEqFloat { location, .. } 1557 | ClauseGuard::LtFloat { location, .. } 1558 | ClauseGuard::AddInt { location, .. } 1559 | ClauseGuard::AddFloat { location, .. } 1560 | ClauseGuard::SubInt { location, .. } 1561 | ClauseGuard::SubFloat { location, .. } 1562 | ClauseGuard::MultInt { location, .. } 1563 | ClauseGuard::MultFloat { location, .. } 1564 | ClauseGuard::DivInt { location, .. } 1565 | ClauseGuard::DivFloat { location, .. } 1566 | ClauseGuard::RemainderInt { location, .. } 1567 | ClauseGuard::FieldAccess { location, .. } 1568 | ClauseGuard::LtEqFloat { location, .. } 1569 | ClauseGuard::ModuleSelect { location, .. } => *location, 1570 } 1571 } 1572 1573 pub fn precedence(&self) -> u8 { 1574 // Ensure that this matches the other precedence function for guards 1575 match self.bin_op_name() { 1576 Some(name) => name.precedence(), 1577 None => u8::MAX, 1578 } 1579 } 1580 1581 pub fn bin_op_name(&self) -> Option<BinOp> { 1582 match self { 1583 ClauseGuard::Or { .. } => Some(BinOp::Or), 1584 ClauseGuard::And { .. } => Some(BinOp::And), 1585 ClauseGuard::Equals { .. } => Some(BinOp::Eq), 1586 ClauseGuard::NotEquals { .. } => Some(BinOp::NotEq), 1587 ClauseGuard::GtInt { .. } => Some(BinOp::GtInt), 1588 ClauseGuard::GtEqInt { .. } => Some(BinOp::GtEqInt), 1589 ClauseGuard::LtInt { .. } => Some(BinOp::LtInt), 1590 ClauseGuard::LtEqInt { .. } => Some(BinOp::LtEqInt), 1591 ClauseGuard::GtFloat { .. } => Some(BinOp::GtFloat), 1592 ClauseGuard::GtEqFloat { .. } => Some(BinOp::GtEqFloat), 1593 ClauseGuard::LtFloat { .. } => Some(BinOp::LtFloat), 1594 ClauseGuard::LtEqFloat { .. } => Some(BinOp::LtEqFloat), 1595 ClauseGuard::AddInt { .. } => Some(BinOp::AddInt), 1596 ClauseGuard::AddFloat { .. } => Some(BinOp::AddFloat), 1597 ClauseGuard::SubInt { .. } => Some(BinOp::SubInt), 1598 ClauseGuard::SubFloat { .. } => Some(BinOp::SubFloat), 1599 ClauseGuard::MultInt { .. } => Some(BinOp::MultInt), 1600 ClauseGuard::MultFloat { .. } => Some(BinOp::MultFloat), 1601 ClauseGuard::DivInt { .. } => Some(BinOp::DivInt), 1602 ClauseGuard::DivFloat { .. } => Some(BinOp::DivFloat), 1603 ClauseGuard::RemainderInt { .. } => Some(BinOp::RemainderInt), 1604 1605 ClauseGuard::Constant(_) 1606 | ClauseGuard::Var { .. } 1607 | ClauseGuard::Not { .. } 1608 | ClauseGuard::TupleIndex { .. } 1609 | ClauseGuard::FieldAccess { .. } 1610 | ClauseGuard::ModuleSelect { .. } => None, 1611 } 1612 } 1613} 1614 1615impl TypedClauseGuard { 1616 pub fn type_(&self) -> Arc<Type> { 1617 match self { 1618 ClauseGuard::Var { type_, .. } => type_.clone(), 1619 ClauseGuard::TupleIndex { type_, .. } => type_.clone(), 1620 ClauseGuard::FieldAccess { type_, .. } => type_.clone(), 1621 ClauseGuard::ModuleSelect { type_, .. } => type_.clone(), 1622 ClauseGuard::Constant(constant) => constant.type_(), 1623 1624 ClauseGuard::AddInt { .. } 1625 | ClauseGuard::SubInt { .. } 1626 | ClauseGuard::MultInt { .. } 1627 | ClauseGuard::DivInt { .. } 1628 | ClauseGuard::RemainderInt { .. } => type_::int(), 1629 1630 ClauseGuard::AddFloat { .. } 1631 | ClauseGuard::SubFloat { .. } 1632 | ClauseGuard::MultFloat { .. } 1633 | ClauseGuard::DivFloat { .. } => type_::float(), 1634 1635 ClauseGuard::Or { .. } 1636 | ClauseGuard::Not { .. } 1637 | ClauseGuard::And { .. } 1638 | ClauseGuard::Equals { .. } 1639 | ClauseGuard::NotEquals { .. } 1640 | ClauseGuard::GtInt { .. } 1641 | ClauseGuard::GtEqInt { .. } 1642 | ClauseGuard::LtInt { .. } 1643 | ClauseGuard::LtEqInt { .. } 1644 | ClauseGuard::GtFloat { .. } 1645 | ClauseGuard::GtEqFloat { .. } 1646 | ClauseGuard::LtFloat { .. } 1647 | ClauseGuard::LtEqFloat { .. } => type_::bool(), 1648 } 1649 } 1650} 1651 1652#[derive(Debug, PartialEq, Eq, Default, Clone, Copy, serde::Serialize, serde::Deserialize)] 1653pub struct SrcSpan { 1654 pub start: u32, 1655 pub end: u32, 1656} 1657 1658impl SrcSpan { 1659 pub fn new(start: u32, end: u32) -> Self { 1660 Self { start, end } 1661 } 1662 1663 pub fn contains(&self, byte_index: u32) -> bool { 1664 byte_index >= self.start && byte_index <= self.end 1665 } 1666} 1667 1668#[derive(Debug, PartialEq, Eq, Clone)] 1669pub struct DefinitionLocation<'module> { 1670 pub module: Option<&'module str>, 1671 pub span: SrcSpan, 1672} 1673 1674pub type UntypedPattern = Pattern<()>; 1675pub type TypedPattern = Pattern<Arc<Type>>; 1676 1677#[derive(Debug, Clone, PartialEq, Eq)] 1678pub enum Pattern<Type> { 1679 Int { 1680 location: SrcSpan, 1681 value: EcoString, 1682 int_value: BigInt, 1683 }, 1684 1685 Float { 1686 location: SrcSpan, 1687 value: EcoString, 1688 }, 1689 1690 String { 1691 location: SrcSpan, 1692 value: EcoString, 1693 }, 1694 1695 /// The creation of a variable. 1696 /// e.g. `assert [this_is_a_var, .._] = x` 1697 Variable { 1698 location: SrcSpan, 1699 name: EcoString, 1700 type_: Type, 1701 }, 1702 1703 /// A reference to a variable in a bit array. This is always a variable 1704 /// being used rather than a new variable being assigned. 1705 /// e.g. `assert <<y:size(somevar)>> = x` 1706 VarUsage { 1707 location: SrcSpan, 1708 name: EcoString, 1709 constructor: Option<ValueConstructor>, 1710 type_: Type, 1711 }, 1712 1713 /// A name given to a sub-pattern using the `as` keyword. 1714 /// e.g. `assert #(1, [_, _] as the_list) = x` 1715 Assign { 1716 name: EcoString, 1717 location: SrcSpan, 1718 pattern: Box<Self>, 1719 }, 1720 1721 /// A pattern that binds to any value but does not assign a variable. 1722 /// Always starts with an underscore. 1723 Discard { 1724 name: EcoString, 1725 location: SrcSpan, 1726 type_: Type, 1727 }, 1728 1729 List { 1730 location: SrcSpan, 1731 elements: Vec<Self>, 1732 tail: Option<Box<Self>>, 1733 type_: Type, 1734 }, 1735 1736 /// The constructor for a custom type. Starts with an uppercase letter. 1737 Constructor { 1738 location: SrcSpan, 1739 name: EcoString, 1740 arguments: Vec<CallArg<Self>>, 1741 module: Option<(EcoString, SrcSpan)>, 1742 constructor: Inferred<PatternConstructor>, 1743 spread: Option<SrcSpan>, 1744 type_: Type, 1745 }, 1746 1747 Tuple { 1748 location: SrcSpan, 1749 elems: Vec<Self>, 1750 }, 1751 1752 BitArray { 1753 location: SrcSpan, 1754 segments: Vec<BitArraySegment<Self, Type>>, 1755 }, 1756 1757 // "prefix" <> variable 1758 StringPrefix { 1759 location: SrcSpan, 1760 left_location: SrcSpan, 1761 left_side_assignment: Option<(EcoString, SrcSpan)>, 1762 right_location: SrcSpan, 1763 left_side_string: EcoString, 1764 /// The variable on the right hand side of the `<>`. 1765 right_side_assignment: AssignName, 1766 }, 1767 1768 /// A placeholder pattern used to allow module analysis to continue 1769 /// even when there are type errors. Should never end up in generated code. 1770 Invalid { 1771 location: SrcSpan, 1772 type_: Type, 1773 }, 1774} 1775 1776impl Default for Inferred<()> { 1777 fn default() -> Self { 1778 Self::Unknown 1779 } 1780} 1781 1782#[derive(Debug, Clone, PartialEq, Eq)] 1783pub enum AssignName { 1784 Variable(EcoString), 1785 Discard(EcoString), 1786} 1787 1788impl AssignName { 1789 pub fn name(&self) -> &EcoString { 1790 match self { 1791 AssignName::Variable(name) | AssignName::Discard(name) => name, 1792 } 1793 } 1794 1795 pub fn to_arg_names(self, location: SrcSpan) -> ArgNames { 1796 match self { 1797 AssignName::Variable(name) => ArgNames::Named { name, location }, 1798 AssignName::Discard(name) => ArgNames::Discard { name, location }, 1799 } 1800 } 1801 1802 pub fn assigned_name(&self) -> Option<&str> { 1803 match self { 1804 AssignName::Variable(name) => Some(name), 1805 AssignName::Discard(_) => None, 1806 } 1807 } 1808} 1809 1810impl<A> Pattern<A> { 1811 pub fn location(&self) -> SrcSpan { 1812 match self { 1813 Pattern::Assign { 1814 pattern, location, .. 1815 } => SrcSpan::new(pattern.location().start, location.end), 1816 Pattern::Int { location, .. } 1817 | Pattern::Variable { location, .. } 1818 | Pattern::VarUsage { location, .. } 1819 | Pattern::List { location, .. } 1820 | Pattern::Float { location, .. } 1821 | Pattern::Discard { location, .. } 1822 | Pattern::String { location, .. } 1823 | Pattern::Tuple { location, .. } 1824 | Pattern::Constructor { location, .. } 1825 | Pattern::StringPrefix { location, .. } 1826 | Pattern::BitArray { location, .. } 1827 | Pattern::Invalid { location, .. } => *location, 1828 } 1829 } 1830 1831 /// Returns `true` if the pattern is [`Discard`]. 1832 /// 1833 /// [`Discard`]: Pattern::Discard 1834 pub fn is_discard(&self) -> bool { 1835 matches!(self, Self::Discard { .. }) 1836 } 1837} 1838 1839impl TypedPattern { 1840 pub fn definition_location(&self) -> Option<DefinitionLocation<'_>> { 1841 match self { 1842 Pattern::Int { .. } 1843 | Pattern::Float { .. } 1844 | Pattern::String { .. } 1845 | Pattern::Variable { .. } 1846 | Pattern::VarUsage { .. } 1847 | Pattern::Assign { .. } 1848 | Pattern::Discard { .. } 1849 | Pattern::List { .. } 1850 | Pattern::Tuple { .. } 1851 | Pattern::BitArray { .. } 1852 | Pattern::StringPrefix { .. } 1853 | Pattern::Invalid { .. } => None, 1854 1855 Pattern::Constructor { constructor, .. } => constructor.definition_location(), 1856 } 1857 } 1858 1859 pub fn get_documentation(&self) -> Option<&str> { 1860 match self { 1861 Pattern::Int { .. } 1862 | Pattern::Float { .. } 1863 | Pattern::String { .. } 1864 | Pattern::Variable { .. } 1865 | Pattern::VarUsage { .. } 1866 | Pattern::Assign { .. } 1867 | Pattern::Discard { .. } 1868 | Pattern::List { .. } 1869 | Pattern::Tuple { .. } 1870 | Pattern::BitArray { .. } 1871 | Pattern::StringPrefix { .. } 1872 | Pattern::Invalid { .. } => None, 1873 1874 Pattern::Constructor { constructor, .. } => constructor.get_documentation(), 1875 } 1876 } 1877 1878 pub fn type_(&self) -> Arc<Type> { 1879 match self { 1880 Pattern::Int { .. } => type_::int(), 1881 Pattern::Float { .. } => type_::float(), 1882 Pattern::String { .. } => type_::string(), 1883 Pattern::BitArray { .. } => type_::bits(), 1884 Pattern::StringPrefix { .. } => type_::string(), 1885 1886 Pattern::Variable { type_, .. } 1887 | Pattern::List { type_, .. } 1888 | Pattern::VarUsage { type_, .. } 1889 | Pattern::Constructor { type_, .. } 1890 | Pattern::Invalid { type_, .. } => type_.clone(), 1891 1892 Pattern::Assign { pattern, .. } => pattern.type_(), 1893 1894 Pattern::Discard { type_, .. } => type_.clone(), 1895 1896 Pattern::Tuple { elems, .. } => type_::tuple(elems.iter().map(|p| p.type_()).collect()), 1897 } 1898 } 1899 1900 fn find_node(&self, byte_index: u32) -> Option<Located<'_>> { 1901 if !self.location().contains(byte_index) { 1902 return None; 1903 } 1904 1905 if let Pattern::Variable { name, .. } = self { 1906 // For pipes the pattern can't be pointed to 1907 if name.as_str().eq(PIPE_VARIABLE) { 1908 return None; 1909 } 1910 } 1911 1912 match self { 1913 Pattern::Int { .. } 1914 | Pattern::Float { .. } 1915 | Pattern::String { .. } 1916 | Pattern::Variable { .. } 1917 | Pattern::VarUsage { .. } 1918 | Pattern::Assign { .. } 1919 | Pattern::Discard { .. } 1920 | Pattern::BitArray { .. } 1921 | Pattern::StringPrefix { .. } 1922 | Pattern::Invalid { .. } => Some(Located::Pattern(self)), 1923 1924 Pattern::Constructor { 1925 arguments, spread, .. 1926 } => match spread { 1927 Some(spread_location) if spread_location.contains(byte_index) => { 1928 Some(Located::PatternSpread { 1929 spread_location: *spread_location, 1930 arguments, 1931 }) 1932 } 1933 1934 Some(_) | None => arguments.iter().find_map(|arg| arg.find_node(byte_index)), 1935 }, 1936 Pattern::List { elements, tail, .. } => elements 1937 .iter() 1938 .find_map(|p| p.find_node(byte_index)) 1939 .or_else(|| tail.as_ref().and_then(|p| p.find_node(byte_index))), 1940 1941 Pattern::Tuple { elems, .. } => elems.iter().find_map(|p| p.find_node(byte_index)), 1942 } 1943 .or(Some(Located::Pattern(self))) 1944 } 1945} 1946impl<A> HasLocation for Pattern<A> { 1947 fn location(&self) -> SrcSpan { 1948 self.location() 1949 } 1950} 1951 1952#[derive(Debug, Clone, Copy, PartialEq, Eq)] 1953pub enum AssignmentKind { 1954 // let x = ... 1955 Let, 1956 // let assert x = ... 1957 Assert { location: SrcSpan }, 1958} 1959 1960impl AssignmentKind { 1961 /// Returns `true` if the assignment kind is [`Assert`]. 1962 /// 1963 /// [`Assert`]: AssignmentKind::Assert 1964 #[must_use] 1965 pub fn is_assert(&self) -> bool { 1966 match self { 1967 Self::Assert { .. } => true, 1968 Self::Let => false, 1969 } 1970 } 1971} 1972 1973// BitArrays 1974 1975pub type UntypedExprBitArraySegment = BitArraySegment<UntypedExpr, ()>; 1976pub type TypedExprBitArraySegment = BitArraySegment<TypedExpr, Arc<Type>>; 1977 1978pub type UntypedConstantBitArraySegment = BitArraySegment<UntypedConstant, ()>; 1979pub type TypedConstantBitArraySegment = BitArraySegment<TypedConstant, Arc<Type>>; 1980 1981pub type UntypedPatternBitArraySegment = BitArraySegment<UntypedPattern, ()>; 1982pub type TypedPatternBitArraySegment = BitArraySegment<TypedPattern, Arc<Type>>; 1983 1984#[derive(Debug, Clone, PartialEq, Eq)] 1985pub struct BitArraySegment<Value, Type> { 1986 pub location: SrcSpan, 1987 pub value: Box<Value>, 1988 pub options: Vec<BitArrayOption<Value>>, 1989 pub type_: Type, 1990} 1991 1992impl TypedExprBitArraySegment { 1993 pub fn find_node(&self, byte_index: u32) -> Option<Located<'_>> { 1994 self.value.find_node(byte_index) 1995 } 1996} 1997 1998pub type TypedConstantBitArraySegmentOption = BitArrayOption<TypedConstant>; 1999 2000#[derive(Debug, PartialEq, Eq, Clone)] 2001pub enum BitArrayOption<Value> { 2002 Bytes { 2003 location: SrcSpan, 2004 }, 2005 2006 Int { 2007 location: SrcSpan, 2008 }, 2009 2010 Float { 2011 location: SrcSpan, 2012 }, 2013 2014 Bits { 2015 location: SrcSpan, 2016 }, 2017 2018 Utf8 { 2019 location: SrcSpan, 2020 }, 2021 2022 Utf16 { 2023 location: SrcSpan, 2024 }, 2025 2026 Utf32 { 2027 location: SrcSpan, 2028 }, 2029 2030 Utf8Codepoint { 2031 location: SrcSpan, 2032 }, 2033 2034 Utf16Codepoint { 2035 location: SrcSpan, 2036 }, 2037 2038 Utf32Codepoint { 2039 location: SrcSpan, 2040 }, 2041 2042 Signed { 2043 location: SrcSpan, 2044 }, 2045 2046 Unsigned { 2047 location: SrcSpan, 2048 }, 2049 2050 Big { 2051 location: SrcSpan, 2052 }, 2053 2054 Little { 2055 location: SrcSpan, 2056 }, 2057 2058 Native { 2059 location: SrcSpan, 2060 }, 2061 2062 Size { 2063 location: SrcSpan, 2064 value: Box<Value>, 2065 short_form: bool, 2066 }, 2067 2068 Unit { 2069 location: SrcSpan, 2070 value: u8, 2071 }, 2072} 2073 2074impl<A> BitArrayOption<A> { 2075 pub fn value(&self) -> Option<&A> { 2076 match self { 2077 BitArrayOption::Size { value, .. } => Some(value), 2078 _ => None, 2079 } 2080 } 2081 2082 pub fn location(&self) -> SrcSpan { 2083 match self { 2084 BitArrayOption::Bytes { location } 2085 | BitArrayOption::Int { location } 2086 | BitArrayOption::Float { location } 2087 | BitArrayOption::Bits { location } 2088 | BitArrayOption::Utf8 { location } 2089 | BitArrayOption::Utf16 { location } 2090 | BitArrayOption::Utf32 { location } 2091 | BitArrayOption::Utf8Codepoint { location } 2092 | BitArrayOption::Utf16Codepoint { location } 2093 | BitArrayOption::Utf32Codepoint { location } 2094 | BitArrayOption::Signed { location } 2095 | BitArrayOption::Unsigned { location } 2096 | BitArrayOption::Big { location } 2097 | BitArrayOption::Little { location } 2098 | BitArrayOption::Native { location } 2099 | BitArrayOption::Size { location, .. } 2100 | BitArrayOption::Unit { location, .. } => *location, 2101 } 2102 } 2103 2104 pub fn label(&self) -> EcoString { 2105 match self { 2106 BitArrayOption::Bytes { .. } => "bytes".into(), 2107 BitArrayOption::Int { .. } => "int".into(), 2108 BitArrayOption::Float { .. } => "float".into(), 2109 BitArrayOption::Bits { .. } => "bits".into(), 2110 BitArrayOption::Utf8 { .. } => "utf8".into(), 2111 BitArrayOption::Utf16 { .. } => "utf16".into(), 2112 BitArrayOption::Utf32 { .. } => "utf32".into(), 2113 BitArrayOption::Utf8Codepoint { .. } => "utf8_codepoint".into(), 2114 BitArrayOption::Utf16Codepoint { .. } => "utf16_codepoint".into(), 2115 BitArrayOption::Utf32Codepoint { .. } => "utf32_codepoint".into(), 2116 BitArrayOption::Signed { .. } => "signed".into(), 2117 BitArrayOption::Unsigned { .. } => "unsigned".into(), 2118 BitArrayOption::Big { .. } => "big".into(), 2119 BitArrayOption::Little { .. } => "little".into(), 2120 BitArrayOption::Native { .. } => "native".into(), 2121 BitArrayOption::Size { .. } => "size".into(), 2122 BitArrayOption::Unit { .. } => "unit".into(), 2123 } 2124 } 2125} 2126 2127#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)] 2128pub enum TodoKind { 2129 Keyword, 2130 EmptyFunction, 2131 IncompleteUse, 2132} 2133 2134#[derive(Debug, Default)] 2135pub struct GroupedStatements { 2136 pub functions: Vec<UntypedFunction>, 2137 pub constants: Vec<UntypedModuleConstant>, 2138 pub custom_types: Vec<UntypedCustomType>, 2139 pub imports: Vec<UntypedImport>, 2140 pub type_aliases: Vec<UntypedTypeAlias>, 2141} 2142 2143impl GroupedStatements { 2144 pub fn new(statements: impl IntoIterator<Item = UntypedDefinition>) -> Self { 2145 let mut this = Self::default(); 2146 2147 for statement in statements { 2148 this.add(statement) 2149 } 2150 2151 this 2152 } 2153 2154 pub fn is_empty(&self) -> bool { 2155 self.len() == 0 2156 } 2157 2158 pub fn len(&self) -> usize { 2159 let Self { 2160 custom_types, 2161 functions, 2162 constants, 2163 imports, 2164 type_aliases, 2165 } = self; 2166 functions.len() + constants.len() + imports.len() + custom_types.len() + type_aliases.len() 2167 } 2168 2169 fn add(&mut self, statement: UntypedDefinition) { 2170 match statement { 2171 Definition::Import(i) => self.imports.push(i), 2172 Definition::Function(f) => self.functions.push(f), 2173 Definition::TypeAlias(t) => self.type_aliases.push(t), 2174 Definition::CustomType(c) => self.custom_types.push(c), 2175 Definition::ModuleConstant(c) => self.constants.push(c), 2176 } 2177 } 2178} 2179 2180/// A statement with in a function body. 2181#[derive(Debug, Clone, PartialEq, Eq)] 2182pub enum Statement<TypeT, ExpressionT> { 2183 /// A bare expression that is not assigned to any variable. 2184 Expression(ExpressionT), 2185 /// Assigning an expression to variables using a pattern. 2186 Assignment(Assignment<TypeT, ExpressionT>), 2187 /// A `use` expression. 2188 Use(Use), 2189} 2190 2191pub type TypedStatement = Statement<Arc<Type>, TypedExpr>; 2192pub type UntypedStatement = Statement<(), UntypedExpr>; 2193 2194impl<T, E> Statement<T, E> { 2195 /// Returns `true` if the statement is [`Expression`]. 2196 /// 2197 /// [`Expression`]: Statement::Expression 2198 #[must_use] 2199 pub fn is_expression(&self) -> bool { 2200 matches!(self, Self::Expression(..)) 2201 } 2202 2203 #[must_use] 2204 pub(crate) fn is_use(&self) -> bool { 2205 match self { 2206 Self::Use(_) => true, 2207 _ => false, 2208 } 2209 } 2210} 2211 2212impl UntypedStatement { 2213 pub fn location(&self) -> SrcSpan { 2214 match self { 2215 Statement::Expression(expression) => expression.location(), 2216 Statement::Assignment(assignment) => assignment.location, 2217 Statement::Use(use_) => use_.location, 2218 } 2219 } 2220 2221 pub fn start_byte_index(&self) -> u32 { 2222 match self { 2223 Statement::Expression(expression) => expression.start_byte_index(), 2224 Statement::Assignment(assignment) => assignment.location.start, 2225 Statement::Use(use_) => use_.location.start, 2226 } 2227 } 2228 2229 pub fn is_placeholder(&self) -> bool { 2230 match self { 2231 Statement::Expression(expression) => expression.is_placeholder(), 2232 Statement::Assignment(_) | Statement::Use(_) => false, 2233 } 2234 } 2235} 2236 2237impl TypedStatement { 2238 pub fn is_println(&self) -> bool { 2239 match self { 2240 Statement::Expression(e) => e.is_println(), 2241 Statement::Assignment(_) => false, 2242 Statement::Use(_) => false, 2243 } 2244 } 2245 2246 pub fn is_non_pipe_expression(&self) -> bool { 2247 match self { 2248 Statement::Expression(expression) => !expression.is_pipeline(), 2249 _ => false, 2250 } 2251 } 2252 2253 pub fn location(&self) -> SrcSpan { 2254 match self { 2255 Statement::Expression(expression) => expression.location(), 2256 Statement::Assignment(assignment) => assignment.location, 2257 Statement::Use(use_) => use_.location, 2258 } 2259 } 2260 2261 pub fn type_(&self) -> Arc<Type> { 2262 match self { 2263 Statement::Expression(expression) => expression.type_(), 2264 Statement::Assignment(assignment) => assignment.type_(), 2265 Statement::Use(_use) => unreachable!("Use must not exist for typed code"), 2266 } 2267 } 2268 2269 pub fn definition_location(&self) -> Option<DefinitionLocation<'_>> { 2270 match self { 2271 Statement::Expression(expression) => expression.definition_location(), 2272 Statement::Assignment(_) => None, 2273 Statement::Use(_) => None, 2274 } 2275 } 2276 2277 pub fn find_node(&self, byte_index: u32) -> Option<Located<'_>> { 2278 match self { 2279 Statement::Use(_) => None, 2280 Statement::Expression(expression) => expression.find_node(byte_index), 2281 Statement::Assignment(assignment) => assignment.find_node(byte_index).or_else(|| { 2282 if assignment.location.contains(byte_index) { 2283 Some(Located::Statement(self)) 2284 } else { 2285 None 2286 } 2287 }), 2288 } 2289 } 2290 2291 pub fn type_defining_location(&self) -> SrcSpan { 2292 match self { 2293 Statement::Expression(expression) => expression.type_defining_location(), 2294 Statement::Assignment(assignment) => assignment.location, 2295 Statement::Use(use_) => use_.location, 2296 } 2297 } 2298} 2299 2300#[derive(Debug, Clone, PartialEq, Eq)] 2301pub struct Assignment<TypeT, ExpressionT> { 2302 pub location: SrcSpan, 2303 pub value: Box<ExpressionT>, 2304 pub pattern: Pattern<TypeT>, 2305 pub kind: AssignmentKind, 2306 pub annotation: Option<TypeAst>, 2307} 2308 2309pub type TypedAssignment = Assignment<Arc<Type>, TypedExpr>; 2310pub type UntypedAssignment = Assignment<(), UntypedExpr>; 2311 2312impl TypedAssignment { 2313 pub fn find_node(&self, byte_index: u32) -> Option<Located<'_>> { 2314 if let Some(annotation) = &self.annotation { 2315 if let Some(l) = annotation.find_node(byte_index, self.pattern.type_()) { 2316 return Some(l); 2317 } 2318 } 2319 self.pattern 2320 .find_node(byte_index) 2321 .or_else(|| self.value.find_node(byte_index)) 2322 } 2323 2324 pub fn type_(&self) -> Arc<Type> { 2325 self.value.type_() 2326 } 2327} 2328 2329#[derive(Debug, Clone, PartialEq, Eq)] 2330pub struct UseAssignment { 2331 pub location: SrcSpan, 2332 pub pattern: UntypedPattern, 2333 pub annotation: Option<TypeAst>, 2334}