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
152 kB 4687 lines
1mod constant; 2mod typed; 3mod untyped; 4 5#[cfg(test)] 6mod tests; 7pub mod visit; 8 9pub use self::typed::{InvalidExpression, TypedExpr}; 10pub use self::untyped::{FunctionLiteralKind, UntypedExpr}; 11 12pub use self::constant::{Constant, TypedConstant, UntypedConstant}; 13 14use crate::analyse::Inferred; 15use crate::ast::typed::pairwise_all; 16use crate::bit_array; 17use crate::build::{ExpressionPosition, Located, Target, module_erlang_name}; 18use crate::exhaustiveness::CompiledCase; 19use crate::parse::{LiteralFloatValue, SpannedString}; 20use crate::type_::error::VariableOrigin; 21use crate::type_::expression::{Implementations, Purity}; 22use crate::type_::printer::Names; 23use crate::type_::{ 24 self, Deprecation, HasType, ModuleValueConstructor, PatternConstructor, Type, TypedCallArg, 25 ValueConstructor, ValueConstructorVariant, nil, 26}; 27use itertools::Itertools; 28use num_traits::Zero; 29use std::collections::HashSet; 30use std::sync::Arc; 31 32use ecow::EcoString; 33use num_bigint::{BigInt, Sign}; 34use num_traits::{One, ToPrimitive}; 35#[cfg(test)] 36use pretty_assertions::assert_eq; 37use vec1::Vec1; 38 39pub const PIPE_VARIABLE: &str = "_pipe"; 40pub const USE_ASSIGNMENT_VARIABLE: &str = "_use"; 41pub const RECORD_UPDATE_VARIABLE: &str = "_record"; 42pub const ASSERT_FAIL_VARIABLE: &str = "_assert_fail"; 43pub const ASSERT_SUBJECT_VARIABLE: &str = "_assert_subject"; 44pub const CAPTURE_VARIABLE: &str = "_capture"; 45pub const BLOCK_VARIABLE: &str = "_block"; 46 47pub trait HasLocation { 48 fn location(&self) -> SrcSpan; 49} 50 51pub type UntypedModule = Module<(), Vec<TargetedDefinition>>; 52pub type TypedModule = Module<type_::ModuleInterface, TypedDefinitions>; 53 54#[derive(Debug, Clone, PartialEq, Eq)] 55pub struct Module<Info, Definitions> { 56 pub name: EcoString, 57 pub documentation: Vec<EcoString>, 58 pub type_info: Info, 59 pub definitions: Definitions, 60 pub names: Names, 61 /// The source byte locations of definition that are unused. 62 /// This is used in code generation to know when definitions can be safely omitted. 63 pub unused_definition_positions: HashSet<u32>, 64} 65 66impl<Info, Definitions> Module<Info, Definitions> { 67 pub fn erlang_name(&self) -> EcoString { 68 module_erlang_name(&self.name) 69 } 70} 71 72impl TypedModule { 73 pub fn find_node(&self, byte_index: u32) -> Option<Located<'_>> { 74 let TypedDefinitions { 75 imports, 76 constants, 77 custom_types, 78 type_aliases, 79 functions, 80 } = &self.definitions; 81 82 imports 83 .iter() 84 .find_map(|import| import.find_node(byte_index)) 85 .or_else(|| (constants.iter()).find_map(|constant| constant.find_node(byte_index))) 86 .or_else(|| (custom_types.iter()).find_map(|type_| type_.find_node(byte_index))) 87 .or_else(|| (type_aliases.iter()).find_map(|alias| alias.find_node(byte_index))) 88 .or_else(|| (functions.iter()).find_map(|function| function.find_node(byte_index))) 89 } 90 91 pub fn find_statement(&self, byte_index: u32) -> Option<&TypedStatement> { 92 // Statements can only be found inside a module function, there's no 93 // need to go over all the other module definitions. 94 self.definitions 95 .functions 96 .iter() 97 .find_map(|function| function.find_statement(byte_index)) 98 } 99 100 pub fn definitions_len(&self) -> usize { 101 let TypedDefinitions { 102 imports, 103 constants, 104 custom_types, 105 type_aliases, 106 functions, 107 } = &self.definitions; 108 109 imports.len() + constants.len() + custom_types.len() + type_aliases.len() + functions.len() 110 } 111} 112 113#[derive(Debug)] 114pub struct TypedDefinitions { 115 pub imports: Vec<TypedImport>, 116 pub constants: Vec<TypedModuleConstant>, 117 pub custom_types: Vec<TypedCustomType>, 118 pub type_aliases: Vec<TypedTypeAlias>, 119 pub functions: Vec<TypedFunction>, 120} 121 122/// The `@target(erlang)` and `@target(javascript)` attributes can be used to 123/// mark a definition as only being for a specific target. 124/// 125/// ```gleam 126/// const x: Int = 1 127/// 128/// @target(erlang) 129/// pub fn main(a) { ...} 130/// ``` 131/// 132#[derive(Debug, Clone, PartialEq, Eq)] 133pub struct TargetedDefinition { 134 pub definition: UntypedDefinition, 135 pub target: Option<Target>, 136} 137 138impl TargetedDefinition { 139 pub fn is_for(&self, target: Target) -> bool { 140 self.target.map(|t| t == target).unwrap_or(true) 141 } 142} 143 144impl UntypedModule { 145 pub fn dependencies(&self, target: Target) -> Vec<(EcoString, SrcSpan)> { 146 self.iter_definitions(target) 147 .flat_map(|definition| match definition { 148 Definition::Import(Import { 149 module, location, .. 150 }) => Some((module.clone(), *location)), 151 Definition::Function(_) 152 | Definition::TypeAlias(_) 153 | Definition::CustomType(_) 154 | Definition::ModuleConstant(_) => None, 155 }) 156 .collect() 157 } 158 159 pub fn iter_definitions(&self, target: Target) -> impl Iterator<Item = &UntypedDefinition> { 160 self.definitions 161 .iter() 162 .filter(move |definition| definition.is_for(target)) 163 .map(|definition| &definition.definition) 164 } 165 166 pub fn into_iter_definitions(self, target: Target) -> impl Iterator<Item = UntypedDefinition> { 167 self.definitions 168 .into_iter() 169 .filter(move |definition| definition.is_for(target)) 170 .map(|definition| definition.definition) 171 } 172} 173 174#[test] 175fn module_dependencies_test() { 176 let parsed = crate::parse::parse_module( 177 camino::Utf8PathBuf::from("test/path"), 178 "import one 179 @target(erlang) 180 import two 181 182 @target(javascript) 183 import three 184 185 import four", 186 &crate::warning::WarningEmitter::null(), 187 ) 188 .expect("syntax error"); 189 let module = parsed.module; 190 191 assert_eq!( 192 vec![ 193 ("one".into(), SrcSpan::new(0, 10)), 194 ("two".into(), SrcSpan::new(45, 55)), 195 ("four".into(), SrcSpan::new(118, 129)), 196 ], 197 module.dependencies(Target::Erlang) 198 ); 199} 200 201pub type TypedArg = Arg<Arc<Type>>; 202pub type UntypedArg = Arg<()>; 203 204#[derive(Debug, Clone, PartialEq, Eq)] 205pub struct Arg<T> { 206 pub names: ArgNames, 207 pub location: SrcSpan, 208 pub annotation: Option<TypeAst>, 209 pub type_: T, 210} 211 212impl<A> Arg<A> { 213 pub fn set_type<B>(self, t: B) -> Arg<B> { 214 Arg { 215 type_: t, 216 names: self.names, 217 location: self.location, 218 annotation: self.annotation, 219 } 220 } 221 222 pub fn get_variable_name(&self) -> Option<&EcoString> { 223 self.names.get_variable_name() 224 } 225 226 pub fn is_capture_hole(&self) -> bool { 227 match &self.names { 228 ArgNames::Named { name, .. } if name == CAPTURE_VARIABLE => true, 229 ArgNames::Discard { .. } 230 | ArgNames::LabelledDiscard { .. } 231 | ArgNames::Named { .. } 232 | ArgNames::NamedLabelled { .. } => false, 233 } 234 } 235} 236 237impl TypedArg { 238 pub fn find_node(&self, byte_index: u32) -> Option<Located<'_>> { 239 if self.location.contains(byte_index) { 240 if let Some(annotation) = &self.annotation { 241 return annotation 242 .find_node(byte_index, self.type_.clone()) 243 .or(Some(Located::Arg(self))); 244 } 245 Some(Located::Arg(self)) 246 } else { 247 None 248 } 249 } 250} 251 252#[derive(Debug, Clone, PartialEq, Eq)] 253pub enum ArgNames { 254 Discard { 255 name: EcoString, 256 location: SrcSpan, 257 }, 258 LabelledDiscard { 259 label: EcoString, 260 label_location: SrcSpan, 261 name: EcoString, 262 name_location: SrcSpan, 263 }, 264 Named { 265 name: EcoString, 266 location: SrcSpan, 267 }, 268 NamedLabelled { 269 label: EcoString, 270 label_location: SrcSpan, 271 name: EcoString, 272 name_location: SrcSpan, 273 }, 274} 275 276impl ArgNames { 277 pub fn get_label(&self) -> Option<&EcoString> { 278 match self { 279 ArgNames::Discard { .. } | ArgNames::Named { .. } => None, 280 ArgNames::LabelledDiscard { label, .. } | ArgNames::NamedLabelled { label, .. } => { 281 Some(label) 282 } 283 } 284 } 285 pub fn get_variable_name(&self) -> Option<&EcoString> { 286 match self { 287 ArgNames::Discard { .. } | ArgNames::LabelledDiscard { .. } => None, 288 ArgNames::NamedLabelled { name, .. } | ArgNames::Named { name, .. } => Some(name), 289 } 290 } 291} 292 293pub type TypedRecordConstructor = RecordConstructor<Arc<Type>>; 294 295#[derive(Debug, Clone, PartialEq, Eq)] 296pub struct RecordConstructor<T> { 297 pub location: SrcSpan, 298 pub name_location: SrcSpan, 299 pub name: EcoString, 300 pub arguments: Vec<RecordConstructorArg<T>>, 301 pub documentation: Option<(u32, EcoString)>, 302 pub deprecation: Deprecation, 303} 304 305impl<A> RecordConstructor<A> { 306 pub fn put_doc(&mut self, new_doc: (u32, EcoString)) { 307 self.documentation = Some(new_doc); 308 } 309} 310 311pub type TypedRecordConstructorArg = RecordConstructorArg<Arc<Type>>; 312 313#[derive(Debug, Clone, PartialEq, Eq)] 314pub struct RecordConstructorArg<T> { 315 pub label: Option<SpannedString>, 316 pub ast: TypeAst, 317 pub location: SrcSpan, 318 pub type_: T, 319 pub doc: Option<(u32, EcoString)>, 320} 321 322impl<T: PartialEq> RecordConstructorArg<T> { 323 pub fn put_doc(&mut self, new_doc: (u32, EcoString)) { 324 self.doc = Some(new_doc); 325 } 326} 327 328#[derive(Debug, Clone, PartialEq, Eq)] 329pub struct TypeAstConstructor { 330 pub location: SrcSpan, 331 pub name: TypeAstConstructorName, 332 pub arguments: Vec<TypeAst>, 333 pub start_parentheses: Option<u32>, 334} 335 336/// This represents a type constructor name, that can either be qualified, or 337/// unqualified. 338#[derive(Debug, Clone, PartialEq, Eq)] 339pub enum TypeAstConstructorName { 340 /// ```gleam 341 /// pub fn wibble() -> wibble.Wibble 342 /// // ^^^^^^ module 343 /// // ^^^^^^ name 344 /// ``` 345 Qualified { 346 module: EcoString, 347 module_location: SrcSpan, 348 dot_location: u32, 349 /// Notice how the name could be missing, this is an error! However, instead 350 /// of treating it like a syntax error we allow parsing it and report it 351 /// later. This way the language server can provide better help! 352 name: Option<(EcoString, SrcSpan)>, 353 }, 354 355 /// ```gleam 356 /// pub fn wibble() -> Wibble 357 /// // ^^^^^^ name 358 /// ``` 359 Unqualified { name: EcoString, location: SrcSpan }, 360} 361 362impl TypeAstConstructorName { 363 pub fn is_qualified(&self) -> bool { 364 match self { 365 TypeAstConstructorName::Qualified { .. } => true, 366 TypeAstConstructorName::Unqualified { .. } => false, 367 } 368 } 369 370 pub fn module_name(&self) -> Option<&EcoString> { 371 match self { 372 TypeAstConstructorName::Qualified { module, .. } => Some(module), 373 TypeAstConstructorName::Unqualified { .. } => None, 374 } 375 } 376 377 pub fn name(&self) -> Option<&EcoString> { 378 match self { 379 TypeAstConstructorName::Unqualified { name, .. } 380 | TypeAstConstructorName::Qualified { 381 name: Some((name, _)), 382 .. 383 } => Some(name), 384 385 TypeAstConstructorName::Qualified { name: None, .. } => None, 386 } 387 } 388 389 pub fn name_location(&self) -> Option<SrcSpan> { 390 match self { 391 TypeAstConstructorName::Unqualified { location, .. } 392 | TypeAstConstructorName::Qualified { 393 name: Some((_, location)), 394 .. 395 } => Some(*location), 396 397 TypeAstConstructorName::Qualified { name: None, .. } => None, 398 } 399 } 400 401 fn is_logically_equal(&self, other: &TypeAstConstructorName) -> bool { 402 match (self, other) { 403 ( 404 TypeAstConstructorName::Qualified { module, name, .. }, 405 TypeAstConstructorName::Qualified { 406 module: other_module, 407 name: other_name, 408 .. 409 }, 410 ) => { 411 module == other_module 412 && match (name, other_name) { 413 (Some((name, _)), Some((other_name, _))) => name == other_name, 414 (None, Some(_)) | (Some(_), None) => false, 415 (None, None) => true, 416 } 417 } 418 419 ( 420 TypeAstConstructorName::Unqualified { name, location: _ }, 421 TypeAstConstructorName::Unqualified { 422 name: other_name, 423 location: _, 424 }, 425 ) => name == other_name, 426 427 ( 428 TypeAstConstructorName::Qualified { .. }, 429 TypeAstConstructorName::Unqualified { .. }, 430 ) 431 | ( 432 TypeAstConstructorName::Unqualified { .. }, 433 TypeAstConstructorName::Qualified { .. }, 434 ) => false, 435 } 436 } 437} 438 439#[derive(Debug, Clone, PartialEq, Eq)] 440pub struct TypeAstFn { 441 pub location: SrcSpan, 442 pub arguments: Vec<TypeAst>, 443 pub return_: Box<TypeAst>, 444} 445 446#[derive(Debug, Clone, PartialEq, Eq)] 447pub struct TypeAstVar { 448 pub location: SrcSpan, 449 pub name: EcoString, 450} 451 452#[derive(Debug, Clone, PartialEq, Eq)] 453pub struct TypeAstTuple { 454 pub location: SrcSpan, 455 pub elements: Vec<TypeAst>, 456} 457 458#[derive(Debug, Clone, PartialEq, Eq)] 459pub struct TypeAstHole { 460 pub location: SrcSpan, 461 pub name: EcoString, 462} 463 464#[derive(Debug, Clone, PartialEq, Eq)] 465pub enum TypeAst { 466 Constructor(TypeAstConstructor), 467 Fn(TypeAstFn), 468 Var(TypeAstVar), 469 Tuple(TypeAstTuple), 470 Hole(TypeAstHole), 471} 472 473impl TypeAst { 474 pub fn location(&self) -> SrcSpan { 475 match self { 476 TypeAst::Fn(TypeAstFn { location, .. }) 477 | TypeAst::Var(TypeAstVar { location, .. }) 478 | TypeAst::Hole(TypeAstHole { location, .. }) 479 | TypeAst::Tuple(TypeAstTuple { location, .. }) 480 | TypeAst::Constructor(TypeAstConstructor { location, .. }) => *location, 481 } 482 } 483 484 pub fn is_logically_equal(&self, other: &TypeAst) -> bool { 485 match self { 486 TypeAst::Constructor(TypeAstConstructor { 487 name, 488 arguments, 489 location: _, 490 start_parentheses: _, 491 }) => match other { 492 TypeAst::Constructor(TypeAstConstructor { 493 name: other_name, 494 arguments: other_arguments, 495 location: _, 496 start_parentheses: _, 497 }) => { 498 name.is_logically_equal(other_name) 499 && arguments.len() == other_arguments.len() 500 && arguments 501 .iter() 502 .zip(other_arguments) 503 .all(|argument| argument.0.is_logically_equal(argument.1)) 504 } 505 TypeAst::Fn(_) | TypeAst::Var(_) | TypeAst::Tuple(_) | TypeAst::Hole(_) => false, 506 }, 507 TypeAst::Fn(TypeAstFn { 508 arguments, 509 return_, 510 location: _, 511 }) => match other { 512 TypeAst::Fn(TypeAstFn { 513 arguments: o_arguments, 514 return_: o_return_, 515 location: _, 516 }) => { 517 arguments.len() == o_arguments.len() 518 && arguments 519 .iter() 520 .zip(o_arguments) 521 .all(|a| a.0.is_logically_equal(a.1)) 522 && return_.is_logically_equal(o_return_) 523 } 524 TypeAst::Constructor(_) 525 | TypeAst::Var(_) 526 | TypeAst::Tuple(_) 527 | TypeAst::Hole(_) => false, 528 }, 529 TypeAst::Var(TypeAstVar { name, location: _ }) => match other { 530 TypeAst::Var(TypeAstVar { 531 name: o_name, 532 location: _, 533 }) => name == o_name, 534 TypeAst::Constructor(_) | TypeAst::Fn(_) | TypeAst::Tuple(_) | TypeAst::Hole(_) => { 535 false 536 } 537 }, 538 TypeAst::Tuple(TypeAstTuple { 539 elements, 540 location: _, 541 }) => match other { 542 TypeAst::Tuple(TypeAstTuple { 543 elements: other_elements, 544 location: _, 545 }) => { 546 elements.len() == other_elements.len() 547 && elements 548 .iter() 549 .zip(other_elements) 550 .all(|a| a.0.is_logically_equal(a.1)) 551 } 552 TypeAst::Constructor(_) | TypeAst::Fn(_) | TypeAst::Var(_) | TypeAst::Hole(_) => { 553 false 554 } 555 }, 556 TypeAst::Hole(TypeAstHole { name, location: _ }) => match other { 557 TypeAst::Hole(TypeAstHole { 558 name: o_name, 559 location: _, 560 }) => name == o_name, 561 TypeAst::Constructor(_) | TypeAst::Fn(_) | TypeAst::Var(_) | TypeAst::Tuple(_) => { 562 false 563 } 564 }, 565 } 566 } 567 568 pub fn find_node(&self, byte_index: u32, type_: Arc<Type>) -> Option<Located<'_>> { 569 if !self.location().contains(byte_index) { 570 return None; 571 } 572 573 match self { 574 TypeAst::Fn(TypeAstFn { 575 arguments, return_, .. 576 }) => type_ 577 .fn_types() 578 .and_then(|(arg_types, ret_type)| { 579 if let Some(arg) = arguments 580 .iter() 581 .zip(arg_types) 582 .find_map(|(arg, arg_type)| arg.find_node(byte_index, arg_type.clone())) 583 { 584 return Some(arg); 585 } 586 if let Some(ret) = return_.find_node(byte_index, ret_type) { 587 return Some(ret); 588 } 589 590 None 591 }) 592 .or(Some(Located::Annotation { ast: self, type_ })), 593 TypeAst::Constructor(TypeAstConstructor { 594 arguments, name, .. 595 }) => { 596 // 597 type_ 598 .named_type_information() 599 .and_then(|(module_name, _, arg_types)| { 600 if let Some(arg) = arguments 601 .iter() 602 .zip(arg_types) 603 .find_map(|(arg, arg_type)| arg.find_node(byte_index, arg_type.clone())) 604 { 605 return Some(arg); 606 } 607 608 if let TypeAstConstructorName::Qualified { 609 module_location, 610 module: module_alias, 611 .. 612 } = name 613 && module_location.contains(byte_index) 614 { 615 return Some(Located::ModuleName { 616 location: *module_location, 617 module_name, 618 module_alias: module_alias.clone(), 619 layer: Layer::Type, 620 }); 621 } 622 623 None 624 }) 625 .or(Some(Located::Annotation { ast: self, type_ })) 626 } 627 TypeAst::Tuple(TypeAstTuple { elements, .. }) => type_ 628 .tuple_types() 629 .and_then(|elem_types| { 630 if let Some(e) = elements 631 .iter() 632 .zip(elem_types) 633 .find_map(|(e, e_type)| e.find_node(byte_index, e_type.clone())) 634 { 635 return Some(e); 636 } 637 638 None 639 }) 640 .or(Some(Located::Annotation { ast: self, type_ })), 641 TypeAst::Var(_) | TypeAst::Hole(_) => Some(Located::Annotation { ast: self, type_ }), 642 } 643 } 644 645 /// Generates an annotation corresponding to the type. 646 pub fn print(&self, buffer: &mut EcoString) { 647 match &self { 648 TypeAst::Var(var) => buffer.push_str(&var.name), 649 TypeAst::Hole(hole) => buffer.push_str(&hole.name), 650 TypeAst::Tuple(tuple) => { 651 buffer.push_str("#("); 652 for (i, element) in tuple.elements.iter().enumerate() { 653 element.print(buffer); 654 if i < tuple.elements.len() - 1 { 655 buffer.push_str(", "); 656 } 657 } 658 buffer.push(')') 659 } 660 TypeAst::Fn(func) => { 661 buffer.push_str("fn("); 662 for (i, argument) in func.arguments.iter().enumerate() { 663 argument.print(buffer); 664 if i < func.arguments.len() - 1 { 665 buffer.push_str(", "); 666 } 667 } 668 buffer.push(')'); 669 buffer.push_str(" -> "); 670 func.return_.print(buffer); 671 } 672 TypeAst::Constructor(constructor) => { 673 match &constructor.name { 674 TypeAstConstructorName::Unqualified { name, .. } => buffer.push_str(name), 675 TypeAstConstructorName::Qualified { module, name, .. } => { 676 buffer.push_str(module); 677 buffer.push('.'); 678 if let Some((name, _name_location)) = name { 679 buffer.push_str(name); 680 } 681 } 682 }; 683 684 if !constructor.arguments.is_empty() { 685 buffer.push('('); 686 for (i, argument) in constructor.arguments.iter().enumerate() { 687 argument.print(buffer); 688 if i < constructor.arguments.len() - 1 { 689 buffer.push_str(", "); 690 } 691 } 692 buffer.push(')'); 693 } 694 } 695 } 696 } 697} 698 699#[test] 700fn type_ast_print_fn() { 701 let mut buffer = EcoString::new(); 702 let ast = TypeAst::Fn(TypeAstFn { 703 location: SrcSpan { start: 1, end: 1 }, 704 arguments: vec![ 705 TypeAst::Var(TypeAstVar { 706 location: SrcSpan { start: 1, end: 1 }, 707 name: "String".into(), 708 }), 709 TypeAst::Var(TypeAstVar { 710 location: SrcSpan { start: 1, end: 1 }, 711 name: "Bool".into(), 712 }), 713 ], 714 return_: Box::new(TypeAst::Var(TypeAstVar { 715 location: SrcSpan { start: 1, end: 1 }, 716 name: "Int".into(), 717 })), 718 }); 719 ast.print(&mut buffer); 720 assert_eq!(&buffer, "fn(String, Bool) -> Int") 721} 722 723#[test] 724fn type_ast_print_constructor() { 725 let mut buffer = EcoString::new(); 726 let ast = TypeAst::Constructor(TypeAstConstructor { 727 name: TypeAstConstructorName::Qualified { 728 module: "some_module".into(), 729 dot_location: 1, 730 module_location: SrcSpan { start: 1, end: 1 }, 731 name: Some(("SomeType".into(), SrcSpan { start: 1, end: 1 })), 732 }, 733 location: SrcSpan { start: 1, end: 1 }, 734 arguments: vec![ 735 TypeAst::Var(TypeAstVar { 736 location: SrcSpan { start: 1, end: 1 }, 737 name: "String".into(), 738 }), 739 TypeAst::Var(TypeAstVar { 740 location: SrcSpan { start: 1, end: 1 }, 741 name: "Bool".into(), 742 }), 743 ], 744 start_parentheses: Some(1), 745 }); 746 ast.print(&mut buffer); 747 assert_eq!(&buffer, "some_module.SomeType(String, Bool)") 748} 749 750#[test] 751fn type_ast_print_tuple() { 752 let mut buffer = EcoString::new(); 753 let ast = TypeAst::Tuple(TypeAstTuple { 754 location: SrcSpan { start: 1, end: 1 }, 755 elements: vec![ 756 TypeAst::Constructor(TypeAstConstructor { 757 name: TypeAstConstructorName::Qualified { 758 module: "some_module".into(), 759 module_location: SrcSpan { start: 1, end: 1 }, 760 dot_location: 1, 761 name: Some(("SomeType".into(), SrcSpan { start: 1, end: 1 })), 762 }, 763 location: SrcSpan { start: 1, end: 1 }, 764 arguments: vec![ 765 TypeAst::Var(TypeAstVar { 766 location: SrcSpan { start: 1, end: 1 }, 767 name: "String".into(), 768 }), 769 TypeAst::Var(TypeAstVar { 770 location: SrcSpan { start: 1, end: 1 }, 771 name: "Bool".into(), 772 }), 773 ], 774 start_parentheses: Some(1), 775 }), 776 TypeAst::Fn(TypeAstFn { 777 location: SrcSpan { start: 1, end: 1 }, 778 arguments: vec![ 779 TypeAst::Var(TypeAstVar { 780 location: SrcSpan { start: 1, end: 1 }, 781 name: "String".into(), 782 }), 783 TypeAst::Var(TypeAstVar { 784 location: SrcSpan { start: 1, end: 1 }, 785 name: "Bool".into(), 786 }), 787 ], 788 return_: Box::new(TypeAst::Var(TypeAstVar { 789 location: SrcSpan { start: 1, end: 1 }, 790 name: "Int".into(), 791 })), 792 }), 793 ], 794 }); 795 ast.print(&mut buffer); 796 assert_eq!( 797 &buffer, 798 "#(some_module.SomeType(String, Bool), fn(String, Bool) -> Int)" 799 ) 800} 801 802#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)] 803pub enum Publicity { 804 Public, 805 Private, 806 Internal { attribute_location: Option<SrcSpan> }, 807} 808 809impl Publicity { 810 pub fn is_private(&self) -> bool { 811 match self { 812 Self::Private => true, 813 Self::Public | Self::Internal { .. } => false, 814 } 815 } 816 817 pub fn is_internal(&self) -> bool { 818 match self { 819 Self::Internal { .. } => true, 820 Self::Public | Self::Private => false, 821 } 822 } 823 824 pub fn is_public(&self) -> bool { 825 match self { 826 Self::Public => true, 827 Self::Internal { .. } | Self::Private => false, 828 } 829 } 830 831 pub fn is_importable(&self) -> bool { 832 match self { 833 Self::Internal { .. } | Self::Public => true, 834 Self::Private => false, 835 } 836 } 837} 838 839#[derive(Debug, Clone, PartialEq, Eq)] 840/// A function definition 841/// 842/// Note that an anonymous function will have `None` as the name field, while a 843/// named function will have `Some`. 844/// 845/// # Example(s) 846/// 847/// ```gleam 848/// // Public function 849/// pub fn wobble() -> String { ... } 850/// // Private function 851/// fn wibble(x: Int) -> Int { ... } 852/// // Anonymous function 853/// fn(x: Int) { ... } 854/// ``` 855pub struct Function<T, Expr> { 856 pub location: SrcSpan, 857 pub body_start: Option<u32>, 858 pub end_position: u32, 859 pub name: Option<SpannedString>, 860 pub arguments: Vec<Arg<T>>, 861 pub body: Vec<Statement<T, Expr>>, 862 pub publicity: Publicity, 863 pub deprecation: Deprecation, 864 pub return_annotation: Option<TypeAst>, 865 pub return_type: T, 866 pub documentation: Option<(u32, EcoString)>, 867 pub external_erlang: Option<(EcoString, EcoString, SrcSpan)>, 868 pub external_javascript: Option<(EcoString, EcoString, SrcSpan)>, 869 pub implementations: Implementations, 870 pub purity: Purity, 871} 872 873pub type TypedFunction = Function<Arc<Type>, TypedExpr>; 874pub type UntypedFunction = Function<(), UntypedExpr>; 875 876impl<T, E> Function<T, E> { 877 pub fn full_location(&self) -> SrcSpan { 878 SrcSpan::new(self.location.start, self.end_position) 879 } 880} 881 882impl TypedFunction { 883 pub fn find_node(&self, byte_index: u32) -> Option<Located<'_>> { 884 // Search for the corresponding node inside the function 885 // only if the index falls within the function's full location. 886 if !self.full_location().contains(byte_index) { 887 return None; 888 } 889 890 if let Some(found) = self 891 .body 892 .iter() 893 .find_map(|statement| statement.find_node(byte_index)) 894 { 895 return Some(found); 896 } 897 898 if let Some(found_arg) = self 899 .arguments 900 .iter() 901 .find_map(|arg| arg.find_node(byte_index)) 902 { 903 return Some(found_arg); 904 }; 905 906 if let Some(found_statement) = self 907 .body 908 .iter() 909 .find(|statement| statement.location().contains(byte_index)) 910 { 911 return Some(Located::Statement(found_statement)); 912 }; 913 914 // Check if location is within the return annotation. 915 if let Some(located) = self 916 .return_annotation 917 .iter() 918 .find_map(|annotation| annotation.find_node(byte_index, self.return_type.clone())) 919 { 920 return Some(located); 921 }; 922 923 // Note that the fn `.location` covers the function head, not 924 // the entire statement. 925 if self.location.contains(byte_index) { 926 Some(Located::ModuleFunction(self)) 927 } else if self.full_location().contains(byte_index) { 928 Some(Located::FunctionBody(self)) 929 } else { 930 None 931 } 932 } 933 934 pub fn find_statement(&self, byte_index: u32) -> Option<&TypedStatement> { 935 if !self.full_location().contains(byte_index) { 936 return None; 937 } 938 939 self.body 940 .iter() 941 .find_map(|statement| statement.find_statement(byte_index)) 942 } 943 944 pub fn main_function(&self) -> Option<&TypedFunction> { 945 if let Some((_, name)) = &self.name 946 && name == "main" 947 { 948 Some(self) 949 } else { 950 None 951 } 952 } 953} 954 955pub type UntypedImport = Import<()>; 956pub type TypedImport = Import<EcoString>; 957 958#[derive(Debug, Clone, PartialEq, Eq)] 959/// Import another Gleam module so the current module can use the types and 960/// values it defines. 961/// 962/// # Example(s) 963/// 964/// ```gleam 965/// import unix/cat 966/// // Import with alias 967/// import animal/cat as kitty 968/// ``` 969pub struct Import<PackageName> { 970 pub documentation: Option<EcoString>, 971 pub location: SrcSpan, 972 pub module_location: SrcSpan, 973 pub module: EcoString, 974 pub as_name: Option<(AssignName, SrcSpan)>, 975 pub unqualified_values: Vec<UnqualifiedImport>, 976 pub unqualified_types: Vec<UnqualifiedImport>, 977 pub package: PackageName, 978} 979 980impl<T> Import<T> { 981 pub fn used_name(&self) -> Option<EcoString> { 982 match self.as_name.as_ref() { 983 Some((AssignName::Variable(name), _)) => Some(name.clone()), 984 Some((AssignName::Discard(_), _)) => None, 985 None => self.module.split('/').next_back().map(EcoString::from), 986 } 987 } 988 989 pub(crate) fn alias_location(&self) -> Option<SrcSpan> { 990 self.as_name.as_ref().map(|(_, location)| *location) 991 } 992} 993 994impl TypedImport { 995 pub fn find_node(&self, byte_index: u32) -> Option<Located<'_>> { 996 if !self.location.contains(byte_index) { 997 return None; 998 } 999 1000 if let Some(unqualified) = self 1001 .unqualified_values 1002 .iter() 1003 .find(|unqualified_value| unqualified_value.location.contains(byte_index)) 1004 { 1005 return Some(Located::UnqualifiedImport( 1006 crate::build::UnqualifiedImport { 1007 name: &unqualified.name, 1008 module: &self.module, 1009 is_type: false, 1010 location: &unqualified.location, 1011 }, 1012 )); 1013 } 1014 1015 if let Some(unqualified) = self 1016 .unqualified_types 1017 .iter() 1018 .find(|unqualified_value| unqualified_value.location.contains(byte_index)) 1019 { 1020 return Some(Located::UnqualifiedImport( 1021 crate::build::UnqualifiedImport { 1022 name: &unqualified.name, 1023 module: &self.module, 1024 is_type: true, 1025 location: &unqualified.location, 1026 }, 1027 )); 1028 } 1029 1030 Some(Located::ModuleImport(self)) 1031 } 1032} 1033 1034pub type UntypedModuleConstant = ModuleConstant<()>; 1035pub type TypedModuleConstant = ModuleConstant<Arc<Type>>; 1036 1037#[derive(Debug, Clone, PartialEq, Eq)] 1038/// A certain fixed value that can be used in multiple places 1039/// 1040/// # Example(s) 1041/// 1042/// ```gleam 1043/// pub const start_year = 2101 1044/// pub const end_year = 2111 1045/// ``` 1046pub struct ModuleConstant<T> { 1047 pub documentation: Option<(u32, EcoString)>, 1048 /// The location of the constant, starting at the "(pub) const" keywords and 1049 /// ending after the ": Type" annotation, or (without an annotation) after its name. 1050 pub location: SrcSpan, 1051 pub publicity: Publicity, 1052 pub name: EcoString, 1053 pub name_location: SrcSpan, 1054 pub annotation: Option<TypeAst>, 1055 pub value: Box<Constant<T>>, 1056 pub type_: T, 1057 pub deprecation: Deprecation, 1058 pub implementations: Implementations, 1059} 1060 1061impl TypedModuleConstant { 1062 pub fn find_node(&self, byte_index: u32) -> Option<Located<'_>> { 1063 // Check if location is within the annotation. 1064 if let Some(annotation) = &self.annotation 1065 && let Some(located) = annotation.find_node(byte_index, self.type_.clone()) 1066 { 1067 return Some(located); 1068 } 1069 1070 if let Some(located) = self.value.find_node(byte_index) { 1071 return Some(located); 1072 } 1073 1074 if self.location.contains(byte_index) { 1075 Some(Located::ModuleConstant(self)) 1076 } else { 1077 None 1078 } 1079 } 1080} 1081 1082pub type UntypedCustomType = CustomType<()>; 1083pub type TypedCustomType = CustomType<Arc<Type>>; 1084 1085#[derive(Debug, Clone, PartialEq, Eq)] 1086/// A newly defined type with one or more constructors. 1087/// Each variant of the custom type can contain different types, so the type is 1088/// the product of the types contained by each variant. 1089/// 1090/// This might be called an algebraic data type (ADT) or tagged union in other 1091/// languages and type systems. 1092/// 1093/// 1094/// # Example(s) 1095/// 1096/// ```gleam 1097/// pub type Cat { 1098/// Cat(name: String, cuteness: Int) 1099/// } 1100/// ``` 1101pub struct CustomType<T> { 1102 pub location: SrcSpan, 1103 pub end_position: u32, 1104 pub name: EcoString, 1105 pub name_location: SrcSpan, 1106 pub publicity: Publicity, 1107 pub constructors: Vec<RecordConstructor<T>>, 1108 pub documentation: Option<(u32, EcoString)>, 1109 pub deprecation: Deprecation, 1110 pub opaque: bool, 1111 /// The names of the type parameters. 1112 pub parameters: Vec<SpannedString>, 1113 /// Once type checked this field will contain the type information for the 1114 /// type parameters. 1115 pub typed_parameters: Vec<T>, 1116 pub external_erlang: Option<(EcoString, EcoString, SrcSpan)>, 1117 pub external_javascript: Option<(EcoString, EcoString, SrcSpan)>, 1118} 1119 1120impl<T> CustomType<T> { 1121 /// The `location` field of a `CustomType` is only the location of `pub type 1122 /// TheName`. This method returns a `SrcSpan` that includes the entire type 1123 /// definition. 1124 pub fn full_location(&self) -> SrcSpan { 1125 SrcSpan::new(self.location.start, self.end_position) 1126 } 1127} 1128 1129impl TypedCustomType { 1130 pub fn find_node(&self, byte_index: u32) -> Option<Located<'_>> { 1131 // Check if location is within the type of one of the arguments of a constructor. 1132 if let Some(constructor) = self 1133 .constructors 1134 .iter() 1135 .find(|constructor| constructor.location.contains(byte_index)) 1136 { 1137 if let Some(annotation) = constructor 1138 .arguments 1139 .iter() 1140 .find(|arg| arg.location.contains(byte_index)) 1141 .and_then(|arg| arg.ast.find_node(byte_index, arg.type_.clone())) 1142 { 1143 return Some(annotation); 1144 } 1145 1146 return Some(Located::VariantConstructorDefinition(constructor)); 1147 } 1148 1149 // Note that the custom type `.location` covers the function 1150 // head, not the entire statement. 1151 if self.full_location().contains(byte_index) { 1152 Some(Located::ModuleCustomType(self)) 1153 } else { 1154 None 1155 } 1156 } 1157} 1158 1159pub type UntypedTypeAlias = TypeAlias<()>; 1160pub type TypedTypeAlias = TypeAlias<Arc<Type>>; 1161 1162#[derive(Debug, Clone, PartialEq, Eq)] 1163/// A new name for an existing type 1164/// 1165/// # Example(s) 1166/// 1167/// ```gleam 1168/// pub type Headers = 1169/// List(#(String, String)) 1170/// ``` 1171pub struct TypeAlias<T> { 1172 pub location: SrcSpan, 1173 pub alias: EcoString, 1174 pub name_location: SrcSpan, 1175 pub parameters: Vec<SpannedString>, 1176 pub type_ast: TypeAst, 1177 pub type_: T, 1178 pub publicity: Publicity, 1179 pub documentation: Option<(u32, EcoString)>, 1180 pub deprecation: Deprecation, 1181} 1182 1183impl TypedTypeAlias { 1184 pub fn find_node(&self, byte_index: u32) -> Option<Located<'_>> { 1185 // Check if location is within the type being aliased. 1186 if let Some(located) = self.type_ast.find_node(byte_index, self.type_.clone()) { 1187 return Some(located); 1188 } 1189 1190 if self.location.contains(byte_index) { 1191 Some(Located::ModuleTypeAlias(self)) 1192 } else { 1193 None 1194 } 1195 } 1196} 1197 1198pub type UntypedDefinition = Definition<(), UntypedExpr, ()>; 1199 1200#[derive(Debug, Clone, PartialEq, Eq)] 1201pub enum Definition<T, Expr, PackageName> { 1202 Function(Function<T, Expr>), 1203 TypeAlias(TypeAlias<T>), 1204 CustomType(CustomType<T>), 1205 Import(Import<PackageName>), 1206 ModuleConstant(ModuleConstant<T>), 1207} 1208 1209impl<A, B, C> Definition<A, B, C> { 1210 pub fn location(&self) -> SrcSpan { 1211 match self { 1212 Definition::Function(Function { location, .. }) 1213 | Definition::Import(Import { location, .. }) 1214 | Definition::TypeAlias(TypeAlias { location, .. }) 1215 | Definition::CustomType(CustomType { location, .. }) 1216 | Definition::ModuleConstant(ModuleConstant { location, .. }) => *location, 1217 } 1218 } 1219 1220 /// Returns `true` if the definition is [`Import`]. 1221 /// 1222 /// [`Import`]: Definition::Import 1223 #[must_use] 1224 pub fn is_import(&self) -> bool { 1225 matches!(self, Self::Import(..)) 1226 } 1227 1228 /// Returns `true` if the module statement is [`Function`]. 1229 /// 1230 /// [`Function`]: ModuleStatement::Function 1231 #[must_use] 1232 pub fn is_function(&self) -> bool { 1233 matches!(self, Self::Function(..)) 1234 } 1235 1236 /// Returns `true` if the module statement is [`CustomType`]. 1237 /// 1238 /// [`CustomType`]: ModuleStatement::CustomType 1239 #[must_use] 1240 pub fn is_custom_type(&self) -> bool { 1241 matches!(self, Self::CustomType(..)) 1242 } 1243 1244 pub fn get_doc(&self) -> Option<EcoString> { 1245 match self { 1246 Definition::Import(Import { .. }) => None, 1247 1248 Definition::Function(Function { 1249 documentation: doc, .. 1250 }) 1251 | Definition::TypeAlias(TypeAlias { 1252 documentation: doc, .. 1253 }) 1254 | Definition::CustomType(CustomType { 1255 documentation: doc, .. 1256 }) 1257 | Definition::ModuleConstant(ModuleConstant { 1258 documentation: doc, .. 1259 }) => doc.as_ref().map(|(_, doc)| doc.clone()), 1260 } 1261 } 1262 1263 pub fn is_internal(&self) -> bool { 1264 match self { 1265 Definition::Function(Function { publicity, .. }) 1266 | Definition::CustomType(CustomType { publicity, .. }) 1267 | Definition::ModuleConstant(ModuleConstant { publicity, .. }) 1268 | Definition::TypeAlias(TypeAlias { publicity, .. }) => publicity.is_internal(), 1269 1270 Definition::Import(_) => false, 1271 } 1272 } 1273} 1274 1275#[derive(Debug, Clone, PartialEq, Eq)] 1276pub struct UnqualifiedImport { 1277 pub location: SrcSpan, 1278 /// The location excluding the potential `as ...` clause, or the `type` keyword 1279 pub imported_name_location: SrcSpan, 1280 pub name: EcoString, 1281 pub as_name: Option<EcoString>, 1282} 1283 1284impl UnqualifiedImport { 1285 pub fn used_name(&self) -> &EcoString { 1286 self.as_name.as_ref().unwrap_or(&self.name) 1287 } 1288} 1289 1290#[derive(Debug, Clone, PartialEq, Eq, Copy, Default, serde::Serialize, serde::Deserialize)] 1291pub enum Layer { 1292 #[default] 1293 Value, 1294 Type, 1295} 1296 1297impl Layer { 1298 /// Returns `true` if the layer is [`Value`]. 1299 pub fn is_value(&self) -> bool { 1300 matches!(self, Self::Value) 1301 } 1302} 1303 1304#[derive(Debug, Clone, Copy, PartialEq, Eq)] 1305pub enum BinOp { 1306 // Boolean logic 1307 And, 1308 Or, 1309 1310 // Equality 1311 Eq, 1312 NotEq, 1313 1314 // Order comparison 1315 LtInt, 1316 LtEqInt, 1317 LtFloat, 1318 LtEqFloat, 1319 GtEqInt, 1320 GtInt, 1321 GtEqFloat, 1322 GtFloat, 1323 1324 // Maths 1325 AddInt, 1326 AddFloat, 1327 SubInt, 1328 SubFloat, 1329 MultInt, 1330 MultFloat, 1331 DivInt, 1332 DivFloat, 1333 RemainderInt, 1334 1335 // Strings 1336 Concatenate, 1337} 1338 1339#[derive(Clone, Copy, Debug, PartialEq)] 1340pub enum OperatorKind { 1341 BooleanLogic, 1342 Equality, 1343 IntComparison, 1344 FLoatComparison, 1345 IntMath, 1346 FloatMath, 1347 StringConcatenation, 1348} 1349 1350pub const PIPE_PRECEDENCE: u8 = 6; 1351 1352impl BinOp { 1353 pub fn precedence(&self) -> u8 { 1354 // Ensure that this matches the other precedence function for guards 1355 match self { 1356 Self::Or => 1, 1357 1358 Self::And => 2, 1359 1360 Self::Eq | Self::NotEq => 3, 1361 1362 Self::LtInt 1363 | Self::LtEqInt 1364 | Self::LtFloat 1365 | Self::LtEqFloat 1366 | Self::GtEqInt 1367 | Self::GtInt 1368 | Self::GtEqFloat 1369 | Self::GtFloat => 4, 1370 1371 Self::Concatenate => 5, 1372 1373 // Pipe is 6 1374 Self::AddInt | Self::AddFloat | Self::SubInt | Self::SubFloat => 7, 1375 1376 Self::MultInt 1377 | Self::MultFloat 1378 | Self::DivInt 1379 | Self::DivFloat 1380 | Self::RemainderInt => 8, 1381 } 1382 } 1383 1384 pub fn name(&self) -> &'static str { 1385 match self { 1386 Self::And => "&&", 1387 Self::Or => "||", 1388 Self::LtInt => "<", 1389 Self::LtEqInt => "<=", 1390 Self::LtFloat => "<.", 1391 Self::LtEqFloat => "<=.", 1392 Self::Eq => "==", 1393 Self::NotEq => "!=", 1394 Self::GtEqInt => ">=", 1395 Self::GtInt => ">", 1396 Self::GtEqFloat => ">=.", 1397 Self::GtFloat => ">.", 1398 Self::AddInt => "+", 1399 Self::AddFloat => "+.", 1400 Self::SubInt => "-", 1401 Self::SubFloat => "-.", 1402 Self::MultInt => "*", 1403 Self::MultFloat => "*.", 1404 Self::DivInt => "/", 1405 Self::DivFloat => "/.", 1406 Self::RemainderInt => "%", 1407 Self::Concatenate => "<>", 1408 } 1409 } 1410 1411 pub fn operator_kind(&self) -> OperatorKind { 1412 match self { 1413 Self::Concatenate => OperatorKind::StringConcatenation, 1414 Self::Eq | Self::NotEq => OperatorKind::Equality, 1415 Self::And | Self::Or => OperatorKind::BooleanLogic, 1416 Self::LtInt | Self::LtEqInt | Self::GtEqInt | Self::GtInt => { 1417 OperatorKind::IntComparison 1418 } 1419 Self::LtFloat | Self::LtEqFloat | Self::GtEqFloat | Self::GtFloat => { 1420 OperatorKind::FLoatComparison 1421 } 1422 Self::AddInt | Self::SubInt | Self::MultInt | Self::RemainderInt | Self::DivInt => { 1423 OperatorKind::IntMath 1424 } 1425 Self::AddFloat | Self::SubFloat | Self::MultFloat | Self::DivFloat => { 1426 OperatorKind::FloatMath 1427 } 1428 } 1429 } 1430 1431 pub fn can_be_grouped_with(&self, other: &BinOp) -> bool { 1432 self.operator_kind() == other.operator_kind() 1433 } 1434 1435 pub fn is_float_operator(&self) -> bool { 1436 match self { 1437 BinOp::LtFloat 1438 | BinOp::LtEqFloat 1439 | BinOp::GtEqFloat 1440 | BinOp::GtFloat 1441 | BinOp::AddFloat 1442 | BinOp::SubFloat 1443 | BinOp::MultFloat 1444 | BinOp::DivFloat => true, 1445 1446 BinOp::And 1447 | BinOp::Or 1448 | BinOp::Eq 1449 | BinOp::NotEq 1450 | BinOp::LtInt 1451 | BinOp::LtEqInt 1452 | BinOp::GtEqInt 1453 | BinOp::GtInt 1454 | BinOp::AddInt 1455 | BinOp::SubInt 1456 | BinOp::MultInt 1457 | BinOp::DivInt 1458 | BinOp::RemainderInt 1459 | BinOp::Concatenate => false, 1460 } 1461 } 1462 1463 fn is_bool_operator(&self) -> bool { 1464 match self { 1465 BinOp::And | BinOp::Or => true, 1466 BinOp::Eq 1467 | BinOp::NotEq 1468 | BinOp::LtInt 1469 | BinOp::LtEqInt 1470 | BinOp::LtFloat 1471 | BinOp::LtEqFloat 1472 | BinOp::GtEqInt 1473 | BinOp::GtInt 1474 | BinOp::GtEqFloat 1475 | BinOp::GtFloat 1476 | BinOp::AddInt 1477 | BinOp::AddFloat 1478 | BinOp::SubInt 1479 | BinOp::SubFloat 1480 | BinOp::MultInt 1481 | BinOp::MultFloat 1482 | BinOp::DivInt 1483 | BinOp::DivFloat 1484 | BinOp::RemainderInt 1485 | BinOp::Concatenate => false, 1486 } 1487 } 1488 1489 pub fn is_int_operator(&self) -> bool { 1490 match self { 1491 BinOp::LtInt 1492 | BinOp::LtEqInt 1493 | BinOp::GtEqInt 1494 | BinOp::GtInt 1495 | BinOp::AddInt 1496 | BinOp::SubInt 1497 | BinOp::MultInt 1498 | BinOp::DivInt 1499 | BinOp::RemainderInt => true, 1500 1501 BinOp::And 1502 | BinOp::Or 1503 | BinOp::Eq 1504 | BinOp::NotEq 1505 | BinOp::LtFloat 1506 | BinOp::LtEqFloat 1507 | BinOp::GtEqFloat 1508 | BinOp::GtFloat 1509 | BinOp::AddFloat 1510 | BinOp::SubFloat 1511 | BinOp::MultFloat 1512 | BinOp::DivFloat 1513 | BinOp::Concatenate => false, 1514 } 1515 } 1516 1517 pub fn float_equivalent(&self) -> Option<BinOp> { 1518 match self { 1519 BinOp::LtInt => Some(BinOp::LtFloat), 1520 BinOp::LtEqInt => Some(BinOp::LtEqFloat), 1521 BinOp::GtEqInt => Some(BinOp::GtEqFloat), 1522 BinOp::GtInt => Some(BinOp::GtFloat), 1523 BinOp::AddInt => Some(BinOp::AddFloat), 1524 BinOp::SubInt => Some(BinOp::SubFloat), 1525 BinOp::MultInt => Some(BinOp::MultFloat), 1526 BinOp::DivInt => Some(BinOp::DivFloat), 1527 BinOp::And 1528 | BinOp::Or 1529 | BinOp::Eq 1530 | BinOp::NotEq 1531 | BinOp::LtFloat 1532 | BinOp::LtEqFloat 1533 | BinOp::GtEqFloat 1534 | BinOp::GtFloat 1535 | BinOp::AddFloat 1536 | BinOp::SubFloat 1537 | BinOp::MultFloat 1538 | BinOp::DivFloat 1539 | BinOp::RemainderInt 1540 | BinOp::Concatenate => None, 1541 } 1542 } 1543 1544 pub fn int_equivalent(&self) -> Option<BinOp> { 1545 match self { 1546 BinOp::LtFloat => Some(BinOp::LtInt), 1547 BinOp::LtEqFloat => Some(BinOp::LtEqInt), 1548 BinOp::GtEqFloat => Some(BinOp::GtEqInt), 1549 BinOp::GtFloat => Some(BinOp::GtInt), 1550 BinOp::AddFloat => Some(BinOp::AddInt), 1551 BinOp::SubFloat => Some(BinOp::SubInt), 1552 BinOp::MultFloat => Some(BinOp::MultInt), 1553 BinOp::DivFloat => Some(BinOp::DivInt), 1554 BinOp::And 1555 | BinOp::Or 1556 | BinOp::Eq 1557 | BinOp::NotEq 1558 | BinOp::LtInt 1559 | BinOp::LtEqInt 1560 | BinOp::GtEqInt 1561 | BinOp::GtInt 1562 | BinOp::AddInt 1563 | BinOp::SubInt 1564 | BinOp::MultInt 1565 | BinOp::DivInt 1566 | BinOp::RemainderInt 1567 | BinOp::Concatenate => None, 1568 } 1569 } 1570 1571 /// This returns how many characters this operator takes. 1572 pub fn size(&self) -> u32 { 1573 match self { 1574 BinOp::LtInt 1575 | BinOp::GtInt 1576 | BinOp::RemainderInt 1577 | BinOp::MultInt 1578 | BinOp::AddInt 1579 | BinOp::SubInt 1580 | BinOp::DivInt => 1, 1581 1582 BinOp::And 1583 | BinOp::Or 1584 | BinOp::Eq 1585 | BinOp::NotEq 1586 | BinOp::LtEqInt 1587 | BinOp::GtEqInt 1588 | BinOp::LtFloat 1589 | BinOp::GtFloat 1590 | BinOp::AddFloat 1591 | BinOp::SubFloat 1592 | BinOp::MultFloat 1593 | BinOp::DivFloat 1594 | BinOp::Concatenate => 2, 1595 1596 BinOp::LtEqFloat | BinOp::GtEqFloat => 3, 1597 } 1598 } 1599} 1600 1601#[derive(Debug, PartialEq, Eq, Clone, serde::Serialize, serde::Deserialize)] 1602pub struct CallArg<A> { 1603 pub label: Option<EcoString>, 1604 pub location: SrcSpan, 1605 pub value: A, 1606 pub implicit: Option<ImplicitCallArgOrigin>, 1607} 1608 1609#[derive(Debug, PartialEq, Eq, Clone, Copy, serde::Serialize, serde::Deserialize)] 1610pub enum ImplicitCallArgOrigin { 1611 /// The implicit callback argument passed as the last argument to the 1612 /// function on the right hand side of `use`. 1613 /// 1614 Use, 1615 /// An argument added by the compiler when rewriting a pipe `left |> right`. 1616 /// 1617 Pipe, 1618 /// An argument added by the compiler to fill in all the missing fields of a 1619 /// record that are being ignored with the `..` syntax. 1620 /// 1621 PatternFieldSpread, 1622 /// An argument used to fill in the missing args when a function on the 1623 /// right hand side of `use` is being called with the wrong arity. 1624 /// 1625 IncorrectArityUse, 1626 /// An argument added by the compiler to fill in the missing args when using 1627 /// the record update synax. 1628 /// 1629 RecordUpdate, 1630} 1631 1632impl<A> CallArg<A> { 1633 #[must_use] 1634 pub fn is_implicit(&self) -> bool { 1635 self.implicit.is_some() 1636 } 1637 1638 #[must_use] 1639 pub fn is_use_implicit_callback(&self) -> bool { 1640 match self.implicit { 1641 Some(ImplicitCallArgOrigin::Use | ImplicitCallArgOrigin::IncorrectArityUse) => true, 1642 Some(_) | None => false, 1643 } 1644 } 1645} 1646 1647impl CallArg<TypedExpr> { 1648 pub fn find_node<'a>( 1649 &'a self, 1650 byte_index: u32, 1651 called_function: &'a TypedExpr, 1652 function_arguments: &'a [TypedCallArg], 1653 ) -> Option<Located<'a>> { 1654 match (self.implicit, &self.value) { 1655 // If a call argument is the implicit use callback then we don't 1656 // want to look at its arguments and body but we don't want to 1657 // return the whole anonymous function if anything else doesn't 1658 // match. 1659 // 1660 // In addition, if the callback is invalid because it couldn't be 1661 // typed, we don't want to return it as it would make it hard for 1662 // the LSP to give any suggestions on the use function being typed. 1663 // 1664 (Some(ImplicitCallArgOrigin::Use), TypedExpr::Invalid { .. }) => None, 1665 // So the code below is exactly the same as 1666 // `TypedExpr::Fn{}.find_node()` except we do not return self as a 1667 // fallback. 1668 // 1669 ( 1670 Some(ImplicitCallArgOrigin::Use), 1671 TypedExpr::Fn { 1672 arguments, body, .. 1673 }, 1674 ) => arguments 1675 .iter() 1676 .find_map(|argument| argument.find_node(byte_index)) 1677 .or_else(|| body.iter().find_map(|s| s.find_node(byte_index))), 1678 // In all other cases we're happy with the default behaviour. 1679 // 1680 _ => match self.value.find_node(byte_index) { 1681 Some(Located::Expression { expression, .. }) 1682 // This is only possibly a label if we are at the end of the expression 1683 // (so not in the middle like `[abc|]`) and if this argument doesn't 1684 // already have a label. 1685 if byte_index == self.value.location().end && self.label.is_none() => 1686 { 1687 Some(Located::Expression { 1688 expression, 1689 position: ExpressionPosition::ArgumentOrLabel { 1690 called_function, 1691 function_arguments, 1692 }, 1693 }) 1694 } 1695 Some(located) => Some(located), 1696 None => { 1697 if self.location.contains(byte_index) && self.label.is_some() { 1698 Some(Located::Label(self.location, self.value.type_())) 1699 } else { 1700 None 1701 } 1702 } 1703 }, 1704 } 1705 } 1706 1707 pub fn find_statement(&self, byte_index: u32) -> Option<&TypedStatement> { 1708 match (self.implicit, &self.value) { 1709 (Some(ImplicitCallArgOrigin::Use), TypedExpr::Invalid { .. }) => None, 1710 (Some(ImplicitCallArgOrigin::Use), TypedExpr::Fn { body, .. }) => { 1711 body.iter().find_map(|s| s.find_statement(byte_index)) 1712 } 1713 1714 _ => self.value.find_statement(byte_index), 1715 } 1716 } 1717 1718 pub fn is_capture_hole(&self) -> bool { 1719 match &self.value { 1720 TypedExpr::Var { name, .. } => name == CAPTURE_VARIABLE, 1721 TypedExpr::Int { .. } 1722 | TypedExpr::Float { .. } 1723 | TypedExpr::String { .. } 1724 | TypedExpr::Block { .. } 1725 | TypedExpr::Pipeline { .. } 1726 | TypedExpr::Fn { .. } 1727 | TypedExpr::List { .. } 1728 | TypedExpr::Call { .. } 1729 | TypedExpr::BinOp { .. } 1730 | TypedExpr::Case { .. } 1731 | TypedExpr::RecordAccess { .. } 1732 | TypedExpr::PositionalAccess { .. } 1733 | TypedExpr::ModuleSelect { .. } 1734 | TypedExpr::Tuple { .. } 1735 | TypedExpr::TupleIndex { .. } 1736 | TypedExpr::Todo { .. } 1737 | TypedExpr::Panic { .. } 1738 | TypedExpr::Echo { .. } 1739 | TypedExpr::BitArray { .. } 1740 | TypedExpr::RecordUpdate { .. } 1741 | TypedExpr::NegateBool { .. } 1742 | TypedExpr::NegateInt { .. } 1743 | TypedExpr::Invalid { .. } => false, 1744 } 1745 } 1746} 1747 1748impl CallArg<TypedPattern> { 1749 pub fn find_node(&self, byte_index: u32) -> Option<Located<'_>> { 1750 match self.value.find_node(byte_index) { 1751 Some(located) => Some(located), 1752 _ => { 1753 if self.location.contains(byte_index) && self.label.is_some() { 1754 Some(Located::Label(self.location, self.value.type_())) 1755 } else { 1756 None 1757 } 1758 } 1759 } 1760 } 1761} 1762 1763impl CallArg<TypedConstant> { 1764 pub fn find_node(&self, byte_index: u32) -> Option<Located<'_>> { 1765 match self.value.find_node(byte_index) { 1766 Some(located) => Some(located), 1767 _ => { 1768 if self.location.contains(byte_index) && self.label.is_some() { 1769 Some(Located::Label(self.location, self.value.type_())) 1770 } else { 1771 None 1772 } 1773 } 1774 } 1775 } 1776} 1777 1778impl CallArg<UntypedExpr> { 1779 pub fn is_capture_hole(&self) -> bool { 1780 match &self.value { 1781 UntypedExpr::Var { name, .. } => name == CAPTURE_VARIABLE, 1782 UntypedExpr::Int { .. } 1783 | UntypedExpr::Float { .. } 1784 | UntypedExpr::String { .. } 1785 | UntypedExpr::Block { .. } 1786 | UntypedExpr::Fn { .. } 1787 | UntypedExpr::List { .. } 1788 | UntypedExpr::Call { .. } 1789 | UntypedExpr::BinOp { .. } 1790 | UntypedExpr::PipeLine { .. } 1791 | UntypedExpr::Case { .. } 1792 | UntypedExpr::FieldAccess { .. } 1793 | UntypedExpr::Tuple { .. } 1794 | UntypedExpr::TupleIndex { .. } 1795 | UntypedExpr::Todo { .. } 1796 | UntypedExpr::Panic { .. } 1797 | UntypedExpr::Echo { .. } 1798 | UntypedExpr::BitArray { .. } 1799 | UntypedExpr::RecordUpdate { .. } 1800 | UntypedExpr::NegateBool { .. } 1801 | UntypedExpr::NegateInt { .. } => false, 1802 } 1803 } 1804} 1805 1806impl<T> CallArg<T> 1807where 1808 T: HasLocation, 1809{ 1810 #[must_use] 1811 pub fn uses_label_shorthand(&self) -> bool { 1812 self.label_shorthand_name().is_some() 1813 } 1814 1815 /// If the call arg is defined using a label shorthand, this will return the 1816 /// label name. 1817 /// 1818 pub fn label_shorthand_name(&self) -> Option<&EcoString> { 1819 if !self.is_implicit() && self.location == self.value.location() { 1820 self.label.as_ref() 1821 } else { 1822 None 1823 } 1824 } 1825} 1826 1827impl<T> HasLocation for CallArg<T> { 1828 fn location(&self) -> SrcSpan { 1829 self.location 1830 } 1831} 1832 1833#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] 1834pub struct RecordBeingUpdated<A> { 1835 pub base: Box<A>, 1836 pub location: SrcSpan, 1837} 1838 1839#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] 1840pub struct RecordUpdateArg<A> { 1841 pub label: EcoString, 1842 pub location: SrcSpan, 1843 pub value: A, 1844} 1845 1846pub type UntypedRecordUpdateArg = RecordUpdateArg<UntypedExpr>; 1847 1848impl<A> HasLocation for RecordUpdateArg<A> { 1849 fn location(&self) -> SrcSpan { 1850 self.location 1851 } 1852} 1853 1854impl<A: HasLocation> RecordUpdateArg<A> { 1855 #[must_use] 1856 pub fn uses_label_shorthand(&self) -> bool { 1857 self.value.location() == self.location 1858 } 1859} 1860 1861pub type MultiPattern<Type> = Vec<Pattern<Type>>; 1862 1863pub type UntypedMultiPattern = MultiPattern<()>; 1864pub type TypedMultiPattern = MultiPattern<Arc<Type>>; 1865 1866pub type TypedClause = Clause<TypedExpr, Arc<Type>>; 1867 1868pub type UntypedClause = Clause<UntypedExpr, ()>; 1869 1870#[derive(Debug, Clone, PartialEq, Eq)] 1871pub struct Clause<Expr, Type> { 1872 pub location: SrcSpan, 1873 pub pattern: MultiPattern<Type>, 1874 pub alternative_patterns: Vec<MultiPattern<Type>>, 1875 pub guard: Option<ClauseGuard<Type>>, 1876 pub then: Expr, 1877} 1878 1879impl<A, B> Clause<A, B> { 1880 pub fn pattern_count(&self) -> usize { 1881 1 + self.alternative_patterns.len() 1882 } 1883} 1884 1885impl TypedClause { 1886 pub fn location(&self) -> SrcSpan { 1887 SrcSpan { 1888 start: self 1889 .pattern 1890 .first() 1891 .map(|p| p.location().start) 1892 .unwrap_or_default(), 1893 end: self.then.location().end, 1894 } 1895 } 1896 1897 pub fn find_node(&self, byte_index: u32) -> Option<Located<'_>> { 1898 self.pattern 1899 .iter() 1900 .find_map(|p| p.find_node(byte_index)) 1901 .or_else(|| { 1902 self.alternative_patterns 1903 .iter() 1904 .flat_map(|p| p.iter()) 1905 .find_map(|p| p.find_node(byte_index)) 1906 }) 1907 .or_else(|| { 1908 self.guard 1909 .as_ref() 1910 .and_then(|guard| guard.find_node(byte_index)) 1911 }) 1912 .or_else(|| self.then.find_node(byte_index)) 1913 } 1914 1915 pub fn pattern_location(&self) -> SrcSpan { 1916 let start = self.pattern.first().map(|pattern| pattern.location().start); 1917 1918 let end = if let Some(last_pattern) = self 1919 .alternative_patterns 1920 .last() 1921 .and_then(|patterns| patterns.last()) 1922 { 1923 Some(last_pattern.location().end) 1924 } else { 1925 self.pattern.last().map(|pattern| pattern.location().end) 1926 }; 1927 1928 SrcSpan::new(start.unwrap_or_default(), end.unwrap_or_default()) 1929 } 1930 1931 /// If the branch is rebuilding exactly one of the matched subjects and 1932 /// returning it, this will return the index of that subject. 1933 /// 1934 /// For example: 1935 /// - `n -> n`, `1 -> 1`, `Ok(1) -> Ok(1)` all return `Some(0)` 1936 /// - `"a", n -> n`, `n, m if n == m -> a` all return `Some(1)` 1937 /// - `_ -> 1`, `Ok(1), _ -> Ok(2)` all return `None` 1938 /// ``` 1939 /// 1940 pub fn returned_subject(&self) -> Option<usize> { 1941 // The pattern must not have any alternative patterns. 1942 if !self.alternative_patterns.is_empty() { 1943 return None; 1944 } 1945 1946 self.pattern 1947 .iter() 1948 .find_position(|pattern| pattern_and_expression_are_the_same(pattern, &self.then)) 1949 .map(|(position, _)| position) 1950 } 1951 1952 /// This returns the names of all the variables bound in this case clause. 1953 /// For example if we had `#(a, b) | c` this will return "a", "b", and "c". 1954 pub fn bound_variables(&self) -> impl Iterator<Item = BoundVariable> { 1955 std::iter::once(&self.pattern) 1956 .chain(&self.alternative_patterns) 1957 .flatten() 1958 .flat_map(|pattern| pattern.bound_variables()) 1959 } 1960 1961 fn syntactically_eq(&self, other: &Self) -> bool { 1962 let patterns_are_equal = pairwise_all(&self.pattern, &other.pattern, |(one, other)| { 1963 one.syntactically_eq(other) 1964 }); 1965 1966 let alternatives_are_equal = pairwise_all( 1967 &self.alternative_patterns, 1968 &other.alternative_patterns, 1969 |(patterns_one, patterns_other)| { 1970 pairwise_all(patterns_one, patterns_other, |(one, other)| -> bool { 1971 one.syntactically_eq(other) 1972 }) 1973 }, 1974 ); 1975 1976 let guards_are_equal = match (&self.guard, &other.guard) { 1977 (None, None) => true, 1978 (None, Some(_)) | (Some(_), None) => false, 1979 (Some(one), Some(other)) => one.syntactically_eq(other), 1980 }; 1981 1982 patterns_are_equal 1983 && alternatives_are_equal 1984 && guards_are_equal 1985 && self.then.syntactically_eq(&other.then) 1986 } 1987} 1988 1989/// Returns true if a pattern and an expression are the same: that is the expression 1990/// would be building the exact matched value back. 1991/// For example, if I had a branch like this: 1992/// 1993/// ```gleam 1994/// [a, b, c] -> [a, b, c] 1995/// ``` 1996/// 1997/// The pattern and the expression would indeed be the same. However, if I had 1998/// something like this: 1999/// 2000/// ```gleam 2001/// [first, ..rest] -> [first] 2002/// ``` 2003/// 2004/// They wouldn't be the same! I'm not building back exactly the value the 2005/// pattern can match on. 2006/// 2007fn pattern_and_expression_are_the_same(pattern: &TypedPattern, expression: &TypedExpr) -> bool { 2008 match (pattern, expression) { 2009 // A pattern could be the same as a block if the block is wrapping just 2010 // a single expression that is the same as the pattern itself! 2011 (pattern, TypedExpr::Block { statements, .. }) if statements.len() == 1 => { 2012 match statements.first() { 2013 Statement::Assignment(_) | Statement::Use(_) | Statement::Assert(_) => false, 2014 Statement::Expression(expression) => { 2015 pattern_and_expression_are_the_same(pattern, expression) 2016 } 2017 } 2018 } 2019 // If the block has many statements then it can never be the same as a 2020 // pattern. 2021 (_, TypedExpr::Block { .. }) => false, 2022 2023 // A pattern and an expression are the same if they're a simple variable 2024 // with exactly the same name: `x -> x`, `a -> a` 2025 ( 2026 TypedPattern::Variable { 2027 name: pattern_var, .. 2028 }, 2029 TypedExpr::Var { name: body_var, .. }, 2030 ) => pattern_var == body_var, 2031 (TypedPattern::Variable { .. }, _) => false, 2032 2033 // Floats, Ints, and Strings are the same if they are exactly the same 2034 // literal. 2035 // `1 -> 1` 2036 // `1.1 -> 1.1` 2037 // `"wibble" -> "wibble"` 2038 ( 2039 TypedPattern::Float { 2040 float_value: pattern_value, 2041 .. 2042 }, 2043 TypedExpr::Float { float_value, .. }, 2044 ) => pattern_value == float_value, 2045 (TypedPattern::Float { .. }, _) => false, 2046 2047 ( 2048 TypedPattern::Int { 2049 int_value: pattern_value, 2050 .. 2051 }, 2052 TypedExpr::Int { int_value, .. }, 2053 ) => pattern_value == int_value, 2054 (TypedPattern::Int { .. }, _) => false, 2055 2056 ( 2057 TypedPattern::String { 2058 value: pattern_value, 2059 .. 2060 }, 2061 TypedExpr::String { value, .. }, 2062 ) => pattern_value == value, 2063 (TypedPattern::String { .. }, _) => false, 2064 2065 // A string prefix is equivalent to building the string back: 2066 // `"wibble" <> wobble -> "wibble" <> wobble` 2067 // `"wibble" as a <> wobble -> a <> wobble` 2068 ( 2069 TypedPattern::StringPrefix { 2070 left_side_assignment, 2071 left_side_string, 2072 right_side_assignment, 2073 .. 2074 }, 2075 TypedExpr::BinOp { 2076 operator: BinOp::Concatenate, 2077 left, 2078 right, 2079 .. 2080 }, 2081 ) => { 2082 let left_side_matches = match (left_side_assignment, left_side_string, left.as_ref()) { 2083 (_, left_side_string, TypedExpr::String { value, .. }) => value == left_side_string, 2084 (Some((left_side_name, _)), _, TypedExpr::Var { name, .. }) => { 2085 left_side_name == name 2086 } 2087 (_, _, _) => false, 2088 }; 2089 let right_side_matches = match (right_side_assignment, right.as_ref()) { 2090 (AssignName::Variable(right_side_name), TypedExpr::Var { name, .. }) => { 2091 name == right_side_name 2092 } 2093 (AssignName::Variable(_) | AssignName::Discard(_), _) => false, 2094 }; 2095 left_side_matches && right_side_matches 2096 } 2097 (TypedPattern::StringPrefix { .. }, _) => false, 2098 2099 // Two tuples where each element is equivalent to the other: 2100 // `#(a, 1, "wibble") -> #(a, 1, "wibble")` 2101 // `#(a, b) -> #(a, b)` 2102 ( 2103 TypedPattern::Tuple { 2104 elements: pattern_elements, 2105 .. 2106 }, 2107 TypedExpr::Tuple { elements, .. }, 2108 ) => { 2109 pattern_elements.len() == elements.len() 2110 && pattern_elements 2111 .iter() 2112 .zip(elements) 2113 .all(|(pattern, expression)| { 2114 pattern_and_expression_are_the_same(pattern, expression) 2115 }) 2116 } 2117 (TypedPattern::Tuple { .. }, _) => false, 2118 2119 // Two lists are the same if each element is equivalent to the other: 2120 // `[] -> []` 2121 // `[a, b] -> [a, b]` 2122 // `[1, ..rest] -> [1, ..rest]` 2123 ( 2124 TypedPattern::List { 2125 elements: pattern_elements, 2126 tail: pattern_tail, 2127 .. 2128 }, 2129 TypedExpr::List { elements, tail, .. }, 2130 ) => { 2131 let tails_are_the_same = match (pattern_tail, tail) { 2132 (None, None) => true, 2133 (None, Some(_)) | (Some(_), None) => false, 2134 (Some(tail_pattern), Some(tail_expression)) => { 2135 pattern_and_expression_are_the_same(&tail_pattern.pattern, tail_expression) 2136 } 2137 }; 2138 2139 tails_are_the_same 2140 && pattern_elements.len() == elements.len() 2141 && pattern_elements 2142 .iter() 2143 .zip(elements) 2144 .all(|(pattern, expression)| { 2145 pattern_and_expression_are_the_same(pattern, expression) 2146 }) 2147 } 2148 (TypedPattern::List { .. }, _) => false, 2149 2150 // Two constructors are the same if the expression is building exactly 2151 // the same value being matched on (regardless of qualification). 2152 // `Ok(a) -> Ok(a)` 2153 // `Ok(1) -> Ok(1)` 2154 // `Wibble(a, b, c) -> Wibble(a, b, c)` 2155 // `Ok(a) -> gleam.Ok(a)` 2156 // `gleam.Ok(1) -> Ok(1)` 2157 ( 2158 TypedPattern::Constructor { 2159 constructor: 2160 Inferred::Known(PatternConstructor { 2161 module: pattern_module, 2162 name: pattern_name, 2163 .. 2164 }), 2165 arguments: pattern_arguments, 2166 spread: None, 2167 .. 2168 }, 2169 TypedExpr::Call { fun, arguments, .. }, 2170 ) => match fun.as_ref() { 2171 TypedExpr::Var { 2172 constructor: 2173 ValueConstructor { 2174 variant: ValueConstructorVariant::Record { name, module, .. }, 2175 .. 2176 }, 2177 .. 2178 } 2179 | TypedExpr::ModuleSelect { 2180 constructor: ModuleValueConstructor::Record { name, .. }, 2181 module_name: module, 2182 .. 2183 } => { 2184 pattern_module == module 2185 && pattern_name == name 2186 && pattern_arguments.len() == arguments.len() 2187 && pattern_arguments 2188 .iter() 2189 .zip(arguments) 2190 .all(|(pattern, expression)| { 2191 pattern_and_expression_are_the_same(&pattern.value, &expression.value) 2192 }) 2193 } 2194 2195 TypedExpr::Int { .. } 2196 | TypedExpr::Float { .. } 2197 | TypedExpr::String { .. } 2198 | TypedExpr::Block { .. } 2199 | TypedExpr::Pipeline { .. } 2200 | TypedExpr::Var { .. } 2201 | TypedExpr::Fn { .. } 2202 | TypedExpr::List { .. } 2203 | TypedExpr::Call { .. } 2204 | TypedExpr::BinOp { .. } 2205 | TypedExpr::Case { .. } 2206 | TypedExpr::RecordAccess { .. } 2207 | TypedExpr::PositionalAccess { .. } 2208 | TypedExpr::ModuleSelect { .. } 2209 | TypedExpr::Tuple { .. } 2210 | TypedExpr::TupleIndex { .. } 2211 | TypedExpr::Todo { .. } 2212 | TypedExpr::Panic { .. } 2213 | TypedExpr::Echo { .. } 2214 | TypedExpr::BitArray { .. } 2215 | TypedExpr::RecordUpdate { .. } 2216 | TypedExpr::NegateBool { .. } 2217 | TypedExpr::NegateInt { .. } 2218 | TypedExpr::Invalid { .. } => false, 2219 }, 2220 2221 // A pattern for a constructor with no arguments: 2222 // `Nil -> Nil` 2223 // `gleam.Nil -> Nil` 2224 // `Nil -> gleam.Nil` 2225 // `Wibble -> Wibble` 2226 ( 2227 TypedPattern::Constructor { 2228 constructor: 2229 Inferred::Known(PatternConstructor { 2230 module: pattern_module, 2231 name: pattern_name, 2232 .. 2233 }), 2234 arguments: pattern_arguments, 2235 spread: None, 2236 .. 2237 }, 2238 TypedExpr::Var { 2239 constructor: 2240 ValueConstructor { 2241 variant: ValueConstructorVariant::Record { name, module, .. }, 2242 .. 2243 }, 2244 .. 2245 } 2246 | TypedExpr::ModuleSelect { 2247 constructor: ModuleValueConstructor::Record { name, .. }, 2248 module_name: module, 2249 .. 2250 }, 2251 ) => pattern_module == module && pattern_name == name && pattern_arguments.is_empty(), 2252 (TypedPattern::Constructor { .. }, _) => false, 2253 2254 // An assignment is the same if the corresponding expression is a 2255 // variable with the same name, or if the inner pattern is the same: 2256 // `Ok(1) as a -> a` 2257 // `Ok(1) as a -> Ok(1)` 2258 ( 2259 TypedPattern::Assign { 2260 name: pattern_name, .. 2261 }, 2262 TypedExpr::Var { name, .. }, 2263 ) => pattern_name == name, 2264 (TypedPattern::Assign { pattern, .. }, expression) => { 2265 pattern_and_expression_are_the_same(pattern, expression) 2266 } 2267 2268 // Bit arrays are trickier as they can use existing variables in their 2269 // pattern and shadow existing variables so for now we just ignore 2270 // those. 2271 (TypedPattern::BitArray { .. } | TypedPattern::BitArraySize { .. }, _) => false, 2272 2273 // A discard is never the same as an expression, same goes for an 2274 // invalid pattern: there's no way to check if it matches an expression! 2275 (TypedPattern::Discard { .. } | TypedPattern::Invalid { .. }, _) => false, 2276 } 2277} 2278 2279pub type UntypedClauseGuard = ClauseGuard<()>; 2280pub type TypedClauseGuard = ClauseGuard<Arc<Type>>; 2281 2282#[derive(Debug, Clone, PartialEq, Eq)] 2283pub enum ClauseGuard<Type> { 2284 Block { 2285 location: SrcSpan, 2286 value: Box<ClauseGuard<Type>>, 2287 }, 2288 2289 BinaryOperator { 2290 location: SrcSpan, 2291 operator: BinOp, 2292 /// This is where the operator starts in the code. For example: 2293 /// ```gleam 2294 /// _ if 1.0 >=. 2.3 -> todo 2295 /// // ^ Here! 2296 /// ``` 2297 operator_start: u32, 2298 left: Box<Self>, 2299 right: Box<Self>, 2300 }, 2301 2302 Not { 2303 location: SrcSpan, 2304 expression: Box<Self>, 2305 }, 2306 2307 Var { 2308 location: SrcSpan, 2309 type_: Type, 2310 name: EcoString, 2311 definition_location: SrcSpan, 2312 origin: VariableOrigin, 2313 }, 2314 2315 TupleIndex { 2316 location: SrcSpan, 2317 index: u64, 2318 type_: Type, 2319 tuple: Box<Self>, 2320 }, 2321 2322 FieldAccess { 2323 label_location: SrcSpan, 2324 index: Option<u64>, 2325 label: EcoString, 2326 type_: Type, 2327 container: Box<Self>, 2328 }, 2329 2330 ModuleSelect { 2331 location: SrcSpan, 2332 field_start: u32, 2333 definition_location: SrcSpan, 2334 type_: Type, 2335 label: EcoString, 2336 module_name: EcoString, 2337 module_alias: EcoString, 2338 literal: Constant<Type>, 2339 }, 2340 2341 Constant(Constant<Type>), 2342 2343 Invalid { 2344 location: SrcSpan, 2345 type_: Type, 2346 }, 2347} 2348 2349impl<A> ClauseGuard<A> { 2350 pub fn location(&self) -> SrcSpan { 2351 match self { 2352 ClauseGuard::Constant(constant) => constant.location(), 2353 ClauseGuard::BinaryOperator { location, .. } 2354 | ClauseGuard::Not { location, .. } 2355 | ClauseGuard::Var { location, .. } 2356 | ClauseGuard::TupleIndex { location, .. } 2357 | ClauseGuard::ModuleSelect { location, .. } 2358 | ClauseGuard::Invalid { location, .. } 2359 | ClauseGuard::Block { location, .. } => *location, 2360 ClauseGuard::FieldAccess { 2361 label_location, 2362 container, 2363 .. 2364 } => container.location().merge(label_location), 2365 } 2366 } 2367 2368 pub fn precedence(&self) -> u8 { 2369 // Ensure that this matches the other precedence function for guards 2370 match self.bin_op_name() { 2371 Some(name) => name.precedence(), 2372 None => u8::MAX, 2373 } 2374 } 2375 2376 pub fn bin_op_name(&self) -> Option<BinOp> { 2377 match self { 2378 ClauseGuard::BinaryOperator { operator, .. } => Some(*operator), 2379 2380 ClauseGuard::Constant(_) 2381 | ClauseGuard::Invalid { .. } 2382 | ClauseGuard::Var { .. } 2383 | ClauseGuard::Not { .. } 2384 | ClauseGuard::TupleIndex { .. } 2385 | ClauseGuard::FieldAccess { .. } 2386 | ClauseGuard::ModuleSelect { .. } 2387 | ClauseGuard::Block { .. } => None, 2388 } 2389 } 2390} 2391 2392impl TypedClauseGuard { 2393 pub fn type_(&self) -> Arc<Type> { 2394 match self { 2395 ClauseGuard::Var { type_, .. } => type_.clone(), 2396 ClauseGuard::TupleIndex { type_, .. } => type_.clone(), 2397 ClauseGuard::FieldAccess { type_, .. } => type_.clone(), 2398 ClauseGuard::ModuleSelect { type_, .. } => type_.clone(), 2399 ClauseGuard::Constant(constant) => constant.type_(), 2400 ClauseGuard::Block { value, .. } => value.type_(), 2401 ClauseGuard::Invalid { type_, .. } => type_.clone(), 2402 2403 ClauseGuard::Not { .. } => type_::bool(), 2404 2405 ClauseGuard::BinaryOperator { operator, .. } => match operator { 2406 BinOp::AddInt 2407 | BinOp::SubInt 2408 | BinOp::MultInt 2409 | BinOp::DivInt 2410 | BinOp::RemainderInt => type_::int(), 2411 BinOp::AddFloat | BinOp::SubFloat | BinOp::MultFloat | BinOp::DivFloat => { 2412 type_::float() 2413 } 2414 BinOp::Concatenate => type_::string(), 2415 BinOp::Or 2416 | BinOp::And 2417 | BinOp::Eq 2418 | BinOp::NotEq 2419 | BinOp::GtInt 2420 | BinOp::GtEqInt 2421 | BinOp::LtInt 2422 | BinOp::LtEqInt 2423 | BinOp::GtFloat 2424 | BinOp::GtEqFloat 2425 | BinOp::LtFloat 2426 | BinOp::LtEqFloat => type_::bool(), 2427 }, 2428 } 2429 } 2430 2431 pub fn find_node(&self, byte_index: u32) -> Option<Located<'_>> { 2432 if !self.location().contains(byte_index) { 2433 return None; 2434 } 2435 2436 match self { 2437 ClauseGuard::ModuleSelect { 2438 location, 2439 module_name, 2440 module_alias, 2441 .. 2442 } => { 2443 let module_span = 2444 SrcSpan::new(location.start, location.start + (module_alias.len() as u32)); 2445 2446 if module_span.contains(byte_index) { 2447 Some(Located::ModuleName { 2448 location: module_span, 2449 module_name: module_name.clone(), 2450 module_alias: module_alias.clone(), 2451 layer: Layer::Value, 2452 }) 2453 } else { 2454 Some(Located::ClauseGuard(self)) 2455 } 2456 } 2457 2458 ClauseGuard::BinaryOperator { left, right, .. } => left 2459 .find_node(byte_index) 2460 .or_else(|| right.find_node(byte_index)), 2461 2462 ClauseGuard::Not { 2463 expression: value, .. 2464 } 2465 | ClauseGuard::TupleIndex { tuple: value, .. } 2466 | ClauseGuard::FieldAccess { 2467 container: value, .. 2468 } 2469 | ClauseGuard::Block { value, .. } => value.find_node(byte_index), 2470 ClauseGuard::Constant(constant) => constant.find_node(byte_index), 2471 ClauseGuard::Var { .. } => Some(Located::ClauseGuard(self)), 2472 ClauseGuard::Invalid { .. } => Some(Located::ClauseGuard(self)), 2473 } 2474 } 2475 2476 pub(crate) fn referenced_variables(&self) -> im::HashSet<&EcoString> { 2477 match self { 2478 ClauseGuard::Var { name, .. } => im::hashset![name], 2479 2480 ClauseGuard::Block { value, .. } => value.referenced_variables(), 2481 ClauseGuard::Not { expression, .. } => expression.referenced_variables(), 2482 ClauseGuard::TupleIndex { tuple, .. } => tuple.referenced_variables(), 2483 ClauseGuard::FieldAccess { container, .. } => container.referenced_variables(), 2484 ClauseGuard::Constant(constant) => constant.referenced_variables(), 2485 ClauseGuard::ModuleSelect { .. } => im::HashSet::new(), 2486 ClauseGuard::Invalid { .. } => im::HashSet::new(), 2487 2488 ClauseGuard::BinaryOperator { left, right, .. } => left 2489 .referenced_variables() 2490 .union(right.referenced_variables()), 2491 } 2492 } 2493 2494 fn syntactically_eq(&self, other: &Self) -> bool { 2495 match (self, other) { 2496 ( 2497 ClauseGuard::Block { value, .. }, 2498 ClauseGuard::Block { 2499 value: other_value, .. 2500 }, 2501 ) => value.syntactically_eq(other_value), 2502 (ClauseGuard::Block { .. }, _) => false, 2503 2504 ( 2505 ClauseGuard::BinaryOperator { left, right, .. }, 2506 ClauseGuard::BinaryOperator { 2507 left: other_left, 2508 right: other_right, 2509 .. 2510 }, 2511 ) => left.syntactically_eq(other_left) && right.syntactically_eq(other_right), 2512 (ClauseGuard::BinaryOperator { .. }, _) => false, 2513 2514 ( 2515 ClauseGuard::Not { expression, .. }, 2516 ClauseGuard::Not { 2517 expression: other_expression, 2518 .. 2519 }, 2520 ) => expression.syntactically_eq(other_expression), 2521 (ClauseGuard::Not { .. }, _) => false, 2522 2523 ( 2524 ClauseGuard::Var { name, .. }, 2525 ClauseGuard::Var { 2526 name: other_name, .. 2527 }, 2528 ) => name == other_name, 2529 (ClauseGuard::Var { .. }, _) => false, 2530 2531 ( 2532 ClauseGuard::TupleIndex { index, tuple, .. }, 2533 ClauseGuard::TupleIndex { 2534 index: other_index, 2535 tuple: other_tuple, 2536 .. 2537 }, 2538 ) => index == other_index && tuple.syntactically_eq(other_tuple), 2539 (ClauseGuard::TupleIndex { .. }, _) => false, 2540 2541 ( 2542 ClauseGuard::FieldAccess { 2543 label, container, .. 2544 }, 2545 ClauseGuard::FieldAccess { 2546 label: other_label, 2547 container: other_container, 2548 .. 2549 }, 2550 ) => label == other_label && container.syntactically_eq(other_container), 2551 (ClauseGuard::FieldAccess { .. }, _) => false, 2552 2553 ( 2554 ClauseGuard::ModuleSelect { 2555 label, 2556 module_alias, 2557 .. 2558 }, 2559 ClauseGuard::ModuleSelect { 2560 label: other_label, 2561 module_alias: other_module_alias, 2562 .. 2563 }, 2564 ) => label == other_label && module_alias == other_module_alias, 2565 (ClauseGuard::ModuleSelect { .. }, _) => false, 2566 2567 (ClauseGuard::Constant(one), ClauseGuard::Constant(other)) => { 2568 one.syntactically_eq(other) 2569 } 2570 (ClauseGuard::Constant(_), _) => false, 2571 2572 // An invalid guard is never the same as another one 2573 (ClauseGuard::Invalid { .. }, _) => false, 2574 } 2575 } 2576 2577 pub fn definition_location(&self) -> Option<DefinitionLocation> { 2578 match self { 2579 ClauseGuard::Block { .. } 2580 | ClauseGuard::BinaryOperator { .. } 2581 | ClauseGuard::Not { .. } 2582 | ClauseGuard::TupleIndex { .. } 2583 | ClauseGuard::Invalid { .. } 2584 | ClauseGuard::FieldAccess { .. } => None, 2585 ClauseGuard::Constant(constant) => constant.definition_location(), 2586 ClauseGuard::Var { 2587 definition_location, 2588 .. 2589 } => Some(DefinitionLocation { 2590 module: None, 2591 span: *definition_location, 2592 }), 2593 ClauseGuard::ModuleSelect { 2594 module_name, 2595 definition_location, 2596 .. 2597 } => Some(DefinitionLocation { 2598 module: Some(module_name.clone()), 2599 span: *definition_location, 2600 }), 2601 } 2602 } 2603} 2604 2605#[derive( 2606 Debug, 2607 PartialEq, 2608 Eq, 2609 PartialOrd, 2610 Ord, 2611 Default, 2612 Clone, 2613 Copy, 2614 serde::Serialize, 2615 serde::Deserialize, 2616 Hash, 2617)] 2618pub struct SrcSpan { 2619 pub start: u32, 2620 pub end: u32, 2621} 2622 2623impl SrcSpan { 2624 pub fn new(start: u32, end: u32) -> Self { 2625 Self { start, end } 2626 } 2627 2628 pub fn contains(&self, byte_index: u32) -> bool { 2629 byte_index >= self.start && byte_index <= self.end 2630 } 2631 2632 pub fn contains_span(&self, span: SrcSpan) -> bool { 2633 self.contains(span.start) && self.contains(span.end) 2634 } 2635 2636 /// Merges two spans into a new one that starts at the start of the smaller 2637 /// one and ends at the end of the bigger one. For example: 2638 /// 2639 /// ```txt 2640 /// wibble wobble 2641 /// ─┬──── ─┬──── 2642 /// │ ╰─ one span 2643 /// ╰─ the other span 2644 /// ─┬────────────── 2645 /// ╰─ the span you get by merging the two 2646 /// ``` 2647 pub fn merge(&self, with: &SrcSpan) -> SrcSpan { 2648 Self { 2649 start: self.start.min(with.start), 2650 end: self.end.max(with.end), 2651 } 2652 } 2653 2654 pub fn is_empty(&self) -> bool { 2655 self.len() == 0 2656 } 2657 2658 pub fn len(&self) -> usize { 2659 (self.end - self.start) as usize 2660 } 2661} 2662 2663#[derive(Debug, PartialEq, Eq, Clone)] 2664pub struct DefinitionLocation { 2665 pub module: Option<EcoString>, 2666 pub span: SrcSpan, 2667} 2668 2669pub type UntypedPattern = Pattern<()>; 2670pub type TypedPattern = Pattern<Arc<Type>>; 2671 2672#[derive(Debug, Clone, PartialEq, Eq)] 2673pub enum Pattern<Type> { 2674 Int { 2675 location: SrcSpan, 2676 value: EcoString, 2677 int_value: BigInt, 2678 }, 2679 2680 Float { 2681 location: SrcSpan, 2682 value: EcoString, 2683 float_value: LiteralFloatValue, 2684 }, 2685 2686 String { 2687 location: SrcSpan, 2688 value: EcoString, 2689 }, 2690 2691 /// The creation of a variable. 2692 /// e.g. `assert [this_is_a_var, .._] = x` 2693 Variable { 2694 location: SrcSpan, 2695 name: EcoString, 2696 type_: Type, 2697 origin: VariableOrigin, 2698 }, 2699 2700 /// The specified size of a bit array. This can either be a literal integer, 2701 /// a reference to a variable, or a maths expression. 2702 /// e.g. `let assert <<y:size(somevar)>> = x` 2703 BitArraySize(BitArraySize<Type>), 2704 2705 /// A name given to a sub-pattern using the `as` keyword. 2706 /// e.g. `assert #(1, [_, _] as the_list) = x` 2707 Assign { 2708 name: EcoString, 2709 location: SrcSpan, 2710 pattern: Box<Self>, 2711 }, 2712 2713 /// A pattern that binds to any value but does not assign a variable. 2714 /// Always starts with an underscore. 2715 Discard { 2716 name: EcoString, 2717 location: SrcSpan, 2718 type_: Type, 2719 }, 2720 2721 List { 2722 location: SrcSpan, 2723 elements: Vec<Self>, 2724 tail: Option<Box<TailPattern<Type>>>, 2725 /// The type of the list, so this is going to be `List(something)`. 2726 /// 2727 type_: Type, 2728 }, 2729 2730 /// The constructor for a custom type. Starts with an uppercase letter. 2731 Constructor { 2732 location: SrcSpan, 2733 name_location: SrcSpan, 2734 name: EcoString, 2735 arguments: Vec<CallArg<Self>>, 2736 module: Option<(EcoString, SrcSpan)>, 2737 constructor: Inferred<PatternConstructor>, 2738 spread: Option<SrcSpan>, 2739 type_: Type, 2740 }, 2741 2742 Tuple { 2743 location: SrcSpan, 2744 elements: Vec<Self>, 2745 }, 2746 2747 BitArray { 2748 location: SrcSpan, 2749 segments: Vec<BitArraySegment<Self, Type>>, 2750 }, 2751 2752 // "prefix" <> variable 2753 StringPrefix { 2754 location: SrcSpan, 2755 left_location: SrcSpan, 2756 left_side_assignment: Option<(EcoString, SrcSpan)>, 2757 right_location: SrcSpan, 2758 left_side_string: EcoString, 2759 /// The variable on the right hand side of the `<>`. 2760 right_side_assignment: AssignName, 2761 }, 2762 2763 /// A placeholder pattern used to allow module analysis to continue 2764 /// even when there are type errors. Should never end up in generated code. 2765 Invalid { 2766 location: SrcSpan, 2767 type_: Type, 2768 }, 2769} 2770 2771pub type TypedBitArraySize = BitArraySize<Arc<Type>>; 2772 2773#[derive(Debug, Clone, PartialEq, Eq)] 2774pub enum BitArraySize<Type> { 2775 Int { 2776 location: SrcSpan, 2777 value: EcoString, 2778 int_value: BigInt, 2779 }, 2780 2781 Variable { 2782 location: SrcSpan, 2783 name: EcoString, 2784 constructor: Option<Box<ValueConstructor>>, 2785 type_: Type, 2786 }, 2787 2788 BinaryOperator { 2789 location: SrcSpan, 2790 operator: IntOperator, 2791 left: Box<Self>, 2792 right: Box<Self>, 2793 }, 2794 2795 Block { 2796 location: SrcSpan, 2797 inner: Box<Self>, 2798 }, 2799} 2800 2801#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)] 2802pub enum IntOperator { 2803 Add, 2804 Subtract, 2805 Multiply, 2806 Divide, 2807 Remainder, 2808} 2809 2810impl IntOperator { 2811 pub fn precedence(&self) -> u8 { 2812 match self { 2813 Self::Add | Self::Subtract => 7, 2814 2815 Self::Multiply | Self::Divide | Self::Remainder => 8, 2816 } 2817 } 2818 2819 pub fn to_bin_op(&self) -> BinOp { 2820 match self { 2821 IntOperator::Add => BinOp::AddInt, 2822 IntOperator::Subtract => BinOp::SubInt, 2823 IntOperator::Multiply => BinOp::MultInt, 2824 IntOperator::Divide => BinOp::DivInt, 2825 IntOperator::Remainder => BinOp::RemainderInt, 2826 } 2827 } 2828} 2829 2830impl<T> BitArraySize<T> { 2831 pub fn location(&self) -> SrcSpan { 2832 match self { 2833 BitArraySize::Int { location, .. } 2834 | BitArraySize::Variable { location, .. } 2835 | BitArraySize::BinaryOperator { location, .. } 2836 | BitArraySize::Block { location, .. } => *location, 2837 } 2838 } 2839 2840 pub fn non_zero_compile_time_number(&self) -> bool { 2841 self.compile_time_number() 2842 .is_some_and(|number| number != BigInt::ZERO) 2843 } 2844 2845 pub fn compile_time_number(&self) -> Option<BigInt> { 2846 match self { 2847 BitArraySize::Int { int_value, .. } => Some(int_value.clone()), 2848 BitArraySize::Block { inner, .. } => inner.compile_time_number(), 2849 BitArraySize::Variable { .. } | BitArraySize::BinaryOperator { .. } => None, 2850 } 2851 } 2852 2853 fn syntactically_eq(&self, other: &Self) -> bool { 2854 match (self, other) { 2855 (BitArraySize::Int { int_value: n, .. }, BitArraySize::Int { int_value: m, .. }) => { 2856 n == m 2857 } 2858 (BitArraySize::Int { .. }, _) => false, 2859 2860 ( 2861 BitArraySize::Variable { name, .. }, 2862 BitArraySize::Variable { 2863 name: other_name, .. 2864 }, 2865 ) => name == other_name, 2866 (BitArraySize::Variable { .. }, _) => false, 2867 2868 ( 2869 BitArraySize::BinaryOperator { 2870 operator, 2871 left, 2872 right, 2873 .. 2874 }, 2875 BitArraySize::BinaryOperator { 2876 operator: other_operator, 2877 left: other_left, 2878 right: other_right, 2879 .. 2880 }, 2881 ) => { 2882 operator == other_operator 2883 && left.syntactically_eq(other_left) 2884 && right.syntactically_eq(other_right) 2885 } 2886 (BitArraySize::BinaryOperator { .. }, _) => false, 2887 2888 ( 2889 BitArraySize::Block { inner, .. }, 2890 BitArraySize::Block { 2891 inner: other_inner, .. 2892 }, 2893 ) => inner.syntactically_eq(other_inner), 2894 (BitArraySize::Block { .. }, _) => false, 2895 } 2896 } 2897} 2898 2899pub type TypedTailPattern = TailPattern<Arc<Type>>; 2900 2901pub type UntypedTailPattern = TailPattern<()>; 2902 2903/// The pattern one can use to match on the rest of a list: 2904/// 2905#[derive(Debug, Clone, PartialEq, Eq)] 2906pub struct TailPattern<Type> { 2907 /// The entire location of the pattern, covering the `..` as well. 2908 /// 2909 pub location: SrcSpan, 2910 2911 /// The name assigned to the rest of the list being matched: 2912 /// 2913 /// ```gleam 2914 /// [wibble, ..] 2915 /// // ^^ no name 2916 /// 2917 /// [wibble, ..rest] 2918 /// // ^^^^^^ a variable name 2919 /// 2920 /// [wibble, .._rest] 2921 /// // ^^^^^^^ a discarded name 2922 /// ``` 2923 /// 2924 pub pattern: Pattern<Type>, 2925} 2926 2927#[derive(Debug, Clone, PartialEq, Eq, Hash)] 2928pub enum AssignName { 2929 Variable(EcoString), 2930 Discard(EcoString), 2931} 2932 2933impl AssignName { 2934 pub fn name(&self) -> &EcoString { 2935 match self { 2936 AssignName::Variable(name) | AssignName::Discard(name) => name, 2937 } 2938 } 2939 2940 pub fn to_arg_names(self, location: SrcSpan) -> ArgNames { 2941 match self { 2942 AssignName::Variable(name) => ArgNames::Named { name, location }, 2943 AssignName::Discard(name) => ArgNames::Discard { name, location }, 2944 } 2945 } 2946 2947 pub fn assigned_name(&self) -> Option<&str> { 2948 match self { 2949 AssignName::Variable(name) => Some(name), 2950 AssignName::Discard(_) => None, 2951 } 2952 } 2953} 2954 2955impl<A> Pattern<A> { 2956 pub fn location(&self) -> SrcSpan { 2957 match self { 2958 Pattern::Assign { 2959 pattern, location, .. 2960 } => SrcSpan::new(pattern.location().start, location.end), 2961 Pattern::Int { location, .. } 2962 | Pattern::Variable { location, .. } 2963 | Pattern::List { location, .. } 2964 | Pattern::Float { location, .. } 2965 | Pattern::Discard { location, .. } 2966 | Pattern::String { location, .. } 2967 | Pattern::Tuple { location, .. } 2968 | Pattern::Constructor { location, .. } 2969 | Pattern::StringPrefix { location, .. } 2970 | Pattern::BitArray { location, .. } 2971 | Pattern::Invalid { location, .. } => *location, 2972 Pattern::BitArraySize(size) => size.location(), 2973 } 2974 } 2975 2976 /// Returns `true` if the pattern is [`Discard`]. 2977 /// 2978 /// [`Discard`]: Pattern::Discard 2979 #[must_use] 2980 pub fn is_discard(&self) -> bool { 2981 matches!(self, Self::Discard { .. }) 2982 } 2983 2984 #[must_use] 2985 pub fn is_variable(&self) -> bool { 2986 matches!(self, Pattern::Variable { .. }) 2987 } 2988 2989 #[must_use] 2990 pub fn is_string(&self) -> bool { 2991 matches!(self, Self::String { .. }) 2992 } 2993} 2994 2995impl TypedPattern { 2996 fn syntactically_eq(&self, other: &Self) -> bool { 2997 match (self, other) { 2998 (Pattern::Int { int_value: n, .. }, Pattern::Int { int_value: m, .. }) => n == m, 2999 (Pattern::Int { .. }, _) => false, 3000 3001 (Pattern::Float { float_value: n, .. }, Pattern::Float { float_value: m, .. }) => { 3002 n == m 3003 } 3004 (Pattern::Float { .. }, _) => false, 3005 3006 ( 3007 Pattern::String { value, .. }, 3008 Pattern::String { 3009 value: other_value, .. 3010 }, 3011 ) => value == other_value, 3012 (Pattern::String { .. }, _) => false, 3013 3014 ( 3015 Pattern::Variable { name, .. }, 3016 Pattern::Variable { 3017 name: other_name, .. 3018 }, 3019 ) => name == other_name, 3020 (Pattern::Variable { .. }, _) => false, 3021 3022 (Pattern::BitArraySize(one), Pattern::BitArraySize(other)) => { 3023 one.syntactically_eq(other) 3024 } 3025 (Pattern::BitArraySize(..), _) => false, 3026 3027 ( 3028 Pattern::Assign { name, pattern, .. }, 3029 Pattern::Assign { 3030 name: other_name, 3031 pattern: other_pattern, 3032 .. 3033 }, 3034 ) => name == other_name && pattern.syntactically_eq(other_pattern), 3035 (Pattern::Assign { .. }, _) => false, 3036 3037 ( 3038 Pattern::Discard { name, .. }, 3039 Pattern::Discard { 3040 name: other_name, .. 3041 }, 3042 ) => name == other_name, 3043 (Pattern::Discard { .. }, _) => false, 3044 3045 ( 3046 Pattern::List { elements, tail, .. }, 3047 Pattern::List { 3048 elements: other_elements, 3049 tail: other_tail, 3050 .. 3051 }, 3052 ) => { 3053 let tails_are_equal = match (tail, other_tail) { 3054 (None, None) => true, 3055 (None, Some(_)) | (Some(_), None) => false, 3056 (Some(one), Some(other)) => one.pattern.syntactically_eq(&other.pattern), 3057 }; 3058 tails_are_equal 3059 && pairwise_all(elements, other_elements, |(one, other)| { 3060 one.syntactically_eq(other) 3061 }) 3062 } 3063 (Pattern::List { .. }, _) => false, 3064 3065 ( 3066 Pattern::Constructor { 3067 name, 3068 arguments, 3069 module, 3070 .. 3071 }, 3072 Pattern::Constructor { 3073 name: other_name, 3074 arguments: other_arguments, 3075 module: other_module, 3076 .. 3077 }, 3078 ) => { 3079 let modules_are_equal = match (module, other_module) { 3080 (None, None) => true, 3081 (None, Some(_)) | (Some(_), None) => false, 3082 (Some((one, _)), Some((other, _))) => one == other, 3083 }; 3084 modules_are_equal 3085 && name == other_name 3086 && pairwise_all(arguments, other_arguments, |(one, other)| { 3087 one.label == other.label && one.value.syntactically_eq(&other.value) 3088 }) 3089 } 3090 (Pattern::Constructor { .. }, _) => false, 3091 3092 ( 3093 Pattern::Tuple { elements, .. }, 3094 Pattern::Tuple { 3095 elements: other_elements, 3096 .. 3097 }, 3098 ) => pairwise_all(elements, other_elements, |(one, other)| { 3099 one.syntactically_eq(other) 3100 }), 3101 (Pattern::Tuple { .. }, _) => false, 3102 3103 ( 3104 Pattern::BitArray { segments, .. }, 3105 Pattern::BitArray { 3106 segments: other_segments, 3107 .. 3108 }, 3109 ) => pairwise_all(segments, other_segments, |(one, other)| { 3110 one.syntactically_eq(other) 3111 }), 3112 (Pattern::BitArray { .. }, _) => false, 3113 3114 ( 3115 Pattern::StringPrefix { 3116 left_side_assignment, 3117 left_side_string, 3118 right_side_assignment, 3119 .. 3120 }, 3121 Pattern::StringPrefix { 3122 left_side_assignment: other_left_side_assignment, 3123 left_side_string: other_left_side_string, 3124 right_side_assignment: other_right_side_assignment, 3125 .. 3126 }, 3127 ) => { 3128 let left_side_assignments_are_equal = 3129 match (left_side_assignment, other_left_side_assignment) { 3130 (None, None) => true, 3131 (None, Some(_)) | (Some(_), None) => false, 3132 (Some((one, _)), Some((other, _))) => one == other, 3133 }; 3134 let right_side_assignments_are_equal = 3135 match (right_side_assignment, other_right_side_assignment) { 3136 (AssignName::Variable(one), AssignName::Variable(other)) => one == other, 3137 (AssignName::Variable(_), AssignName::Discard(_)) => false, 3138 (AssignName::Discard(one), AssignName::Discard(other)) => one == other, 3139 (AssignName::Discard(_), AssignName::Variable(_)) => false, 3140 }; 3141 left_side_string == other_left_side_string 3142 && left_side_assignments_are_equal 3143 && right_side_assignments_are_equal 3144 } 3145 (Pattern::StringPrefix { .. }, _) => false, 3146 3147 (Pattern::Invalid { .. }, _) => false, 3148 } 3149 } 3150} 3151 3152/// A variable bound inside a pattern. 3153#[derive(Debug, Clone)] 3154pub struct BoundVariable { 3155 pub name: BoundVariableName, 3156 pub location: SrcSpan, 3157 pub type_: Arc<Type>, 3158} 3159 3160#[derive(Debug, Clone)] 3161pub enum BoundVariableName { 3162 /// A record's labelled field introduced with the shorthand syntax. 3163 ShorthandLabel { name: EcoString }, 3164 ListTail { 3165 name: EcoString, 3166 /// The location of the whole tail, from the `..` prefix until the end of the variable. 3167 tail_location: SrcSpan, 3168 }, 3169 /// Any other variable name. 3170 Regular { name: EcoString }, 3171} 3172 3173impl BoundVariable { 3174 pub fn name(&self) -> EcoString { 3175 match &self.name { 3176 BoundVariableName::ShorthandLabel { name } 3177 | BoundVariableName::ListTail { name, .. } 3178 | BoundVariableName::Regular { name } => name.clone(), 3179 } 3180 } 3181} 3182 3183impl TypedPattern { 3184 pub fn definition_location(&self) -> Option<DefinitionLocation> { 3185 match self { 3186 Pattern::Int { .. } 3187 | Pattern::Float { .. } 3188 | Pattern::String { .. } 3189 | Pattern::Variable { .. } 3190 | Pattern::BitArraySize { .. } 3191 | Pattern::Assign { .. } 3192 | Pattern::Discard { .. } 3193 | Pattern::List { .. } 3194 | Pattern::Tuple { .. } 3195 | Pattern::BitArray { .. } 3196 | Pattern::StringPrefix { .. } 3197 | Pattern::Invalid { .. } => None, 3198 3199 Pattern::Constructor { constructor, .. } => constructor.definition_location(), 3200 } 3201 } 3202 3203 pub fn get_documentation(&self) -> Option<&str> { 3204 match self { 3205 Pattern::Int { .. } 3206 | Pattern::Float { .. } 3207 | Pattern::String { .. } 3208 | Pattern::Variable { .. } 3209 | Pattern::BitArraySize { .. } 3210 | Pattern::Assign { .. } 3211 | Pattern::Discard { .. } 3212 | Pattern::List { .. } 3213 | Pattern::Tuple { .. } 3214 | Pattern::BitArray { .. } 3215 | Pattern::StringPrefix { .. } 3216 | Pattern::Invalid { .. } => None, 3217 3218 Pattern::Constructor { constructor, .. } => constructor.get_documentation(), 3219 } 3220 } 3221 3222 pub fn type_(&self) -> Arc<Type> { 3223 match self { 3224 Pattern::Int { .. } => type_::int(), 3225 Pattern::Float { .. } => type_::float(), 3226 Pattern::String { .. } => type_::string(), 3227 Pattern::BitArray { .. } => type_::bit_array(), 3228 Pattern::StringPrefix { .. } => type_::string(), 3229 3230 Pattern::Variable { type_, .. } 3231 | Pattern::List { type_, .. } 3232 | Pattern::Constructor { type_, .. } 3233 | Pattern::Invalid { type_, .. } => type_.clone(), 3234 3235 Pattern::Assign { pattern, .. } => pattern.type_(), 3236 3237 // Bit array sizes should always be integers 3238 Pattern::BitArraySize(_) => type_::int(), 3239 3240 Pattern::Discard { type_, .. } => type_.clone(), 3241 3242 Pattern::Tuple { elements, .. } => { 3243 type_::tuple(elements.iter().map(|p| p.type_()).collect()) 3244 } 3245 } 3246 } 3247 3248 fn find_node(&self, byte_index: u32) -> Option<Located<'_>> { 3249 if !self.location().contains(byte_index) { 3250 return None; 3251 } 3252 3253 if let Pattern::Variable { name, .. } = self { 3254 // For pipes the pattern can't be pointed to 3255 if name.as_str().eq(PIPE_VARIABLE) { 3256 return None; 3257 } 3258 } 3259 3260 match self { 3261 Pattern::Int { .. } 3262 | Pattern::Float { .. } 3263 | Pattern::String { .. } 3264 | Pattern::Variable { .. } 3265 | Pattern::BitArraySize { .. } 3266 | Pattern::Discard { .. } 3267 | Pattern::Invalid { .. } => Some(Located::Pattern(self)), 3268 Pattern::StringPrefix { 3269 left_side_assignment, 3270 right_side_assignment, 3271 right_location, 3272 .. 3273 } => { 3274 // Handle the prefix alias: "prefix" as name 3275 if let Some((name, left_side_assignment_location)) = left_side_assignment 3276 && left_side_assignment_location.contains(byte_index) 3277 { 3278 return Some(Located::StringPrefixPatternVariable { 3279 location: *left_side_assignment_location, 3280 name, 3281 }); 3282 } 3283 3284 // Handle the suffix: <> name 3285 if let AssignName::Variable(name) = right_side_assignment 3286 && right_location.contains(byte_index) 3287 { 3288 return Some(Located::StringPrefixPatternVariable { 3289 location: *right_location, 3290 name, 3291 }); 3292 } 3293 3294 Some(Located::Pattern(self)) 3295 } 3296 Pattern::Assign { pattern, .. } => pattern 3297 .find_node(byte_index) 3298 .or_else(|| Some(Located::Pattern(self))), 3299 3300 Pattern::Constructor { 3301 module, 3302 spread, 3303 arguments, 3304 constructor, 3305 .. 3306 } => { 3307 if let Some((module_alias, module_location)) = module 3308 && let Inferred::Known(constructor) = constructor 3309 && module_location.contains(byte_index) 3310 { 3311 Some(Located::ModuleName { 3312 location: *module_location, 3313 module_name: constructor.module.clone(), 3314 module_alias: module_alias.clone(), 3315 layer: Layer::Value, 3316 }) 3317 } else if let Some(spread_location) = spread 3318 && spread_location.contains(byte_index) 3319 { 3320 Some(Located::PatternSpread { 3321 spread_location: *spread_location, 3322 pattern: self, 3323 }) 3324 } else { 3325 arguments 3326 .iter() 3327 .find_map(|argument| argument.find_node(byte_index)) 3328 } 3329 } 3330 3331 Pattern::List { elements, tail, .. } => elements 3332 .iter() 3333 .find_map(|element| element.find_node(byte_index)) 3334 .or_else(|| { 3335 tail.as_ref() 3336 .and_then(|tail| tail.pattern.find_node(byte_index)) 3337 }), 3338 3339 Pattern::Tuple { elements, .. } => elements 3340 .iter() 3341 .find_map(|element| element.find_node(byte_index)), 3342 3343 Pattern::BitArray { segments, .. } => segments 3344 .iter() 3345 .find_map(|segment| segment.find_node(byte_index)) 3346 .or(Some(Located::Pattern(self))), 3347 } 3348 .or(Some(Located::Pattern(self))) 3349 } 3350 3351 /// If the pattern is a `Constructor` with a spread, it returns a tuple with 3352 /// all the ignored fields. Split in unlabelled and labelled ones. 3353 /// 3354 pub fn unused_arguments(&self) -> Option<PatternUnusedArguments> { 3355 let TypedPattern::Constructor { 3356 arguments, 3357 spread: Some(_), 3358 .. 3359 } = self 3360 else { 3361 return None; 3362 }; 3363 3364 let mut positional = vec![]; 3365 let mut labelled = vec![]; 3366 for argument in arguments { 3367 // We only want to display the arguments that were ignored using `..`. 3368 // Any argument ignored that way is marked as implicit, so if it is 3369 // not implicit we just ignore it. 3370 if !argument.is_implicit() { 3371 continue; 3372 } 3373 let type_ = argument.value.type_(); 3374 match &argument.label { 3375 Some(label) => labelled.push((label.clone(), type_)), 3376 None => positional.push(type_), 3377 } 3378 } 3379 3380 Some(PatternUnusedArguments { 3381 positional, 3382 labelled, 3383 }) 3384 } 3385 3386 /// Whether the pattern always matches. For example, a tuple or simple 3387 /// variable assignment always match and can never fail. 3388 #[must_use] 3389 pub fn always_matches(&self) -> bool { 3390 match self { 3391 Pattern::Variable { .. } | Pattern::Discard { .. } => true, 3392 Pattern::Assign { pattern, .. } => pattern.always_matches(), 3393 Pattern::Tuple { elements, .. } => { 3394 elements.iter().all(|element| element.always_matches()) 3395 } 3396 Pattern::Int { .. } 3397 | Pattern::Float { .. } 3398 | Pattern::String { .. } 3399 | Pattern::BitArraySize { .. } 3400 | Pattern::List { .. } 3401 | Pattern::Constructor { .. } 3402 | Pattern::BitArray { .. } 3403 | Pattern::StringPrefix { .. } 3404 | Pattern::Invalid { .. } => false, 3405 } 3406 } 3407 3408 pub fn bound_variables(&self) -> Vec<BoundVariable> { 3409 let mut variables = Vec::new(); 3410 self.collect_bound_variables(&mut variables); 3411 variables 3412 } 3413 3414 fn collect_bound_variables(&self, variables: &mut Vec<BoundVariable>) { 3415 match self { 3416 Pattern::Int { .. } 3417 | Pattern::Float { .. } 3418 | Pattern::String { .. } 3419 | Pattern::Discard { .. } 3420 | Pattern::Invalid { .. } => {} 3421 3422 Pattern::Variable { 3423 name, 3424 location, 3425 type_, 3426 .. 3427 } => variables.push(BoundVariable { 3428 name: BoundVariableName::Regular { name: name.clone() }, 3429 location: *location, 3430 type_: type_.clone(), 3431 }), 3432 Pattern::BitArraySize { .. } => {} 3433 Pattern::Assign { 3434 name, 3435 pattern, 3436 location, 3437 } => { 3438 variables.push(BoundVariable { 3439 name: BoundVariableName::Regular { name: name.clone() }, 3440 location: *location, 3441 type_: pattern.type_(), 3442 }); 3443 pattern.collect_bound_variables(variables); 3444 } 3445 Pattern::List { 3446 elements, 3447 tail, 3448 type_, 3449 .. 3450 } => { 3451 for element in elements { 3452 element.collect_bound_variables(variables); 3453 } 3454 if let Some(tail) = tail 3455 && let Pattern::Variable { name, location, .. } = tail.pattern.to_owned() 3456 { 3457 variables.push(BoundVariable { 3458 name: BoundVariableName::ListTail { 3459 name, 3460 tail_location: tail.location, 3461 }, 3462 location, 3463 type_: type_.clone(), 3464 }) 3465 }; 3466 } 3467 Pattern::Constructor { arguments, .. } => { 3468 for argument in arguments { 3469 if let Some(name) = argument.label_shorthand_name() { 3470 variables.push(BoundVariable { 3471 name: BoundVariableName::ShorthandLabel { name: name.clone() }, 3472 location: argument.location, 3473 type_: argument.value.type_(), 3474 }) 3475 } else { 3476 argument.value.collect_bound_variables(variables); 3477 } 3478 } 3479 } 3480 Pattern::Tuple { elements, .. } => { 3481 for element in elements { 3482 element.collect_bound_variables(variables); 3483 } 3484 } 3485 Pattern::BitArray { segments, .. } => { 3486 for segment in segments { 3487 segment.value.collect_bound_variables(variables); 3488 } 3489 } 3490 Pattern::StringPrefix { 3491 left_side_assignment, 3492 right_side_assignment, 3493 right_location, 3494 .. 3495 } => { 3496 if let Some((name, location)) = left_side_assignment { 3497 variables.push(BoundVariable { 3498 name: BoundVariableName::Regular { name: name.clone() }, 3499 location: *location, 3500 type_: type_::string(), 3501 }); 3502 } 3503 match right_side_assignment { 3504 AssignName::Variable(name) => variables.push(BoundVariable { 3505 name: BoundVariableName::Regular { name: name.clone() }, 3506 location: *right_location, 3507 type_: type_::string(), 3508 }), 3509 AssignName::Discard(_) => {} 3510 } 3511 } 3512 } 3513 } 3514} 3515 3516#[derive(Debug, Default)] 3517pub struct PatternUnusedArguments { 3518 pub positional: Vec<Arc<Type>>, 3519 pub labelled: Vec<(EcoString, Arc<Type>)>, 3520} 3521 3522impl<A> HasLocation for Pattern<A> { 3523 fn location(&self) -> SrcSpan { 3524 self.location() 3525 } 3526} 3527 3528#[derive(Debug, Clone, PartialEq, Eq)] 3529pub enum AssignmentKind<Expression> { 3530 /// let x = ... 3531 Let, 3532 /// This is a let assignment generated by the compiler for intermediate 3533 /// variables needed by record updates and `use`. 3534 /// Like a regular `Let` assignment this can never fail. 3535 /// 3536 Generated, 3537 /// let assert x = ... 3538 Assert { 3539 /// The src byte span of the `let assert` 3540 /// 3541 /// ```gleam 3542 /// let assert Wibble = todo 3543 /// ^^^^^^^^^^ 3544 /// ``` 3545 location: SrcSpan, 3546 3547 /// The byte index of the start of `assert` 3548 /// 3549 /// ```gleam 3550 /// let assert Wibble = todo 3551 /// ^ 3552 /// ``` 3553 assert_keyword_start: u32, 3554 3555 /// The message given to the assertion: 3556 /// 3557 /// ```gleam 3558 /// let asset Ok(a) = something() as "This will never fail" 3559 /// ^^^^^^^^^^^^^^^^^^^^^^ 3560 /// ``` 3561 message: Option<Expression>, 3562 }, 3563} 3564 3565impl<Expression> AssignmentKind<Expression> { 3566 /// Returns `true` if the assignment kind is [`Assert`]. 3567 /// 3568 /// [`Assert`]: AssignmentKind::Assert 3569 #[must_use] 3570 pub fn is_assert(&self) -> bool { 3571 match self { 3572 Self::Assert { .. } => true, 3573 Self::Let | Self::Generated => false, 3574 } 3575 } 3576} 3577 3578// BitArrays 3579 3580pub type UntypedExprBitArraySegment = BitArraySegment<UntypedExpr, ()>; 3581pub type TypedExprBitArraySegment = BitArraySegment<TypedExpr, Arc<Type>>; 3582 3583pub type UntypedConstantBitArraySegment = BitArraySegment<UntypedConstant, ()>; 3584pub type TypedConstantBitArraySegment = BitArraySegment<TypedConstant, Arc<Type>>; 3585 3586pub type UntypedPatternBitArraySegment = BitArraySegment<UntypedPattern, ()>; 3587pub type TypedPatternBitArraySegment = BitArraySegment<TypedPattern, Arc<Type>>; 3588 3589#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] 3590pub struct BitArraySegment<Value, Type> { 3591 pub location: SrcSpan, 3592 pub value: Box<Value>, 3593 pub options: Vec<BitArrayOption<Value>>, 3594 pub type_: Type, 3595} 3596 3597#[derive(Debug, PartialEq, Eq, Copy, Clone, Hash, serde::Serialize, serde::Deserialize)] 3598pub enum Endianness { 3599 Big, 3600 Little, 3601} 3602 3603impl Endianness { 3604 pub fn is_big(&self) -> bool { 3605 *self == Endianness::Big 3606 } 3607} 3608 3609impl<Value, Type> HasLocation for BitArraySegment<Value, Type> { 3610 fn location(&self) -> SrcSpan { 3611 self.location 3612 } 3613} 3614 3615impl<Type> BitArraySegment<Pattern<Type>, Type> { 3616 /// Returns the value of the pattern unwrapping any assign pattern. 3617 /// 3618 pub fn value_unwrapping_assign(&self) -> &Pattern<Type> { 3619 match self.value.as_ref() { 3620 Pattern::Assign { pattern, .. } => pattern, 3621 Pattern::Int { .. } 3622 | Pattern::Float { .. } 3623 | Pattern::String { .. } 3624 | Pattern::Variable { .. } 3625 | Pattern::BitArraySize { .. } 3626 | Pattern::Discard { .. } 3627 | Pattern::List { .. } 3628 | Pattern::Constructor { .. } 3629 | Pattern::Tuple { .. } 3630 | Pattern::BitArray { .. } 3631 | Pattern::StringPrefix { .. } 3632 | Pattern::Invalid { .. } => self.value.as_ref(), 3633 } 3634 } 3635} 3636 3637impl<Value, Type> BitArraySegment<Value, Type> { 3638 #[must_use] 3639 pub fn has_native_option(&self) -> bool { 3640 self.options 3641 .iter() 3642 .any(|x| matches!(x, BitArrayOption::Native { .. })) 3643 } 3644 3645 #[must_use] 3646 pub fn has_utf16_codepoint_option(&self) -> bool { 3647 self.options 3648 .iter() 3649 .any(|x| matches!(x, BitArrayOption::Utf16Codepoint { .. })) 3650 } 3651 3652 #[must_use] 3653 pub fn has_utf32_codepoint_option(&self) -> bool { 3654 self.options 3655 .iter() 3656 .any(|x| matches!(x, BitArrayOption::Utf32Codepoint { .. })) 3657 } 3658 3659 #[must_use] 3660 pub fn has_utf16_option(&self) -> bool { 3661 self.options 3662 .iter() 3663 .any(|x| matches!(x, BitArrayOption::Utf16 { .. })) 3664 } 3665 3666 #[must_use] 3667 pub fn has_utf32_option(&self) -> bool { 3668 self.options 3669 .iter() 3670 .any(|x| matches!(x, BitArrayOption::Utf32 { .. })) 3671 } 3672 3673 pub fn endianness(&self) -> Endianness { 3674 if self 3675 .options 3676 .iter() 3677 .any(|x| matches!(x, BitArrayOption::Little { .. })) 3678 { 3679 Endianness::Little 3680 } else { 3681 Endianness::Big 3682 } 3683 } 3684 3685 pub(crate) fn signed(&self) -> bool { 3686 self.options 3687 .iter() 3688 .any(|x| matches!(x, BitArrayOption::Signed { .. })) 3689 } 3690 3691 pub fn size(&self) -> Option<&Value> { 3692 self.options.iter().find_map(|x| match x { 3693 BitArrayOption::Size { value, .. } => Some(value.as_ref()), 3694 BitArrayOption::Bytes { .. } 3695 | BitArrayOption::Int { .. } 3696 | BitArrayOption::Float { .. } 3697 | BitArrayOption::Bits { .. } 3698 | BitArrayOption::Utf8 { .. } 3699 | BitArrayOption::Utf16 { .. } 3700 | BitArrayOption::Utf32 { .. } 3701 | BitArrayOption::Utf8Codepoint { .. } 3702 | BitArrayOption::Utf16Codepoint { .. } 3703 | BitArrayOption::Utf32Codepoint { .. } 3704 | BitArrayOption::Signed { .. } 3705 | BitArrayOption::Unsigned { .. } 3706 | BitArrayOption::Big { .. } 3707 | BitArrayOption::Little { .. } 3708 | BitArrayOption::Native { .. } 3709 | BitArrayOption::Unit { .. } => None, 3710 }) 3711 } 3712 3713 /// Returns the unit of `size` in the bit array segment. The `unit` option 3714 /// overrides the `bytes` option, so if a segment has both, the unit is what 3715 /// is specified in `unit`, not 8. 3716 pub fn unit(&self) -> u8 { 3717 let mut has_bytes_option = false; 3718 3719 for option in self.options.iter() { 3720 match option { 3721 BitArrayOption::Unit { value, .. } => return *value, 3722 BitArrayOption::Bytes { .. } => has_bytes_option = true, 3723 BitArrayOption::Int { .. } 3724 | BitArrayOption::Float { .. } 3725 | BitArrayOption::Bits { .. } 3726 | BitArrayOption::Utf8 { .. } 3727 | BitArrayOption::Utf16 { .. } 3728 | BitArrayOption::Utf32 { .. } 3729 | BitArrayOption::Utf8Codepoint { .. } 3730 | BitArrayOption::Utf16Codepoint { .. } 3731 | BitArrayOption::Utf32Codepoint { .. } 3732 | BitArrayOption::Signed { .. } 3733 | BitArrayOption::Unsigned { .. } 3734 | BitArrayOption::Big { .. } 3735 | BitArrayOption::Little { .. } 3736 | BitArrayOption::Native { .. } 3737 | BitArrayOption::Size { .. } => {} 3738 } 3739 } 3740 3741 if has_bytes_option { 8 } else { 1 } 3742 } 3743 3744 pub(crate) fn has_bits_option(&self) -> bool { 3745 self.options 3746 .iter() 3747 .any(|option| matches!(option, BitArrayOption::Bits { .. })) 3748 } 3749 3750 pub(crate) fn has_bytes_option(&self) -> bool { 3751 self.options 3752 .iter() 3753 .any(|option| matches!(option, BitArrayOption::Bytes { .. })) 3754 } 3755} 3756 3757impl<Value, Type> BitArraySegment<Value, Type> { 3758 #[must_use] 3759 pub(crate) fn has_type_option(&self) -> bool { 3760 self.options.iter().any(|option| option.is_type_option()) 3761 } 3762} 3763 3764impl TypedExprBitArraySegment { 3765 pub fn find_node(&self, byte_index: u32) -> Option<Located<'_>> { 3766 self.value.find_node(byte_index) 3767 } 3768 3769 fn syntactically_eq(&self, other: &Self) -> bool { 3770 self.value.syntactically_eq(&other.value) 3771 && pairwise_all(&self.options, &other.options, |(option, other_option)| { 3772 option.syntactically_eq(other_option, |size, other_size| { 3773 size.syntactically_eq(other_size) 3774 }) 3775 }) 3776 } 3777} 3778 3779impl<TypedValue> BitArraySegment<TypedValue, Arc<Type>> 3780where 3781 TypedValue: HasType + HasLocation + Clone + bit_array::GetLiteralValue, 3782{ 3783 pub fn check_for_truncated_value(&self) -> Option<BitArraySegmentTruncation> { 3784 // Both the size and the value must be two compile-time known constants. 3785 let segment_bits = self.bits_size()?.to_i64()?; 3786 let literal_value = self.value.as_int_literal()?; 3787 if segment_bits <= 0 { 3788 return None; 3789 } 3790 3791 let safe_range = match literal_value.sign() { 3792 Sign::NoSign => return None, 3793 Sign::Minus => { 3794 (-(BigInt::one() << (segment_bits - 1))) 3795 ..((BigInt::one() << (segment_bits - 1)) - 1) 3796 } 3797 Sign::Plus => BigInt::ZERO..(BigInt::one() << segment_bits), 3798 }; 3799 3800 if !safe_range.contains(&literal_value) { 3801 Some(BitArraySegmentTruncation { 3802 truncated_value: literal_value.clone(), 3803 truncated_into: truncate(&literal_value, segment_bits), 3804 value_location: self.value.location(), 3805 segment_bits, 3806 }) 3807 } else { 3808 None 3809 } 3810 } 3811 3812 /// If the segment size is a compile-time known constant this returns the 3813 /// segment size in bits, taking the segment's unit into consideration! 3814 /// 3815 fn bits_size(&self) -> Option<BigInt> { 3816 let size = match self.size() { 3817 None if self.type_.is_int() => 8.into(), 3818 None => 64.into(), 3819 Some(value) => value.as_int_literal()?, 3820 }; 3821 3822 let unit = self.unit(); 3823 Some(size * unit) 3824 } 3825} 3826 3827/// As Björn said, when a value is smaller than the segment's size it will be 3828/// truncated, only taking the first `n` bits: 3829/// 3830/// > It will be silently truncated. In general, when storing value an integer 3831/// > `I` into a segment of size `N`, the actual value stored will be 3832/// > `I band ((1 bsl N) - 1)`. 3833/// 3834/// <https://erlangforums.com/t/what-happens-when-a-bit-array-segment-size-is-smaller-than-its-value/4650/2?u=giacomocavalieri> 3835/// 3836/// Thank you Björn! 3837/// 3838fn truncate(literal_value: &BigInt, segment_bits: i64) -> BigInt { 3839 literal_value & ((BigInt::one() << segment_bits) - BigInt::one()) 3840} 3841 3842#[derive(serde::Deserialize, serde::Serialize, Eq, PartialEq, Clone, Debug)] 3843pub struct BitArraySegmentTruncation { 3844 /// The value that would end up being truncated. 3845 pub truncated_value: BigInt, 3846 /// What the value would be truncated into. 3847 pub truncated_into: BigInt, 3848 /// The span of the segment's value being truncated. 3849 pub value_location: SrcSpan, 3850 /// The size of the segment. 3851 pub segment_bits: i64, 3852} 3853 3854impl TypedPatternBitArraySegment { 3855 pub fn find_node(&self, byte_index: u32) -> Option<Located<'_>> { 3856 self.value.find_node(byte_index).or_else(|| { 3857 self.options 3858 .iter() 3859 .find_map(|option| option.find_node(byte_index)) 3860 }) 3861 } 3862 3863 fn syntactically_eq(&self, other: &Self) -> bool { 3864 self.value.syntactically_eq(&other.value) 3865 && pairwise_all(&self.options, &other.options, |(option, other_option)| { 3866 option.syntactically_eq(other_option, |size, other_size| { 3867 size.syntactically_eq(other_size) 3868 }) 3869 }) 3870 } 3871} 3872 3873impl TypedConstantBitArraySegment { 3874 pub fn find_node(&self, byte_index: u32) -> Option<Located<'_>> { 3875 self.value.find_node(byte_index).or_else(|| { 3876 self.options 3877 .iter() 3878 .find_map(|option| option.find_node(byte_index)) 3879 }) 3880 } 3881 3882 fn syntactically_eq(&self, other: &Self) -> bool { 3883 self.value.syntactically_eq(&other.value) 3884 && pairwise_all(&self.options, &other.options, |(option, other_option)| { 3885 option.syntactically_eq(other_option, |size, other_size| { 3886 size.syntactically_eq(other_size) 3887 }) 3888 }) 3889 } 3890} 3891 3892pub type TypedConstantBitArraySegmentOption = BitArrayOption<TypedConstant>; 3893 3894#[derive(Debug, PartialEq, Eq, Clone, serde::Serialize, serde::Deserialize)] 3895pub enum BitArrayOption<Value> { 3896 Bytes { 3897 location: SrcSpan, 3898 }, 3899 3900 Int { 3901 location: SrcSpan, 3902 }, 3903 3904 Float { 3905 location: SrcSpan, 3906 }, 3907 3908 Bits { 3909 location: SrcSpan, 3910 }, 3911 3912 Utf8 { 3913 location: SrcSpan, 3914 }, 3915 3916 Utf16 { 3917 location: SrcSpan, 3918 }, 3919 3920 Utf32 { 3921 location: SrcSpan, 3922 }, 3923 3924 Utf8Codepoint { 3925 location: SrcSpan, 3926 }, 3927 3928 Utf16Codepoint { 3929 location: SrcSpan, 3930 }, 3931 3932 Utf32Codepoint { 3933 location: SrcSpan, 3934 }, 3935 3936 Signed { 3937 location: SrcSpan, 3938 }, 3939 3940 Unsigned { 3941 location: SrcSpan, 3942 }, 3943 3944 Big { 3945 location: SrcSpan, 3946 }, 3947 3948 Little { 3949 location: SrcSpan, 3950 }, 3951 3952 Native { 3953 location: SrcSpan, 3954 }, 3955 3956 Size { 3957 location: SrcSpan, 3958 value: Box<Value>, 3959 short_form: bool, 3960 }, 3961 3962 Unit { 3963 location: SrcSpan, 3964 value: u8, 3965 }, 3966} 3967 3968impl<A> BitArrayOption<A> { 3969 pub fn value(&self) -> Option<&A> { 3970 match self { 3971 BitArrayOption::Size { value, .. } => Some(value), 3972 BitArrayOption::Bytes { .. } 3973 | BitArrayOption::Int { .. } 3974 | BitArrayOption::Float { .. } 3975 | BitArrayOption::Bits { .. } 3976 | BitArrayOption::Utf8 { .. } 3977 | BitArrayOption::Utf16 { .. } 3978 | BitArrayOption::Utf32 { .. } 3979 | BitArrayOption::Utf8Codepoint { .. } 3980 | BitArrayOption::Utf16Codepoint { .. } 3981 | BitArrayOption::Utf32Codepoint { .. } 3982 | BitArrayOption::Signed { .. } 3983 | BitArrayOption::Unsigned { .. } 3984 | BitArrayOption::Big { .. } 3985 | BitArrayOption::Little { .. } 3986 | BitArrayOption::Native { .. } 3987 | BitArrayOption::Unit { .. } => None, 3988 } 3989 } 3990 3991 pub fn location(&self) -> SrcSpan { 3992 match self { 3993 BitArrayOption::Bytes { location } 3994 | BitArrayOption::Int { location } 3995 | BitArrayOption::Float { location } 3996 | BitArrayOption::Bits { location } 3997 | BitArrayOption::Utf8 { location } 3998 | BitArrayOption::Utf16 { location } 3999 | BitArrayOption::Utf32 { location } 4000 | BitArrayOption::Utf8Codepoint { location } 4001 | BitArrayOption::Utf16Codepoint { location } 4002 | BitArrayOption::Utf32Codepoint { location } 4003 | BitArrayOption::Signed { location } 4004 | BitArrayOption::Unsigned { location } 4005 | BitArrayOption::Big { location } 4006 | BitArrayOption::Little { location } 4007 | BitArrayOption::Native { location } 4008 | BitArrayOption::Size { location, .. } 4009 | BitArrayOption::Unit { location, .. } => *location, 4010 } 4011 } 4012 4013 pub fn label(&self) -> EcoString { 4014 match self { 4015 BitArrayOption::Bytes { .. } => "bytes".into(), 4016 BitArrayOption::Int { .. } => "int".into(), 4017 BitArrayOption::Float { .. } => "float".into(), 4018 BitArrayOption::Bits { .. } => "bits".into(), 4019 BitArrayOption::Utf8 { .. } => "utf8".into(), 4020 BitArrayOption::Utf16 { .. } => "utf16".into(), 4021 BitArrayOption::Utf32 { .. } => "utf32".into(), 4022 BitArrayOption::Utf8Codepoint { .. } => "utf8_codepoint".into(), 4023 BitArrayOption::Utf16Codepoint { .. } => "utf16_codepoint".into(), 4024 BitArrayOption::Utf32Codepoint { .. } => "utf32_codepoint".into(), 4025 BitArrayOption::Signed { .. } => "signed".into(), 4026 BitArrayOption::Unsigned { .. } => "unsigned".into(), 4027 BitArrayOption::Big { .. } => "big".into(), 4028 BitArrayOption::Little { .. } => "little".into(), 4029 BitArrayOption::Native { .. } => "native".into(), 4030 BitArrayOption::Size { .. } => "size".into(), 4031 BitArrayOption::Unit { .. } => "unit".into(), 4032 } 4033 } 4034 4035 fn is_type_option(&self) -> bool { 4036 match self { 4037 BitArrayOption::Bytes { .. } 4038 | BitArrayOption::Int { .. } 4039 | BitArrayOption::Float { .. } 4040 | BitArrayOption::Bits { .. } 4041 | BitArrayOption::Utf8 { .. } 4042 | BitArrayOption::Utf16 { .. } 4043 | BitArrayOption::Utf32 { .. } 4044 | BitArrayOption::Utf8Codepoint { .. } 4045 | BitArrayOption::Utf16Codepoint { .. } 4046 | BitArrayOption::Utf32Codepoint { .. } => true, 4047 4048 BitArrayOption::Signed { .. } 4049 | BitArrayOption::Unsigned { .. } 4050 | BitArrayOption::Big { .. } 4051 | BitArrayOption::Little { .. } 4052 | BitArrayOption::Native { .. } 4053 | BitArrayOption::Size { .. } 4054 | BitArrayOption::Unit { .. } => false, 4055 } 4056 } 4057 4058 fn syntactically_eq(&self, other: &Self, compare_sizes: impl Fn(&A, &A) -> bool) -> bool { 4059 match (self, other) { 4060 (BitArrayOption::Bytes { .. }, BitArrayOption::Bytes { .. }) => true, 4061 (BitArrayOption::Bytes { .. }, _) => false, 4062 4063 (BitArrayOption::Int { .. }, BitArrayOption::Int { .. }) => true, 4064 (BitArrayOption::Int { .. }, _) => false, 4065 4066 (BitArrayOption::Float { .. }, BitArrayOption::Float { .. }) => true, 4067 (BitArrayOption::Float { .. }, _) => false, 4068 4069 (BitArrayOption::Bits { .. }, BitArrayOption::Bits { .. }) => true, 4070 (BitArrayOption::Bits { .. }, _) => false, 4071 4072 (BitArrayOption::Utf8 { .. }, BitArrayOption::Utf8 { .. }) => true, 4073 (BitArrayOption::Utf8 { .. }, _) => false, 4074 4075 (BitArrayOption::Utf16 { .. }, BitArrayOption::Utf16 { .. }) => true, 4076 (BitArrayOption::Utf16 { .. }, _) => false, 4077 4078 (BitArrayOption::Utf32 { .. }, BitArrayOption::Utf32 { .. }) => true, 4079 (BitArrayOption::Utf32 { .. }, _) => false, 4080 4081 (BitArrayOption::Utf8Codepoint { .. }, BitArrayOption::Utf8Codepoint { .. }) => true, 4082 (BitArrayOption::Utf8Codepoint { .. }, _) => false, 4083 4084 (BitArrayOption::Utf16Codepoint { .. }, BitArrayOption::Utf16Codepoint { .. }) => true, 4085 (BitArrayOption::Utf16Codepoint { .. }, _) => false, 4086 4087 (BitArrayOption::Utf32Codepoint { .. }, BitArrayOption::Utf32Codepoint { .. }) => true, 4088 (BitArrayOption::Utf32Codepoint { .. }, _) => false, 4089 4090 (BitArrayOption::Signed { .. }, BitArrayOption::Signed { .. }) => true, 4091 (BitArrayOption::Signed { .. }, _) => false, 4092 4093 (BitArrayOption::Unsigned { .. }, BitArrayOption::Unsigned { .. }) => true, 4094 (BitArrayOption::Unsigned { .. }, _) => false, 4095 4096 (BitArrayOption::Big { .. }, BitArrayOption::Big { .. }) => true, 4097 (BitArrayOption::Big { .. }, _) => false, 4098 4099 (BitArrayOption::Little { .. }, BitArrayOption::Little { .. }) => true, 4100 (BitArrayOption::Little { .. }, _) => false, 4101 4102 (BitArrayOption::Native { .. }, BitArrayOption::Native { .. }) => true, 4103 (BitArrayOption::Native { .. }, _) => false, 4104 4105 ( 4106 BitArrayOption::Unit { value, .. }, 4107 BitArrayOption::Unit { 4108 value: other_value, .. 4109 }, 4110 ) => value == other_value, 4111 (BitArrayOption::Unit { .. }, _) => false, 4112 4113 ( 4114 BitArrayOption::Size { 4115 value, short_form, .. 4116 }, 4117 BitArrayOption::Size { 4118 value: other_value, 4119 short_form: other_short_form, 4120 .. 4121 }, 4122 ) => short_form == other_short_form && compare_sizes(value, other_value), 4123 (BitArrayOption::Size { .. }, _) => false, 4124 } 4125 } 4126} 4127 4128impl BitArrayOption<TypedConstant> { 4129 fn referenced_variables(&self) -> im::HashSet<&EcoString> { 4130 match self { 4131 BitArrayOption::Bytes { .. } 4132 | BitArrayOption::Int { .. } 4133 | BitArrayOption::Float { .. } 4134 | BitArrayOption::Bits { .. } 4135 | BitArrayOption::Utf8 { .. } 4136 | BitArrayOption::Utf16 { .. } 4137 | BitArrayOption::Utf32 { .. } 4138 | BitArrayOption::Utf8Codepoint { .. } 4139 | BitArrayOption::Utf16Codepoint { .. } 4140 | BitArrayOption::Utf32Codepoint { .. } 4141 | BitArrayOption::Signed { .. } 4142 | BitArrayOption::Unsigned { .. } 4143 | BitArrayOption::Big { .. } 4144 | BitArrayOption::Little { .. } 4145 | BitArrayOption::Unit { .. } 4146 | BitArrayOption::Native { .. } => im::hashset![], 4147 4148 BitArrayOption::Size { value, .. } => value.referenced_variables(), 4149 } 4150 } 4151} 4152 4153impl BitArrayOption<TypedPattern> { 4154 pub fn find_node(&self, byte_index: u32) -> Option<Located<'_>> { 4155 match self { 4156 BitArrayOption::Bytes { .. } 4157 | BitArrayOption::Int { .. } 4158 | BitArrayOption::Float { .. } 4159 | BitArrayOption::Bits { .. } 4160 | BitArrayOption::Utf8 { .. } 4161 | BitArrayOption::Utf16 { .. } 4162 | BitArrayOption::Utf32 { .. } 4163 | BitArrayOption::Utf8Codepoint { .. } 4164 | BitArrayOption::Utf16Codepoint { .. } 4165 | BitArrayOption::Utf32Codepoint { .. } 4166 | BitArrayOption::Signed { .. } 4167 | BitArrayOption::Unsigned { .. } 4168 | BitArrayOption::Big { .. } 4169 | BitArrayOption::Little { .. } 4170 | BitArrayOption::Native { .. } 4171 | BitArrayOption::Unit { .. } => None, 4172 BitArrayOption::Size { value, .. } => value.find_node(byte_index), 4173 } 4174 } 4175} 4176 4177impl BitArrayOption<TypedConstant> { 4178 pub fn find_node(&self, byte_index: u32) -> Option<Located<'_>> { 4179 match self { 4180 BitArrayOption::Bytes { .. } 4181 | BitArrayOption::Int { .. } 4182 | BitArrayOption::Float { .. } 4183 | BitArrayOption::Bits { .. } 4184 | BitArrayOption::Utf8 { .. } 4185 | BitArrayOption::Utf16 { .. } 4186 | BitArrayOption::Utf32 { .. } 4187 | BitArrayOption::Utf8Codepoint { .. } 4188 | BitArrayOption::Utf16Codepoint { .. } 4189 | BitArrayOption::Utf32Codepoint { .. } 4190 | BitArrayOption::Signed { .. } 4191 | BitArrayOption::Unsigned { .. } 4192 | BitArrayOption::Big { .. } 4193 | BitArrayOption::Little { .. } 4194 | BitArrayOption::Native { .. } 4195 | BitArrayOption::Unit { .. } => None, 4196 BitArrayOption::Size { value, .. } => value.find_node(byte_index), 4197 } 4198 } 4199} 4200 4201#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)] 4202pub enum TodoKind { 4203 Keyword, 4204 EmptyFunction { function_location: SrcSpan }, 4205 IncompleteUse, 4206 EmptyBlock, 4207} 4208 4209#[derive(Debug, Default)] 4210pub struct GroupedDefinitions { 4211 pub functions: Vec<UntypedFunction>, 4212 pub constants: Vec<UntypedModuleConstant>, 4213 pub custom_types: Vec<UntypedCustomType>, 4214 pub imports: Vec<UntypedImport>, 4215 pub type_aliases: Vec<UntypedTypeAlias>, 4216} 4217 4218impl GroupedDefinitions { 4219 pub fn new(definitions: impl IntoIterator<Item = UntypedDefinition>) -> Self { 4220 let mut this = Self::default(); 4221 4222 for definition in definitions { 4223 this.add(definition) 4224 } 4225 4226 this 4227 } 4228 4229 pub fn len(&self) -> usize { 4230 let Self { 4231 custom_types, 4232 functions, 4233 constants, 4234 imports, 4235 type_aliases, 4236 } = self; 4237 functions.len() + constants.len() + imports.len() + custom_types.len() + type_aliases.len() 4238 } 4239 4240 fn add(&mut self, statement: UntypedDefinition) { 4241 match statement { 4242 Definition::Import(import) => self.imports.push(import), 4243 Definition::Function(function) => self.functions.push(function), 4244 Definition::TypeAlias(type_alias) => self.type_aliases.push(type_alias), 4245 Definition::CustomType(custom_type) => self.custom_types.push(custom_type), 4246 Definition::ModuleConstant(constant) => self.constants.push(constant), 4247 } 4248 } 4249} 4250 4251/// A statement with in a function body. 4252#[derive(Debug, Clone, PartialEq, Eq)] 4253pub enum Statement<TypeT, ExpressionT> { 4254 /// A bare expression that is not assigned to any variable. 4255 Expression(ExpressionT), 4256 /// Assigning an expression to variables using a pattern. 4257 Assignment(Box<Assignment<TypeT, ExpressionT>>), 4258 /// A `use` expression. 4259 Use(Use<TypeT, ExpressionT>), 4260 /// A bool assertion. 4261 Assert(Assert<ExpressionT>), 4262} 4263 4264pub type UntypedUse = Use<(), UntypedExpr>; 4265pub type TypedUse = Use<Arc<Type>, TypedExpr>; 4266 4267#[derive(Debug, Clone, PartialEq, Eq)] 4268pub struct Use<TypeT, ExpressionT> { 4269 /// In an untyped use this is the expression with the untyped code of the 4270 /// callback function. 4271 /// 4272 /// In a typed use this is the typed function call the use expression 4273 /// desugars to. 4274 /// 4275 pub call: Box<ExpressionT>, 4276 4277 /// This is the location of the whole use line, starting from the `use` 4278 /// keyword and ending with the function call on the right hand side of 4279 /// `<-`. 4280 /// 4281 /// ```gleam 4282 /// use a <- result.try(result) 4283 /// ^^^^^^^^^^^^^^^^^^^^^^^^^^^ 4284 /// ``` 4285 /// 4286 pub location: SrcSpan, 4287 4288 /// This is the location of the expression on the right hand side of the use 4289 /// arrow. 4290 /// 4291 /// ```gleam 4292 /// use a <- result.try(result) 4293 /// ^^^^^^^^^^^^^^^^^^ 4294 /// ``` 4295 /// 4296 pub right_hand_side_location: SrcSpan, 4297 4298 /// This is the SrcSpan of the patterns you find on the left hand side of 4299 /// `<-` in a use expression. 4300 /// 4301 /// ```gleam 4302 /// use pattern1, pattern2 <- todo 4303 /// ^^^^^^^^^^^^^^^^^^ 4304 /// ``` 4305 /// 4306 /// In case there's no patterns it will be corresponding to the SrcSpan of 4307 /// the `use` keyword itself. 4308 /// 4309 pub assignments_location: SrcSpan, 4310 4311 /// The patterns on the left hand side of `<-` in a use expression. 4312 /// 4313 pub assignments: Vec<UseAssignment<TypeT>>, 4314} 4315 4316pub type UntypedUseAssignment = UseAssignment<()>; 4317pub type TypedUseAssignment = UseAssignment<Arc<Type>>; 4318 4319#[derive(Debug, Clone, PartialEq, Eq)] 4320pub struct UseAssignment<TypeT> { 4321 pub location: SrcSpan, 4322 pub pattern: Pattern<TypeT>, 4323 pub annotation: Option<TypeAst>, 4324} 4325 4326impl TypedUse { 4327 pub fn find_node(&self, byte_index: u32) -> Option<Located<'_>> { 4328 for assignment in self.assignments.iter() { 4329 if let Some(found) = assignment.pattern.find_node(byte_index) { 4330 return Some(found); 4331 } 4332 if let Some(found) = assignment 4333 .annotation 4334 .as_ref() 4335 .and_then(|annotation| annotation.find_node(byte_index, assignment.pattern.type_())) 4336 { 4337 return Some(found); 4338 } 4339 } 4340 self.call.find_node(byte_index) 4341 } 4342 4343 pub fn callback_arguments(&self) -> Option<&Vec<TypedArg>> { 4344 let TypedExpr::Call { arguments, .. } = self.call.as_ref() else { 4345 return None; 4346 }; 4347 let callback = arguments.iter().last()?; 4348 let TypedExpr::Fn { arguments, .. } = &callback.value else { 4349 // The expression might be invalid so we have to return a None here 4350 return None; 4351 }; 4352 Some(arguments) 4353 } 4354} 4355 4356pub type TypedStatement = Statement<Arc<Type>, TypedExpr>; 4357pub type UntypedStatement = Statement<(), UntypedExpr>; 4358 4359impl<T, E> Statement<T, E> { 4360 /// Returns `true` if the statement is [`Expression`]. 4361 /// 4362 /// [`Expression`]: Statement::Expression 4363 #[must_use] 4364 pub fn is_expression(&self) -> bool { 4365 matches!(self, Self::Expression(..)) 4366 } 4367 4368 #[must_use] 4369 pub fn is_use(&self) -> bool { 4370 matches!(self, Self::Use(_)) 4371 } 4372} 4373 4374impl UntypedStatement { 4375 pub fn location(&self) -> SrcSpan { 4376 match self { 4377 Statement::Expression(expression) => expression.location(), 4378 Statement::Assignment(assignment) => assignment.location, 4379 Statement::Use(use_) => use_.location.merge(&use_.call.location()), 4380 Statement::Assert(assert) => assert.location, 4381 } 4382 } 4383 4384 pub fn start_byte_index(&self) -> u32 { 4385 match self { 4386 Statement::Expression(expression) => expression.start_byte_index(), 4387 Statement::Assignment(assignment) => assignment.location.start, 4388 Statement::Use(use_) => use_.location.start, 4389 Statement::Assert(assert) => assert.location.start, 4390 } 4391 } 4392} 4393 4394impl TypedStatement { 4395 pub fn is_println(&self) -> bool { 4396 match self { 4397 Statement::Expression(e) => e.is_println(), 4398 Statement::Assignment(_) => false, 4399 Statement::Use(_) => false, 4400 Statement::Assert(_) => false, 4401 } 4402 } 4403 4404 pub fn location(&self) -> SrcSpan { 4405 match self { 4406 Statement::Expression(expression) => expression.location(), 4407 Statement::Assignment(assignment) => assignment.location, 4408 // A use statement covers the entire block: `use_.location` covers 4409 // just the use's first line and not what comes after it. 4410 Statement::Use(use_) => use_.location.merge(&use_.call.location()), 4411 Statement::Assert(assert) => assert.location, 4412 } 4413 } 4414 4415 /// Returns the location of the last element of a statement. This means that 4416 /// if the statement is a use you'll get the location of the last item at 4417 /// the end of its block. 4418 pub fn last_location(&self) -> SrcSpan { 4419 match self { 4420 Statement::Expression(expression) => expression.last_location(), 4421 Statement::Assignment(assignment) => assignment.value.last_location(), 4422 Statement::Use(use_) => use_.call.last_location(), 4423 Statement::Assert(assert) => assert.value.last_location(), 4424 } 4425 } 4426 4427 pub fn type_(&self) -> Arc<Type> { 4428 match self { 4429 Statement::Expression(expression) => expression.type_(), 4430 Statement::Assignment(assignment) => assignment.type_(), 4431 Statement::Use(use_) => use_.call.type_(), 4432 Statement::Assert(_) => nil(), 4433 } 4434 } 4435 4436 pub fn definition_location(&self) -> Option<DefinitionLocation> { 4437 match self { 4438 Statement::Expression(expression) => expression.definition_location(), 4439 Statement::Assignment(_) => None, 4440 Statement::Use(use_) => use_.call.definition_location(), 4441 Statement::Assert(_) => None, 4442 } 4443 } 4444 4445 pub fn find_node(&self, byte_index: u32) -> Option<Located<'_>> { 4446 match self { 4447 Statement::Use(use_) => use_.find_node(byte_index), 4448 Statement::Expression(expression) => expression.find_node(byte_index), 4449 Statement::Assignment(assignment) => assignment.find_node(byte_index).or_else(|| { 4450 if assignment.location.contains(byte_index) { 4451 Some(Located::Statement(self)) 4452 } else { 4453 None 4454 } 4455 }), 4456 Statement::Assert(assert) => assert.find_node(byte_index).or_else(|| { 4457 if assert.location.contains(byte_index) { 4458 Some(Located::Statement(self)) 4459 } else { 4460 None 4461 } 4462 }), 4463 } 4464 } 4465 4466 pub fn find_statement(&self, byte_index: u32) -> Option<&TypedStatement> { 4467 match self { 4468 Statement::Use(use_) => use_.call.find_statement(byte_index), 4469 Statement::Expression(expression) => expression.find_statement(byte_index), 4470 Statement::Assignment(assignment) => { 4471 assignment.value.find_statement(byte_index).or_else(|| { 4472 if assignment.location.contains(byte_index) { 4473 Some(self) 4474 } else { 4475 None 4476 } 4477 }) 4478 } 4479 Statement::Assert(assert) => assert.value.find_statement(byte_index).or_else(|| { 4480 if assert.location.contains(byte_index) { 4481 Some(self) 4482 } else { 4483 None 4484 } 4485 }), 4486 } 4487 } 4488 4489 pub fn type_defining_location(&self) -> SrcSpan { 4490 match self { 4491 Statement::Expression(expression) => expression.type_defining_location(), 4492 Statement::Assignment(assignment) => assignment.location, 4493 Statement::Use(use_) => use_.location, 4494 Statement::Assert(assert) => assert.location, 4495 } 4496 } 4497 4498 fn is_pure_value_constructor(&self) -> bool { 4499 match self { 4500 Statement::Expression(expression) => expression.is_pure_value_constructor(), 4501 Statement::Assignment(assignment) => { 4502 // A let assert is not considered a pure value constructor 4503 // as it could crash the program! 4504 !assignment.kind.is_assert() && assignment.value.is_pure_value_constructor() 4505 } 4506 Statement::Use(Use { call, .. }) => call.is_pure_value_constructor(), 4507 // Assert statements by definition are not pure 4508 Statement::Assert(_) => false, 4509 } 4510 } 4511 4512 fn syntactically_eq(&self, other: &Self) -> bool { 4513 match (self, other) { 4514 (Statement::Expression(one), Statement::Expression(other)) => { 4515 one.syntactically_eq(other) 4516 } 4517 (Statement::Expression(_), _) => false, 4518 4519 (Statement::Assignment(one), Statement::Assignment(other)) => { 4520 one.pattern.syntactically_eq(&other.pattern) 4521 && one.value.syntactically_eq(&other.value) 4522 } 4523 (Statement::Assignment(_), _) => false, 4524 4525 (Statement::Use(one), Statement::Use(other)) => one.call.syntactically_eq(&other.call), 4526 (Statement::Use(_), _) => false, 4527 4528 (Statement::Assert(one), Statement::Assert(other)) => { 4529 let messages_are_equal = match (&one.message, &other.message) { 4530 (None, None) => true, 4531 (None, Some(_)) | (Some(_), None) => false, 4532 (Some(one), Some(other)) => one.syntactically_eq(other), 4533 }; 4534 messages_are_equal && one.value.syntactically_eq(&other.value) 4535 } 4536 (Statement::Assert(_), _) => false, 4537 } 4538 } 4539} 4540 4541#[derive(Debug, Clone, PartialEq, Eq)] 4542pub struct Assignment<TypeT, ExpressionT> { 4543 pub location: SrcSpan, 4544 pub value: ExpressionT, 4545 pub pattern: Pattern<TypeT>, 4546 pub kind: AssignmentKind<ExpressionT>, 4547 pub compiled_case: CompiledCase, 4548 /// This will be true for assignments that are automatically generated by 4549 /// the compiler. 4550 pub annotation: Option<TypeAst>, 4551} 4552 4553pub type TypedAssignment = Assignment<Arc<Type>, TypedExpr>; 4554pub type UntypedAssignment = Assignment<(), UntypedExpr>; 4555 4556impl TypedAssignment { 4557 pub fn find_node(&self, byte_index: u32) -> Option<Located<'_>> { 4558 if let Some(annotation) = &self.annotation 4559 && let Some(l) = annotation.find_node(byte_index, self.pattern.type_()) 4560 { 4561 return Some(l); 4562 } 4563 self.pattern 4564 .find_node(byte_index) 4565 .or_else(|| self.value.find_node(byte_index)) 4566 } 4567 4568 pub fn type_(&self) -> Arc<Type> { 4569 self.value.type_() 4570 } 4571} 4572 4573pub type TypedAssert = Assert<TypedExpr>; 4574pub type UntypedAssert = Assert<UntypedExpr>; 4575 4576#[derive(Debug, Clone, PartialEq, Eq)] 4577pub struct Assert<Expression> { 4578 pub location: SrcSpan, 4579 pub value: Expression, 4580 pub message: Option<Expression>, 4581} 4582 4583impl TypedAssert { 4584 pub fn find_node(&self, byte_index: u32) -> Option<Located<'_>> { 4585 if let Some(found) = self.value.find_node(byte_index) { 4586 return Some(found); 4587 } 4588 if let Some(message) = &self.message 4589 && let Some(found) = message.find_node(byte_index) 4590 { 4591 return Some(found); 4592 } 4593 None 4594 } 4595} 4596 4597/// A pipeline is desugared to a series of assignments: 4598/// 4599/// ```gleam 4600/// wibble |> wobble |> woo 4601/// ``` 4602/// 4603/// Becomes: 4604/// 4605/// ```erl 4606/// Pipe1 = wibble 4607/// Pipe2 = wobble(Pipe1) 4608/// woo(Pipe2) 4609/// ``` 4610/// 4611/// This represents one of such assignments once the pipeline has been desugared 4612/// and each step has been typed. 4613/// 4614/// > We're not using a more general `TypedAssignment` node since that has much 4615/// > more informations to carry around. This one is limited since we know it 4616/// > will always be in the form `VarName = <Expr>`, with no patterns on the 4617/// > left hand side of the assignment. 4618/// > Being more constrained simplifies code generation for pipelines! 4619/// 4620#[derive(Debug, Clone, PartialEq, Eq)] 4621pub struct TypedPipelineAssignment { 4622 /// This is the location of the corresponding pipeline step. 4623 /// 4624 /// Take this pipeline: 4625 /// 4626 /// ```gleam 4627 /// wibble |> wobble |> woo 4628 /// ``` 4629 /// 4630 /// It's made of two steps and a final expression: 4631 /// 4632 /// ```gleam 4633 /// let step_0 = wibble 4634 /// let step_1 = wobble(step_0) 4635 /// woo(step_1) 4636 /// ``` 4637 /// 4638 /// The locations of each step would be the following: 4639 /// 4640 /// ```gleam 4641 /// wibble |> wobble |> woo 4642 /// ^^^^^^ location of first step 4643 /// ^^^^^^ location of second step 4644 /// ``` 4645 /// 4646 pub location: SrcSpan, 4647 pub name: EcoString, 4648 pub value: Box<TypedExpr>, 4649} 4650 4651impl TypedPipelineAssignment { 4652 pub fn find_node(&self, byte_index: u32) -> Option<Located<'_>> { 4653 self.value.find_node(byte_index) 4654 } 4655 4656 pub fn find_statement(&self, byte_index: u32) -> Option<&TypedStatement> { 4657 self.value.find_statement(byte_index) 4658 } 4659 4660 pub fn type_(&self) -> Arc<Type> { 4661 self.value.type_() 4662 } 4663} 4664 4665/// The kind of desugaring that might take place when rewriting a pipeline to 4666/// regular assignments. 4667/// 4668#[derive(Debug, Clone, Copy, PartialEq, Eq)] 4669pub enum PipelineAssignmentKind { 4670 /// In case `a |> b(c)` is desugared to `b(a, c)`. 4671 FirstArgument { 4672 /// The location of the second argument of the call, in case there's any: 4673 /// - `a |> b(c, d)`: here it's `Some` wrapping the location of `c`. 4674 /// - `a |> b()`: here it's `None`. 4675 second_argument: Option<SrcSpan>, 4676 }, 4677 4678 /// In case there's an explicit hole and `a |> b(_, c)` is desugared to 4679 /// `b(a, c)`. 4680 Hole { hole: SrcSpan }, 4681 4682 /// In case `a |> b(c)` is desugared to `b(c)(a)` 4683 FunctionCall, 4684 4685 /// In case there's an echo in the middle of a pipeline `a |> echo` 4686 Echo, 4687}