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