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
106 kB 3433 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 /// The specified size of a bit array. This can either be a literal integer, 2019 /// a reference to a variable, or a maths expression. 2020 /// e.g. `let assert <<y:size(somevar)>> = x` 2021 BitArraySize(BitArraySize<Type>), 2022 2023 /// A name given to a sub-pattern using the `as` keyword. 2024 /// e.g. `assert #(1, [_, _] as the_list) = x` 2025 Assign { 2026 name: EcoString, 2027 location: SrcSpan, 2028 pattern: Box<Self>, 2029 }, 2030 2031 /// A pattern that binds to any value but does not assign a variable. 2032 /// Always starts with an underscore. 2033 Discard { 2034 name: EcoString, 2035 location: SrcSpan, 2036 type_: Type, 2037 }, 2038 2039 List { 2040 location: SrcSpan, 2041 elements: Vec<Self>, 2042 tail: Option<Box<Self>>, 2043 type_: Type, 2044 }, 2045 2046 /// The constructor for a custom type. Starts with an uppercase letter. 2047 Constructor { 2048 location: SrcSpan, 2049 name_location: SrcSpan, 2050 name: EcoString, 2051 arguments: Vec<CallArg<Self>>, 2052 module: Option<(EcoString, SrcSpan)>, 2053 constructor: Inferred<PatternConstructor>, 2054 spread: Option<SrcSpan>, 2055 type_: Type, 2056 }, 2057 2058 Tuple { 2059 location: SrcSpan, 2060 elements: Vec<Self>, 2061 }, 2062 2063 BitArray { 2064 location: SrcSpan, 2065 segments: Vec<BitArraySegment<Self, Type>>, 2066 }, 2067 2068 // "prefix" <> variable 2069 StringPrefix { 2070 location: SrcSpan, 2071 left_location: SrcSpan, 2072 left_side_assignment: Option<(EcoString, SrcSpan)>, 2073 right_location: SrcSpan, 2074 left_side_string: EcoString, 2075 /// The variable on the right hand side of the `<>`. 2076 right_side_assignment: AssignName, 2077 }, 2078 2079 /// A placeholder pattern used to allow module analysis to continue 2080 /// even when there are type errors. Should never end up in generated code. 2081 Invalid { 2082 location: SrcSpan, 2083 type_: Type, 2084 }, 2085} 2086 2087pub type TypedBitArraySize = BitArraySize<Arc<Type>>; 2088 2089#[derive(Debug, Clone, PartialEq, Eq)] 2090pub enum BitArraySize<Type> { 2091 Int { 2092 location: SrcSpan, 2093 value: EcoString, 2094 int_value: BigInt, 2095 }, 2096 2097 Variable { 2098 location: SrcSpan, 2099 name: EcoString, 2100 constructor: Option<ValueConstructor>, 2101 type_: Type, 2102 }, 2103 2104 BinaryOperator { 2105 location: SrcSpan, 2106 operator: IntegerOperator, 2107 left: Box<Self>, 2108 right: Box<Self>, 2109 }, 2110} 2111 2112#[derive(Debug, Clone, Copy, PartialEq, Eq)] 2113pub enum IntegerOperator { 2114 Add, 2115 Subtract, 2116 Multiply, 2117 Divide, 2118 Remainder, 2119} 2120 2121impl IntegerOperator { 2122 pub fn precedence(&self) -> u8 { 2123 match self { 2124 Self::Add | Self::Subtract => 7, 2125 2126 Self::Multiply | Self::Divide | Self::Remainder => 8, 2127 } 2128 } 2129} 2130 2131impl<T> BitArraySize<T> { 2132 pub fn location(&self) -> SrcSpan { 2133 match self { 2134 BitArraySize::Int { location, .. } 2135 | BitArraySize::Variable { location, .. } 2136 | BitArraySize::BinaryOperator { location, .. } => *location, 2137 } 2138 } 2139} 2140 2141impl Default for Inferred<()> { 2142 fn default() -> Self { 2143 Self::Unknown 2144 } 2145} 2146 2147#[derive(Debug, Clone, PartialEq, Eq, Hash)] 2148pub enum AssignName { 2149 Variable(EcoString), 2150 Discard(EcoString), 2151} 2152 2153impl AssignName { 2154 pub fn name(&self) -> &EcoString { 2155 match self { 2156 AssignName::Variable(name) | AssignName::Discard(name) => name, 2157 } 2158 } 2159 2160 pub fn to_arg_names(self, location: SrcSpan) -> ArgNames { 2161 match self { 2162 AssignName::Variable(name) => ArgNames::Named { name, location }, 2163 AssignName::Discard(name) => ArgNames::Discard { name, location }, 2164 } 2165 } 2166 2167 pub fn assigned_name(&self) -> Option<&str> { 2168 match self { 2169 AssignName::Variable(name) => Some(name), 2170 AssignName::Discard(_) => None, 2171 } 2172 } 2173} 2174 2175impl<A> Pattern<A> { 2176 pub fn location(&self) -> SrcSpan { 2177 match self { 2178 Pattern::Assign { 2179 pattern, location, .. 2180 } => SrcSpan::new(pattern.location().start, location.end), 2181 Pattern::Int { location, .. } 2182 | Pattern::Variable { location, .. } 2183 | Pattern::List { location, .. } 2184 | Pattern::Float { location, .. } 2185 | Pattern::Discard { location, .. } 2186 | Pattern::String { location, .. } 2187 | Pattern::Tuple { location, .. } 2188 | Pattern::Constructor { location, .. } 2189 | Pattern::StringPrefix { location, .. } 2190 | Pattern::BitArray { location, .. } 2191 | Pattern::Invalid { location, .. } => *location, 2192 Pattern::BitArraySize(size) => size.location(), 2193 } 2194 } 2195 2196 /// Returns `true` if the pattern is [`Discard`]. 2197 /// 2198 /// [`Discard`]: Pattern::Discard 2199 #[must_use] 2200 pub fn is_discard(&self) -> bool { 2201 matches!(self, Self::Discard { .. }) 2202 } 2203 2204 #[must_use] 2205 pub fn is_variable(&self) -> bool { 2206 match self { 2207 Pattern::Variable { .. } => true, 2208 _ => false, 2209 } 2210 } 2211 2212 #[must_use] 2213 pub fn is_string(&self) -> bool { 2214 matches!(self, Self::String { .. }) 2215 } 2216} 2217 2218impl TypedPattern { 2219 pub fn definition_location(&self) -> Option<DefinitionLocation> { 2220 match self { 2221 Pattern::Int { .. } 2222 | Pattern::Float { .. } 2223 | Pattern::String { .. } 2224 | Pattern::Variable { .. } 2225 | Pattern::BitArraySize { .. } 2226 | Pattern::Assign { .. } 2227 | Pattern::Discard { .. } 2228 | Pattern::List { .. } 2229 | Pattern::Tuple { .. } 2230 | Pattern::BitArray { .. } 2231 | Pattern::StringPrefix { .. } 2232 | Pattern::Invalid { .. } => None, 2233 2234 Pattern::Constructor { constructor, .. } => constructor.definition_location(), 2235 } 2236 } 2237 2238 pub fn get_documentation(&self) -> Option<&str> { 2239 match self { 2240 Pattern::Int { .. } 2241 | Pattern::Float { .. } 2242 | Pattern::String { .. } 2243 | Pattern::Variable { .. } 2244 | Pattern::BitArraySize { .. } 2245 | Pattern::Assign { .. } 2246 | Pattern::Discard { .. } 2247 | Pattern::List { .. } 2248 | Pattern::Tuple { .. } 2249 | Pattern::BitArray { .. } 2250 | Pattern::StringPrefix { .. } 2251 | Pattern::Invalid { .. } => None, 2252 2253 Pattern::Constructor { constructor, .. } => constructor.get_documentation(), 2254 } 2255 } 2256 2257 pub fn type_(&self) -> Arc<Type> { 2258 match self { 2259 Pattern::Int { .. } => type_::int(), 2260 Pattern::Float { .. } => type_::float(), 2261 Pattern::String { .. } => type_::string(), 2262 Pattern::BitArray { .. } => type_::bit_array(), 2263 Pattern::StringPrefix { .. } => type_::string(), 2264 2265 Pattern::Variable { type_, .. } 2266 | Pattern::List { type_, .. } 2267 | Pattern::Constructor { type_, .. } 2268 | Pattern::Invalid { type_, .. } => type_.clone(), 2269 2270 Pattern::Assign { pattern, .. } => pattern.type_(), 2271 2272 // Bit array sizes should always be integers 2273 Pattern::BitArraySize(_) => type_::int(), 2274 2275 Pattern::Discard { type_, .. } => type_.clone(), 2276 2277 Pattern::Tuple { elements, .. } => { 2278 type_::tuple(elements.iter().map(|p| p.type_()).collect()) 2279 } 2280 } 2281 } 2282 2283 fn find_node(&self, byte_index: u32) -> Option<Located<'_>> { 2284 if !self.location().contains(byte_index) { 2285 return None; 2286 } 2287 2288 if let Pattern::Variable { name, .. } = self { 2289 // For pipes the pattern can't be pointed to 2290 if name.as_str().eq(PIPE_VARIABLE) { 2291 return None; 2292 } 2293 } 2294 2295 match self { 2296 Pattern::Int { .. } 2297 | Pattern::Float { .. } 2298 | Pattern::String { .. } 2299 | Pattern::Variable { .. } 2300 | Pattern::BitArraySize { .. } 2301 | Pattern::Assign { .. } 2302 | Pattern::Discard { .. } 2303 | Pattern::StringPrefix { .. } 2304 | Pattern::Invalid { .. } => Some(Located::Pattern(self)), 2305 2306 Pattern::Constructor { 2307 arguments, spread, .. 2308 } => match spread { 2309 Some(spread_location) if spread_location.contains(byte_index) => { 2310 Some(Located::PatternSpread { 2311 spread_location: *spread_location, 2312 pattern: self, 2313 }) 2314 } 2315 2316 Some(_) | None => arguments.iter().find_map(|arg| arg.find_node(byte_index)), 2317 }, 2318 Pattern::List { elements, tail, .. } => elements 2319 .iter() 2320 .find_map(|p| p.find_node(byte_index)) 2321 .or_else(|| tail.as_ref().and_then(|p| p.find_node(byte_index))), 2322 2323 Pattern::Tuple { elements, .. } => { 2324 elements.iter().find_map(|p| p.find_node(byte_index)) 2325 } 2326 2327 Pattern::BitArray { segments, .. } => segments 2328 .iter() 2329 .find_map(|segment| segment.find_node(byte_index)) 2330 .or(Some(Located::Pattern(self))), 2331 } 2332 .or(Some(Located::Pattern(self))) 2333 } 2334 2335 /// If the pattern is a `Constructor` with a spread, it returns a tuple with 2336 /// all the ignored fields. Split in unlabelled and labelled ones. 2337 /// 2338 pub(crate) fn unused_arguments(&self) -> Option<PatternUnusedArguments> { 2339 let TypedPattern::Constructor { 2340 arguments, 2341 spread: Some(_), 2342 .. 2343 } = self 2344 else { 2345 return None; 2346 }; 2347 2348 let mut positional = vec![]; 2349 let mut labelled = vec![]; 2350 for argument in arguments { 2351 // We only want to display the arguments that were ignored using `..`. 2352 // Any argument ignored that way is marked as implicit, so if it is 2353 // not implicit we just ignore it. 2354 if !argument.is_implicit() { 2355 continue; 2356 } 2357 let type_ = argument.value.type_(); 2358 match &argument.label { 2359 Some(label) => labelled.push((label.clone(), type_)), 2360 None => positional.push(type_), 2361 } 2362 } 2363 2364 Some(PatternUnusedArguments { 2365 positional, 2366 labelled, 2367 }) 2368 } 2369 2370 /// Whether the pattern always matches. For example, a tuple or simple 2371 /// variable assignment always match and can never fail. 2372 #[must_use] 2373 pub fn always_matches(&self) -> bool { 2374 match self { 2375 Pattern::Variable { .. } | Pattern::Discard { .. } => true, 2376 Pattern::Assign { pattern, .. } => pattern.always_matches(), 2377 Pattern::Tuple { elements, .. } => { 2378 elements.iter().all(|element| element.always_matches()) 2379 } 2380 Pattern::Int { .. } 2381 | Pattern::Float { .. } 2382 | Pattern::String { .. } 2383 | Pattern::BitArraySize { .. } 2384 | Pattern::List { .. } 2385 | Pattern::Constructor { .. } 2386 | Pattern::BitArray { .. } 2387 | Pattern::StringPrefix { .. } 2388 | Pattern::Invalid { .. } => false, 2389 } 2390 } 2391 2392 pub fn bound_variables(&self) -> Vec<EcoString> { 2393 let mut variables = Vec::new(); 2394 self.collect_bound_variables(&mut variables); 2395 variables 2396 } 2397 2398 fn collect_bound_variables(&self, variables: &mut Vec<EcoString>) { 2399 match self { 2400 Pattern::Int { .. } 2401 | Pattern::Float { .. } 2402 | Pattern::String { .. } 2403 | Pattern::Discard { .. } 2404 | Pattern::Invalid { .. } => {} 2405 2406 Pattern::Variable { name, .. } => variables.push(name.clone()), 2407 Pattern::VarUsage { .. } => {} 2408 Pattern::Assign { name, pattern, .. } => { 2409 variables.push(name.clone()); 2410 pattern.collect_bound_variables(variables); 2411 } 2412 Pattern::List { elements, tail, .. } => { 2413 for element in elements { 2414 element.collect_bound_variables(variables); 2415 } 2416 if let Some(tail) = tail { 2417 tail.collect_bound_variables(variables); 2418 } 2419 } 2420 Pattern::Constructor { arguments, .. } => { 2421 for argument in arguments { 2422 argument.value.collect_bound_variables(variables); 2423 } 2424 } 2425 Pattern::Tuple { elements, .. } => { 2426 for element in elements { 2427 element.collect_bound_variables(variables); 2428 } 2429 } 2430 Pattern::BitArray { segments, .. } => { 2431 for segment in segments { 2432 segment.value.collect_bound_variables(variables); 2433 } 2434 } 2435 Pattern::StringPrefix { 2436 left_side_assignment, 2437 right_side_assignment, 2438 .. 2439 } => { 2440 if let Some((left_variable, _)) = left_side_assignment { 2441 variables.push(left_variable.clone()); 2442 } 2443 match right_side_assignment { 2444 AssignName::Variable(name) => variables.push(name.clone()), 2445 AssignName::Discard(_) => {} 2446 } 2447 } 2448 } 2449 } 2450} 2451 2452#[derive(Debug, Default)] 2453pub struct PatternUnusedArguments { 2454 pub positional: Vec<Arc<Type>>, 2455 pub labelled: Vec<(EcoString, Arc<Type>)>, 2456} 2457 2458impl<A> HasLocation for Pattern<A> { 2459 fn location(&self) -> SrcSpan { 2460 self.location() 2461 } 2462} 2463 2464#[derive(Debug, Clone, PartialEq, Eq)] 2465pub enum AssignmentKind<Expression> { 2466 /// let x = ... 2467 Let, 2468 /// This is a let assignment generated by the compiler for intermediate variables 2469 /// needed by record updates and `use`. 2470 /// Like a regular `Let` assignment this can never fail. 2471 /// 2472 Generated, 2473 /// let assert x = ... 2474 Assert { 2475 /// The src byte span of the `let assert` 2476 /// 2477 /// ```gleam 2478 /// let assert Wibble = todo 2479 /// ^^^^^^^^^^ 2480 /// ``` 2481 location: SrcSpan, 2482 2483 /// The byte index of the start of `assert` 2484 /// 2485 /// ```gleam 2486 /// let assert Wibble = todo 2487 /// ^ 2488 /// ``` 2489 assert_keyword_start: u32, 2490 2491 /// The message given to the assertion: 2492 /// 2493 /// ```gleam 2494 /// let asset Ok(a) = something() as "This will never fail" 2495 /// ^^^^^^^^^^^^^^^^^^^^^^ 2496 /// ``` 2497 message: Option<Expression>, 2498 }, 2499} 2500 2501impl<Expression> AssignmentKind<Expression> { 2502 /// Returns `true` if the assignment kind is [`Assert`]. 2503 /// 2504 /// [`Assert`]: AssignmentKind::Assert 2505 #[must_use] 2506 pub fn is_assert(&self) -> bool { 2507 match self { 2508 Self::Assert { .. } => true, 2509 Self::Let | Self::Generated => false, 2510 } 2511 } 2512} 2513 2514// BitArrays 2515 2516pub type UntypedExprBitArraySegment = BitArraySegment<UntypedExpr, ()>; 2517pub type TypedExprBitArraySegment = BitArraySegment<TypedExpr, Arc<Type>>; 2518 2519pub type UntypedConstantBitArraySegment = BitArraySegment<UntypedConstant, ()>; 2520pub type TypedConstantBitArraySegment = BitArraySegment<TypedConstant, Arc<Type>>; 2521 2522pub type UntypedPatternBitArraySegment = BitArraySegment<UntypedPattern, ()>; 2523pub type TypedPatternBitArraySegment = BitArraySegment<TypedPattern, Arc<Type>>; 2524 2525#[derive(Debug, Clone, PartialEq, Eq)] 2526pub struct BitArraySegment<Value, Type> { 2527 pub location: SrcSpan, 2528 pub value: Box<Value>, 2529 pub options: Vec<BitArrayOption<Value>>, 2530 pub type_: Type, 2531} 2532 2533#[derive(Debug, PartialEq, Eq, Copy, Clone, Hash)] 2534pub enum Endianness { 2535 Big, 2536 Little, 2537} 2538 2539impl Endianness { 2540 pub fn is_big(&self) -> bool { 2541 *self == Endianness::Big 2542 } 2543} 2544 2545impl<Type> BitArraySegment<Pattern<Type>, Type> { 2546 /// Returns the value of the pattern unwrapping any assign pattern. 2547 /// 2548 pub fn value_unwrapping_assign(&self) -> &Pattern<Type> { 2549 match self.value.as_ref() { 2550 Pattern::Assign { pattern, .. } => pattern, 2551 Pattern::Int { .. } 2552 | Pattern::Float { .. } 2553 | Pattern::String { .. } 2554 | Pattern::Variable { .. } 2555 | Pattern::BitArraySize { .. } 2556 | Pattern::Discard { .. } 2557 | Pattern::List { .. } 2558 | Pattern::Constructor { .. } 2559 | Pattern::Tuple { .. } 2560 | Pattern::BitArray { .. } 2561 | Pattern::StringPrefix { .. } 2562 | Pattern::Invalid { .. } => self.value.as_ref(), 2563 } 2564 } 2565} 2566 2567impl<Value, Type> BitArraySegment<Value, Type> { 2568 #[must_use] 2569 pub fn has_native_option(&self) -> bool { 2570 self.options 2571 .iter() 2572 .any(|x| matches!(x, BitArrayOption::Native { .. })) 2573 } 2574 2575 #[must_use] 2576 pub fn has_utf16_codepoint_option(&self) -> bool { 2577 self.options 2578 .iter() 2579 .any(|x| matches!(x, BitArrayOption::Utf16Codepoint { .. })) 2580 } 2581 2582 #[must_use] 2583 pub fn has_utf32_codepoint_option(&self) -> bool { 2584 self.options 2585 .iter() 2586 .any(|x| matches!(x, BitArrayOption::Utf32Codepoint { .. })) 2587 } 2588 2589 #[must_use] 2590 pub fn has_utf16_option(&self) -> bool { 2591 self.options 2592 .iter() 2593 .any(|x| matches!(x, BitArrayOption::Utf16 { .. })) 2594 } 2595 2596 #[must_use] 2597 pub fn has_utf32_option(&self) -> bool { 2598 self.options 2599 .iter() 2600 .any(|x| matches!(x, BitArrayOption::Utf32 { .. })) 2601 } 2602 2603 pub fn endianness(&self) -> Endianness { 2604 if self 2605 .options 2606 .iter() 2607 .any(|x| matches!(x, BitArrayOption::Little { .. })) 2608 { 2609 Endianness::Little 2610 } else { 2611 Endianness::Big 2612 } 2613 } 2614 2615 pub(crate) fn signed(&self) -> bool { 2616 self.options 2617 .iter() 2618 .any(|x| matches!(x, BitArrayOption::Signed { .. })) 2619 } 2620 2621 pub fn size(&self) -> Option<&Value> { 2622 self.options.iter().find_map(|x| match x { 2623 BitArrayOption::Size { value, .. } => Some(value.as_ref()), 2624 _ => None, 2625 }) 2626 } 2627 2628 pub fn unit(&self) -> u8 { 2629 self.options 2630 .iter() 2631 .find_map(|option| match option { 2632 BitArrayOption::Unit { value, .. } => Some(*value), 2633 BitArrayOption::Bytes { .. } => Some(8), 2634 _ => None, 2635 }) 2636 .unwrap_or(1) 2637 } 2638 2639 pub(crate) fn has_bits_option(&self) -> bool { 2640 self.options.iter().any(|option| match option { 2641 BitArrayOption::Bits { .. } => true, 2642 _ => false, 2643 }) 2644 } 2645 2646 pub(crate) fn has_bytes_option(&self) -> bool { 2647 self.options.iter().any(|option| match option { 2648 BitArrayOption::Bytes { .. } => true, 2649 _ => false, 2650 }) 2651 } 2652} 2653 2654impl<Value, Type> BitArraySegment<Value, Type> { 2655 #[must_use] 2656 pub(crate) fn has_type_option(&self) -> bool { 2657 self.options.iter().any(|option| option.is_type_option()) 2658 } 2659} 2660 2661impl TypedExprBitArraySegment { 2662 pub fn find_node(&self, byte_index: u32) -> Option<Located<'_>> { 2663 self.value.find_node(byte_index) 2664 } 2665} 2666 2667impl<TypedValue> BitArraySegment<TypedValue, Arc<Type>> 2668where 2669 TypedValue: HasType + HasLocation + Clone + bit_array::GetLiteralValue, 2670{ 2671 pub(crate) fn check_for_truncated_value(&self) -> Option<BitArraySegmentTruncation> { 2672 // Both the size and the value must be two compile-time known constants. 2673 let segment_bits = self.bits_size()?.to_i64()?; 2674 let literal_value = self.value.as_int_literal()?; 2675 if segment_bits <= 0 { 2676 return None; 2677 } 2678 2679 let safe_range = match literal_value.sign() { 2680 Sign::NoSign => return None, 2681 Sign::Minus => { 2682 (-(BigInt::one() << (segment_bits - 1))) 2683 ..((BigInt::one() << (segment_bits - 1)) - 1) 2684 } 2685 Sign::Plus => BigInt::ZERO..(BigInt::one() << segment_bits), 2686 }; 2687 2688 if !safe_range.contains(&literal_value) { 2689 Some(BitArraySegmentTruncation { 2690 truncated_value: literal_value.clone(), 2691 truncated_into: truncate(&literal_value, segment_bits), 2692 value_location: self.value.location(), 2693 segment_bits, 2694 }) 2695 } else { 2696 None 2697 } 2698 } 2699 2700 /// If the segment size is a compile-time known constant this returns the 2701 /// segment size in bits, taking the segment's unit into consideration! 2702 /// 2703 fn bits_size(&self) -> Option<BigInt> { 2704 let size = match self.size() { 2705 None if self.type_.is_int() => 8.into(), 2706 None => 64.into(), 2707 Some(value) => value.as_int_literal()?, 2708 }; 2709 2710 let unit = self.unit(); 2711 Some(size * unit) 2712 } 2713} 2714 2715/// As Björn said, when a value is smaller than the segment's size it will be 2716/// truncated, only taking the first `n` bits: 2717/// 2718/// > It will be silently truncated. In general, when storing value an integer 2719/// > `I` into a segment of size `N`, the actual value stored will be 2720/// > `I band ((1 bsl N) - 1)`. 2721/// 2722/// <https://erlangforums.com/t/what-happens-when-a-bit-array-segment-size-is-smaller-than-its-value/4650/2?u=giacomocavalieri> 2723/// 2724/// Thank you Björn! 2725/// 2726fn truncate(literal_value: &BigInt, segment_bits: i64) -> BigInt { 2727 literal_value & ((BigInt::one() << segment_bits) - BigInt::one()) 2728} 2729 2730#[derive(serde::Deserialize, serde::Serialize, Eq, PartialEq, Clone, Debug)] 2731pub struct BitArraySegmentTruncation { 2732 /// The value that would end up being truncated. 2733 pub truncated_value: BigInt, 2734 /// What the value would be truncated into. 2735 pub truncated_into: BigInt, 2736 /// The span of the segment's value being truncated. 2737 pub value_location: SrcSpan, 2738 /// The size of the segment. 2739 pub segment_bits: i64, 2740} 2741 2742impl TypedPatternBitArraySegment { 2743 pub fn find_node(&self, byte_index: u32) -> Option<Located<'_>> { 2744 self.value.find_node(byte_index).or_else(|| { 2745 self.options 2746 .iter() 2747 .find_map(|option| option.find_node(byte_index)) 2748 }) 2749 } 2750} 2751 2752impl TypedConstantBitArraySegment { 2753 pub fn find_node(&self, byte_index: u32) -> Option<Located<'_>> { 2754 self.value.find_node(byte_index).or_else(|| { 2755 self.options 2756 .iter() 2757 .find_map(|option| option.find_node(byte_index)) 2758 }) 2759 } 2760} 2761 2762pub type TypedConstantBitArraySegmentOption = BitArrayOption<TypedConstant>; 2763 2764#[derive(Debug, PartialEq, Eq, Clone)] 2765pub enum BitArrayOption<Value> { 2766 Bytes { 2767 location: SrcSpan, 2768 }, 2769 2770 Int { 2771 location: SrcSpan, 2772 }, 2773 2774 Float { 2775 location: SrcSpan, 2776 }, 2777 2778 Bits { 2779 location: SrcSpan, 2780 }, 2781 2782 Utf8 { 2783 location: SrcSpan, 2784 }, 2785 2786 Utf16 { 2787 location: SrcSpan, 2788 }, 2789 2790 Utf32 { 2791 location: SrcSpan, 2792 }, 2793 2794 Utf8Codepoint { 2795 location: SrcSpan, 2796 }, 2797 2798 Utf16Codepoint { 2799 location: SrcSpan, 2800 }, 2801 2802 Utf32Codepoint { 2803 location: SrcSpan, 2804 }, 2805 2806 Signed { 2807 location: SrcSpan, 2808 }, 2809 2810 Unsigned { 2811 location: SrcSpan, 2812 }, 2813 2814 Big { 2815 location: SrcSpan, 2816 }, 2817 2818 Little { 2819 location: SrcSpan, 2820 }, 2821 2822 Native { 2823 location: SrcSpan, 2824 }, 2825 2826 Size { 2827 location: SrcSpan, 2828 value: Box<Value>, 2829 short_form: bool, 2830 }, 2831 2832 Unit { 2833 location: SrcSpan, 2834 value: u8, 2835 }, 2836} 2837 2838impl<A> BitArrayOption<A> { 2839 pub fn value(&self) -> Option<&A> { 2840 match self { 2841 BitArrayOption::Size { value, .. } => Some(value), 2842 _ => None, 2843 } 2844 } 2845 2846 pub fn location(&self) -> SrcSpan { 2847 match self { 2848 BitArrayOption::Bytes { location } 2849 | BitArrayOption::Int { location } 2850 | BitArrayOption::Float { location } 2851 | BitArrayOption::Bits { location } 2852 | BitArrayOption::Utf8 { location } 2853 | BitArrayOption::Utf16 { location } 2854 | BitArrayOption::Utf32 { location } 2855 | BitArrayOption::Utf8Codepoint { location } 2856 | BitArrayOption::Utf16Codepoint { location } 2857 | BitArrayOption::Utf32Codepoint { location } 2858 | BitArrayOption::Signed { location } 2859 | BitArrayOption::Unsigned { location } 2860 | BitArrayOption::Big { location } 2861 | BitArrayOption::Little { location } 2862 | BitArrayOption::Native { location } 2863 | BitArrayOption::Size { location, .. } 2864 | BitArrayOption::Unit { location, .. } => *location, 2865 } 2866 } 2867 2868 pub fn label(&self) -> EcoString { 2869 match self { 2870 BitArrayOption::Bytes { .. } => "bytes".into(), 2871 BitArrayOption::Int { .. } => "int".into(), 2872 BitArrayOption::Float { .. } => "float".into(), 2873 BitArrayOption::Bits { .. } => "bits".into(), 2874 BitArrayOption::Utf8 { .. } => "utf8".into(), 2875 BitArrayOption::Utf16 { .. } => "utf16".into(), 2876 BitArrayOption::Utf32 { .. } => "utf32".into(), 2877 BitArrayOption::Utf8Codepoint { .. } => "utf8_codepoint".into(), 2878 BitArrayOption::Utf16Codepoint { .. } => "utf16_codepoint".into(), 2879 BitArrayOption::Utf32Codepoint { .. } => "utf32_codepoint".into(), 2880 BitArrayOption::Signed { .. } => "signed".into(), 2881 BitArrayOption::Unsigned { .. } => "unsigned".into(), 2882 BitArrayOption::Big { .. } => "big".into(), 2883 BitArrayOption::Little { .. } => "little".into(), 2884 BitArrayOption::Native { .. } => "native".into(), 2885 BitArrayOption::Size { .. } => "size".into(), 2886 BitArrayOption::Unit { .. } => "unit".into(), 2887 } 2888 } 2889 2890 fn is_type_option(&self) -> bool { 2891 match self { 2892 BitArrayOption::Bytes { .. } 2893 | BitArrayOption::Int { .. } 2894 | BitArrayOption::Float { .. } 2895 | BitArrayOption::Bits { .. } 2896 | BitArrayOption::Utf8 { .. } 2897 | BitArrayOption::Utf16 { .. } 2898 | BitArrayOption::Utf32 { .. } 2899 | BitArrayOption::Utf8Codepoint { .. } 2900 | BitArrayOption::Utf16Codepoint { .. } 2901 | BitArrayOption::Utf32Codepoint { .. } => true, 2902 2903 BitArrayOption::Signed { .. } 2904 | BitArrayOption::Unsigned { .. } 2905 | BitArrayOption::Big { .. } 2906 | BitArrayOption::Little { .. } 2907 | BitArrayOption::Native { .. } 2908 | BitArrayOption::Size { .. } 2909 | BitArrayOption::Unit { .. } => false, 2910 } 2911 } 2912} 2913 2914impl BitArrayOption<TypedConstant> { 2915 fn referenced_variables(&self) -> im::HashSet<&EcoString> { 2916 match self { 2917 BitArrayOption::Bytes { .. } 2918 | BitArrayOption::Int { .. } 2919 | BitArrayOption::Float { .. } 2920 | BitArrayOption::Bits { .. } 2921 | BitArrayOption::Utf8 { .. } 2922 | BitArrayOption::Utf16 { .. } 2923 | BitArrayOption::Utf32 { .. } 2924 | BitArrayOption::Utf8Codepoint { .. } 2925 | BitArrayOption::Utf16Codepoint { .. } 2926 | BitArrayOption::Utf32Codepoint { .. } 2927 | BitArrayOption::Signed { .. } 2928 | BitArrayOption::Unsigned { .. } 2929 | BitArrayOption::Big { .. } 2930 | BitArrayOption::Little { .. } 2931 | BitArrayOption::Unit { .. } 2932 | BitArrayOption::Native { .. } => im::hashset![], 2933 2934 BitArrayOption::Size { value, .. } => value.referenced_variables(), 2935 } 2936 } 2937} 2938 2939impl BitArrayOption<TypedPattern> { 2940 pub fn find_node(&self, byte_index: u32) -> Option<Located<'_>> { 2941 match self { 2942 BitArrayOption::Bytes { .. } 2943 | BitArrayOption::Int { .. } 2944 | BitArrayOption::Float { .. } 2945 | BitArrayOption::Bits { .. } 2946 | BitArrayOption::Utf8 { .. } 2947 | BitArrayOption::Utf16 { .. } 2948 | BitArrayOption::Utf32 { .. } 2949 | BitArrayOption::Utf8Codepoint { .. } 2950 | BitArrayOption::Utf16Codepoint { .. } 2951 | BitArrayOption::Utf32Codepoint { .. } 2952 | BitArrayOption::Signed { .. } 2953 | BitArrayOption::Unsigned { .. } 2954 | BitArrayOption::Big { .. } 2955 | BitArrayOption::Little { .. } 2956 | BitArrayOption::Native { .. } 2957 | BitArrayOption::Unit { .. } => None, 2958 BitArrayOption::Size { value, .. } => value.find_node(byte_index), 2959 } 2960 } 2961} 2962 2963impl BitArrayOption<TypedConstant> { 2964 pub fn find_node(&self, byte_index: u32) -> Option<Located<'_>> { 2965 match self { 2966 BitArrayOption::Bytes { .. } 2967 | BitArrayOption::Int { .. } 2968 | BitArrayOption::Float { .. } 2969 | BitArrayOption::Bits { .. } 2970 | BitArrayOption::Utf8 { .. } 2971 | BitArrayOption::Utf16 { .. } 2972 | BitArrayOption::Utf32 { .. } 2973 | BitArrayOption::Utf8Codepoint { .. } 2974 | BitArrayOption::Utf16Codepoint { .. } 2975 | BitArrayOption::Utf32Codepoint { .. } 2976 | BitArrayOption::Signed { .. } 2977 | BitArrayOption::Unsigned { .. } 2978 | BitArrayOption::Big { .. } 2979 | BitArrayOption::Little { .. } 2980 | BitArrayOption::Native { .. } 2981 | BitArrayOption::Unit { .. } => None, 2982 BitArrayOption::Size { value, .. } => value.find_node(byte_index), 2983 } 2984 } 2985} 2986 2987#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)] 2988pub enum TodoKind { 2989 Keyword, 2990 EmptyFunction { function_location: SrcSpan }, 2991 IncompleteUse, 2992 EmptyBlock, 2993} 2994 2995#[derive(Debug, Default)] 2996pub struct GroupedDefinitions { 2997 pub functions: Vec<UntypedFunction>, 2998 pub constants: Vec<UntypedModuleConstant>, 2999 pub custom_types: Vec<UntypedCustomType>, 3000 pub imports: Vec<UntypedImport>, 3001 pub type_aliases: Vec<UntypedTypeAlias>, 3002} 3003 3004impl GroupedDefinitions { 3005 pub fn new(definitions: impl IntoIterator<Item = UntypedDefinition>) -> Self { 3006 let mut this = Self::default(); 3007 3008 for definition in definitions { 3009 this.add(definition) 3010 } 3011 3012 this 3013 } 3014 3015 pub fn is_empty(&self) -> bool { 3016 self.len() == 0 3017 } 3018 3019 pub fn len(&self) -> usize { 3020 let Self { 3021 custom_types, 3022 functions, 3023 constants, 3024 imports, 3025 type_aliases, 3026 } = self; 3027 functions.len() + constants.len() + imports.len() + custom_types.len() + type_aliases.len() 3028 } 3029 3030 fn add(&mut self, statement: UntypedDefinition) { 3031 match statement { 3032 Definition::Import(import) => self.imports.push(import), 3033 Definition::Function(function) => self.functions.push(function), 3034 Definition::TypeAlias(type_alias) => self.type_aliases.push(type_alias), 3035 Definition::CustomType(custom_type) => self.custom_types.push(custom_type), 3036 Definition::ModuleConstant(constant) => self.constants.push(constant), 3037 } 3038 } 3039} 3040 3041/// A statement with in a function body. 3042#[derive(Debug, Clone, PartialEq, Eq)] 3043pub enum Statement<TypeT, ExpressionT> { 3044 /// A bare expression that is not assigned to any variable. 3045 Expression(ExpressionT), 3046 /// Assigning an expression to variables using a pattern. 3047 Assignment(Box<Assignment<TypeT, ExpressionT>>), 3048 /// A `use` expression. 3049 Use(Use<TypeT, ExpressionT>), 3050 /// A bool assertion. 3051 Assert(Assert<ExpressionT>), 3052} 3053 3054pub type UntypedUse = Use<(), UntypedExpr>; 3055pub type TypedUse = Use<Arc<Type>, TypedExpr>; 3056 3057#[derive(Debug, Clone, PartialEq, Eq)] 3058pub struct Use<TypeT, ExpressionT> { 3059 /// In an untyped use this is the expression with the untyped code of the 3060 /// callback function. 3061 /// 3062 /// In a typed use this is the typed function call the use expression 3063 /// desugars to. 3064 /// 3065 pub call: Box<ExpressionT>, 3066 3067 /// This is the location of the whole use line, starting from the `use` 3068 /// keyword and ending with the function call on the right hand side of 3069 /// `<-`. 3070 /// 3071 /// ```gleam 3072 /// use a <- result.try(result) 3073 /// ^^^^^^^^^^^^^^^^^^^^^^^^^^^ 3074 /// ``` 3075 /// 3076 pub location: SrcSpan, 3077 3078 /// This is the location of the expression on the right hand side of the use 3079 /// arrow. 3080 /// 3081 /// ```gleam 3082 /// use a <- result.try(result) 3083 /// ^^^^^^^^^^^^^^^^^^ 3084 /// ``` 3085 /// 3086 pub right_hand_side_location: SrcSpan, 3087 3088 /// This is the SrcSpan of the patterns you find on the left hand side of 3089 /// `<-` in a use expression. 3090 /// 3091 /// ```gleam 3092 /// use pattern1, pattern2 <- todo 3093 /// ^^^^^^^^^^^^^^^^^^ 3094 /// ``` 3095 /// 3096 /// In case there's no patterns it will be corresponding to the SrcSpan of 3097 /// the `use` keyword itself. 3098 /// 3099 pub assignments_location: SrcSpan, 3100 3101 /// The patterns on the left hand side of `<-` in a use expression. 3102 /// 3103 pub assignments: Vec<UseAssignment<TypeT>>, 3104} 3105 3106pub type UntypedUseAssignment = UseAssignment<()>; 3107pub type TypedUseAssignment = UseAssignment<Arc<Type>>; 3108 3109#[derive(Debug, Clone, PartialEq, Eq)] 3110pub struct UseAssignment<TypeT> { 3111 pub location: SrcSpan, 3112 pub pattern: Pattern<TypeT>, 3113 pub annotation: Option<TypeAst>, 3114} 3115 3116impl TypedUse { 3117 pub fn find_node(&self, byte_index: u32) -> Option<Located<'_>> { 3118 for assignment in self.assignments.iter() { 3119 if let Some(found) = assignment.pattern.find_node(byte_index) { 3120 return Some(found); 3121 } 3122 if let Some(found) = assignment 3123 .annotation 3124 .as_ref() 3125 .and_then(|annotation| annotation.find_node(byte_index, assignment.pattern.type_())) 3126 { 3127 return Some(found); 3128 } 3129 } 3130 self.call.find_node(byte_index) 3131 } 3132 3133 pub fn callback_arguments(&self) -> Option<&Vec<TypedArg>> { 3134 let TypedExpr::Call { args, .. } = self.call.as_ref() else { 3135 return None; 3136 }; 3137 let callback = args.iter().last()?; 3138 let TypedExpr::Fn { args, .. } = &callback.value else { 3139 // The expression might be invalid so we have to return a None here 3140 return None; 3141 }; 3142 Some(args) 3143 } 3144} 3145 3146pub type TypedStatement = Statement<Arc<Type>, TypedExpr>; 3147pub type UntypedStatement = Statement<(), UntypedExpr>; 3148 3149impl<T, E> Statement<T, E> { 3150 /// Returns `true` if the statement is [`Expression`]. 3151 /// 3152 /// [`Expression`]: Statement::Expression 3153 #[must_use] 3154 pub fn is_expression(&self) -> bool { 3155 matches!(self, Self::Expression(..)) 3156 } 3157 3158 #[must_use] 3159 pub(crate) fn is_use(&self) -> bool { 3160 match self { 3161 Self::Use(_) => true, 3162 _ => false, 3163 } 3164 } 3165} 3166 3167impl UntypedStatement { 3168 pub fn location(&self) -> SrcSpan { 3169 match self { 3170 Statement::Expression(expression) => expression.location(), 3171 Statement::Assignment(assignment) => assignment.location, 3172 Statement::Use(use_) => use_.location, 3173 Statement::Assert(assert) => assert.location, 3174 } 3175 } 3176 3177 pub fn start_byte_index(&self) -> u32 { 3178 match self { 3179 Statement::Expression(expression) => expression.start_byte_index(), 3180 Statement::Assignment(assignment) => assignment.location.start, 3181 Statement::Use(use_) => use_.location.start, 3182 Statement::Assert(assert) => assert.location.start, 3183 } 3184 } 3185 3186 pub fn is_placeholder(&self) -> bool { 3187 match self { 3188 Statement::Expression(expression) => expression.is_placeholder(), 3189 Statement::Assignment(_) | Statement::Use(_) | Statement::Assert(_) => false, 3190 } 3191 } 3192} 3193 3194impl TypedStatement { 3195 pub fn is_println(&self) -> bool { 3196 match self { 3197 Statement::Expression(e) => e.is_println(), 3198 Statement::Assignment(_) => false, 3199 Statement::Use(_) => false, 3200 Statement::Assert(_) => false, 3201 } 3202 } 3203 3204 pub fn location(&self) -> SrcSpan { 3205 match self { 3206 Statement::Expression(expression) => expression.location(), 3207 Statement::Assignment(assignment) => assignment.location, 3208 Statement::Use(use_) => use_.location, 3209 Statement::Assert(assert) => assert.location, 3210 } 3211 } 3212 3213 /// Returns the location of the last element of a statement. This means that 3214 /// if the statement is a use you'll get the location of the last item at 3215 /// the end of its block. 3216 pub fn last_location(&self) -> SrcSpan { 3217 match self { 3218 Statement::Expression(expression) => expression.last_location(), 3219 Statement::Assignment(assignment) => assignment.value.last_location(), 3220 Statement::Use(use_) => use_.call.last_location(), 3221 Statement::Assert(assert) => assert.value.last_location(), 3222 } 3223 } 3224 3225 pub fn type_(&self) -> Arc<Type> { 3226 match self { 3227 Statement::Expression(expression) => expression.type_(), 3228 Statement::Assignment(assignment) => assignment.type_(), 3229 Statement::Use(use_) => use_.call.type_(), 3230 Statement::Assert(_) => nil(), 3231 } 3232 } 3233 3234 pub fn definition_location(&self) -> Option<DefinitionLocation> { 3235 match self { 3236 Statement::Expression(expression) => expression.definition_location(), 3237 Statement::Assignment(_) => None, 3238 Statement::Use(use_) => use_.call.definition_location(), 3239 Statement::Assert(_) => None, 3240 } 3241 } 3242 3243 pub fn find_node(&self, byte_index: u32) -> Option<Located<'_>> { 3244 match self { 3245 Statement::Use(use_) => use_.find_node(byte_index), 3246 Statement::Expression(expression) => expression.find_node(byte_index), 3247 Statement::Assignment(assignment) => assignment.find_node(byte_index).or_else(|| { 3248 if assignment.location.contains(byte_index) { 3249 Some(Located::Statement(self)) 3250 } else { 3251 None 3252 } 3253 }), 3254 Statement::Assert(assert) => assert.find_node(byte_index).or_else(|| { 3255 if assert.location.contains(byte_index) { 3256 Some(Located::Statement(self)) 3257 } else { 3258 None 3259 } 3260 }), 3261 } 3262 } 3263 3264 pub fn find_statement(&self, byte_index: u32) -> Option<&TypedStatement> { 3265 match self { 3266 Statement::Use(use_) => use_.call.find_statement(byte_index), 3267 Statement::Expression(expression) => expression.find_statement(byte_index), 3268 Statement::Assignment(assignment) => { 3269 assignment.value.find_statement(byte_index).or_else(|| { 3270 if assignment.location.contains(byte_index) { 3271 Some(self) 3272 } else { 3273 None 3274 } 3275 }) 3276 } 3277 Statement::Assert(assert) => assert.value.find_statement(byte_index).or_else(|| { 3278 if assert.location.contains(byte_index) { 3279 Some(self) 3280 } else { 3281 None 3282 } 3283 }), 3284 } 3285 } 3286 3287 pub fn type_defining_location(&self) -> SrcSpan { 3288 match self { 3289 Statement::Expression(expression) => expression.type_defining_location(), 3290 Statement::Assignment(assignment) => assignment.location, 3291 Statement::Use(use_) => use_.location, 3292 Statement::Assert(assert) => assert.location, 3293 } 3294 } 3295 3296 fn is_pure_value_constructor(&self) -> bool { 3297 match self { 3298 Statement::Expression(expression) => expression.is_pure_value_constructor(), 3299 Statement::Assignment(assignment) => { 3300 // A let assert is not considered a pure value constructor 3301 // as it could crash the program! 3302 !assignment.kind.is_assert() && assignment.value.is_pure_value_constructor() 3303 } 3304 Statement::Use(Use { call, .. }) => call.is_pure_value_constructor(), 3305 // Assert statements by definition are not pure 3306 Statement::Assert(_) => false, 3307 } 3308 } 3309} 3310 3311#[derive(Debug, Clone, PartialEq, Eq)] 3312pub struct Assignment<TypeT, ExpressionT> { 3313 pub location: SrcSpan, 3314 pub value: ExpressionT, 3315 pub pattern: Pattern<TypeT>, 3316 pub kind: AssignmentKind<ExpressionT>, 3317 pub compiled_case: CompiledCase, 3318 /// This will be true for assignments that are automatically generated by 3319 /// the compiler. 3320 pub annotation: Option<TypeAst>, 3321} 3322 3323pub type TypedAssignment = Assignment<Arc<Type>, TypedExpr>; 3324pub type UntypedAssignment = Assignment<(), UntypedExpr>; 3325 3326impl TypedAssignment { 3327 pub fn find_node(&self, byte_index: u32) -> Option<Located<'_>> { 3328 if let Some(annotation) = &self.annotation { 3329 if let Some(l) = annotation.find_node(byte_index, self.pattern.type_()) { 3330 return Some(l); 3331 } 3332 } 3333 self.pattern 3334 .find_node(byte_index) 3335 .or_else(|| self.value.find_node(byte_index)) 3336 } 3337 3338 pub fn type_(&self) -> Arc<Type> { 3339 self.value.type_() 3340 } 3341} 3342 3343pub type TypedAssert = Assert<TypedExpr>; 3344pub type UntypedAssert = Assert<UntypedExpr>; 3345 3346#[derive(Debug, Clone, PartialEq, Eq)] 3347pub struct Assert<Expression> { 3348 pub location: SrcSpan, 3349 pub value: Expression, 3350 pub message: Option<Expression>, 3351} 3352 3353impl TypedAssert { 3354 pub fn find_node(&self, byte_index: u32) -> Option<Located<'_>> { 3355 if let Some(found) = self.value.find_node(byte_index) { 3356 return Some(found); 3357 } 3358 if let Some(message) = &self.message { 3359 if let Some(found) = message.find_node(byte_index) { 3360 return Some(found); 3361 } 3362 } 3363 None 3364 } 3365} 3366 3367/// A pipeline is desugared to a series of assignments: 3368/// 3369/// ```gleam 3370/// wibble |> wobble |> woo 3371/// ``` 3372/// 3373/// Becomes: 3374/// 3375/// ```erl 3376/// Pipe1 = wibble 3377/// Pipe2 = wobble(Pipe1) 3378/// woo(Pipe2) 3379/// ``` 3380/// 3381/// This represents one of such assignments once the pipeline has been desugared 3382/// and each step has been typed. 3383/// 3384/// > We're not using a more general `TypedAssignment` node since that has much 3385/// > more informations to carry around. This one is limited since we know it 3386/// > will always be in the form `VarName = <Expr>`, with no patterns on the 3387/// > left hand side of the assignment. 3388/// > Being more constrained simplifies code generation for pipelines! 3389/// 3390#[derive(Debug, Clone, PartialEq, Eq)] 3391pub struct TypedPipelineAssignment { 3392 pub location: SrcSpan, 3393 pub name: EcoString, 3394 pub value: Box<TypedExpr>, 3395} 3396 3397impl TypedPipelineAssignment { 3398 pub fn find_node(&self, byte_index: u32) -> Option<Located<'_>> { 3399 self.value.find_node(byte_index) 3400 } 3401 3402 pub fn find_statement(&self, byte_index: u32) -> Option<&TypedStatement> { 3403 self.value.find_statement(byte_index) 3404 } 3405 3406 pub fn type_(&self) -> Arc<Type> { 3407 self.value.type_() 3408 } 3409} 3410 3411/// The kind of desugaring that might take place when rewriting a pipeline to 3412/// regular assignments. 3413/// 3414#[derive(Debug, Clone, Copy, PartialEq, Eq)] 3415pub enum PipelineAssignmentKind { 3416 /// In case `a |> b(c)` is desugared to `b(a, c)`. 3417 FirstArgument { 3418 /// The location of the second argument of the call, in case there's any: 3419 /// - `a |> b(c, d)`: here it's `Some` wrapping the location of `c`. 3420 /// - `a |> b()`: here it's `None`. 3421 second_argument: Option<SrcSpan>, 3422 }, 3423 3424 /// In case there's an explicit hole and `a |> b(_, c)` is desugared to 3425 /// `b(a, c)`. 3426 Hole { hole: SrcSpan }, 3427 3428 /// In case `a |> b(c)` is desugared to `b(c)(a)` 3429 FunctionCall, 3430 3431 /// In case there's an echo in the middle of a pipeline `a |> echo` 3432 Echo, 3433}