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