Fork of daniellemaywood.uk/gleam — Wasm codegen work
2

Configure Feed

Select the types of activity you want to include in your feed.

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