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
105 kB 3382 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}; 11 12pub use self::constant::{Constant, TypedConstant, UntypedConstant}; 13 14use crate::analyse::Inferred; 15use crate::bit_array; 16use crate::build::{ExpressionPosition, Located, Target, module_erlang_name}; 17use crate::exhaustiveness::CompiledCase; 18use crate::parse::SpannedString; 19use crate::type_::error::VariableOrigin; 20use crate::type_::expression::{Implementations, Purity}; 21use crate::type_::printer::Names; 22use crate::type_::{ 23 self, Deprecation, HasType, ModuleValueConstructor, PatternConstructor, Type, TypedCallArg, 24 ValueConstructor, nil, 25}; 26use std::collections::HashSet; 27use std::sync::Arc; 28 29use ecow::EcoString; 30use num_bigint::{BigInt, Sign}; 31use num_traits::{One, ToPrimitive}; 32#[cfg(test)] 33use pretty_assertions::assert_eq; 34use vec1::Vec1; 35 36pub const PIPE_VARIABLE: &str = "_pipe"; 37pub const USE_ASSIGNMENT_VARIABLE: &str = "_use"; 38pub const RECORD_UPDATE_VARIABLE: &str = "_record"; 39pub const ASSERT_FAIL_VARIABLE: &str = "_assert_fail"; 40pub const ASSERT_SUBJECT_VARIABLE: &str = "_assert_subject"; 41pub const CAPTURE_VARIABLE: &str = "_capture"; 42pub const BLOCK_VARIABLE: &str = "_block"; 43 44pub trait HasLocation { 45 fn location(&self) -> SrcSpan; 46} 47 48pub type TypedModule = Module<type_::ModuleInterface, TypedDefinition>; 49 50pub type UntypedModule = Module<(), TargetedDefinition>; 51 52#[derive(Debug, Clone, PartialEq, Eq)] 53pub struct Module<Info, Definitions> { 54 pub name: EcoString, 55 pub documentation: Vec<EcoString>, 56 pub type_info: Info, 57 pub definitions: Vec<Definitions>, 58 pub names: Names, 59 /// The source byte locations of definition that are unused. 60 /// This is used in code generation to know when definitions can be safely omitted. 61 pub unused_definition_positions: HashSet<u32>, 62} 63 64impl<Info, Definitions> Module<Info, Definitions> { 65 pub fn erlang_name(&self) -> EcoString { 66 module_erlang_name(&self.name) 67 } 68} 69 70impl TypedModule { 71 pub fn find_node(&self, byte_index: u32) -> Option<Located<'_>> { 72 self.definitions 73 .iter() 74 .find_map(|definition| definition.find_node(byte_index)) 75 } 76 77 pub fn find_statement(&self, byte_index: u32) -> Option<&TypedStatement> { 78 self.definitions 79 .iter() 80 .find_map(|definition| definition.find_statement(byte_index)) 81 } 82} 83 84/// The `@target(erlang)` and `@target(javascript)` attributes can be used to 85/// mark a definition as only being for a specific target. 86/// 87/// ```gleam 88/// const x: Int = 1 89/// 90/// @target(erlang) 91/// pub fn main(a) { ...} 92/// ``` 93/// 94#[derive(Debug, Clone, PartialEq, Eq)] 95pub struct TargetedDefinition { 96 pub definition: UntypedDefinition, 97 pub target: Option<Target>, 98} 99 100impl TargetedDefinition { 101 pub fn is_for(&self, target: Target) -> bool { 102 self.target.map(|t| t == target).unwrap_or(true) 103 } 104} 105 106impl UntypedModule { 107 pub fn dependencies(&self, target: Target) -> Vec<(EcoString, SrcSpan)> { 108 self.iter_definitions(target) 109 .flat_map(|definition| match definition { 110 Definition::Import(Import { 111 module, location, .. 112 }) => Some((module.clone(), *location)), 113 _ => None, 114 }) 115 .collect() 116 } 117 118 pub fn iter_definitions(&self, target: Target) -> impl Iterator<Item = &UntypedDefinition> { 119 self.definitions 120 .iter() 121 .filter(move |definition| definition.is_for(target)) 122 .map(|definition| &definition.definition) 123 } 124 125 pub fn into_iter_definitions(self, target: Target) -> impl Iterator<Item = UntypedDefinition> { 126 self.definitions 127 .into_iter() 128 .filter(move |definition| definition.is_for(target)) 129 .map(|definition| definition.definition) 130 } 131} 132 133#[test] 134fn module_dependencies_test() { 135 let parsed = crate::parse::parse_module( 136 camino::Utf8PathBuf::from("test/path"), 137 "import one 138 @target(erlang) 139 import two 140 141 @target(javascript) 142 import three 143 144 import four", 145 &crate::warning::WarningEmitter::null(), 146 ) 147 .expect("syntax error"); 148 let module = parsed.module; 149 150 assert_eq!( 151 vec![ 152 ("one".into(), SrcSpan::new(0, 10)), 153 ("two".into(), SrcSpan::new(45, 55)), 154 ("four".into(), SrcSpan::new(118, 129)), 155 ], 156 module.dependencies(Target::Erlang) 157 ); 158} 159 160pub type TypedArg = Arg<Arc<Type>>; 161pub type UntypedArg = Arg<()>; 162 163#[derive(Debug, Clone, PartialEq, Eq)] 164pub struct Arg<T> { 165 pub names: ArgNames, 166 pub location: SrcSpan, 167 pub annotation: Option<TypeAst>, 168 pub type_: T, 169} 170 171impl<A> Arg<A> { 172 pub fn set_type<B>(self, t: B) -> Arg<B> { 173 Arg { 174 type_: t, 175 names: self.names, 176 location: self.location, 177 annotation: self.annotation, 178 } 179 } 180 181 pub fn get_variable_name(&self) -> Option<&EcoString> { 182 self.names.get_variable_name() 183 } 184 185 pub fn is_capture_hole(&self) -> bool { 186 match &self.names { 187 ArgNames::Named { name, .. } if name == CAPTURE_VARIABLE => true, 188 _ => false, 189 } 190 } 191} 192 193impl TypedArg { 194 pub fn find_node(&self, byte_index: u32) -> Option<Located<'_>> { 195 if self.location.contains(byte_index) { 196 if let Some(annotation) = &self.annotation { 197 return annotation 198 .find_node(byte_index, self.type_.clone()) 199 .or(Some(Located::Arg(self))); 200 } 201 Some(Located::Arg(self)) 202 } else { 203 None 204 } 205 } 206} 207 208#[derive(Debug, Clone, PartialEq, Eq)] 209pub enum ArgNames { 210 Discard { 211 name: EcoString, 212 location: SrcSpan, 213 }, 214 LabelledDiscard { 215 label: EcoString, 216 label_location: SrcSpan, 217 name: EcoString, 218 name_location: SrcSpan, 219 }, 220 Named { 221 name: EcoString, 222 location: SrcSpan, 223 }, 224 NamedLabelled { 225 label: EcoString, 226 label_location: SrcSpan, 227 name: EcoString, 228 name_location: SrcSpan, 229 }, 230} 231 232impl ArgNames { 233 pub fn get_label(&self) -> Option<&EcoString> { 234 match self { 235 ArgNames::Discard { .. } | ArgNames::Named { .. } => None, 236 ArgNames::LabelledDiscard { label, .. } | ArgNames::NamedLabelled { label, .. } => { 237 Some(label) 238 } 239 } 240 } 241 pub fn get_variable_name(&self) -> Option<&EcoString> { 242 match self { 243 ArgNames::Discard { .. } | ArgNames::LabelledDiscard { .. } => None, 244 ArgNames::NamedLabelled { name, .. } | ArgNames::Named { name, .. } => Some(name), 245 } 246 } 247} 248 249pub type TypedRecordConstructor = RecordConstructor<Arc<Type>>; 250 251#[derive(Debug, Clone, PartialEq, Eq)] 252pub struct RecordConstructor<T> { 253 pub location: SrcSpan, 254 pub name_location: SrcSpan, 255 pub name: EcoString, 256 pub arguments: Vec<RecordConstructorArg<T>>, 257 pub documentation: Option<(u32, EcoString)>, 258 pub deprecation: Deprecation, 259} 260 261impl<A> RecordConstructor<A> { 262 pub fn put_doc(&mut self, new_doc: (u32, EcoString)) { 263 self.documentation = Some(new_doc); 264 } 265} 266 267pub type TypedRecordConstructorArg = RecordConstructorArg<Arc<Type>>; 268 269#[derive(Debug, Clone, PartialEq, Eq)] 270pub struct RecordConstructorArg<T> { 271 pub label: Option<SpannedString>, 272 pub ast: TypeAst, 273 pub location: SrcSpan, 274 pub type_: T, 275 pub doc: Option<(u32, EcoString)>, 276} 277 278impl<T: PartialEq> RecordConstructorArg<T> { 279 pub fn put_doc(&mut self, new_doc: (u32, EcoString)) { 280 self.doc = Some(new_doc); 281 } 282} 283 284#[derive(Debug, Clone, PartialEq, Eq)] 285pub struct TypeAstConstructor { 286 pub location: SrcSpan, 287 pub name_location: SrcSpan, 288 pub module: Option<(EcoString, SrcSpan)>, 289 pub name: EcoString, 290 pub arguments: Vec<TypeAst>, 291} 292 293#[derive(Debug, Clone, PartialEq, Eq)] 294pub struct TypeAstFn { 295 pub location: SrcSpan, 296 pub arguments: Vec<TypeAst>, 297 pub return_: Box<TypeAst>, 298} 299 300#[derive(Debug, Clone, PartialEq, Eq)] 301pub struct TypeAstVar { 302 pub location: SrcSpan, 303 pub name: EcoString, 304} 305 306#[derive(Debug, Clone, PartialEq, Eq)] 307pub struct TypeAstTuple { 308 pub location: SrcSpan, 309 pub elements: Vec<TypeAst>, 310} 311 312#[derive(Debug, Clone, PartialEq, Eq)] 313pub struct TypeAstHole { 314 pub location: SrcSpan, 315 pub name: EcoString, 316} 317 318#[derive(Debug, Clone, PartialEq, Eq)] 319pub enum TypeAst { 320 Constructor(TypeAstConstructor), 321 Fn(TypeAstFn), 322 Var(TypeAstVar), 323 Tuple(TypeAstTuple), 324 Hole(TypeAstHole), 325} 326 327impl TypeAst { 328 pub fn location(&self) -> SrcSpan { 329 match self { 330 TypeAst::Fn(TypeAstFn { location, .. }) 331 | TypeAst::Var(TypeAstVar { location, .. }) 332 | TypeAst::Hole(TypeAstHole { location, .. }) 333 | TypeAst::Tuple(TypeAstTuple { location, .. }) 334 | TypeAst::Constructor(TypeAstConstructor { location, .. }) => *location, 335 } 336 } 337 338 pub fn is_logically_equal(&self, other: &TypeAst) -> bool { 339 match self { 340 TypeAst::Constructor(TypeAstConstructor { 341 module, 342 name, 343 arguments, 344 location: _, 345 name_location: _, 346 }) => match other { 347 TypeAst::Constructor(TypeAstConstructor { 348 module: o_module, 349 name: o_name, 350 arguments: o_arguments, 351 location: _, 352 name_location: _, 353 }) => { 354 let module_name = 355 |m: &Option<(EcoString, _)>| m.as_ref().map(|(m, _)| m.clone()); 356 module_name(module) == module_name(o_module) 357 && name == o_name 358 && arguments.len() == o_arguments.len() 359 && arguments 360 .iter() 361 .zip(o_arguments) 362 .all(|a| a.0.is_logically_equal(a.1)) 363 } 364 _ => false, 365 }, 366 TypeAst::Fn(TypeAstFn { 367 arguments, 368 return_, 369 location: _, 370 }) => match other { 371 TypeAst::Fn(TypeAstFn { 372 arguments: o_arguments, 373 return_: o_return_, 374 location: _, 375 }) => { 376 arguments.len() == o_arguments.len() 377 && arguments 378 .iter() 379 .zip(o_arguments) 380 .all(|a| a.0.is_logically_equal(a.1)) 381 && return_.is_logically_equal(o_return_) 382 } 383 _ => false, 384 }, 385 TypeAst::Var(TypeAstVar { name, location: _ }) => match other { 386 TypeAst::Var(TypeAstVar { 387 name: o_name, 388 location: _, 389 }) => name == o_name, 390 _ => false, 391 }, 392 TypeAst::Tuple(TypeAstTuple { 393 elements, 394 location: _, 395 }) => match other { 396 TypeAst::Tuple(TypeAstTuple { 397 elements: other_elements, 398 location: _, 399 }) => { 400 elements.len() == other_elements.len() 401 && elements 402 .iter() 403 .zip(other_elements) 404 .all(|a| a.0.is_logically_equal(a.1)) 405 } 406 _ => false, 407 }, 408 TypeAst::Hole(TypeAstHole { name, location: _ }) => match other { 409 TypeAst::Hole(TypeAstHole { 410 name: o_name, 411 location: _, 412 }) => name == o_name, 413 _ => false, 414 }, 415 } 416 } 417 418 pub fn find_node(&self, byte_index: u32, type_: Arc<Type>) -> Option<Located<'_>> { 419 if !self.location().contains(byte_index) { 420 return None; 421 } 422 423 match self { 424 TypeAst::Fn(TypeAstFn { 425 arguments, return_, .. 426 }) => type_ 427 .fn_types() 428 .and_then(|(arg_types, ret_type)| { 429 if let Some(arg) = arguments 430 .iter() 431 .zip(arg_types) 432 .find_map(|(arg, arg_type)| arg.find_node(byte_index, arg_type.clone())) 433 { 434 return Some(arg); 435 } 436 if let Some(ret) = return_.find_node(byte_index, ret_type) { 437 return Some(ret); 438 } 439 440 None 441 }) 442 .or(Some(Located::Annotation { ast: self, type_ })), 443 TypeAst::Constructor(TypeAstConstructor { 444 arguments, module, .. 445 }) => type_ 446 .constructor_types() 447 .and_then(|arg_types| { 448 if let Some(arg) = arguments 449 .iter() 450 .zip(arg_types) 451 .find_map(|(arg, arg_type)| arg.find_node(byte_index, arg_type.clone())) 452 { 453 return Some(arg); 454 } 455 456 None 457 }) 458 .or(module.as_ref().and_then(|(name, location)| { 459 if location.contains(byte_index) { 460 Some(Located::ModuleName { 461 location: *location, 462 name, 463 layer: Layer::Type, 464 }) 465 } else { 466 None 467 } 468 })) 469 .or(Some(Located::Annotation { ast: self, type_ })), 470 TypeAst::Tuple(TypeAstTuple { elements, .. }) => type_ 471 .tuple_types() 472 .and_then(|elem_types| { 473 if let Some(e) = elements 474 .iter() 475 .zip(elem_types) 476 .find_map(|(e, e_type)| e.find_node(byte_index, e_type.clone())) 477 { 478 return Some(e); 479 } 480 481 None 482 }) 483 .or(Some(Located::Annotation { ast: self, type_ })), 484 TypeAst::Var(_) | TypeAst::Hole(_) => Some(Located::Annotation { ast: self, type_ }), 485 } 486 } 487 488 /// Generates an annotation corresponding to the type. 489 pub fn print(&self, buffer: &mut EcoString) { 490 match &self { 491 TypeAst::Var(var) => buffer.push_str(&var.name), 492 TypeAst::Hole(hole) => buffer.push_str(&hole.name), 493 TypeAst::Tuple(tuple) => { 494 buffer.push_str("#("); 495 for (i, element) in tuple.elements.iter().enumerate() { 496 element.print(buffer); 497 if i < tuple.elements.len() - 1 { 498 buffer.push_str(", "); 499 } 500 } 501 buffer.push(')') 502 } 503 TypeAst::Fn(func) => { 504 buffer.push_str("fn("); 505 for (i, argument) in func.arguments.iter().enumerate() { 506 argument.print(buffer); 507 if i < func.arguments.len() - 1 { 508 buffer.push_str(", "); 509 } 510 } 511 buffer.push(')'); 512 buffer.push_str(" -> "); 513 func.return_.print(buffer); 514 } 515 TypeAst::Constructor(constructor) => { 516 if let Some((module, _)) = &constructor.module { 517 buffer.push_str(module); 518 buffer.push('.'); 519 } 520 buffer.push_str(&constructor.name); 521 if !constructor.arguments.is_empty() { 522 buffer.push('('); 523 for (i, argument) in constructor.arguments.iter().enumerate() { 524 argument.print(buffer); 525 if i < constructor.arguments.len() - 1 { 526 buffer.push_str(", "); 527 } 528 } 529 buffer.push(')'); 530 } 531 } 532 } 533 } 534} 535 536#[test] 537fn type_ast_print_fn() { 538 let mut buffer = EcoString::new(); 539 let ast = TypeAst::Fn(TypeAstFn { 540 location: SrcSpan { start: 1, end: 1 }, 541 arguments: vec![ 542 TypeAst::Var(TypeAstVar { 543 location: SrcSpan { start: 1, end: 1 }, 544 name: "String".into(), 545 }), 546 TypeAst::Var(TypeAstVar { 547 location: SrcSpan { start: 1, end: 1 }, 548 name: "Bool".into(), 549 }), 550 ], 551 return_: Box::new(TypeAst::Var(TypeAstVar { 552 location: SrcSpan { start: 1, end: 1 }, 553 name: "Int".into(), 554 })), 555 }); 556 ast.print(&mut buffer); 557 assert_eq!(&buffer, "fn(String, Bool) -> Int") 558} 559 560#[test] 561fn type_ast_print_constructor() { 562 let mut buffer = EcoString::new(); 563 let ast = TypeAst::Constructor(TypeAstConstructor { 564 name: "SomeType".into(), 565 module: Some(("some_module".into(), SrcSpan { start: 1, end: 1 })), 566 location: SrcSpan { start: 1, end: 1 }, 567 name_location: SrcSpan { start: 1, end: 1 }, 568 arguments: vec![ 569 TypeAst::Var(TypeAstVar { 570 location: SrcSpan { start: 1, end: 1 }, 571 name: "String".into(), 572 }), 573 TypeAst::Var(TypeAstVar { 574 location: SrcSpan { start: 1, end: 1 }, 575 name: "Bool".into(), 576 }), 577 ], 578 }); 579 ast.print(&mut buffer); 580 assert_eq!(&buffer, "some_module.SomeType(String, Bool)") 581} 582 583#[test] 584fn type_ast_print_tuple() { 585 let mut buffer = EcoString::new(); 586 let ast = TypeAst::Tuple(TypeAstTuple { 587 location: SrcSpan { start: 1, end: 1 }, 588 elements: vec![ 589 TypeAst::Constructor(TypeAstConstructor { 590 name: "SomeType".into(), 591 module: Some(("some_module".into(), SrcSpan { start: 1, end: 1 })), 592 location: SrcSpan { start: 1, end: 1 }, 593 name_location: SrcSpan { start: 1, end: 1 }, 594 arguments: vec![ 595 TypeAst::Var(TypeAstVar { 596 location: SrcSpan { start: 1, end: 1 }, 597 name: "String".into(), 598 }), 599 TypeAst::Var(TypeAstVar { 600 location: SrcSpan { start: 1, end: 1 }, 601 name: "Bool".into(), 602 }), 603 ], 604 }), 605 TypeAst::Fn(TypeAstFn { 606 location: SrcSpan { start: 1, end: 1 }, 607 arguments: vec![ 608 TypeAst::Var(TypeAstVar { 609 location: SrcSpan { start: 1, end: 1 }, 610 name: "String".into(), 611 }), 612 TypeAst::Var(TypeAstVar { 613 location: SrcSpan { start: 1, end: 1 }, 614 name: "Bool".into(), 615 }), 616 ], 617 return_: Box::new(TypeAst::Var(TypeAstVar { 618 location: SrcSpan { start: 1, end: 1 }, 619 name: "Int".into(), 620 })), 621 }), 622 ], 623 }); 624 ast.print(&mut buffer); 625 assert_eq!( 626 &buffer, 627 "#(some_module.SomeType(String, Bool), fn(String, Bool) -> Int)" 628 ) 629} 630 631#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)] 632pub enum Publicity { 633 Public, 634 Private, 635 Internal { attribute_location: Option<SrcSpan> }, 636} 637 638impl Publicity { 639 pub fn is_private(&self) -> bool { 640 match self { 641 Self::Private => true, 642 Self::Public | Self::Internal { .. } => false, 643 } 644 } 645 646 pub fn is_internal(&self) -> bool { 647 match self { 648 Self::Internal { .. } => true, 649 Self::Public | Self::Private => false, 650 } 651 } 652 653 pub fn is_public(&self) -> bool { 654 match self { 655 Self::Public => true, 656 Self::Internal { .. } | Self::Private => false, 657 } 658 } 659 660 pub fn is_importable(&self) -> bool { 661 match self { 662 Self::Internal { .. } | Self::Public => true, 663 Self::Private => false, 664 } 665 } 666} 667 668#[derive(Debug, Clone, PartialEq, Eq)] 669/// A function definition 670/// 671/// Note that an anonymous function will have `None` as the name field, while a 672/// named function will have `Some`. 673/// 674/// # Example(s) 675/// 676/// ```gleam 677/// // Public function 678/// pub fn wobble() -> String { ... } 679/// // Private function 680/// fn wibble(x: Int) -> Int { ... } 681/// // Anonymous function 682/// fn(x: Int) { ... } 683/// ``` 684pub struct Function<T, Expr> { 685 pub location: SrcSpan, 686 pub end_position: u32, 687 pub name: Option<SpannedString>, 688 pub arguments: Vec<Arg<T>>, 689 pub body: Vec1<Statement<T, Expr>>, 690 pub publicity: Publicity, 691 pub deprecation: Deprecation, 692 pub return_annotation: Option<TypeAst>, 693 pub return_type: T, 694 pub documentation: Option<(u32, EcoString)>, 695 pub external_erlang: Option<(EcoString, EcoString, SrcSpan)>, 696 pub external_javascript: Option<(EcoString, EcoString, SrcSpan)>, 697 pub implementations: Implementations, 698 pub purity: Purity, 699} 700 701pub type TypedFunction = Function<Arc<Type>, TypedExpr>; 702pub type UntypedFunction = Function<(), UntypedExpr>; 703 704impl<T, E> Function<T, E> { 705 pub fn full_location(&self) -> SrcSpan { 706 SrcSpan::new(self.location.start, self.end_position) 707 } 708} 709 710pub type UntypedImport = Import<()>; 711 712#[derive(Debug, Clone, PartialEq, Eq)] 713/// Import another Gleam module so the current module can use the types and 714/// values it defines. 715/// 716/// # Example(s) 717/// 718/// ```gleam 719/// import unix/cat 720/// // Import with alias 721/// import animal/cat as kitty 722/// ``` 723pub struct Import<PackageName> { 724 pub documentation: Option<EcoString>, 725 pub location: SrcSpan, 726 pub module: EcoString, 727 pub as_name: Option<(AssignName, SrcSpan)>, 728 pub unqualified_values: Vec<UnqualifiedImport>, 729 pub unqualified_types: Vec<UnqualifiedImport>, 730 pub package: PackageName, 731} 732 733impl<T> Import<T> { 734 pub(crate) fn used_name(&self) -> Option<EcoString> { 735 match self.as_name.as_ref() { 736 Some((AssignName::Variable(name), _)) => Some(name.clone()), 737 Some((AssignName::Discard(_), _)) => None, 738 None => self.module.split('/').next_back().map(EcoString::from), 739 } 740 } 741 742 pub(crate) fn alias_location(&self) -> Option<SrcSpan> { 743 self.as_name.as_ref().map(|(_, location)| *location) 744 } 745} 746 747pub type UntypedModuleConstant = ModuleConstant<(), ()>; 748pub type TypedModuleConstant = ModuleConstant<Arc<Type>, EcoString>; 749 750#[derive(Debug, Clone, PartialEq, Eq)] 751/// A certain fixed value that can be used in multiple places 752/// 753/// # Example(s) 754/// 755/// ```gleam 756/// pub const start_year = 2101 757/// pub const end_year = 2111 758/// ``` 759pub struct ModuleConstant<T, ConstantRecordTag> { 760 pub documentation: Option<(u32, EcoString)>, 761 /// The location of the constant, starting at the "(pub) const" keywords and 762 /// ending after the ": Type" annotation, or (without an annotation) after its name. 763 pub location: SrcSpan, 764 pub publicity: Publicity, 765 pub name: EcoString, 766 pub name_location: SrcSpan, 767 pub annotation: Option<TypeAst>, 768 pub value: Box<Constant<T, ConstantRecordTag>>, 769 pub type_: T, 770 pub deprecation: Deprecation, 771 pub implementations: Implementations, 772} 773 774pub type UntypedCustomType = CustomType<()>; 775pub type TypedCustomType = CustomType<Arc<Type>>; 776 777#[derive(Debug, Clone, PartialEq, Eq)] 778/// A newly defined type with one or more constructors. 779/// Each variant of the custom type can contain different types, so the type is 780/// the product of the types contained by each variant. 781/// 782/// This might be called an algebraic data type (ADT) or tagged union in other 783/// languages and type systems. 784/// 785/// 786/// # Example(s) 787/// 788/// ```gleam 789/// pub type Cat { 790/// Cat(name: String, cuteness: Int) 791/// } 792/// ``` 793pub struct CustomType<T> { 794 pub location: SrcSpan, 795 pub end_position: u32, 796 pub name: EcoString, 797 pub name_location: SrcSpan, 798 pub publicity: Publicity, 799 pub constructors: Vec<RecordConstructor<T>>, 800 pub documentation: Option<(u32, EcoString)>, 801 pub deprecation: Deprecation, 802 pub opaque: bool, 803 /// The names of the type parameters. 804 pub parameters: Vec<SpannedString>, 805 /// Once type checked this field will contain the type information for the 806 /// type parameters. 807 pub typed_parameters: Vec<T>, 808} 809 810impl<T> CustomType<T> { 811 /// The `location` field of a `CustomType` is only the location of `pub type 812 /// TheName`. This method returns a `SrcSpan` that includes the entire type 813 /// definition. 814 pub fn full_location(&self) -> SrcSpan { 815 SrcSpan::new(self.location.start, self.end_position) 816 } 817} 818 819pub type UntypedTypeAlias = TypeAlias<()>; 820 821#[derive(Debug, Clone, PartialEq, Eq)] 822/// A new name for an existing type 823/// 824/// # Example(s) 825/// 826/// ```gleam 827/// pub type Headers = 828/// List(#(String, String)) 829/// ``` 830pub struct TypeAlias<T> { 831 pub location: SrcSpan, 832 pub alias: EcoString, 833 pub name_location: SrcSpan, 834 pub parameters: Vec<SpannedString>, 835 pub type_ast: TypeAst, 836 pub type_: T, 837 pub publicity: Publicity, 838 pub documentation: Option<(u32, EcoString)>, 839 pub deprecation: Deprecation, 840} 841 842pub type TypedDefinition = Definition<Arc<Type>, TypedExpr, EcoString, EcoString>; 843pub type UntypedDefinition = Definition<(), UntypedExpr, (), ()>; 844 845#[derive(Debug, Clone, PartialEq, Eq)] 846pub enum Definition<T, Expr, ConstantRecordTag, PackageName> { 847 Function(Function<T, Expr>), 848 849 TypeAlias(TypeAlias<T>), 850 851 CustomType(CustomType<T>), 852 853 Import(Import<PackageName>), 854 855 ModuleConstant(ModuleConstant<T, ConstantRecordTag>), 856} 857 858impl TypedDefinition { 859 pub fn main_function(&self) -> Option<&TypedFunction> { 860 match self { 861 Definition::Function(f) if f.name.as_ref().is_some_and(|(_, name)| name == "main") => { 862 Some(f) 863 } 864 _ => None, 865 } 866 } 867 868 pub fn find_node(&self, byte_index: u32) -> Option<Located<'_>> { 869 match self { 870 Definition::Function(function) => { 871 // Search for the corresponding node inside the function 872 // only if the index falls within the function's full location. 873 if !function.full_location().contains(byte_index) { 874 return None; 875 } 876 877 if let Some(found) = function.body.iter().find_map(|s| s.find_node(byte_index)) { 878 return Some(found); 879 } 880 881 if let Some(found_arg) = function 882 .arguments 883 .iter() 884 .find_map(|arg| arg.find_node(byte_index)) 885 { 886 return Some(found_arg); 887 }; 888 889 if let Some(found_statement) = function 890 .body 891 .iter() 892 .find(|statement| statement.location().contains(byte_index)) 893 { 894 return Some(Located::Statement(found_statement)); 895 }; 896 897 // Check if location is within the return annotation. 898 if let Some(l) = function 899 .return_annotation 900 .iter() 901 .find_map(|a| a.find_node(byte_index, function.return_type.clone())) 902 { 903 return Some(l); 904 }; 905 906 // Note that the fn `.location` covers the function head, not 907 // the entire statement. 908 if function.location.contains(byte_index) { 909 Some(Located::ModuleStatement(self)) 910 } else if function.full_location().contains(byte_index) { 911 Some(Located::FunctionBody(function)) 912 } else { 913 None 914 } 915 } 916 917 Definition::CustomType(custom) => { 918 // Check if location is within the type of one of the arguments of a constructor. 919 if let Some(constructor) = custom 920 .constructors 921 .iter() 922 .find(|constructor| constructor.location.contains(byte_index)) 923 { 924 if let Some(annotation) = constructor 925 .arguments 926 .iter() 927 .find(|arg| arg.location.contains(byte_index)) 928 .and_then(|arg| arg.ast.find_node(byte_index, arg.type_.clone())) 929 { 930 return Some(annotation); 931 } 932 933 return Some(Located::VariantConstructorDefinition(constructor)); 934 } 935 936 // Note that the custom type `.location` covers the function 937 // head, not the entire statement. 938 if custom.full_location().contains(byte_index) { 939 Some(Located::ModuleStatement(self)) 940 } else { 941 None 942 } 943 } 944 945 Definition::TypeAlias(alias) => { 946 // Check if location is within the type being aliased. 947 if let Some(l) = alias.type_ast.find_node(byte_index, alias.type_.clone()) { 948 return Some(l); 949 } 950 951 if alias.location.contains(byte_index) { 952 Some(Located::ModuleStatement(self)) 953 } else { 954 None 955 } 956 } 957 958 Definition::ModuleConstant(constant) => { 959 // Check if location is within the annotation. 960 if let Some(annotation) = &constant.annotation { 961 if let Some(l) = annotation.find_node(byte_index, constant.type_.clone()) { 962 return Some(l); 963 } 964 } 965 966 if let Some(located) = constant.value.find_node(byte_index) { 967 return Some(located); 968 } 969 970 if constant.location.contains(byte_index) { 971 Some(Located::ModuleStatement(self)) 972 } else { 973 None 974 } 975 } 976 977 Definition::Import(import) => { 978 if self.location().contains(byte_index) { 979 if let Some(unqualified) = import 980 .unqualified_values 981 .iter() 982 .find(|i| i.location.contains(byte_index)) 983 { 984 return Some(Located::UnqualifiedImport( 985 crate::build::UnqualifiedImport { 986 name: &unqualified.name, 987 module: &import.module, 988 is_type: false, 989 location: &unqualified.location, 990 }, 991 )); 992 } 993 994 if let Some(unqualified) = import 995 .unqualified_types 996 .iter() 997 .find(|i| i.location.contains(byte_index)) 998 { 999 return Some(Located::UnqualifiedImport( 1000 crate::build::UnqualifiedImport { 1001 name: &unqualified.name, 1002 module: &import.module, 1003 is_type: true, 1004 location: &unqualified.location, 1005 }, 1006 )); 1007 } 1008 1009 Some(Located::ModuleStatement(self)) 1010 } else { 1011 None 1012 } 1013 } 1014 } 1015 } 1016 1017 pub fn find_statement(&self, byte_index: u32) -> Option<&TypedStatement> { 1018 match self { 1019 Definition::Function(function) => { 1020 if !function.full_location().contains(byte_index) { 1021 return None; 1022 } 1023 1024 function 1025 .body 1026 .iter() 1027 .find_map(|statement| statement.find_statement(byte_index)) 1028 } 1029 1030 _ => None, 1031 } 1032 } 1033} 1034 1035impl<A, B, C, E> Definition<A, B, C, E> { 1036 pub fn location(&self) -> SrcSpan { 1037 match self { 1038 Definition::Function(Function { location, .. }) 1039 | Definition::Import(Import { location, .. }) 1040 | Definition::TypeAlias(TypeAlias { location, .. }) 1041 | Definition::CustomType(CustomType { location, .. }) 1042 | Definition::ModuleConstant(ModuleConstant { location, .. }) => *location, 1043 } 1044 } 1045 1046 /// Returns `true` if the definition is [`Import`]. 1047 /// 1048 /// [`Import`]: Definition::Import 1049 #[must_use] 1050 pub fn is_import(&self) -> bool { 1051 matches!(self, Self::Import(..)) 1052 } 1053 1054 /// Returns `true` if the module statement is [`Function`]. 1055 /// 1056 /// [`Function`]: ModuleStatement::Function 1057 #[must_use] 1058 pub fn is_function(&self) -> bool { 1059 matches!(self, Self::Function(..)) 1060 } 1061 1062 pub fn put_doc(&mut self, new_doc: (u32, EcoString)) { 1063 match self { 1064 Definition::Import(Import { .. }) => (), 1065 1066 Definition::Function(Function { documentation, .. }) 1067 | Definition::TypeAlias(TypeAlias { documentation, .. }) 1068 | Definition::CustomType(CustomType { documentation, .. }) 1069 | Definition::ModuleConstant(ModuleConstant { documentation, .. }) => { 1070 let _ = documentation.replace(new_doc); 1071 } 1072 } 1073 } 1074 1075 pub fn get_doc(&self) -> Option<EcoString> { 1076 match self { 1077 Definition::Import(Import { .. }) => None, 1078 1079 Definition::Function(Function { 1080 documentation: doc, .. 1081 }) 1082 | Definition::TypeAlias(TypeAlias { 1083 documentation: doc, .. 1084 }) 1085 | Definition::CustomType(CustomType { 1086 documentation: doc, .. 1087 }) 1088 | Definition::ModuleConstant(ModuleConstant { 1089 documentation: doc, .. 1090 }) => doc.as_ref().map(|(_, doc)| doc.clone()), 1091 } 1092 } 1093 1094 pub fn is_internal(&self) -> bool { 1095 match self { 1096 Definition::Function(Function { publicity, .. }) 1097 | Definition::CustomType(CustomType { publicity, .. }) 1098 | Definition::ModuleConstant(ModuleConstant { publicity, .. }) 1099 | Definition::TypeAlias(TypeAlias { publicity, .. }) => publicity.is_internal(), 1100 1101 Definition::Import(_) => false, 1102 } 1103 } 1104} 1105 1106#[derive(Debug, Clone, PartialEq, Eq)] 1107pub struct UnqualifiedImport { 1108 pub location: SrcSpan, 1109 /// The location excluding the potential `as ...` clause, or the `type` keyword 1110 pub imported_name_location: SrcSpan, 1111 pub name: EcoString, 1112 pub as_name: Option<EcoString>, 1113} 1114 1115impl UnqualifiedImport { 1116 pub fn used_name(&self) -> &EcoString { 1117 self.as_name.as_ref().unwrap_or(&self.name) 1118 } 1119} 1120 1121#[derive(Debug, Clone, PartialEq, Eq, Copy, Default, serde::Serialize, serde::Deserialize)] 1122pub enum Layer { 1123 #[default] 1124 Value, 1125 Type, 1126} 1127 1128impl Layer { 1129 /// Returns `true` if the layer is [`Value`]. 1130 pub fn is_value(&self) -> bool { 1131 matches!(self, Self::Value) 1132 } 1133} 1134 1135#[derive(Debug, Clone, Copy, PartialEq, Eq)] 1136pub enum BinOp { 1137 // Boolean logic 1138 And, 1139 Or, 1140 1141 // Equality 1142 Eq, 1143 NotEq, 1144 1145 // Order comparison 1146 LtInt, 1147 LtEqInt, 1148 LtFloat, 1149 LtEqFloat, 1150 GtEqInt, 1151 GtInt, 1152 GtEqFloat, 1153 GtFloat, 1154 1155 // Maths 1156 AddInt, 1157 AddFloat, 1158 SubInt, 1159 SubFloat, 1160 MultInt, 1161 MultFloat, 1162 DivInt, 1163 DivFloat, 1164 RemainderInt, 1165 1166 // Strings 1167 Concatenate, 1168} 1169 1170#[derive(Clone, Copy, Debug, PartialEq)] 1171pub enum OperatorKind { 1172 BooleanLogic, 1173 Equality, 1174 IntComparison, 1175 FLoatComparison, 1176 IntMath, 1177 FloatMath, 1178 StringConcatenation, 1179} 1180 1181pub const PIPE_PRECEDENCE: u8 = 6; 1182 1183impl BinOp { 1184 pub fn precedence(&self) -> u8 { 1185 // Ensure that this matches the other precedence function for guards 1186 match self { 1187 Self::Or => 1, 1188 1189 Self::And => 2, 1190 1191 Self::Eq | Self::NotEq => 3, 1192 1193 Self::LtInt 1194 | Self::LtEqInt 1195 | Self::LtFloat 1196 | Self::LtEqFloat 1197 | Self::GtEqInt 1198 | Self::GtInt 1199 | Self::GtEqFloat 1200 | Self::GtFloat => 4, 1201 1202 Self::Concatenate => 5, 1203 1204 // Pipe is 6 1205 Self::AddInt | Self::AddFloat | Self::SubInt | Self::SubFloat => 7, 1206 1207 Self::MultInt 1208 | Self::MultFloat 1209 | Self::DivInt 1210 | Self::DivFloat 1211 | Self::RemainderInt => 8, 1212 } 1213 } 1214 1215 pub fn name(&self) -> &'static str { 1216 match self { 1217 Self::And => "&&", 1218 Self::Or => "||", 1219 Self::LtInt => "<", 1220 Self::LtEqInt => "<=", 1221 Self::LtFloat => "<.", 1222 Self::LtEqFloat => "<=.", 1223 Self::Eq => "==", 1224 Self::NotEq => "!=", 1225 Self::GtEqInt => ">=", 1226 Self::GtInt => ">", 1227 Self::GtEqFloat => ">=.", 1228 Self::GtFloat => ">.", 1229 Self::AddInt => "+", 1230 Self::AddFloat => "+.", 1231 Self::SubInt => "-", 1232 Self::SubFloat => "-.", 1233 Self::MultInt => "*", 1234 Self::MultFloat => "*.", 1235 Self::DivInt => "/", 1236 Self::DivFloat => "/.", 1237 Self::RemainderInt => "%", 1238 Self::Concatenate => "<>", 1239 } 1240 } 1241 1242 pub fn operator_kind(&self) -> OperatorKind { 1243 match self { 1244 Self::Concatenate => OperatorKind::StringConcatenation, 1245 Self::Eq | Self::NotEq => OperatorKind::Equality, 1246 Self::And | Self::Or => OperatorKind::BooleanLogic, 1247 Self::LtInt | Self::LtEqInt | Self::GtEqInt | Self::GtInt => { 1248 OperatorKind::IntComparison 1249 } 1250 Self::LtFloat | Self::LtEqFloat | Self::GtEqFloat | Self::GtFloat => { 1251 OperatorKind::FLoatComparison 1252 } 1253 Self::AddInt | Self::SubInt | Self::MultInt | Self::RemainderInt | Self::DivInt => { 1254 OperatorKind::IntMath 1255 } 1256 Self::AddFloat | Self::SubFloat | Self::MultFloat | Self::DivFloat => { 1257 OperatorKind::FloatMath 1258 } 1259 } 1260 } 1261 1262 pub fn can_be_grouped_with(&self, other: &BinOp) -> bool { 1263 self.operator_kind() == other.operator_kind() 1264 } 1265 1266 pub(crate) fn is_float_operator(&self) -> bool { 1267 match self { 1268 BinOp::LtFloat 1269 | BinOp::LtEqFloat 1270 | BinOp::GtEqFloat 1271 | BinOp::GtFloat 1272 | BinOp::AddFloat 1273 | BinOp::SubFloat 1274 | BinOp::MultFloat 1275 | BinOp::DivFloat => true, 1276 1277 BinOp::And 1278 | BinOp::Or 1279 | BinOp::Eq 1280 | BinOp::NotEq 1281 | BinOp::LtInt 1282 | BinOp::LtEqInt 1283 | BinOp::GtEqInt 1284 | BinOp::GtInt 1285 | BinOp::AddInt 1286 | BinOp::SubInt 1287 | BinOp::MultInt 1288 | BinOp::DivInt 1289 | BinOp::RemainderInt 1290 | BinOp::Concatenate => false, 1291 } 1292 } 1293 1294 fn is_bool_operator(&self) -> bool { 1295 match self { 1296 BinOp::And | BinOp::Or => true, 1297 _ => false, 1298 } 1299 } 1300 1301 pub(crate) fn is_int_operator(&self) -> bool { 1302 match self { 1303 BinOp::LtInt 1304 | BinOp::LtEqInt 1305 | BinOp::GtEqInt 1306 | BinOp::GtInt 1307 | BinOp::AddInt 1308 | BinOp::SubInt 1309 | BinOp::MultInt 1310 | BinOp::DivInt 1311 | BinOp::RemainderInt => true, 1312 1313 BinOp::And 1314 | BinOp::Or 1315 | BinOp::Eq 1316 | BinOp::NotEq 1317 | BinOp::LtFloat 1318 | BinOp::LtEqFloat 1319 | BinOp::GtEqFloat 1320 | BinOp::GtFloat 1321 | BinOp::AddFloat 1322 | BinOp::SubFloat 1323 | BinOp::MultFloat 1324 | BinOp::DivFloat 1325 | BinOp::Concatenate => false, 1326 } 1327 } 1328 1329 pub fn float_equivalent(&self) -> Option<BinOp> { 1330 match self { 1331 BinOp::LtInt => Some(BinOp::LtFloat), 1332 BinOp::LtEqInt => Some(BinOp::LtEqFloat), 1333 BinOp::GtEqInt => Some(BinOp::GtEqFloat), 1334 BinOp::GtInt => Some(BinOp::GtFloat), 1335 BinOp::AddInt => Some(BinOp::AddFloat), 1336 BinOp::SubInt => Some(BinOp::SubFloat), 1337 BinOp::MultInt => Some(BinOp::MultFloat), 1338 BinOp::DivInt => Some(BinOp::DivFloat), 1339 _ => None, 1340 } 1341 } 1342 1343 pub fn int_equivalent(&self) -> Option<BinOp> { 1344 match self { 1345 BinOp::LtFloat => Some(BinOp::LtInt), 1346 BinOp::LtEqFloat => Some(BinOp::LtEqInt), 1347 BinOp::GtEqFloat => Some(BinOp::GtEqInt), 1348 BinOp::GtFloat => Some(BinOp::GtInt), 1349 BinOp::AddFloat => Some(BinOp::AddInt), 1350 BinOp::SubFloat => Some(BinOp::SubInt), 1351 BinOp::MultFloat => Some(BinOp::MultInt), 1352 BinOp::DivFloat => Some(BinOp::DivInt), 1353 _ => None, 1354 } 1355 } 1356} 1357 1358#[derive(Debug, PartialEq, Eq, Clone)] 1359pub struct CallArg<A> { 1360 pub label: Option<EcoString>, 1361 pub location: SrcSpan, 1362 pub value: A, 1363 pub implicit: Option<ImplicitCallArgOrigin>, 1364} 1365 1366#[derive(Debug, PartialEq, Eq, Clone, Copy)] 1367pub enum ImplicitCallArgOrigin { 1368 /// The implicit callback argument passed as the last argument to the 1369 /// function on the right hand side of `use`. 1370 /// 1371 Use, 1372 /// An argument added by the compiler when rewriting a pipe `left |> right`. 1373 /// 1374 Pipe, 1375 /// An argument added by the compiler to fill in all the missing fields of a 1376 /// record that are being ignored with the `..` syntax. 1377 /// 1378 PatternFieldSpread, 1379 /// An argument used to fill in the missing args when a function on the 1380 /// right hand side of `use` is being called with the wrong arity. 1381 /// 1382 IncorrectArityUse, 1383 /// An argument adde by the compiler to fill in the missing args when using 1384 /// the record update synax. 1385 /// 1386 RecordUpdate, 1387} 1388 1389impl<A> CallArg<A> { 1390 #[must_use] 1391 pub fn is_implicit(&self) -> bool { 1392 self.implicit.is_some() 1393 } 1394 1395 #[must_use] 1396 pub fn is_use_implicit_callback(&self) -> bool { 1397 match self.implicit { 1398 Some(ImplicitCallArgOrigin::Use | ImplicitCallArgOrigin::IncorrectArityUse) => true, 1399 Some(_) | None => false, 1400 } 1401 } 1402} 1403 1404impl CallArg<TypedExpr> { 1405 pub fn find_node<'a>( 1406 &'a self, 1407 byte_index: u32, 1408 called_function: &'a TypedExpr, 1409 function_arguments: &'a [TypedCallArg], 1410 ) -> Option<Located<'a>> { 1411 match (self.implicit, &self.value) { 1412 // If a call argument is the implicit use callback then we don't 1413 // want to look at its arguments and body but we don't want to 1414 // return the whole anonymous function if anything else doesn't 1415 // match. 1416 // 1417 // In addition, if the callback is invalid because it couldn't be 1418 // typed, we don't want to return it as it would make it hard for 1419 // the LSP to give any suggestions on the use function being typed. 1420 // 1421 (Some(ImplicitCallArgOrigin::Use), TypedExpr::Invalid { .. }) => None, 1422 // So the code below is exactly the same as 1423 // `TypedExpr::Fn{}.find_node()` except we do not return self as a 1424 // fallback. 1425 // 1426 (Some(ImplicitCallArgOrigin::Use), TypedExpr::Fn { args, body, .. }) => args 1427 .iter() 1428 .find_map(|arg| arg.find_node(byte_index)) 1429 .or_else(|| body.iter().find_map(|s| s.find_node(byte_index))), 1430 // In all other cases we're happy with the default behaviour. 1431 // 1432 _ => match self.value.find_node(byte_index) { 1433 Some(Located::Expression { expression, .. }) 1434 // This is only possibly a label if we are at the end of the expression 1435 // (so not in the middle like `[abc|]`) and if this argument doesn't 1436 // already have a label. 1437 if byte_index == self.value.location().end && self.label.is_none() => 1438 { 1439 Some(Located::Expression { 1440 expression, 1441 position: ExpressionPosition::ArgumentOrLabel { 1442 called_function, 1443 function_arguments, 1444 }, 1445 }) 1446 } 1447 Some(located) => Some(located), 1448 None => { 1449 if self.location.contains(byte_index) && self.label.is_some() { 1450 Some(Located::Label(self.location, self.value.type_())) 1451 } else { 1452 None 1453 } 1454 } 1455 }, 1456 } 1457 } 1458 1459 pub fn find_statement(&self, byte_index: u32) -> Option<&TypedStatement> { 1460 match (self.implicit, &self.value) { 1461 (Some(ImplicitCallArgOrigin::Use), TypedExpr::Invalid { .. }) => None, 1462 (Some(ImplicitCallArgOrigin::Use), TypedExpr::Fn { body, .. }) => { 1463 body.iter().find_map(|s| s.find_statement(byte_index)) 1464 } 1465 1466 _ => self.value.find_statement(byte_index), 1467 } 1468 } 1469 1470 pub fn is_capture_hole(&self) -> bool { 1471 match &self.value { 1472 TypedExpr::Var { name, .. } => name == CAPTURE_VARIABLE, 1473 _ => false, 1474 } 1475 } 1476} 1477 1478impl CallArg<TypedPattern> { 1479 pub fn find_node(&self, byte_index: u32) -> Option<Located<'_>> { 1480 match self.value.find_node(byte_index) { 1481 Some(located) => Some(located), 1482 _ => { 1483 if self.location.contains(byte_index) && self.label.is_some() { 1484 Some(Located::Label(self.location, self.value.type_())) 1485 } else { 1486 None 1487 } 1488 } 1489 } 1490 } 1491} 1492 1493impl CallArg<TypedConstant> { 1494 pub fn find_node(&self, byte_index: u32) -> Option<Located<'_>> { 1495 match self.value.find_node(byte_index) { 1496 Some(located) => Some(located), 1497 _ => { 1498 if self.location.contains(byte_index) && self.label.is_some() { 1499 Some(Located::Label(self.location, self.value.type_())) 1500 } else { 1501 None 1502 } 1503 } 1504 } 1505 } 1506} 1507 1508impl CallArg<UntypedExpr> { 1509 pub fn is_capture_hole(&self) -> bool { 1510 match &self.value { 1511 UntypedExpr::Var { name, .. } => name == CAPTURE_VARIABLE, 1512 _ => false, 1513 } 1514 } 1515} 1516 1517impl<T> CallArg<T> 1518where 1519 T: HasLocation, 1520{ 1521 #[must_use] 1522 pub fn uses_label_shorthand(&self) -> bool { 1523 self.label.is_some() && self.location == self.value.location() 1524 } 1525} 1526 1527impl<T> HasLocation for CallArg<T> { 1528 fn location(&self) -> SrcSpan { 1529 self.location 1530 } 1531} 1532 1533#[derive(Debug, Clone, PartialEq, Eq)] 1534pub struct RecordBeingUpdated { 1535 pub base: Box<UntypedExpr>, 1536 pub location: SrcSpan, 1537} 1538 1539#[derive(Debug, Clone, PartialEq, Eq)] 1540pub struct UntypedRecordUpdateArg { 1541 pub label: EcoString, 1542 pub location: SrcSpan, 1543 pub value: UntypedExpr, 1544} 1545 1546impl UntypedRecordUpdateArg { 1547 #[must_use] 1548 pub fn uses_label_shorthand(&self) -> bool { 1549 self.value.location() == self.location 1550 } 1551} 1552 1553impl HasLocation for UntypedRecordUpdateArg { 1554 fn location(&self) -> SrcSpan { 1555 self.location 1556 } 1557} 1558 1559pub type MultiPattern<Type> = Vec<Pattern<Type>>; 1560 1561pub type UntypedMultiPattern = MultiPattern<()>; 1562pub type TypedMultiPattern = MultiPattern<Arc<Type>>; 1563 1564pub type TypedClause = Clause<TypedExpr, Arc<Type>, EcoString>; 1565 1566pub type UntypedClause = Clause<UntypedExpr, (), ()>; 1567 1568#[derive(Debug, Clone, PartialEq, Eq)] 1569pub struct Clause<Expr, Type, RecordTag> { 1570 pub location: SrcSpan, 1571 pub pattern: MultiPattern<Type>, 1572 pub alternative_patterns: Vec<MultiPattern<Type>>, 1573 pub guard: Option<ClauseGuard<Type, RecordTag>>, 1574 pub then: Expr, 1575} 1576 1577impl<A, B, C> Clause<A, B, C> { 1578 pub fn pattern_count(&self) -> usize { 1579 1 + self.alternative_patterns.len() 1580 } 1581} 1582 1583impl TypedClause { 1584 pub fn location(&self) -> SrcSpan { 1585 SrcSpan { 1586 start: self 1587 .pattern 1588 .first() 1589 .map(|p| p.location().start) 1590 .unwrap_or_default(), 1591 end: self.then.location().end, 1592 } 1593 } 1594 1595 pub fn find_node(&self, byte_index: u32) -> Option<Located<'_>> { 1596 self.pattern 1597 .iter() 1598 .find_map(|p| p.find_node(byte_index)) 1599 .or_else(|| self.then.find_node(byte_index)) 1600 } 1601 1602 pub fn pattern_location(&self) -> SrcSpan { 1603 let start = self.pattern.first().map(|pattern| pattern.location().start); 1604 1605 let end = if let Some(last_pattern) = self 1606 .alternative_patterns 1607 .last() 1608 .and_then(|patterns| patterns.last()) 1609 { 1610 Some(last_pattern.location().end) 1611 } else { 1612 self.pattern.last().map(|pattern| pattern.location().end) 1613 }; 1614 1615 SrcSpan::new(start.unwrap_or_default(), end.unwrap_or_default()) 1616 } 1617} 1618 1619pub type UntypedClauseGuard = ClauseGuard<(), ()>; 1620pub type TypedClauseGuard = ClauseGuard<Arc<Type>, EcoString>; 1621 1622#[derive(Debug, Clone, PartialEq, Eq)] 1623pub enum ClauseGuard<Type, RecordTag> { 1624 Equals { 1625 location: SrcSpan, 1626 left: Box<Self>, 1627 right: Box<Self>, 1628 }, 1629 1630 NotEquals { 1631 location: SrcSpan, 1632 left: Box<Self>, 1633 right: Box<Self>, 1634 }, 1635 1636 GtInt { 1637 location: SrcSpan, 1638 left: Box<Self>, 1639 right: Box<Self>, 1640 }, 1641 1642 GtEqInt { 1643 location: SrcSpan, 1644 left: Box<Self>, 1645 right: Box<Self>, 1646 }, 1647 1648 LtInt { 1649 location: SrcSpan, 1650 left: Box<Self>, 1651 right: Box<Self>, 1652 }, 1653 1654 LtEqInt { 1655 location: SrcSpan, 1656 left: Box<Self>, 1657 right: Box<Self>, 1658 }, 1659 1660 GtFloat { 1661 location: SrcSpan, 1662 left: Box<Self>, 1663 right: Box<Self>, 1664 }, 1665 1666 GtEqFloat { 1667 location: SrcSpan, 1668 left: Box<Self>, 1669 right: Box<Self>, 1670 }, 1671 1672 LtFloat { 1673 location: SrcSpan, 1674 left: Box<Self>, 1675 right: Box<Self>, 1676 }, 1677 1678 LtEqFloat { 1679 location: SrcSpan, 1680 left: Box<Self>, 1681 right: Box<Self>, 1682 }, 1683 1684 AddInt { 1685 location: SrcSpan, 1686 left: Box<Self>, 1687 right: Box<Self>, 1688 }, 1689 1690 AddFloat { 1691 location: SrcSpan, 1692 left: Box<Self>, 1693 right: Box<Self>, 1694 }, 1695 1696 SubInt { 1697 location: SrcSpan, 1698 left: Box<Self>, 1699 right: Box<Self>, 1700 }, 1701 1702 SubFloat { 1703 location: SrcSpan, 1704 left: Box<Self>, 1705 right: Box<Self>, 1706 }, 1707 1708 MultInt { 1709 location: SrcSpan, 1710 left: Box<Self>, 1711 right: Box<Self>, 1712 }, 1713 1714 MultFloat { 1715 location: SrcSpan, 1716 left: Box<Self>, 1717 right: Box<Self>, 1718 }, 1719 1720 DivInt { 1721 location: SrcSpan, 1722 left: Box<Self>, 1723 right: Box<Self>, 1724 }, 1725 1726 DivFloat { 1727 location: SrcSpan, 1728 left: Box<Self>, 1729 right: Box<Self>, 1730 }, 1731 1732 RemainderInt { 1733 location: SrcSpan, 1734 left: Box<Self>, 1735 right: Box<Self>, 1736 }, 1737 1738 Or { 1739 location: SrcSpan, 1740 left: Box<Self>, 1741 right: Box<Self>, 1742 }, 1743 1744 And { 1745 location: SrcSpan, 1746 left: Box<Self>, 1747 right: Box<Self>, 1748 }, 1749 1750 Not { 1751 location: SrcSpan, 1752 expression: Box<Self>, 1753 }, 1754 1755 Var { 1756 location: SrcSpan, 1757 type_: Type, 1758 name: EcoString, 1759 definition_location: SrcSpan, 1760 }, 1761 1762 TupleIndex { 1763 location: SrcSpan, 1764 index: u64, 1765 type_: Type, 1766 tuple: Box<Self>, 1767 }, 1768 1769 FieldAccess { 1770 location: SrcSpan, 1771 index: Option<u64>, 1772 label: EcoString, 1773 type_: Type, 1774 container: Box<Self>, 1775 }, 1776 1777 ModuleSelect { 1778 location: SrcSpan, 1779 type_: Type, 1780 label: EcoString, 1781 module_name: EcoString, 1782 module_alias: EcoString, 1783 literal: Constant<Type, RecordTag>, 1784 }, 1785 1786 Constant(Constant<Type, RecordTag>), 1787} 1788 1789impl<A, B> ClauseGuard<A, B> { 1790 pub fn location(&self) -> SrcSpan { 1791 match self { 1792 ClauseGuard::Constant(constant) => constant.location(), 1793 ClauseGuard::Or { location, .. } 1794 | ClauseGuard::And { location, .. } 1795 | ClauseGuard::Not { location, .. } 1796 | ClauseGuard::Var { location, .. } 1797 | ClauseGuard::TupleIndex { location, .. } 1798 | ClauseGuard::Equals { location, .. } 1799 | ClauseGuard::NotEquals { location, .. } 1800 | ClauseGuard::GtInt { location, .. } 1801 | ClauseGuard::GtEqInt { location, .. } 1802 | ClauseGuard::LtInt { location, .. } 1803 | ClauseGuard::LtEqInt { location, .. } 1804 | ClauseGuard::GtFloat { location, .. } 1805 | ClauseGuard::GtEqFloat { location, .. } 1806 | ClauseGuard::LtFloat { location, .. } 1807 | ClauseGuard::AddInt { location, .. } 1808 | ClauseGuard::AddFloat { location, .. } 1809 | ClauseGuard::SubInt { location, .. } 1810 | ClauseGuard::SubFloat { location, .. } 1811 | ClauseGuard::MultInt { location, .. } 1812 | ClauseGuard::MultFloat { location, .. } 1813 | ClauseGuard::DivInt { location, .. } 1814 | ClauseGuard::DivFloat { location, .. } 1815 | ClauseGuard::RemainderInt { location, .. } 1816 | ClauseGuard::FieldAccess { location, .. } 1817 | ClauseGuard::LtEqFloat { location, .. } 1818 | ClauseGuard::ModuleSelect { location, .. } => *location, 1819 } 1820 } 1821 1822 pub fn precedence(&self) -> u8 { 1823 // Ensure that this matches the other precedence function for guards 1824 match self.bin_op_name() { 1825 Some(name) => name.precedence(), 1826 None => u8::MAX, 1827 } 1828 } 1829 1830 pub fn bin_op_name(&self) -> Option<BinOp> { 1831 match self { 1832 ClauseGuard::Or { .. } => Some(BinOp::Or), 1833 ClauseGuard::And { .. } => Some(BinOp::And), 1834 ClauseGuard::Equals { .. } => Some(BinOp::Eq), 1835 ClauseGuard::NotEquals { .. } => Some(BinOp::NotEq), 1836 ClauseGuard::GtInt { .. } => Some(BinOp::GtInt), 1837 ClauseGuard::GtEqInt { .. } => Some(BinOp::GtEqInt), 1838 ClauseGuard::LtInt { .. } => Some(BinOp::LtInt), 1839 ClauseGuard::LtEqInt { .. } => Some(BinOp::LtEqInt), 1840 ClauseGuard::GtFloat { .. } => Some(BinOp::GtFloat), 1841 ClauseGuard::GtEqFloat { .. } => Some(BinOp::GtEqFloat), 1842 ClauseGuard::LtFloat { .. } => Some(BinOp::LtFloat), 1843 ClauseGuard::LtEqFloat { .. } => Some(BinOp::LtEqFloat), 1844 ClauseGuard::AddInt { .. } => Some(BinOp::AddInt), 1845 ClauseGuard::AddFloat { .. } => Some(BinOp::AddFloat), 1846 ClauseGuard::SubInt { .. } => Some(BinOp::SubInt), 1847 ClauseGuard::SubFloat { .. } => Some(BinOp::SubFloat), 1848 ClauseGuard::MultInt { .. } => Some(BinOp::MultInt), 1849 ClauseGuard::MultFloat { .. } => Some(BinOp::MultFloat), 1850 ClauseGuard::DivInt { .. } => Some(BinOp::DivInt), 1851 ClauseGuard::DivFloat { .. } => Some(BinOp::DivFloat), 1852 ClauseGuard::RemainderInt { .. } => Some(BinOp::RemainderInt), 1853 1854 ClauseGuard::Constant(_) 1855 | ClauseGuard::Var { .. } 1856 | ClauseGuard::Not { .. } 1857 | ClauseGuard::TupleIndex { .. } 1858 | ClauseGuard::FieldAccess { .. } 1859 | ClauseGuard::ModuleSelect { .. } => None, 1860 } 1861 } 1862} 1863 1864impl TypedClauseGuard { 1865 pub fn type_(&self) -> Arc<Type> { 1866 match self { 1867 ClauseGuard::Var { type_, .. } => type_.clone(), 1868 ClauseGuard::TupleIndex { type_, .. } => type_.clone(), 1869 ClauseGuard::FieldAccess { type_, .. } => type_.clone(), 1870 ClauseGuard::ModuleSelect { type_, .. } => type_.clone(), 1871 ClauseGuard::Constant(constant) => constant.type_(), 1872 1873 ClauseGuard::AddInt { .. } 1874 | ClauseGuard::SubInt { .. } 1875 | ClauseGuard::MultInt { .. } 1876 | ClauseGuard::DivInt { .. } 1877 | ClauseGuard::RemainderInt { .. } => type_::int(), 1878 1879 ClauseGuard::AddFloat { .. } 1880 | ClauseGuard::SubFloat { .. } 1881 | ClauseGuard::MultFloat { .. } 1882 | ClauseGuard::DivFloat { .. } => type_::float(), 1883 1884 ClauseGuard::Or { .. } 1885 | ClauseGuard::Not { .. } 1886 | ClauseGuard::And { .. } 1887 | ClauseGuard::Equals { .. } 1888 | ClauseGuard::NotEquals { .. } 1889 | ClauseGuard::GtInt { .. } 1890 | ClauseGuard::GtEqInt { .. } 1891 | ClauseGuard::LtInt { .. } 1892 | ClauseGuard::LtEqInt { .. } 1893 | ClauseGuard::GtFloat { .. } 1894 | ClauseGuard::GtEqFloat { .. } 1895 | ClauseGuard::LtFloat { .. } 1896 | ClauseGuard::LtEqFloat { .. } => type_::bool(), 1897 } 1898 } 1899 1900 pub(crate) fn referenced_variables(&self) -> im::HashSet<&EcoString> { 1901 match self { 1902 ClauseGuard::Var { name, .. } => im::hashset![name], 1903 1904 ClauseGuard::Not { expression, .. } => expression.referenced_variables(), 1905 ClauseGuard::TupleIndex { tuple, .. } => tuple.referenced_variables(), 1906 ClauseGuard::FieldAccess { container, .. } => container.referenced_variables(), 1907 ClauseGuard::Constant(constant) => constant.referenced_variables(), 1908 ClauseGuard::ModuleSelect { .. } => im::HashSet::new(), 1909 1910 ClauseGuard::Equals { left, right, .. } 1911 | ClauseGuard::NotEquals { left, right, .. } 1912 | ClauseGuard::GtInt { left, right, .. } 1913 | ClauseGuard::GtEqInt { left, right, .. } 1914 | ClauseGuard::LtInt { left, right, .. } 1915 | ClauseGuard::LtEqInt { left, right, .. } 1916 | ClauseGuard::GtFloat { left, right, .. } 1917 | ClauseGuard::GtEqFloat { left, right, .. } 1918 | ClauseGuard::LtFloat { left, right, .. } 1919 | ClauseGuard::LtEqFloat { left, right, .. } 1920 | ClauseGuard::AddInt { left, right, .. } 1921 | ClauseGuard::AddFloat { left, right, .. } 1922 | ClauseGuard::SubInt { left, right, .. } 1923 | ClauseGuard::SubFloat { left, right, .. } 1924 | ClauseGuard::MultInt { left, right, .. } 1925 | ClauseGuard::MultFloat { left, right, .. } 1926 | ClauseGuard::DivInt { left, right, .. } 1927 | ClauseGuard::DivFloat { left, right, .. } 1928 | ClauseGuard::RemainderInt { left, right, .. } 1929 | ClauseGuard::And { left, right, .. } 1930 | ClauseGuard::Or { left, right, .. } => left 1931 .referenced_variables() 1932 .union(right.referenced_variables()), 1933 } 1934 } 1935} 1936 1937#[derive( 1938 Debug, 1939 PartialEq, 1940 Eq, 1941 PartialOrd, 1942 Ord, 1943 Default, 1944 Clone, 1945 Copy, 1946 serde::Serialize, 1947 serde::Deserialize, 1948)] 1949pub struct SrcSpan { 1950 pub start: u32, 1951 pub end: u32, 1952} 1953 1954impl SrcSpan { 1955 pub fn new(start: u32, end: u32) -> Self { 1956 Self { start, end } 1957 } 1958 1959 pub fn contains(&self, byte_index: u32) -> bool { 1960 byte_index >= self.start && byte_index <= self.end 1961 } 1962 1963 /// Merges two spans into a new one that starts at the start of the smaller 1964 /// one and ends at the end of the bigger one. For example: 1965 /// 1966 /// ```txt 1967 /// wibble wobble 1968 /// ─┬──── ─┬──── 1969 /// │ ╰─ one span 1970 /// ╰─ the other span 1971 /// ─┬────────────── 1972 /// ╰─ the span you get by merging the two 1973 /// ``` 1974 pub fn merge(&self, with: &SrcSpan) -> SrcSpan { 1975 Self { 1976 start: self.start.min(with.start), 1977 end: self.end.max(with.end), 1978 } 1979 } 1980} 1981 1982#[derive(Debug, PartialEq, Eq, Clone)] 1983pub struct DefinitionLocation { 1984 pub module: Option<EcoString>, 1985 pub span: SrcSpan, 1986} 1987 1988pub type UntypedPattern = Pattern<()>; 1989pub type TypedPattern = Pattern<Arc<Type>>; 1990 1991#[derive(Debug, Clone, PartialEq, Eq)] 1992pub enum Pattern<Type> { 1993 Int { 1994 location: SrcSpan, 1995 value: EcoString, 1996 int_value: BigInt, 1997 }, 1998 1999 Float { 2000 location: SrcSpan, 2001 value: EcoString, 2002 }, 2003 2004 String { 2005 location: SrcSpan, 2006 value: EcoString, 2007 }, 2008 2009 /// The creation of a variable. 2010 /// e.g. `assert [this_is_a_var, .._] = x` 2011 Variable { 2012 location: SrcSpan, 2013 name: EcoString, 2014 type_: Type, 2015 origin: VariableOrigin, 2016 }, 2017 2018 /// A reference to a variable in a bit array. This is always a variable 2019 /// being used rather than a new variable being assigned. 2020 /// e.g. `assert <<y:size(somevar)>> = x` 2021 VarUsage { 2022 location: SrcSpan, 2023 name: EcoString, 2024 constructor: Option<ValueConstructor>, 2025 type_: Type, 2026 }, 2027 2028 /// A name given to a sub-pattern using the `as` keyword. 2029 /// e.g. `assert #(1, [_, _] as the_list) = x` 2030 Assign { 2031 name: EcoString, 2032 location: SrcSpan, 2033 pattern: Box<Self>, 2034 }, 2035 2036 /// A pattern that binds to any value but does not assign a variable. 2037 /// Always starts with an underscore. 2038 Discard { 2039 name: EcoString, 2040 location: SrcSpan, 2041 type_: Type, 2042 }, 2043 2044 List { 2045 location: SrcSpan, 2046 elements: Vec<Self>, 2047 tail: Option<Box<Self>>, 2048 type_: Type, 2049 }, 2050 2051 /// The constructor for a custom type. Starts with an uppercase letter. 2052 Constructor { 2053 location: SrcSpan, 2054 name_location: SrcSpan, 2055 name: EcoString, 2056 arguments: Vec<CallArg<Self>>, 2057 module: Option<(EcoString, SrcSpan)>, 2058 constructor: Inferred<PatternConstructor>, 2059 spread: Option<SrcSpan>, 2060 type_: Type, 2061 }, 2062 2063 Tuple { 2064 location: SrcSpan, 2065 elements: Vec<Self>, 2066 }, 2067 2068 BitArray { 2069 location: SrcSpan, 2070 segments: Vec<BitArraySegment<Self, Type>>, 2071 }, 2072 2073 // "prefix" <> variable 2074 StringPrefix { 2075 location: SrcSpan, 2076 left_location: SrcSpan, 2077 left_side_assignment: Option<(EcoString, SrcSpan)>, 2078 right_location: SrcSpan, 2079 left_side_string: EcoString, 2080 /// The variable on the right hand side of the `<>`. 2081 right_side_assignment: AssignName, 2082 }, 2083 2084 /// A placeholder pattern used to allow module analysis to continue 2085 /// even when there are type errors. Should never end up in generated code. 2086 Invalid { 2087 location: SrcSpan, 2088 type_: Type, 2089 }, 2090} 2091 2092impl Default for Inferred<()> { 2093 fn default() -> Self { 2094 Self::Unknown 2095 } 2096} 2097 2098#[derive(Debug, Clone, PartialEq, Eq, Hash)] 2099pub enum AssignName { 2100 Variable(EcoString), 2101 Discard(EcoString), 2102} 2103 2104impl AssignName { 2105 pub fn name(&self) -> &EcoString { 2106 match self { 2107 AssignName::Variable(name) | AssignName::Discard(name) => name, 2108 } 2109 } 2110 2111 pub fn to_arg_names(self, location: SrcSpan) -> ArgNames { 2112 match self { 2113 AssignName::Variable(name) => ArgNames::Named { name, location }, 2114 AssignName::Discard(name) => ArgNames::Discard { name, location }, 2115 } 2116 } 2117 2118 pub fn assigned_name(&self) -> Option<&str> { 2119 match self { 2120 AssignName::Variable(name) => Some(name), 2121 AssignName::Discard(_) => None, 2122 } 2123 } 2124} 2125 2126impl<A> Pattern<A> { 2127 pub fn location(&self) -> SrcSpan { 2128 match self { 2129 Pattern::Assign { 2130 pattern, location, .. 2131 } => SrcSpan::new(pattern.location().start, location.end), 2132 Pattern::Int { location, .. } 2133 | Pattern::Variable { location, .. } 2134 | Pattern::VarUsage { location, .. } 2135 | Pattern::List { location, .. } 2136 | Pattern::Float { location, .. } 2137 | Pattern::Discard { location, .. } 2138 | Pattern::String { location, .. } 2139 | Pattern::Tuple { location, .. } 2140 | Pattern::Constructor { location, .. } 2141 | Pattern::StringPrefix { location, .. } 2142 | Pattern::BitArray { location, .. } 2143 | Pattern::Invalid { location, .. } => *location, 2144 } 2145 } 2146 2147 /// Returns `true` if the pattern is [`Discard`]. 2148 /// 2149 /// [`Discard`]: Pattern::Discard 2150 #[must_use] 2151 pub fn is_discard(&self) -> bool { 2152 matches!(self, Self::Discard { .. }) 2153 } 2154 2155 #[must_use] 2156 pub fn is_variable(&self) -> bool { 2157 match self { 2158 Pattern::Variable { .. } => true, 2159 _ => false, 2160 } 2161 } 2162 2163 #[must_use] 2164 pub fn is_string(&self) -> bool { 2165 matches!(self, Self::String { .. }) 2166 } 2167} 2168 2169impl TypedPattern { 2170 pub fn definition_location(&self) -> Option<DefinitionLocation> { 2171 match self { 2172 Pattern::Int { .. } 2173 | Pattern::Float { .. } 2174 | Pattern::String { .. } 2175 | Pattern::Variable { .. } 2176 | Pattern::VarUsage { .. } 2177 | Pattern::Assign { .. } 2178 | Pattern::Discard { .. } 2179 | Pattern::List { .. } 2180 | Pattern::Tuple { .. } 2181 | Pattern::BitArray { .. } 2182 | Pattern::StringPrefix { .. } 2183 | Pattern::Invalid { .. } => None, 2184 2185 Pattern::Constructor { constructor, .. } => constructor.definition_location(), 2186 } 2187 } 2188 2189 pub fn get_documentation(&self) -> Option<&str> { 2190 match self { 2191 Pattern::Int { .. } 2192 | Pattern::Float { .. } 2193 | Pattern::String { .. } 2194 | Pattern::Variable { .. } 2195 | Pattern::VarUsage { .. } 2196 | Pattern::Assign { .. } 2197 | Pattern::Discard { .. } 2198 | Pattern::List { .. } 2199 | Pattern::Tuple { .. } 2200 | Pattern::BitArray { .. } 2201 | Pattern::StringPrefix { .. } 2202 | Pattern::Invalid { .. } => None, 2203 2204 Pattern::Constructor { constructor, .. } => constructor.get_documentation(), 2205 } 2206 } 2207 2208 pub fn type_(&self) -> Arc<Type> { 2209 match self { 2210 Pattern::Int { .. } => type_::int(), 2211 Pattern::Float { .. } => type_::float(), 2212 Pattern::String { .. } => type_::string(), 2213 Pattern::BitArray { .. } => type_::bit_array(), 2214 Pattern::StringPrefix { .. } => type_::string(), 2215 2216 Pattern::Variable { type_, .. } 2217 | Pattern::List { type_, .. } 2218 | Pattern::VarUsage { type_, .. } 2219 | Pattern::Constructor { type_, .. } 2220 | Pattern::Invalid { type_, .. } => type_.clone(), 2221 2222 Pattern::Assign { pattern, .. } => pattern.type_(), 2223 2224 Pattern::Discard { type_, .. } => type_.clone(), 2225 2226 Pattern::Tuple { elements, .. } => { 2227 type_::tuple(elements.iter().map(|p| p.type_()).collect()) 2228 } 2229 } 2230 } 2231 2232 fn find_node(&self, byte_index: u32) -> Option<Located<'_>> { 2233 if !self.location().contains(byte_index) { 2234 return None; 2235 } 2236 2237 if let Pattern::Variable { name, .. } = self { 2238 // For pipes the pattern can't be pointed to 2239 if name.as_str().eq(PIPE_VARIABLE) { 2240 return None; 2241 } 2242 } 2243 2244 match self { 2245 Pattern::Int { .. } 2246 | Pattern::Float { .. } 2247 | Pattern::String { .. } 2248 | Pattern::Variable { .. } 2249 | Pattern::VarUsage { .. } 2250 | Pattern::Assign { .. } 2251 | Pattern::Discard { .. } 2252 | Pattern::StringPrefix { .. } 2253 | Pattern::Invalid { .. } => Some(Located::Pattern(self)), 2254 2255 Pattern::Constructor { 2256 arguments, spread, .. 2257 } => match spread { 2258 Some(spread_location) if spread_location.contains(byte_index) => { 2259 Some(Located::PatternSpread { 2260 spread_location: *spread_location, 2261 pattern: self, 2262 }) 2263 } 2264 2265 Some(_) | None => arguments.iter().find_map(|arg| arg.find_node(byte_index)), 2266 }, 2267 Pattern::List { elements, tail, .. } => elements 2268 .iter() 2269 .find_map(|p| p.find_node(byte_index)) 2270 .or_else(|| tail.as_ref().and_then(|p| p.find_node(byte_index))), 2271 2272 Pattern::Tuple { elements, .. } => { 2273 elements.iter().find_map(|p| p.find_node(byte_index)) 2274 } 2275 2276 Pattern::BitArray { segments, .. } => segments 2277 .iter() 2278 .find_map(|segment| segment.find_node(byte_index)) 2279 .or(Some(Located::Pattern(self))), 2280 } 2281 .or(Some(Located::Pattern(self))) 2282 } 2283 2284 /// If the pattern is a `Constructor` with a spread, it returns a tuple with 2285 /// all the ignored fields. Split in unlabelled and labelled ones. 2286 /// 2287 pub(crate) fn unused_arguments(&self) -> Option<PatternUnusedArguments> { 2288 let TypedPattern::Constructor { 2289 arguments, 2290 spread: Some(_), 2291 .. 2292 } = self 2293 else { 2294 return None; 2295 }; 2296 2297 let mut positional = vec![]; 2298 let mut labelled = vec![]; 2299 for argument in arguments { 2300 // We only want to display the arguments that were ignored using `..`. 2301 // Any argument ignored that way is marked as implicit, so if it is 2302 // not implicit we just ignore it. 2303 if !argument.is_implicit() { 2304 continue; 2305 } 2306 let type_ = argument.value.type_(); 2307 match &argument.label { 2308 Some(label) => labelled.push((label.clone(), type_)), 2309 None => positional.push(type_), 2310 } 2311 } 2312 2313 Some(PatternUnusedArguments { 2314 positional, 2315 labelled, 2316 }) 2317 } 2318 2319 /// Whether the pattern always matches. For example, a tuple or simple 2320 /// variable assignment always match and can never fail. 2321 #[must_use] 2322 pub fn always_matches(&self) -> bool { 2323 match self { 2324 Pattern::Variable { .. } | Pattern::Discard { .. } => true, 2325 Pattern::Assign { pattern, .. } => pattern.always_matches(), 2326 Pattern::Tuple { elements, .. } => { 2327 elements.iter().all(|element| element.always_matches()) 2328 } 2329 Pattern::Int { .. } 2330 | Pattern::Float { .. } 2331 | Pattern::String { .. } 2332 | Pattern::VarUsage { .. } 2333 | Pattern::List { .. } 2334 | Pattern::Constructor { .. } 2335 | Pattern::BitArray { .. } 2336 | Pattern::StringPrefix { .. } 2337 | Pattern::Invalid { .. } => false, 2338 } 2339 } 2340 2341 pub fn bound_variables(&self) -> Vec<EcoString> { 2342 let mut variables = Vec::new(); 2343 self.collect_bound_variables(&mut variables); 2344 variables 2345 } 2346 2347 fn collect_bound_variables(&self, variables: &mut Vec<EcoString>) { 2348 match self { 2349 Pattern::Int { .. } 2350 | Pattern::Float { .. } 2351 | Pattern::String { .. } 2352 | Pattern::Discard { .. } 2353 | Pattern::Invalid { .. } => {} 2354 2355 Pattern::Variable { name, .. } => variables.push(name.clone()), 2356 Pattern::VarUsage { .. } => {} 2357 Pattern::Assign { name, pattern, .. } => { 2358 variables.push(name.clone()); 2359 pattern.collect_bound_variables(variables); 2360 } 2361 Pattern::List { elements, tail, .. } => { 2362 for element in elements { 2363 element.collect_bound_variables(variables); 2364 } 2365 if let Some(tail) = tail { 2366 tail.collect_bound_variables(variables); 2367 } 2368 } 2369 Pattern::Constructor { arguments, .. } => { 2370 for argument in arguments { 2371 argument.value.collect_bound_variables(variables); 2372 } 2373 } 2374 Pattern::Tuple { elements, .. } => { 2375 for element in elements { 2376 element.collect_bound_variables(variables); 2377 } 2378 } 2379 Pattern::BitArray { segments, .. } => { 2380 for segment in segments { 2381 segment.value.collect_bound_variables(variables); 2382 } 2383 } 2384 Pattern::StringPrefix { 2385 left_side_assignment, 2386 right_side_assignment, 2387 .. 2388 } => { 2389 if let Some((left_variable, _)) = left_side_assignment { 2390 variables.push(left_variable.clone()); 2391 } 2392 match right_side_assignment { 2393 AssignName::Variable(name) => variables.push(name.clone()), 2394 AssignName::Discard(_) => {} 2395 } 2396 } 2397 } 2398 } 2399} 2400 2401#[derive(Debug, Default)] 2402pub struct PatternUnusedArguments { 2403 pub positional: Vec<Arc<Type>>, 2404 pub labelled: Vec<(EcoString, Arc<Type>)>, 2405} 2406 2407impl<A> HasLocation for Pattern<A> { 2408 fn location(&self) -> SrcSpan { 2409 self.location() 2410 } 2411} 2412 2413#[derive(Debug, Clone, PartialEq, Eq)] 2414pub enum AssignmentKind<Expression> { 2415 /// let x = ... 2416 Let, 2417 /// This is a let assignment generated by the compiler for intermediate variables 2418 /// needed by record updates and `use`. 2419 /// Like a regular `Let` assignment this can never fail. 2420 /// 2421 Generated, 2422 /// let assert x = ... 2423 Assert { 2424 /// The src byte span of the `let assert` 2425 /// 2426 /// ```gleam 2427 /// let assert Wibble = todo 2428 /// ^^^^^^^^^^ 2429 /// ``` 2430 location: SrcSpan, 2431 2432 /// The byte index of the start of `assert` 2433 /// 2434 /// ```gleam 2435 /// let assert Wibble = todo 2436 /// ^ 2437 /// ``` 2438 assert_keyword_start: u32, 2439 2440 /// The message given to the assertion: 2441 /// 2442 /// ```gleam 2443 /// let asset Ok(a) = something() as "This will never fail" 2444 /// ^^^^^^^^^^^^^^^^^^^^^^ 2445 /// ``` 2446 message: Option<Expression>, 2447 }, 2448} 2449 2450impl<Expression> AssignmentKind<Expression> { 2451 /// Returns `true` if the assignment kind is [`Assert`]. 2452 /// 2453 /// [`Assert`]: AssignmentKind::Assert 2454 #[must_use] 2455 pub fn is_assert(&self) -> bool { 2456 match self { 2457 Self::Assert { .. } => true, 2458 Self::Let | Self::Generated => false, 2459 } 2460 } 2461} 2462 2463// BitArrays 2464 2465pub type UntypedExprBitArraySegment = BitArraySegment<UntypedExpr, ()>; 2466pub type TypedExprBitArraySegment = BitArraySegment<TypedExpr, Arc<Type>>; 2467 2468pub type UntypedConstantBitArraySegment = BitArraySegment<UntypedConstant, ()>; 2469pub type TypedConstantBitArraySegment = BitArraySegment<TypedConstant, Arc<Type>>; 2470 2471pub type UntypedPatternBitArraySegment = BitArraySegment<UntypedPattern, ()>; 2472pub type TypedPatternBitArraySegment = BitArraySegment<TypedPattern, Arc<Type>>; 2473 2474#[derive(Debug, Clone, PartialEq, Eq)] 2475pub struct BitArraySegment<Value, Type> { 2476 pub location: SrcSpan, 2477 pub value: Box<Value>, 2478 pub options: Vec<BitArrayOption<Value>>, 2479 pub type_: Type, 2480} 2481 2482#[derive(Debug, PartialEq, Eq, Copy, Clone, Hash)] 2483pub enum Endianness { 2484 Big, 2485 Little, 2486} 2487 2488impl Endianness { 2489 pub fn is_big(&self) -> bool { 2490 *self == Endianness::Big 2491 } 2492} 2493 2494impl<Type> BitArraySegment<Pattern<Type>, Type> { 2495 /// Returns the value of the pattern unwrapping any assign pattern. 2496 /// 2497 pub fn value_unwrapping_assign(&self) -> &Pattern<Type> { 2498 match self.value.as_ref() { 2499 Pattern::Assign { pattern, .. } => pattern, 2500 Pattern::Int { .. } 2501 | Pattern::Float { .. } 2502 | Pattern::String { .. } 2503 | Pattern::Variable { .. } 2504 | Pattern::VarUsage { .. } 2505 | Pattern::Discard { .. } 2506 | Pattern::List { .. } 2507 | Pattern::Constructor { .. } 2508 | Pattern::Tuple { .. } 2509 | Pattern::BitArray { .. } 2510 | Pattern::StringPrefix { .. } 2511 | Pattern::Invalid { .. } => self.value.as_ref(), 2512 } 2513 } 2514} 2515 2516impl<Value, Type> BitArraySegment<Value, Type> { 2517 #[must_use] 2518 pub fn has_native_option(&self) -> bool { 2519 self.options 2520 .iter() 2521 .any(|x| matches!(x, BitArrayOption::Native { .. })) 2522 } 2523 2524 #[must_use] 2525 pub fn has_utf16_codepoint_option(&self) -> bool { 2526 self.options 2527 .iter() 2528 .any(|x| matches!(x, BitArrayOption::Utf16Codepoint { .. })) 2529 } 2530 2531 #[must_use] 2532 pub fn has_utf32_codepoint_option(&self) -> bool { 2533 self.options 2534 .iter() 2535 .any(|x| matches!(x, BitArrayOption::Utf32Codepoint { .. })) 2536 } 2537 2538 #[must_use] 2539 pub fn has_utf16_option(&self) -> bool { 2540 self.options 2541 .iter() 2542 .any(|x| matches!(x, BitArrayOption::Utf16 { .. })) 2543 } 2544 2545 #[must_use] 2546 pub fn has_utf32_option(&self) -> bool { 2547 self.options 2548 .iter() 2549 .any(|x| matches!(x, BitArrayOption::Utf32 { .. })) 2550 } 2551 2552 pub fn endianness(&self) -> Endianness { 2553 if self 2554 .options 2555 .iter() 2556 .any(|x| matches!(x, BitArrayOption::Little { .. })) 2557 { 2558 Endianness::Little 2559 } else { 2560 Endianness::Big 2561 } 2562 } 2563 2564 pub(crate) fn signed(&self) -> bool { 2565 self.options 2566 .iter() 2567 .any(|x| matches!(x, BitArrayOption::Signed { .. })) 2568 } 2569 2570 pub fn size(&self) -> Option<&Value> { 2571 self.options.iter().find_map(|x| match x { 2572 BitArrayOption::Size { value, .. } => Some(value.as_ref()), 2573 _ => None, 2574 }) 2575 } 2576 2577 pub fn unit(&self) -> u8 { 2578 self.options 2579 .iter() 2580 .find_map(|option| match option { 2581 BitArrayOption::Unit { value, .. } => Some(*value), 2582 BitArrayOption::Bytes { .. } => Some(8), 2583 _ => None, 2584 }) 2585 .unwrap_or(1) 2586 } 2587 2588 pub(crate) fn has_bits_option(&self) -> bool { 2589 self.options.iter().any(|option| match option { 2590 BitArrayOption::Bits { .. } => true, 2591 _ => false, 2592 }) 2593 } 2594 2595 pub(crate) fn has_bytes_option(&self) -> bool { 2596 self.options.iter().any(|option| match option { 2597 BitArrayOption::Bytes { .. } => true, 2598 _ => false, 2599 }) 2600 } 2601} 2602 2603impl<Value, Type> BitArraySegment<Value, Type> { 2604 #[must_use] 2605 pub(crate) fn has_type_option(&self) -> bool { 2606 self.options.iter().any(|option| option.is_type_option()) 2607 } 2608} 2609 2610impl TypedExprBitArraySegment { 2611 pub fn find_node(&self, byte_index: u32) -> Option<Located<'_>> { 2612 self.value.find_node(byte_index) 2613 } 2614} 2615 2616impl<TypedValue> BitArraySegment<TypedValue, Arc<Type>> 2617where 2618 TypedValue: HasType + HasLocation + Clone + bit_array::GetLiteralValue, 2619{ 2620 pub(crate) fn check_for_truncated_value(&self) -> Option<BitArraySegmentTruncation> { 2621 // Both the size and the value must be two compile-time known constants. 2622 let segment_bits = self.bits_size()?.to_i64()?; 2623 let literal_value = self.value.as_int_literal()?; 2624 if segment_bits <= 0 { 2625 return None; 2626 } 2627 2628 let safe_range = match literal_value.sign() { 2629 Sign::NoSign => return None, 2630 Sign::Minus => { 2631 (-(BigInt::one() << (segment_bits - 1))) 2632 ..((BigInt::one() << (segment_bits - 1)) - 1) 2633 } 2634 Sign::Plus => BigInt::ZERO..(BigInt::one() << segment_bits), 2635 }; 2636 2637 if !safe_range.contains(&literal_value) { 2638 Some(BitArraySegmentTruncation { 2639 truncated_value: literal_value.clone(), 2640 truncated_into: truncate(&literal_value, segment_bits), 2641 value_location: self.value.location(), 2642 segment_bits, 2643 }) 2644 } else { 2645 None 2646 } 2647 } 2648 2649 /// If the segment size is a compile-time known constant this returns the 2650 /// segment size in bits, taking the segment's unit into consideration! 2651 /// 2652 fn bits_size(&self) -> Option<BigInt> { 2653 let size = match self.size() { 2654 None if self.type_.is_int() => 8.into(), 2655 None => 64.into(), 2656 Some(value) => value.as_int_literal()?, 2657 }; 2658 2659 let unit = self.unit(); 2660 Some(size * unit) 2661 } 2662} 2663 2664/// As Björn said, when a value is smaller than the segment's size it will be 2665/// truncated, only taking the first `n` bits: 2666/// 2667/// > It will be silently truncated. In general, when storing value an integer 2668/// > `I` into a segment of size `N`, the actual value stored will be 2669/// > `I band ((1 bsl N) - 1)`. 2670/// 2671/// <https://erlangforums.com/t/what-happens-when-a-bit-array-segment-size-is-smaller-than-its-value/4650/2?u=giacomocavalieri> 2672/// 2673/// Thank you Björn! 2674/// 2675fn truncate(literal_value: &BigInt, segment_bits: i64) -> BigInt { 2676 literal_value & ((BigInt::one() << segment_bits) - BigInt::one()) 2677} 2678 2679#[derive(serde::Deserialize, serde::Serialize, Eq, PartialEq, Clone, Debug)] 2680pub struct BitArraySegmentTruncation { 2681 /// The value that would end up being truncated. 2682 pub truncated_value: BigInt, 2683 /// What the value would be truncated into. 2684 pub truncated_into: BigInt, 2685 /// The span of the segment's value being truncated. 2686 pub value_location: SrcSpan, 2687 /// The size of the segment. 2688 pub segment_bits: i64, 2689} 2690 2691impl TypedPatternBitArraySegment { 2692 pub fn find_node(&self, byte_index: u32) -> Option<Located<'_>> { 2693 self.value.find_node(byte_index).or_else(|| { 2694 self.options 2695 .iter() 2696 .find_map(|option| option.find_node(byte_index)) 2697 }) 2698 } 2699} 2700 2701impl TypedConstantBitArraySegment { 2702 pub fn find_node(&self, byte_index: u32) -> Option<Located<'_>> { 2703 self.value.find_node(byte_index).or_else(|| { 2704 self.options 2705 .iter() 2706 .find_map(|option| option.find_node(byte_index)) 2707 }) 2708 } 2709} 2710 2711pub type TypedConstantBitArraySegmentOption = BitArrayOption<TypedConstant>; 2712 2713#[derive(Debug, PartialEq, Eq, Clone)] 2714pub enum BitArrayOption<Value> { 2715 Bytes { 2716 location: SrcSpan, 2717 }, 2718 2719 Int { 2720 location: SrcSpan, 2721 }, 2722 2723 Float { 2724 location: SrcSpan, 2725 }, 2726 2727 Bits { 2728 location: SrcSpan, 2729 }, 2730 2731 Utf8 { 2732 location: SrcSpan, 2733 }, 2734 2735 Utf16 { 2736 location: SrcSpan, 2737 }, 2738 2739 Utf32 { 2740 location: SrcSpan, 2741 }, 2742 2743 Utf8Codepoint { 2744 location: SrcSpan, 2745 }, 2746 2747 Utf16Codepoint { 2748 location: SrcSpan, 2749 }, 2750 2751 Utf32Codepoint { 2752 location: SrcSpan, 2753 }, 2754 2755 Signed { 2756 location: SrcSpan, 2757 }, 2758 2759 Unsigned { 2760 location: SrcSpan, 2761 }, 2762 2763 Big { 2764 location: SrcSpan, 2765 }, 2766 2767 Little { 2768 location: SrcSpan, 2769 }, 2770 2771 Native { 2772 location: SrcSpan, 2773 }, 2774 2775 Size { 2776 location: SrcSpan, 2777 value: Box<Value>, 2778 short_form: bool, 2779 }, 2780 2781 Unit { 2782 location: SrcSpan, 2783 value: u8, 2784 }, 2785} 2786 2787impl<A> BitArrayOption<A> { 2788 pub fn value(&self) -> Option<&A> { 2789 match self { 2790 BitArrayOption::Size { value, .. } => Some(value), 2791 _ => None, 2792 } 2793 } 2794 2795 pub fn location(&self) -> SrcSpan { 2796 match self { 2797 BitArrayOption::Bytes { location } 2798 | BitArrayOption::Int { location } 2799 | BitArrayOption::Float { location } 2800 | BitArrayOption::Bits { location } 2801 | BitArrayOption::Utf8 { location } 2802 | BitArrayOption::Utf16 { location } 2803 | BitArrayOption::Utf32 { location } 2804 | BitArrayOption::Utf8Codepoint { location } 2805 | BitArrayOption::Utf16Codepoint { location } 2806 | BitArrayOption::Utf32Codepoint { location } 2807 | BitArrayOption::Signed { location } 2808 | BitArrayOption::Unsigned { location } 2809 | BitArrayOption::Big { location } 2810 | BitArrayOption::Little { location } 2811 | BitArrayOption::Native { location } 2812 | BitArrayOption::Size { location, .. } 2813 | BitArrayOption::Unit { location, .. } => *location, 2814 } 2815 } 2816 2817 pub fn label(&self) -> EcoString { 2818 match self { 2819 BitArrayOption::Bytes { .. } => "bytes".into(), 2820 BitArrayOption::Int { .. } => "int".into(), 2821 BitArrayOption::Float { .. } => "float".into(), 2822 BitArrayOption::Bits { .. } => "bits".into(), 2823 BitArrayOption::Utf8 { .. } => "utf8".into(), 2824 BitArrayOption::Utf16 { .. } => "utf16".into(), 2825 BitArrayOption::Utf32 { .. } => "utf32".into(), 2826 BitArrayOption::Utf8Codepoint { .. } => "utf8_codepoint".into(), 2827 BitArrayOption::Utf16Codepoint { .. } => "utf16_codepoint".into(), 2828 BitArrayOption::Utf32Codepoint { .. } => "utf32_codepoint".into(), 2829 BitArrayOption::Signed { .. } => "signed".into(), 2830 BitArrayOption::Unsigned { .. } => "unsigned".into(), 2831 BitArrayOption::Big { .. } => "big".into(), 2832 BitArrayOption::Little { .. } => "little".into(), 2833 BitArrayOption::Native { .. } => "native".into(), 2834 BitArrayOption::Size { .. } => "size".into(), 2835 BitArrayOption::Unit { .. } => "unit".into(), 2836 } 2837 } 2838 2839 fn is_type_option(&self) -> bool { 2840 match self { 2841 BitArrayOption::Bytes { .. } 2842 | BitArrayOption::Int { .. } 2843 | BitArrayOption::Float { .. } 2844 | BitArrayOption::Bits { .. } 2845 | BitArrayOption::Utf8 { .. } 2846 | BitArrayOption::Utf16 { .. } 2847 | BitArrayOption::Utf32 { .. } 2848 | BitArrayOption::Utf8Codepoint { .. } 2849 | BitArrayOption::Utf16Codepoint { .. } 2850 | BitArrayOption::Utf32Codepoint { .. } => true, 2851 2852 BitArrayOption::Signed { .. } 2853 | BitArrayOption::Unsigned { .. } 2854 | BitArrayOption::Big { .. } 2855 | BitArrayOption::Little { .. } 2856 | BitArrayOption::Native { .. } 2857 | BitArrayOption::Size { .. } 2858 | BitArrayOption::Unit { .. } => false, 2859 } 2860 } 2861} 2862 2863impl BitArrayOption<TypedConstant> { 2864 fn referenced_variables(&self) -> im::HashSet<&EcoString> { 2865 match self { 2866 BitArrayOption::Bytes { .. } 2867 | BitArrayOption::Int { .. } 2868 | BitArrayOption::Float { .. } 2869 | BitArrayOption::Bits { .. } 2870 | BitArrayOption::Utf8 { .. } 2871 | BitArrayOption::Utf16 { .. } 2872 | BitArrayOption::Utf32 { .. } 2873 | BitArrayOption::Utf8Codepoint { .. } 2874 | BitArrayOption::Utf16Codepoint { .. } 2875 | BitArrayOption::Utf32Codepoint { .. } 2876 | BitArrayOption::Signed { .. } 2877 | BitArrayOption::Unsigned { .. } 2878 | BitArrayOption::Big { .. } 2879 | BitArrayOption::Little { .. } 2880 | BitArrayOption::Unit { .. } 2881 | BitArrayOption::Native { .. } => im::hashset![], 2882 2883 BitArrayOption::Size { value, .. } => value.referenced_variables(), 2884 } 2885 } 2886} 2887 2888impl BitArrayOption<TypedPattern> { 2889 pub fn find_node(&self, byte_index: u32) -> Option<Located<'_>> { 2890 match self { 2891 BitArrayOption::Bytes { .. } 2892 | BitArrayOption::Int { .. } 2893 | BitArrayOption::Float { .. } 2894 | BitArrayOption::Bits { .. } 2895 | BitArrayOption::Utf8 { .. } 2896 | BitArrayOption::Utf16 { .. } 2897 | BitArrayOption::Utf32 { .. } 2898 | BitArrayOption::Utf8Codepoint { .. } 2899 | BitArrayOption::Utf16Codepoint { .. } 2900 | BitArrayOption::Utf32Codepoint { .. } 2901 | BitArrayOption::Signed { .. } 2902 | BitArrayOption::Unsigned { .. } 2903 | BitArrayOption::Big { .. } 2904 | BitArrayOption::Little { .. } 2905 | BitArrayOption::Native { .. } 2906 | BitArrayOption::Unit { .. } => None, 2907 BitArrayOption::Size { value, .. } => value.find_node(byte_index), 2908 } 2909 } 2910} 2911 2912impl BitArrayOption<TypedConstant> { 2913 pub fn find_node(&self, byte_index: u32) -> Option<Located<'_>> { 2914 match self { 2915 BitArrayOption::Bytes { .. } 2916 | BitArrayOption::Int { .. } 2917 | BitArrayOption::Float { .. } 2918 | BitArrayOption::Bits { .. } 2919 | BitArrayOption::Utf8 { .. } 2920 | BitArrayOption::Utf16 { .. } 2921 | BitArrayOption::Utf32 { .. } 2922 | BitArrayOption::Utf8Codepoint { .. } 2923 | BitArrayOption::Utf16Codepoint { .. } 2924 | BitArrayOption::Utf32Codepoint { .. } 2925 | BitArrayOption::Signed { .. } 2926 | BitArrayOption::Unsigned { .. } 2927 | BitArrayOption::Big { .. } 2928 | BitArrayOption::Little { .. } 2929 | BitArrayOption::Native { .. } 2930 | BitArrayOption::Unit { .. } => None, 2931 BitArrayOption::Size { value, .. } => value.find_node(byte_index), 2932 } 2933 } 2934} 2935 2936#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)] 2937pub enum TodoKind { 2938 Keyword, 2939 EmptyFunction { function_location: SrcSpan }, 2940 IncompleteUse, 2941 EmptyBlock, 2942} 2943 2944#[derive(Debug, Default)] 2945pub struct GroupedDefinitions { 2946 pub functions: Vec<UntypedFunction>, 2947 pub constants: Vec<UntypedModuleConstant>, 2948 pub custom_types: Vec<UntypedCustomType>, 2949 pub imports: Vec<UntypedImport>, 2950 pub type_aliases: Vec<UntypedTypeAlias>, 2951} 2952 2953impl GroupedDefinitions { 2954 pub fn new(definitions: impl IntoIterator<Item = UntypedDefinition>) -> Self { 2955 let mut this = Self::default(); 2956 2957 for definition in definitions { 2958 this.add(definition) 2959 } 2960 2961 this 2962 } 2963 2964 pub fn is_empty(&self) -> bool { 2965 self.len() == 0 2966 } 2967 2968 pub fn len(&self) -> usize { 2969 let Self { 2970 custom_types, 2971 functions, 2972 constants, 2973 imports, 2974 type_aliases, 2975 } = self; 2976 functions.len() + constants.len() + imports.len() + custom_types.len() + type_aliases.len() 2977 } 2978 2979 fn add(&mut self, statement: UntypedDefinition) { 2980 match statement { 2981 Definition::Import(import) => self.imports.push(import), 2982 Definition::Function(function) => self.functions.push(function), 2983 Definition::TypeAlias(type_alias) => self.type_aliases.push(type_alias), 2984 Definition::CustomType(custom_type) => self.custom_types.push(custom_type), 2985 Definition::ModuleConstant(constant) => self.constants.push(constant), 2986 } 2987 } 2988} 2989 2990/// A statement with in a function body. 2991#[derive(Debug, Clone, PartialEq, Eq)] 2992pub enum Statement<TypeT, ExpressionT> { 2993 /// A bare expression that is not assigned to any variable. 2994 Expression(ExpressionT), 2995 /// Assigning an expression to variables using a pattern. 2996 Assignment(Box<Assignment<TypeT, ExpressionT>>), 2997 /// A `use` expression. 2998 Use(Use<TypeT, ExpressionT>), 2999 /// A bool assertion. 3000 Assert(Assert<ExpressionT>), 3001} 3002 3003pub type UntypedUse = Use<(), UntypedExpr>; 3004pub type TypedUse = Use<Arc<Type>, TypedExpr>; 3005 3006#[derive(Debug, Clone, PartialEq, Eq)] 3007pub struct Use<TypeT, ExpressionT> { 3008 /// In an untyped use this is the expression with the untyped code of the 3009 /// callback function. 3010 /// 3011 /// In a typed use this is the typed function call the use expression 3012 /// desugars to. 3013 /// 3014 pub call: Box<ExpressionT>, 3015 3016 /// This is the location of the whole use line, starting from the `use` 3017 /// keyword and ending with the function call on the right hand side of 3018 /// `<-`. 3019 /// 3020 /// ```gleam 3021 /// use a <- result.try(result) 3022 /// ^^^^^^^^^^^^^^^^^^^^^^^^^^^ 3023 /// ``` 3024 /// 3025 pub location: SrcSpan, 3026 3027 /// This is the location of the expression on the right hand side of the use 3028 /// arrow. 3029 /// 3030 /// ```gleam 3031 /// use a <- result.try(result) 3032 /// ^^^^^^^^^^^^^^^^^^ 3033 /// ``` 3034 /// 3035 pub right_hand_side_location: SrcSpan, 3036 3037 /// This is the SrcSpan of the patterns you find on the left hand side of 3038 /// `<-` in a use expression. 3039 /// 3040 /// ```gleam 3041 /// use pattern1, pattern2 <- todo 3042 /// ^^^^^^^^^^^^^^^^^^ 3043 /// ``` 3044 /// 3045 /// In case there's no patterns it will be corresponding to the SrcSpan of 3046 /// the `use` keyword itself. 3047 /// 3048 pub assignments_location: SrcSpan, 3049 3050 /// The patterns on the left hand side of `<-` in a use expression. 3051 /// 3052 pub assignments: Vec<UseAssignment<TypeT>>, 3053} 3054 3055pub type UntypedUseAssignment = UseAssignment<()>; 3056pub type TypedUseAssignment = UseAssignment<Arc<Type>>; 3057 3058#[derive(Debug, Clone, PartialEq, Eq)] 3059pub struct UseAssignment<TypeT> { 3060 pub location: SrcSpan, 3061 pub pattern: Pattern<TypeT>, 3062 pub annotation: Option<TypeAst>, 3063} 3064 3065impl TypedUse { 3066 pub fn find_node(&self, byte_index: u32) -> Option<Located<'_>> { 3067 for assignment in self.assignments.iter() { 3068 if let Some(found) = assignment.pattern.find_node(byte_index) { 3069 return Some(found); 3070 } 3071 if let Some(found) = assignment 3072 .annotation 3073 .as_ref() 3074 .and_then(|annotation| annotation.find_node(byte_index, assignment.pattern.type_())) 3075 { 3076 return Some(found); 3077 } 3078 } 3079 self.call.find_node(byte_index) 3080 } 3081 3082 pub fn callback_arguments(&self) -> Option<&Vec<TypedArg>> { 3083 let TypedExpr::Call { args, .. } = self.call.as_ref() else { 3084 return None; 3085 }; 3086 let callback = args.iter().last()?; 3087 let TypedExpr::Fn { args, .. } = &callback.value else { 3088 // The expression might be invalid so we have to return a None here 3089 return None; 3090 }; 3091 Some(args) 3092 } 3093} 3094 3095pub type TypedStatement = Statement<Arc<Type>, TypedExpr>; 3096pub type UntypedStatement = Statement<(), UntypedExpr>; 3097 3098impl<T, E> Statement<T, E> { 3099 /// Returns `true` if the statement is [`Expression`]. 3100 /// 3101 /// [`Expression`]: Statement::Expression 3102 #[must_use] 3103 pub fn is_expression(&self) -> bool { 3104 matches!(self, Self::Expression(..)) 3105 } 3106 3107 #[must_use] 3108 pub(crate) fn is_use(&self) -> bool { 3109 match self { 3110 Self::Use(_) => true, 3111 _ => false, 3112 } 3113 } 3114} 3115 3116impl UntypedStatement { 3117 pub fn location(&self) -> SrcSpan { 3118 match self { 3119 Statement::Expression(expression) => expression.location(), 3120 Statement::Assignment(assignment) => assignment.location, 3121 Statement::Use(use_) => use_.location, 3122 Statement::Assert(assert) => assert.location, 3123 } 3124 } 3125 3126 pub fn start_byte_index(&self) -> u32 { 3127 match self { 3128 Statement::Expression(expression) => expression.start_byte_index(), 3129 Statement::Assignment(assignment) => assignment.location.start, 3130 Statement::Use(use_) => use_.location.start, 3131 Statement::Assert(assert) => assert.location.start, 3132 } 3133 } 3134 3135 pub fn is_placeholder(&self) -> bool { 3136 match self { 3137 Statement::Expression(expression) => expression.is_placeholder(), 3138 Statement::Assignment(_) | Statement::Use(_) | Statement::Assert(_) => false, 3139 } 3140 } 3141} 3142 3143impl TypedStatement { 3144 pub fn is_println(&self) -> bool { 3145 match self { 3146 Statement::Expression(e) => e.is_println(), 3147 Statement::Assignment(_) => false, 3148 Statement::Use(_) => false, 3149 Statement::Assert(_) => false, 3150 } 3151 } 3152 3153 pub fn location(&self) -> SrcSpan { 3154 match self { 3155 Statement::Expression(expression) => expression.location(), 3156 Statement::Assignment(assignment) => assignment.location, 3157 Statement::Use(use_) => use_.location, 3158 Statement::Assert(assert) => assert.location, 3159 } 3160 } 3161 3162 /// Returns the location of the last element of a statement. This means that 3163 /// if the statement is a use you'll get the location of the last item at 3164 /// the end of its block. 3165 pub fn last_location(&self) -> SrcSpan { 3166 match self { 3167 Statement::Expression(expression) => expression.last_location(), 3168 Statement::Assignment(assignment) => assignment.value.last_location(), 3169 Statement::Use(use_) => use_.call.last_location(), 3170 Statement::Assert(assert) => assert.value.last_location(), 3171 } 3172 } 3173 3174 pub fn type_(&self) -> Arc<Type> { 3175 match self { 3176 Statement::Expression(expression) => expression.type_(), 3177 Statement::Assignment(assignment) => assignment.type_(), 3178 Statement::Use(use_) => use_.call.type_(), 3179 Statement::Assert(_) => nil(), 3180 } 3181 } 3182 3183 pub fn definition_location(&self) -> Option<DefinitionLocation> { 3184 match self { 3185 Statement::Expression(expression) => expression.definition_location(), 3186 Statement::Assignment(_) => None, 3187 Statement::Use(use_) => use_.call.definition_location(), 3188 Statement::Assert(_) => None, 3189 } 3190 } 3191 3192 pub fn find_node(&self, byte_index: u32) -> Option<Located<'_>> { 3193 match self { 3194 Statement::Use(use_) => use_.find_node(byte_index), 3195 Statement::Expression(expression) => expression.find_node(byte_index), 3196 Statement::Assignment(assignment) => assignment.find_node(byte_index).or_else(|| { 3197 if assignment.location.contains(byte_index) { 3198 Some(Located::Statement(self)) 3199 } else { 3200 None 3201 } 3202 }), 3203 Statement::Assert(assert) => assert.find_node(byte_index).or_else(|| { 3204 if assert.location.contains(byte_index) { 3205 Some(Located::Statement(self)) 3206 } else { 3207 None 3208 } 3209 }), 3210 } 3211 } 3212 3213 pub fn find_statement(&self, byte_index: u32) -> Option<&TypedStatement> { 3214 match self { 3215 Statement::Use(use_) => use_.call.find_statement(byte_index), 3216 Statement::Expression(expression) => expression.find_statement(byte_index), 3217 Statement::Assignment(assignment) => { 3218 assignment.value.find_statement(byte_index).or_else(|| { 3219 if assignment.location.contains(byte_index) { 3220 Some(self) 3221 } else { 3222 None 3223 } 3224 }) 3225 } 3226 Statement::Assert(assert) => assert.value.find_statement(byte_index).or_else(|| { 3227 if assert.location.contains(byte_index) { 3228 Some(self) 3229 } else { 3230 None 3231 } 3232 }), 3233 } 3234 } 3235 3236 pub fn type_defining_location(&self) -> SrcSpan { 3237 match self { 3238 Statement::Expression(expression) => expression.type_defining_location(), 3239 Statement::Assignment(assignment) => assignment.location, 3240 Statement::Use(use_) => use_.location, 3241 Statement::Assert(assert) => assert.location, 3242 } 3243 } 3244 3245 fn is_pure_value_constructor(&self) -> bool { 3246 match self { 3247 Statement::Expression(expression) => expression.is_pure_value_constructor(), 3248 Statement::Assignment(assignment) => { 3249 // A let assert is not considered a pure value constructor 3250 // as it could crash the program! 3251 !assignment.kind.is_assert() && assignment.value.is_pure_value_constructor() 3252 } 3253 Statement::Use(Use { call, .. }) => call.is_pure_value_constructor(), 3254 // Assert statements by definition are not pure 3255 Statement::Assert(_) => false, 3256 } 3257 } 3258} 3259 3260#[derive(Debug, Clone, PartialEq, Eq)] 3261pub struct Assignment<TypeT, ExpressionT> { 3262 pub location: SrcSpan, 3263 pub value: ExpressionT, 3264 pub pattern: Pattern<TypeT>, 3265 pub kind: AssignmentKind<ExpressionT>, 3266 pub compiled_case: CompiledCase, 3267 /// This will be true for assignments that are automatically generated by 3268 /// the compiler. 3269 pub annotation: Option<TypeAst>, 3270} 3271 3272pub type TypedAssignment = Assignment<Arc<Type>, TypedExpr>; 3273pub type UntypedAssignment = Assignment<(), UntypedExpr>; 3274 3275impl TypedAssignment { 3276 pub fn find_node(&self, byte_index: u32) -> Option<Located<'_>> { 3277 if let Some(annotation) = &self.annotation { 3278 if let Some(l) = annotation.find_node(byte_index, self.pattern.type_()) { 3279 return Some(l); 3280 } 3281 } 3282 self.pattern 3283 .find_node(byte_index) 3284 .or_else(|| self.value.find_node(byte_index)) 3285 } 3286 3287 pub fn type_(&self) -> Arc<Type> { 3288 self.value.type_() 3289 } 3290} 3291 3292pub type TypedAssert = Assert<TypedExpr>; 3293pub type UntypedAssert = Assert<UntypedExpr>; 3294 3295#[derive(Debug, Clone, PartialEq, Eq)] 3296pub struct Assert<Expression> { 3297 pub location: SrcSpan, 3298 pub value: Expression, 3299 pub message: Option<Expression>, 3300} 3301 3302impl TypedAssert { 3303 pub fn find_node(&self, byte_index: u32) -> Option<Located<'_>> { 3304 if let Some(found) = self.value.find_node(byte_index) { 3305 return Some(found); 3306 } 3307 if let Some(message) = &self.message { 3308 if let Some(found) = message.find_node(byte_index) { 3309 return Some(found); 3310 } 3311 } 3312 None 3313 } 3314} 3315 3316/// A pipeline is desugared to a series of assignments: 3317/// 3318/// ```gleam 3319/// wibble |> wobble |> woo 3320/// ``` 3321/// 3322/// Becomes: 3323/// 3324/// ```erl 3325/// Pipe1 = wibble 3326/// Pipe2 = wobble(Pipe1) 3327/// woo(Pipe2) 3328/// ``` 3329/// 3330/// This represents one of such assignments once the pipeline has been desugared 3331/// and each step has been typed. 3332/// 3333/// > We're not using a more general `TypedAssignment` node since that has much 3334/// > more informations to carry around. This one is limited since we know it 3335/// > will always be in the form `VarName = <Expr>`, with no patterns on the 3336/// > left hand side of the assignment. 3337/// > Being more constrained simplifies code generation for pipelines! 3338/// 3339#[derive(Debug, Clone, PartialEq, Eq)] 3340pub struct TypedPipelineAssignment { 3341 pub location: SrcSpan, 3342 pub name: EcoString, 3343 pub value: Box<TypedExpr>, 3344} 3345 3346impl TypedPipelineAssignment { 3347 pub fn find_node(&self, byte_index: u32) -> Option<Located<'_>> { 3348 self.value.find_node(byte_index) 3349 } 3350 3351 pub fn find_statement(&self, byte_index: u32) -> Option<&TypedStatement> { 3352 self.value.find_statement(byte_index) 3353 } 3354 3355 pub fn type_(&self) -> Arc<Type> { 3356 self.value.type_() 3357 } 3358} 3359 3360/// The kind of desugaring that might take place when rewriting a pipeline to 3361/// regular assignments. 3362/// 3363#[derive(Debug, Clone, Copy, PartialEq, Eq)] 3364pub enum PipelineAssignmentKind { 3365 /// In case `a |> b(c)` is desugared to `b(a, c)`. 3366 FirstArgument { 3367 /// The location of the second argument of the call, in case there's any: 3368 /// - `a |> b(c, d)`: here it's `Some` wrapping the location of `c`. 3369 /// - `a |> b()`: here it's `None`. 3370 second_argument: Option<SrcSpan>, 3371 }, 3372 3373 /// In case there's an explicit hole and `a |> b(_, c)` is desugared to 3374 /// `b(a, c)`. 3375 Hole { hole: SrcSpan }, 3376 3377 /// In case `a |> b(c)` is desugared to `b(c)(a)` 3378 FunctionCall, 3379 3380 /// In case there's an echo in the middle of a pipeline `a |> echo` 3381 Echo, 3382}