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