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
107 kB 3458 lines
1mod constant; 2mod typed; 3mod untyped; 4 5#[cfg(test)] 6mod tests; 7pub mod visit; 8 9pub use self::typed::TypedExpr; 10pub use self::untyped::{FunctionLiteralKind, UntypedExpr}; 11 12pub use self::constant::{Constant, TypedConstant, UntypedConstant}; 13 14use crate::analyse::Inferred; 15use crate::bit_array; 16use crate::build::{ExpressionPosition, Located, Target, module_erlang_name}; 17use crate::exhaustiveness::CompiledCase; 18use crate::parse::SpannedString; 19use crate::type_::error::VariableOrigin; 20use crate::type_::expression::{Implementations, Purity}; 21use crate::type_::printer::Names; 22use crate::type_::{ 23 self, Deprecation, HasType, ModuleValueConstructor, PatternConstructor, Type, TypedCallArg, 24 ValueConstructor, nil, 25}; 26use num_traits::Zero; 27use std::collections::HashSet; 28use std::sync::Arc; 29 30use ecow::EcoString; 31use num_bigint::{BigInt, Sign}; 32use num_traits::{One, ToPrimitive}; 33#[cfg(test)] 34use pretty_assertions::assert_eq; 35use vec1::Vec1; 36 37pub const PIPE_VARIABLE: &str = "_pipe"; 38pub const USE_ASSIGNMENT_VARIABLE: &str = "_use"; 39pub const RECORD_UPDATE_VARIABLE: &str = "_record"; 40pub const ASSERT_FAIL_VARIABLE: &str = "_assert_fail"; 41pub const ASSERT_SUBJECT_VARIABLE: &str = "_assert_subject"; 42pub const CAPTURE_VARIABLE: &str = "_capture"; 43pub const BLOCK_VARIABLE: &str = "_block"; 44 45pub trait HasLocation { 46 fn location(&self) -> SrcSpan; 47} 48 49pub type TypedModule = Module<type_::ModuleInterface, TypedDefinition>; 50 51pub type UntypedModule = Module<(), TargetedDefinition>; 52 53#[derive(Debug, Clone, PartialEq, Eq)] 54pub struct Module<Info, Definitions> { 55 pub name: EcoString, 56 pub documentation: Vec<EcoString>, 57 pub type_info: Info, 58 pub definitions: Vec<Definitions>, 59 pub names: Names, 60 /// The source byte locations of definition that are unused. 61 /// This is used in code generation to know when definitions can be safely omitted. 62 pub unused_definition_positions: HashSet<u32>, 63} 64 65impl<Info, Definitions> Module<Info, Definitions> { 66 pub fn erlang_name(&self) -> EcoString { 67 module_erlang_name(&self.name) 68 } 69} 70 71impl TypedModule { 72 pub fn find_node(&self, byte_index: u32) -> Option<Located<'_>> { 73 self.definitions 74 .iter() 75 .find_map(|definition| definition.find_node(byte_index)) 76 } 77 78 pub fn find_statement(&self, byte_index: u32) -> Option<&TypedStatement> { 79 self.definitions 80 .iter() 81 .find_map(|definition| definition.find_statement(byte_index)) 82 } 83} 84 85/// The `@target(erlang)` and `@target(javascript)` attributes can be used to 86/// mark a definition as only being for a specific target. 87/// 88/// ```gleam 89/// const x: Int = 1 90/// 91/// @target(erlang) 92/// pub fn main(a) { ...} 93/// ``` 94/// 95#[derive(Debug, Clone, PartialEq, Eq)] 96pub struct TargetedDefinition { 97 pub definition: UntypedDefinition, 98 pub target: Option<Target>, 99} 100 101impl TargetedDefinition { 102 pub fn is_for(&self, target: Target) -> bool { 103 self.target.map(|t| t == target).unwrap_or(true) 104 } 105} 106 107impl UntypedModule { 108 pub fn dependencies(&self, target: Target) -> Vec<(EcoString, SrcSpan)> { 109 self.iter_definitions(target) 110 .flat_map(|definition| match definition { 111 Definition::Import(Import { 112 module, location, .. 113 }) => Some((module.clone(), *location)), 114 _ => None, 115 }) 116 .collect() 117 } 118 119 pub fn iter_definitions(&self, target: Target) -> impl Iterator<Item = &UntypedDefinition> { 120 self.definitions 121 .iter() 122 .filter(move |definition| definition.is_for(target)) 123 .map(|definition| &definition.definition) 124 } 125 126 pub fn into_iter_definitions(self, target: Target) -> impl Iterator<Item = UntypedDefinition> { 127 self.definitions 128 .into_iter() 129 .filter(move |definition| definition.is_for(target)) 130 .map(|definition| definition.definition) 131 } 132} 133 134#[test] 135fn module_dependencies_test() { 136 let parsed = crate::parse::parse_module( 137 camino::Utf8PathBuf::from("test/path"), 138 "import one 139 @target(erlang) 140 import two 141 142 @target(javascript) 143 import three 144 145 import four", 146 &crate::warning::WarningEmitter::null(), 147 ) 148 .expect("syntax error"); 149 let module = parsed.module; 150 151 assert_eq!( 152 vec![ 153 ("one".into(), SrcSpan::new(0, 10)), 154 ("two".into(), SrcSpan::new(45, 55)), 155 ("four".into(), SrcSpan::new(118, 129)), 156 ], 157 module.dependencies(Target::Erlang) 158 ); 159} 160 161pub type TypedArg = Arg<Arc<Type>>; 162pub type UntypedArg = Arg<()>; 163 164#[derive(Debug, Clone, PartialEq, Eq)] 165pub struct Arg<T> { 166 pub names: ArgNames, 167 pub location: SrcSpan, 168 pub annotation: Option<TypeAst>, 169 pub type_: T, 170} 171 172impl<A> Arg<A> { 173 pub fn set_type<B>(self, t: B) -> Arg<B> { 174 Arg { 175 type_: t, 176 names: self.names, 177 location: self.location, 178 annotation: self.annotation, 179 } 180 } 181 182 pub fn get_variable_name(&self) -> Option<&EcoString> { 183 self.names.get_variable_name() 184 } 185 186 pub fn is_capture_hole(&self) -> bool { 187 match &self.names { 188 ArgNames::Named { name, .. } if name == CAPTURE_VARIABLE => true, 189 _ => false, 190 } 191 } 192} 193 194impl TypedArg { 195 pub fn find_node(&self, byte_index: u32) -> Option<Located<'_>> { 196 if self.location.contains(byte_index) { 197 if let Some(annotation) = &self.annotation { 198 return annotation 199 .find_node(byte_index, self.type_.clone()) 200 .or(Some(Located::Arg(self))); 201 } 202 Some(Located::Arg(self)) 203 } else { 204 None 205 } 206 } 207} 208 209#[derive(Debug, Clone, PartialEq, Eq)] 210pub enum ArgNames { 211 Discard { 212 name: EcoString, 213 location: SrcSpan, 214 }, 215 LabelledDiscard { 216 label: EcoString, 217 label_location: SrcSpan, 218 name: EcoString, 219 name_location: SrcSpan, 220 }, 221 Named { 222 name: EcoString, 223 location: SrcSpan, 224 }, 225 NamedLabelled { 226 label: EcoString, 227 label_location: SrcSpan, 228 name: EcoString, 229 name_location: SrcSpan, 230 }, 231} 232 233impl ArgNames { 234 pub fn get_label(&self) -> Option<&EcoString> { 235 match self { 236 ArgNames::Discard { .. } | ArgNames::Named { .. } => None, 237 ArgNames::LabelledDiscard { label, .. } | ArgNames::NamedLabelled { label, .. } => { 238 Some(label) 239 } 240 } 241 } 242 pub fn get_variable_name(&self) -> Option<&EcoString> { 243 match self { 244 ArgNames::Discard { .. } | ArgNames::LabelledDiscard { .. } => None, 245 ArgNames::NamedLabelled { name, .. } | ArgNames::Named { name, .. } => Some(name), 246 } 247 } 248} 249 250pub type TypedRecordConstructor = RecordConstructor<Arc<Type>>; 251 252#[derive(Debug, Clone, PartialEq, Eq)] 253pub struct RecordConstructor<T> { 254 pub location: SrcSpan, 255 pub name_location: SrcSpan, 256 pub name: EcoString, 257 pub arguments: Vec<RecordConstructorArg<T>>, 258 pub documentation: Option<(u32, EcoString)>, 259 pub deprecation: Deprecation, 260} 261 262impl<A> RecordConstructor<A> { 263 pub fn put_doc(&mut self, new_doc: (u32, EcoString)) { 264 self.documentation = Some(new_doc); 265 } 266} 267 268pub type TypedRecordConstructorArg = RecordConstructorArg<Arc<Type>>; 269 270#[derive(Debug, Clone, PartialEq, Eq)] 271pub struct RecordConstructorArg<T> { 272 pub label: Option<SpannedString>, 273 pub ast: TypeAst, 274 pub location: SrcSpan, 275 pub type_: T, 276 pub doc: Option<(u32, EcoString)>, 277} 278 279impl<T: PartialEq> RecordConstructorArg<T> { 280 pub fn put_doc(&mut self, new_doc: (u32, EcoString)) { 281 self.doc = Some(new_doc); 282 } 283} 284 285#[derive(Debug, Clone, PartialEq, Eq)] 286pub struct TypeAstConstructor { 287 pub location: SrcSpan, 288 pub name_location: SrcSpan, 289 pub module: Option<(EcoString, SrcSpan)>, 290 pub name: EcoString, 291 pub arguments: Vec<TypeAst>, 292} 293 294#[derive(Debug, Clone, PartialEq, Eq)] 295pub struct TypeAstFn { 296 pub location: SrcSpan, 297 pub arguments: Vec<TypeAst>, 298 pub return_: Box<TypeAst>, 299} 300 301#[derive(Debug, Clone, PartialEq, Eq)] 302pub struct TypeAstVar { 303 pub location: SrcSpan, 304 pub name: EcoString, 305} 306 307#[derive(Debug, Clone, PartialEq, Eq)] 308pub struct TypeAstTuple { 309 pub location: SrcSpan, 310 pub elements: Vec<TypeAst>, 311} 312 313#[derive(Debug, Clone, PartialEq, Eq)] 314pub struct TypeAstHole { 315 pub location: SrcSpan, 316 pub name: EcoString, 317} 318 319#[derive(Debug, Clone, PartialEq, Eq)] 320pub enum TypeAst { 321 Constructor(TypeAstConstructor), 322 Fn(TypeAstFn), 323 Var(TypeAstVar), 324 Tuple(TypeAstTuple), 325 Hole(TypeAstHole), 326} 327 328impl TypeAst { 329 pub fn location(&self) -> SrcSpan { 330 match self { 331 TypeAst::Fn(TypeAstFn { location, .. }) 332 | TypeAst::Var(TypeAstVar { location, .. }) 333 | TypeAst::Hole(TypeAstHole { location, .. }) 334 | TypeAst::Tuple(TypeAstTuple { location, .. }) 335 | TypeAst::Constructor(TypeAstConstructor { location, .. }) => *location, 336 } 337 } 338 339 pub fn is_logically_equal(&self, other: &TypeAst) -> bool { 340 match self { 341 TypeAst::Constructor(TypeAstConstructor { 342 module, 343 name, 344 arguments, 345 location: _, 346 name_location: _, 347 }) => match other { 348 TypeAst::Constructor(TypeAstConstructor { 349 module: o_module, 350 name: o_name, 351 arguments: o_arguments, 352 location: _, 353 name_location: _, 354 }) => { 355 let module_name = 356 |m: &Option<(EcoString, _)>| m.as_ref().map(|(m, _)| m.clone()); 357 module_name(module) == module_name(o_module) 358 && name == o_name 359 && arguments.len() == o_arguments.len() 360 && arguments 361 .iter() 362 .zip(o_arguments) 363 .all(|a| a.0.is_logically_equal(a.1)) 364 } 365 _ => false, 366 }, 367 TypeAst::Fn(TypeAstFn { 368 arguments, 369 return_, 370 location: _, 371 }) => match other { 372 TypeAst::Fn(TypeAstFn { 373 arguments: o_arguments, 374 return_: o_return_, 375 location: _, 376 }) => { 377 arguments.len() == o_arguments.len() 378 && arguments 379 .iter() 380 .zip(o_arguments) 381 .all(|a| a.0.is_logically_equal(a.1)) 382 && return_.is_logically_equal(o_return_) 383 } 384 _ => false, 385 }, 386 TypeAst::Var(TypeAstVar { name, location: _ }) => match other { 387 TypeAst::Var(TypeAstVar { 388 name: o_name, 389 location: _, 390 }) => name == o_name, 391 _ => false, 392 }, 393 TypeAst::Tuple(TypeAstTuple { 394 elements, 395 location: _, 396 }) => match other { 397 TypeAst::Tuple(TypeAstTuple { 398 elements: other_elements, 399 location: _, 400 }) => { 401 elements.len() == other_elements.len() 402 && elements 403 .iter() 404 .zip(other_elements) 405 .all(|a| a.0.is_logically_equal(a.1)) 406 } 407 _ => false, 408 }, 409 TypeAst::Hole(TypeAstHole { name, location: _ }) => match other { 410 TypeAst::Hole(TypeAstHole { 411 name: o_name, 412 location: _, 413 }) => name == o_name, 414 _ => false, 415 }, 416 } 417 } 418 419 pub fn find_node(&self, byte_index: u32, type_: Arc<Type>) -> Option<Located<'_>> { 420 if !self.location().contains(byte_index) { 421 return None; 422 } 423 424 match self { 425 TypeAst::Fn(TypeAstFn { 426 arguments, return_, .. 427 }) => type_ 428 .fn_types() 429 .and_then(|(arg_types, ret_type)| { 430 if let Some(arg) = arguments 431 .iter() 432 .zip(arg_types) 433 .find_map(|(arg, arg_type)| arg.find_node(byte_index, arg_type.clone())) 434 { 435 return Some(arg); 436 } 437 if let Some(ret) = return_.find_node(byte_index, ret_type) { 438 return Some(ret); 439 } 440 441 None 442 }) 443 .or(Some(Located::Annotation { ast: self, type_ })), 444 TypeAst::Constructor(TypeAstConstructor { 445 arguments, module, .. 446 }) => type_ 447 .constructor_types() 448 .and_then(|arg_types| { 449 if let Some(arg) = arguments 450 .iter() 451 .zip(arg_types) 452 .find_map(|(arg, arg_type)| arg.find_node(byte_index, arg_type.clone())) 453 { 454 return Some(arg); 455 } 456 457 None 458 }) 459 .or(module.as_ref().and_then(|(name, location)| { 460 if location.contains(byte_index) { 461 Some(Located::ModuleName { 462 location: *location, 463 name, 464 layer: Layer::Type, 465 }) 466 } else { 467 None 468 } 469 })) 470 .or(Some(Located::Annotation { ast: self, type_ })), 471 TypeAst::Tuple(TypeAstTuple { elements, .. }) => type_ 472 .tuple_types() 473 .and_then(|elem_types| { 474 if let Some(e) = elements 475 .iter() 476 .zip(elem_types) 477 .find_map(|(e, e_type)| e.find_node(byte_index, e_type.clone())) 478 { 479 return Some(e); 480 } 481 482 None 483 }) 484 .or(Some(Located::Annotation { ast: self, type_ })), 485 TypeAst::Var(_) | TypeAst::Hole(_) => Some(Located::Annotation { ast: self, type_ }), 486 } 487 } 488 489 /// Generates an annotation corresponding to the type. 490 pub fn print(&self, buffer: &mut EcoString) { 491 match &self { 492 TypeAst::Var(var) => buffer.push_str(&var.name), 493 TypeAst::Hole(hole) => buffer.push_str(&hole.name), 494 TypeAst::Tuple(tuple) => { 495 buffer.push_str("#("); 496 for (i, element) in tuple.elements.iter().enumerate() { 497 element.print(buffer); 498 if i < tuple.elements.len() - 1 { 499 buffer.push_str(", "); 500 } 501 } 502 buffer.push(')') 503 } 504 TypeAst::Fn(func) => { 505 buffer.push_str("fn("); 506 for (i, argument) in func.arguments.iter().enumerate() { 507 argument.print(buffer); 508 if i < func.arguments.len() - 1 { 509 buffer.push_str(", "); 510 } 511 } 512 buffer.push(')'); 513 buffer.push_str(" -> "); 514 func.return_.print(buffer); 515 } 516 TypeAst::Constructor(constructor) => { 517 if let Some((module, _)) = &constructor.module { 518 buffer.push_str(module); 519 buffer.push('.'); 520 } 521 buffer.push_str(&constructor.name); 522 if !constructor.arguments.is_empty() { 523 buffer.push('('); 524 for (i, argument) in constructor.arguments.iter().enumerate() { 525 argument.print(buffer); 526 if i < constructor.arguments.len() - 1 { 527 buffer.push_str(", "); 528 } 529 } 530 buffer.push(')'); 531 } 532 } 533 } 534 } 535} 536 537#[test] 538fn type_ast_print_fn() { 539 let mut buffer = EcoString::new(); 540 let ast = TypeAst::Fn(TypeAstFn { 541 location: SrcSpan { start: 1, end: 1 }, 542 arguments: vec![ 543 TypeAst::Var(TypeAstVar { 544 location: SrcSpan { start: 1, end: 1 }, 545 name: "String".into(), 546 }), 547 TypeAst::Var(TypeAstVar { 548 location: SrcSpan { start: 1, end: 1 }, 549 name: "Bool".into(), 550 }), 551 ], 552 return_: Box::new(TypeAst::Var(TypeAstVar { 553 location: SrcSpan { start: 1, end: 1 }, 554 name: "Int".into(), 555 })), 556 }); 557 ast.print(&mut buffer); 558 assert_eq!(&buffer, "fn(String, Bool) -> Int") 559} 560 561#[test] 562fn type_ast_print_constructor() { 563 let mut buffer = EcoString::new(); 564 let ast = TypeAst::Constructor(TypeAstConstructor { 565 name: "SomeType".into(), 566 module: Some(("some_module".into(), SrcSpan { start: 1, end: 1 })), 567 location: SrcSpan { start: 1, end: 1 }, 568 name_location: SrcSpan { start: 1, end: 1 }, 569 arguments: vec![ 570 TypeAst::Var(TypeAstVar { 571 location: SrcSpan { start: 1, end: 1 }, 572 name: "String".into(), 573 }), 574 TypeAst::Var(TypeAstVar { 575 location: SrcSpan { start: 1, end: 1 }, 576 name: "Bool".into(), 577 }), 578 ], 579 }); 580 ast.print(&mut buffer); 581 assert_eq!(&buffer, "some_module.SomeType(String, Bool)") 582} 583 584#[test] 585fn type_ast_print_tuple() { 586 let mut buffer = EcoString::new(); 587 let ast = TypeAst::Tuple(TypeAstTuple { 588 location: SrcSpan { start: 1, end: 1 }, 589 elements: vec![ 590 TypeAst::Constructor(TypeAstConstructor { 591 name: "SomeType".into(), 592 module: Some(("some_module".into(), SrcSpan { start: 1, end: 1 })), 593 location: SrcSpan { start: 1, end: 1 }, 594 name_location: SrcSpan { start: 1, end: 1 }, 595 arguments: vec![ 596 TypeAst::Var(TypeAstVar { 597 location: SrcSpan { start: 1, end: 1 }, 598 name: "String".into(), 599 }), 600 TypeAst::Var(TypeAstVar { 601 location: SrcSpan { start: 1, end: 1 }, 602 name: "Bool".into(), 603 }), 604 ], 605 }), 606 TypeAst::Fn(TypeAstFn { 607 location: SrcSpan { start: 1, end: 1 }, 608 arguments: vec![ 609 TypeAst::Var(TypeAstVar { 610 location: SrcSpan { start: 1, end: 1 }, 611 name: "String".into(), 612 }), 613 TypeAst::Var(TypeAstVar { 614 location: SrcSpan { start: 1, end: 1 }, 615 name: "Bool".into(), 616 }), 617 ], 618 return_: Box::new(TypeAst::Var(TypeAstVar { 619 location: SrcSpan { start: 1, end: 1 }, 620 name: "Int".into(), 621 })), 622 }), 623 ], 624 }); 625 ast.print(&mut buffer); 626 assert_eq!( 627 &buffer, 628 "#(some_module.SomeType(String, Bool), fn(String, Bool) -> Int)" 629 ) 630} 631 632#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)] 633pub enum Publicity { 634 Public, 635 Private, 636 Internal { attribute_location: Option<SrcSpan> }, 637} 638 639impl Publicity { 640 pub fn is_private(&self) -> bool { 641 match self { 642 Self::Private => true, 643 Self::Public | Self::Internal { .. } => false, 644 } 645 } 646 647 pub fn is_internal(&self) -> bool { 648 match self { 649 Self::Internal { .. } => true, 650 Self::Public | Self::Private => false, 651 } 652 } 653 654 pub fn is_public(&self) -> bool { 655 match self { 656 Self::Public => true, 657 Self::Internal { .. } | Self::Private => false, 658 } 659 } 660 661 pub fn is_importable(&self) -> bool { 662 match self { 663 Self::Internal { .. } | Self::Public => true, 664 Self::Private => false, 665 } 666 } 667} 668 669#[derive(Debug, Clone, PartialEq, Eq)] 670/// A function definition 671/// 672/// Note that an anonymous function will have `None` as the name field, while a 673/// named function will have `Some`. 674/// 675/// # Example(s) 676/// 677/// ```gleam 678/// // Public function 679/// pub fn wobble() -> String { ... } 680/// // Private function 681/// fn wibble(x: Int) -> Int { ... } 682/// // Anonymous function 683/// fn(x: Int) { ... } 684/// ``` 685pub struct Function<T, Expr> { 686 pub location: SrcSpan, 687 pub end_position: u32, 688 pub name: Option<SpannedString>, 689 pub arguments: Vec<Arg<T>>, 690 pub body: Vec1<Statement<T, Expr>>, 691 pub publicity: Publicity, 692 pub deprecation: Deprecation, 693 pub return_annotation: Option<TypeAst>, 694 pub return_type: T, 695 pub documentation: Option<(u32, EcoString)>, 696 pub external_erlang: Option<(EcoString, EcoString, SrcSpan)>, 697 pub external_javascript: Option<(EcoString, EcoString, SrcSpan)>, 698 pub implementations: Implementations, 699 pub purity: Purity, 700} 701 702pub type TypedFunction = Function<Arc<Type>, TypedExpr>; 703pub type UntypedFunction = Function<(), UntypedExpr>; 704 705impl<T, E> Function<T, E> { 706 pub fn full_location(&self) -> SrcSpan { 707 SrcSpan::new(self.location.start, self.end_position) 708 } 709} 710 711pub type UntypedImport = Import<()>; 712 713#[derive(Debug, Clone, PartialEq, Eq)] 714/// Import another Gleam module so the current module can use the types and 715/// values it defines. 716/// 717/// # Example(s) 718/// 719/// ```gleam 720/// import unix/cat 721/// // Import with alias 722/// import animal/cat as kitty 723/// ``` 724pub struct Import<PackageName> { 725 pub documentation: Option<EcoString>, 726 pub location: SrcSpan, 727 pub module: EcoString, 728 pub as_name: Option<(AssignName, SrcSpan)>, 729 pub unqualified_values: Vec<UnqualifiedImport>, 730 pub unqualified_types: Vec<UnqualifiedImport>, 731 pub package: PackageName, 732} 733 734impl<T> Import<T> { 735 pub(crate) fn used_name(&self) -> Option<EcoString> { 736 match self.as_name.as_ref() { 737 Some((AssignName::Variable(name), _)) => Some(name.clone()), 738 Some((AssignName::Discard(_), _)) => None, 739 None => self.module.split('/').next_back().map(EcoString::from), 740 } 741 } 742 743 pub(crate) fn alias_location(&self) -> Option<SrcSpan> { 744 self.as_name.as_ref().map(|(_, location)| *location) 745 } 746} 747 748pub type UntypedModuleConstant = ModuleConstant<(), ()>; 749pub type TypedModuleConstant = ModuleConstant<Arc<Type>, EcoString>; 750 751#[derive(Debug, Clone, PartialEq, Eq)] 752/// A certain fixed value that can be used in multiple places 753/// 754/// # Example(s) 755/// 756/// ```gleam 757/// pub const start_year = 2101 758/// pub const end_year = 2111 759/// ``` 760pub struct ModuleConstant<T, ConstantRecordTag> { 761 pub documentation: Option<(u32, EcoString)>, 762 /// The location of the constant, starting at the "(pub) const" keywords and 763 /// ending after the ": Type" annotation, or (without an annotation) after its name. 764 pub location: SrcSpan, 765 pub publicity: Publicity, 766 pub name: EcoString, 767 pub name_location: SrcSpan, 768 pub annotation: Option<TypeAst>, 769 pub value: Box<Constant<T, ConstantRecordTag>>, 770 pub type_: T, 771 pub deprecation: Deprecation, 772 pub implementations: Implementations, 773} 774 775pub type UntypedCustomType = CustomType<()>; 776pub type TypedCustomType = CustomType<Arc<Type>>; 777 778#[derive(Debug, Clone, PartialEq, Eq)] 779/// A newly defined type with one or more constructors. 780/// Each variant of the custom type can contain different types, so the type is 781/// the product of the types contained by each variant. 782/// 783/// This might be called an algebraic data type (ADT) or tagged union in other 784/// languages and type systems. 785/// 786/// 787/// # Example(s) 788/// 789/// ```gleam 790/// pub type Cat { 791/// Cat(name: String, cuteness: Int) 792/// } 793/// ``` 794pub struct CustomType<T> { 795 pub location: SrcSpan, 796 pub end_position: u32, 797 pub name: EcoString, 798 pub name_location: SrcSpan, 799 pub publicity: Publicity, 800 pub constructors: Vec<RecordConstructor<T>>, 801 pub documentation: Option<(u32, EcoString)>, 802 pub deprecation: Deprecation, 803 pub opaque: bool, 804 /// The names of the type parameters. 805 pub parameters: Vec<SpannedString>, 806 /// Once type checked this field will contain the type information for the 807 /// type parameters. 808 pub typed_parameters: Vec<T>, 809} 810 811impl<T> CustomType<T> { 812 /// The `location` field of a `CustomType` is only the location of `pub type 813 /// TheName`. This method returns a `SrcSpan` that includes the entire type 814 /// definition. 815 pub fn full_location(&self) -> SrcSpan { 816 SrcSpan::new(self.location.start, self.end_position) 817 } 818} 819 820pub type UntypedTypeAlias = TypeAlias<()>; 821 822#[derive(Debug, Clone, PartialEq, Eq)] 823/// A new name for an existing type 824/// 825/// # Example(s) 826/// 827/// ```gleam 828/// pub type Headers = 829/// List(#(String, String)) 830/// ``` 831pub struct TypeAlias<T> { 832 pub location: SrcSpan, 833 pub alias: EcoString, 834 pub name_location: SrcSpan, 835 pub parameters: Vec<SpannedString>, 836 pub type_ast: TypeAst, 837 pub type_: T, 838 pub publicity: Publicity, 839 pub documentation: Option<(u32, EcoString)>, 840 pub deprecation: Deprecation, 841} 842 843pub type TypedDefinition = Definition<Arc<Type>, TypedExpr, EcoString, EcoString>; 844pub type UntypedDefinition = Definition<(), UntypedExpr, (), ()>; 845 846#[derive(Debug, Clone, PartialEq, Eq)] 847pub enum Definition<T, Expr, ConstantRecordTag, PackageName> { 848 Function(Function<T, Expr>), 849 850 TypeAlias(TypeAlias<T>), 851 852 CustomType(CustomType<T>), 853 854 Import(Import<PackageName>), 855 856 ModuleConstant(ModuleConstant<T, ConstantRecordTag>), 857} 858 859impl TypedDefinition { 860 pub fn main_function(&self) -> Option<&TypedFunction> { 861 match self { 862 Definition::Function(f) if f.name.as_ref().is_some_and(|(_, name)| name == "main") => { 863 Some(f) 864 } 865 _ => None, 866 } 867 } 868 869 pub fn find_node(&self, byte_index: u32) -> Option<Located<'_>> { 870 match self { 871 Definition::Function(function) => { 872 // Search for the corresponding node inside the function 873 // only if the index falls within the function's full location. 874 if !function.full_location().contains(byte_index) { 875 return None; 876 } 877 878 if let Some(found) = function.body.iter().find_map(|s| s.find_node(byte_index)) { 879 return Some(found); 880 } 881 882 if let Some(found_arg) = function 883 .arguments 884 .iter() 885 .find_map(|arg| arg.find_node(byte_index)) 886 { 887 return Some(found_arg); 888 }; 889 890 if let Some(found_statement) = function 891 .body 892 .iter() 893 .find(|statement| statement.location().contains(byte_index)) 894 { 895 return Some(Located::Statement(found_statement)); 896 }; 897 898 // Check if location is within the return annotation. 899 if let Some(l) = function 900 .return_annotation 901 .iter() 902 .find_map(|a| a.find_node(byte_index, function.return_type.clone())) 903 { 904 return Some(l); 905 }; 906 907 // Note that the fn `.location` covers the function head, not 908 // the entire statement. 909 if function.location.contains(byte_index) { 910 Some(Located::ModuleStatement(self)) 911 } else if function.full_location().contains(byte_index) { 912 Some(Located::FunctionBody(function)) 913 } else { 914 None 915 } 916 } 917 918 Definition::CustomType(custom) => { 919 // Check if location is within the type of one of the arguments of a constructor. 920 if let Some(constructor) = custom 921 .constructors 922 .iter() 923 .find(|constructor| constructor.location.contains(byte_index)) 924 { 925 if let Some(annotation) = constructor 926 .arguments 927 .iter() 928 .find(|arg| arg.location.contains(byte_index)) 929 .and_then(|arg| arg.ast.find_node(byte_index, arg.type_.clone())) 930 { 931 return Some(annotation); 932 } 933 934 return Some(Located::VariantConstructorDefinition(constructor)); 935 } 936 937 // Note that the custom type `.location` covers the function 938 // head, not the entire statement. 939 if custom.full_location().contains(byte_index) { 940 Some(Located::ModuleStatement(self)) 941 } else { 942 None 943 } 944 } 945 946 Definition::TypeAlias(alias) => { 947 // Check if location is within the type being aliased. 948 if let Some(l) = alias.type_ast.find_node(byte_index, alias.type_.clone()) { 949 return Some(l); 950 } 951 952 if alias.location.contains(byte_index) { 953 Some(Located::ModuleStatement(self)) 954 } else { 955 None 956 } 957 } 958 959 Definition::ModuleConstant(constant) => { 960 // Check if location is within the annotation. 961 if let Some(annotation) = &constant.annotation { 962 if let Some(l) = annotation.find_node(byte_index, constant.type_.clone()) { 963 return Some(l); 964 } 965 } 966 967 if let Some(located) = constant.value.find_node(byte_index) { 968 return Some(located); 969 } 970 971 if constant.location.contains(byte_index) { 972 Some(Located::ModuleStatement(self)) 973 } else { 974 None 975 } 976 } 977 978 Definition::Import(import) => { 979 if self.location().contains(byte_index) { 980 if let Some(unqualified) = import 981 .unqualified_values 982 .iter() 983 .find(|i| i.location.contains(byte_index)) 984 { 985 return Some(Located::UnqualifiedImport( 986 crate::build::UnqualifiedImport { 987 name: &unqualified.name, 988 module: &import.module, 989 is_type: false, 990 location: &unqualified.location, 991 }, 992 )); 993 } 994 995 if let Some(unqualified) = import 996 .unqualified_types 997 .iter() 998 .find(|i| i.location.contains(byte_index)) 999 { 1000 return Some(Located::UnqualifiedImport( 1001 crate::build::UnqualifiedImport { 1002 name: &unqualified.name, 1003 module: &import.module, 1004 is_type: true, 1005 location: &unqualified.location, 1006 }, 1007 )); 1008 } 1009 1010 Some(Located::ModuleStatement(self)) 1011 } else { 1012 None 1013 } 1014 } 1015 } 1016 } 1017 1018 pub fn find_statement(&self, byte_index: u32) -> Option<&TypedStatement> { 1019 match self { 1020 Definition::Function(function) => { 1021 if !function.full_location().contains(byte_index) { 1022 return None; 1023 } 1024 1025 function 1026 .body 1027 .iter() 1028 .find_map(|statement| statement.find_statement(byte_index)) 1029 } 1030 1031 _ => None, 1032 } 1033 } 1034} 1035 1036impl<A, B, C, E> Definition<A, B, C, E> { 1037 pub fn location(&self) -> SrcSpan { 1038 match self { 1039 Definition::Function(Function { location, .. }) 1040 | Definition::Import(Import { location, .. }) 1041 | Definition::TypeAlias(TypeAlias { location, .. }) 1042 | Definition::CustomType(CustomType { location, .. }) 1043 | Definition::ModuleConstant(ModuleConstant { location, .. }) => *location, 1044 } 1045 } 1046 1047 /// Returns `true` if the definition is [`Import`]. 1048 /// 1049 /// [`Import`]: Definition::Import 1050 #[must_use] 1051 pub fn is_import(&self) -> bool { 1052 matches!(self, Self::Import(..)) 1053 } 1054 1055 /// Returns `true` if the module statement is [`Function`]. 1056 /// 1057 /// [`Function`]: ModuleStatement::Function 1058 #[must_use] 1059 pub fn is_function(&self) -> bool { 1060 matches!(self, Self::Function(..)) 1061 } 1062 1063 pub fn put_doc(&mut self, new_doc: (u32, EcoString)) { 1064 match self { 1065 Definition::Import(Import { .. }) => (), 1066 1067 Definition::Function(Function { documentation, .. }) 1068 | Definition::TypeAlias(TypeAlias { documentation, .. }) 1069 | Definition::CustomType(CustomType { documentation, .. }) 1070 | Definition::ModuleConstant(ModuleConstant { documentation, .. }) => { 1071 let _ = documentation.replace(new_doc); 1072 } 1073 } 1074 } 1075 1076 pub fn get_doc(&self) -> Option<EcoString> { 1077 match self { 1078 Definition::Import(Import { .. }) => None, 1079 1080 Definition::Function(Function { 1081 documentation: doc, .. 1082 }) 1083 | Definition::TypeAlias(TypeAlias { 1084 documentation: doc, .. 1085 }) 1086 | Definition::CustomType(CustomType { 1087 documentation: doc, .. 1088 }) 1089 | Definition::ModuleConstant(ModuleConstant { 1090 documentation: doc, .. 1091 }) => doc.as_ref().map(|(_, doc)| doc.clone()), 1092 } 1093 } 1094 1095 pub fn is_internal(&self) -> bool { 1096 match self { 1097 Definition::Function(Function { publicity, .. }) 1098 | Definition::CustomType(CustomType { publicity, .. }) 1099 | Definition::ModuleConstant(ModuleConstant { publicity, .. }) 1100 | Definition::TypeAlias(TypeAlias { publicity, .. }) => publicity.is_internal(), 1101 1102 Definition::Import(_) => false, 1103 } 1104 } 1105} 1106 1107#[derive(Debug, Clone, PartialEq, Eq)] 1108pub struct UnqualifiedImport { 1109 pub location: SrcSpan, 1110 /// The location excluding the potential `as ...` clause, or the `type` keyword 1111 pub imported_name_location: SrcSpan, 1112 pub name: EcoString, 1113 pub as_name: Option<EcoString>, 1114} 1115 1116impl UnqualifiedImport { 1117 pub fn used_name(&self) -> &EcoString { 1118 self.as_name.as_ref().unwrap_or(&self.name) 1119 } 1120} 1121 1122#[derive(Debug, Clone, PartialEq, Eq, Copy, Default, serde::Serialize, serde::Deserialize)] 1123pub enum Layer { 1124 #[default] 1125 Value, 1126 Type, 1127} 1128 1129impl Layer { 1130 /// Returns `true` if the layer is [`Value`]. 1131 pub fn is_value(&self) -> bool { 1132 matches!(self, Self::Value) 1133 } 1134} 1135 1136#[derive(Debug, Clone, Copy, PartialEq, Eq)] 1137pub enum BinOp { 1138 // Boolean logic 1139 And, 1140 Or, 1141 1142 // Equality 1143 Eq, 1144 NotEq, 1145 1146 // Order comparison 1147 LtInt, 1148 LtEqInt, 1149 LtFloat, 1150 LtEqFloat, 1151 GtEqInt, 1152 GtInt, 1153 GtEqFloat, 1154 GtFloat, 1155 1156 // Maths 1157 AddInt, 1158 AddFloat, 1159 SubInt, 1160 SubFloat, 1161 MultInt, 1162 MultFloat, 1163 DivInt, 1164 DivFloat, 1165 RemainderInt, 1166 1167 // Strings 1168 Concatenate, 1169} 1170 1171#[derive(Clone, Copy, Debug, PartialEq)] 1172pub enum OperatorKind { 1173 BooleanLogic, 1174 Equality, 1175 IntComparison, 1176 FLoatComparison, 1177 IntMath, 1178 FloatMath, 1179 StringConcatenation, 1180} 1181 1182pub const PIPE_PRECEDENCE: u8 = 6; 1183 1184impl BinOp { 1185 pub fn precedence(&self) -> u8 { 1186 // Ensure that this matches the other precedence function for guards 1187 match self { 1188 Self::Or => 1, 1189 1190 Self::And => 2, 1191 1192 Self::Eq | Self::NotEq => 3, 1193 1194 Self::LtInt 1195 | Self::LtEqInt 1196 | Self::LtFloat 1197 | Self::LtEqFloat 1198 | Self::GtEqInt 1199 | Self::GtInt 1200 | Self::GtEqFloat 1201 | Self::GtFloat => 4, 1202 1203 Self::Concatenate => 5, 1204 1205 // Pipe is 6 1206 Self::AddInt | Self::AddFloat | Self::SubInt | Self::SubFloat => 7, 1207 1208 Self::MultInt 1209 | Self::MultFloat 1210 | Self::DivInt 1211 | Self::DivFloat 1212 | Self::RemainderInt => 8, 1213 } 1214 } 1215 1216 pub fn name(&self) -> &'static str { 1217 match self { 1218 Self::And => "&&", 1219 Self::Or => "||", 1220 Self::LtInt => "<", 1221 Self::LtEqInt => "<=", 1222 Self::LtFloat => "<.", 1223 Self::LtEqFloat => "<=.", 1224 Self::Eq => "==", 1225 Self::NotEq => "!=", 1226 Self::GtEqInt => ">=", 1227 Self::GtInt => ">", 1228 Self::GtEqFloat => ">=.", 1229 Self::GtFloat => ">.", 1230 Self::AddInt => "+", 1231 Self::AddFloat => "+.", 1232 Self::SubInt => "-", 1233 Self::SubFloat => "-.", 1234 Self::MultInt => "*", 1235 Self::MultFloat => "*.", 1236 Self::DivInt => "/", 1237 Self::DivFloat => "/.", 1238 Self::RemainderInt => "%", 1239 Self::Concatenate => "<>", 1240 } 1241 } 1242 1243 pub fn operator_kind(&self) -> OperatorKind { 1244 match self { 1245 Self::Concatenate => OperatorKind::StringConcatenation, 1246 Self::Eq | Self::NotEq => OperatorKind::Equality, 1247 Self::And | Self::Or => OperatorKind::BooleanLogic, 1248 Self::LtInt | Self::LtEqInt | Self::GtEqInt | Self::GtInt => { 1249 OperatorKind::IntComparison 1250 } 1251 Self::LtFloat | Self::LtEqFloat | Self::GtEqFloat | Self::GtFloat => { 1252 OperatorKind::FLoatComparison 1253 } 1254 Self::AddInt | Self::SubInt | Self::MultInt | Self::RemainderInt | Self::DivInt => { 1255 OperatorKind::IntMath 1256 } 1257 Self::AddFloat | Self::SubFloat | Self::MultFloat | Self::DivFloat => { 1258 OperatorKind::FloatMath 1259 } 1260 } 1261 } 1262 1263 pub fn can_be_grouped_with(&self, other: &BinOp) -> bool { 1264 self.operator_kind() == other.operator_kind() 1265 } 1266 1267 pub(crate) fn is_float_operator(&self) -> bool { 1268 match self { 1269 BinOp::LtFloat 1270 | BinOp::LtEqFloat 1271 | BinOp::GtEqFloat 1272 | BinOp::GtFloat 1273 | BinOp::AddFloat 1274 | BinOp::SubFloat 1275 | BinOp::MultFloat 1276 | BinOp::DivFloat => true, 1277 1278 BinOp::And 1279 | BinOp::Or 1280 | BinOp::Eq 1281 | BinOp::NotEq 1282 | BinOp::LtInt 1283 | BinOp::LtEqInt 1284 | BinOp::GtEqInt 1285 | BinOp::GtInt 1286 | BinOp::AddInt 1287 | BinOp::SubInt 1288 | BinOp::MultInt 1289 | BinOp::DivInt 1290 | BinOp::RemainderInt 1291 | BinOp::Concatenate => false, 1292 } 1293 } 1294 1295 fn is_bool_operator(&self) -> bool { 1296 match self { 1297 BinOp::And | BinOp::Or => true, 1298 _ => false, 1299 } 1300 } 1301 1302 pub(crate) fn is_int_operator(&self) -> bool { 1303 match self { 1304 BinOp::LtInt 1305 | BinOp::LtEqInt 1306 | BinOp::GtEqInt 1307 | BinOp::GtInt 1308 | BinOp::AddInt 1309 | BinOp::SubInt 1310 | BinOp::MultInt 1311 | BinOp::DivInt 1312 | BinOp::RemainderInt => true, 1313 1314 BinOp::And 1315 | BinOp::Or 1316 | BinOp::Eq 1317 | BinOp::NotEq 1318 | BinOp::LtFloat 1319 | BinOp::LtEqFloat 1320 | BinOp::GtEqFloat 1321 | BinOp::GtFloat 1322 | BinOp::AddFloat 1323 | BinOp::SubFloat 1324 | BinOp::MultFloat 1325 | BinOp::DivFloat 1326 | BinOp::Concatenate => false, 1327 } 1328 } 1329 1330 pub fn float_equivalent(&self) -> Option<BinOp> { 1331 match self { 1332 BinOp::LtInt => Some(BinOp::LtFloat), 1333 BinOp::LtEqInt => Some(BinOp::LtEqFloat), 1334 BinOp::GtEqInt => Some(BinOp::GtEqFloat), 1335 BinOp::GtInt => Some(BinOp::GtFloat), 1336 BinOp::AddInt => Some(BinOp::AddFloat), 1337 BinOp::SubInt => Some(BinOp::SubFloat), 1338 BinOp::MultInt => Some(BinOp::MultFloat), 1339 BinOp::DivInt => Some(BinOp::DivFloat), 1340 _ => None, 1341 } 1342 } 1343 1344 pub fn int_equivalent(&self) -> Option<BinOp> { 1345 match self { 1346 BinOp::LtFloat => Some(BinOp::LtInt), 1347 BinOp::LtEqFloat => Some(BinOp::LtEqInt), 1348 BinOp::GtEqFloat => Some(BinOp::GtEqInt), 1349 BinOp::GtFloat => Some(BinOp::GtInt), 1350 BinOp::AddFloat => Some(BinOp::AddInt), 1351 BinOp::SubFloat => Some(BinOp::SubInt), 1352 BinOp::MultFloat => Some(BinOp::MultInt), 1353 BinOp::DivFloat => Some(BinOp::DivInt), 1354 _ => None, 1355 } 1356 } 1357} 1358 1359#[derive(Debug, PartialEq, Eq, Clone)] 1360pub struct CallArg<A> { 1361 pub label: Option<EcoString>, 1362 pub location: SrcSpan, 1363 pub value: A, 1364 pub implicit: Option<ImplicitCallArgOrigin>, 1365} 1366 1367#[derive(Debug, PartialEq, Eq, Clone, Copy)] 1368pub enum ImplicitCallArgOrigin { 1369 /// The implicit callback argument passed as the last argument to the 1370 /// function on the right hand side of `use`. 1371 /// 1372 Use, 1373 /// An argument added by the compiler when rewriting a pipe `left |> right`. 1374 /// 1375 Pipe, 1376 /// An argument added by the compiler to fill in all the missing fields of a 1377 /// record that are being ignored with the `..` syntax. 1378 /// 1379 PatternFieldSpread, 1380 /// An argument used to fill in the missing args when a function on the 1381 /// right hand side of `use` is being called with the wrong arity. 1382 /// 1383 IncorrectArityUse, 1384 /// An argument adde by the compiler to fill in the missing args when using 1385 /// the record update synax. 1386 /// 1387 RecordUpdate, 1388} 1389 1390impl<A> CallArg<A> { 1391 #[must_use] 1392 pub fn is_implicit(&self) -> bool { 1393 self.implicit.is_some() 1394 } 1395 1396 #[must_use] 1397 pub fn is_use_implicit_callback(&self) -> bool { 1398 match self.implicit { 1399 Some(ImplicitCallArgOrigin::Use | ImplicitCallArgOrigin::IncorrectArityUse) => true, 1400 Some(_) | None => false, 1401 } 1402 } 1403} 1404 1405impl CallArg<TypedExpr> { 1406 pub fn find_node<'a>( 1407 &'a self, 1408 byte_index: u32, 1409 called_function: &'a TypedExpr, 1410 function_arguments: &'a [TypedCallArg], 1411 ) -> Option<Located<'a>> { 1412 match (self.implicit, &self.value) { 1413 // If a call argument is the implicit use callback then we don't 1414 // want to look at its arguments and body but we don't want to 1415 // return the whole anonymous function if anything else doesn't 1416 // match. 1417 // 1418 // In addition, if the callback is invalid because it couldn't be 1419 // typed, we don't want to return it as it would make it hard for 1420 // the LSP to give any suggestions on the use function being typed. 1421 // 1422 (Some(ImplicitCallArgOrigin::Use), TypedExpr::Invalid { .. }) => None, 1423 // So the code below is exactly the same as 1424 // `TypedExpr::Fn{}.find_node()` except we do not return self as a 1425 // fallback. 1426 // 1427 (Some(ImplicitCallArgOrigin::Use), TypedExpr::Fn { args, body, .. }) => args 1428 .iter() 1429 .find_map(|arg| arg.find_node(byte_index)) 1430 .or_else(|| body.iter().find_map(|s| s.find_node(byte_index))), 1431 // In all other cases we're happy with the default behaviour. 1432 // 1433 _ => match self.value.find_node(byte_index) { 1434 Some(Located::Expression { expression, .. }) 1435 // This is only possibly a label if we are at the end of the expression 1436 // (so not in the middle like `[abc|]`) and if this argument doesn't 1437 // already have a label. 1438 if byte_index == self.value.location().end && self.label.is_none() => 1439 { 1440 Some(Located::Expression { 1441 expression, 1442 position: ExpressionPosition::ArgumentOrLabel { 1443 called_function, 1444 function_arguments, 1445 }, 1446 }) 1447 } 1448 Some(located) => Some(located), 1449 None => { 1450 if self.location.contains(byte_index) && self.label.is_some() { 1451 Some(Located::Label(self.location, self.value.type_())) 1452 } else { 1453 None 1454 } 1455 } 1456 }, 1457 } 1458 } 1459 1460 pub fn find_statement(&self, byte_index: u32) -> Option<&TypedStatement> { 1461 match (self.implicit, &self.value) { 1462 (Some(ImplicitCallArgOrigin::Use), TypedExpr::Invalid { .. }) => None, 1463 (Some(ImplicitCallArgOrigin::Use), TypedExpr::Fn { body, .. }) => { 1464 body.iter().find_map(|s| s.find_statement(byte_index)) 1465 } 1466 1467 _ => self.value.find_statement(byte_index), 1468 } 1469 } 1470 1471 pub fn is_capture_hole(&self) -> bool { 1472 match &self.value { 1473 TypedExpr::Var { name, .. } => name == CAPTURE_VARIABLE, 1474 _ => false, 1475 } 1476 } 1477} 1478 1479impl CallArg<TypedPattern> { 1480 pub fn find_node(&self, byte_index: u32) -> Option<Located<'_>> { 1481 match self.value.find_node(byte_index) { 1482 Some(located) => Some(located), 1483 _ => { 1484 if self.location.contains(byte_index) && self.label.is_some() { 1485 Some(Located::Label(self.location, self.value.type_())) 1486 } else { 1487 None 1488 } 1489 } 1490 } 1491 } 1492} 1493 1494impl CallArg<TypedConstant> { 1495 pub fn find_node(&self, byte_index: u32) -> Option<Located<'_>> { 1496 match self.value.find_node(byte_index) { 1497 Some(located) => Some(located), 1498 _ => { 1499 if self.location.contains(byte_index) && self.label.is_some() { 1500 Some(Located::Label(self.location, self.value.type_())) 1501 } else { 1502 None 1503 } 1504 } 1505 } 1506 } 1507} 1508 1509impl CallArg<UntypedExpr> { 1510 pub fn is_capture_hole(&self) -> bool { 1511 match &self.value { 1512 UntypedExpr::Var { name, .. } => name == CAPTURE_VARIABLE, 1513 _ => false, 1514 } 1515 } 1516} 1517 1518impl<T> CallArg<T> 1519where 1520 T: HasLocation, 1521{ 1522 #[must_use] 1523 pub fn uses_label_shorthand(&self) -> bool { 1524 self.label.is_some() && self.location == self.value.location() 1525 } 1526} 1527 1528impl<T> HasLocation for CallArg<T> { 1529 fn location(&self) -> SrcSpan { 1530 self.location 1531 } 1532} 1533 1534#[derive(Debug, Clone, PartialEq, Eq)] 1535pub struct RecordBeingUpdated { 1536 pub base: Box<UntypedExpr>, 1537 pub location: SrcSpan, 1538} 1539 1540#[derive(Debug, Clone, PartialEq, Eq)] 1541pub struct UntypedRecordUpdateArg { 1542 pub label: EcoString, 1543 pub location: SrcSpan, 1544 pub value: UntypedExpr, 1545} 1546 1547impl UntypedRecordUpdateArg { 1548 #[must_use] 1549 pub fn uses_label_shorthand(&self) -> bool { 1550 self.value.location() == self.location 1551 } 1552} 1553 1554impl HasLocation for UntypedRecordUpdateArg { 1555 fn location(&self) -> SrcSpan { 1556 self.location 1557 } 1558} 1559 1560pub type MultiPattern<Type> = Vec<Pattern<Type>>; 1561 1562pub type UntypedMultiPattern = MultiPattern<()>; 1563pub type TypedMultiPattern = MultiPattern<Arc<Type>>; 1564 1565pub type TypedClause = Clause<TypedExpr, Arc<Type>, EcoString>; 1566 1567pub type UntypedClause = Clause<UntypedExpr, (), ()>; 1568 1569#[derive(Debug, Clone, PartialEq, Eq)] 1570pub struct Clause<Expr, Type, RecordTag> { 1571 pub location: SrcSpan, 1572 pub pattern: MultiPattern<Type>, 1573 pub alternative_patterns: Vec<MultiPattern<Type>>, 1574 pub guard: Option<ClauseGuard<Type, RecordTag>>, 1575 pub then: Expr, 1576} 1577 1578impl<A, B, C> Clause<A, B, C> { 1579 pub fn pattern_count(&self) -> usize { 1580 1 + self.alternative_patterns.len() 1581 } 1582} 1583 1584impl TypedClause { 1585 pub fn location(&self) -> SrcSpan { 1586 SrcSpan { 1587 start: self 1588 .pattern 1589 .first() 1590 .map(|p| p.location().start) 1591 .unwrap_or_default(), 1592 end: self.then.location().end, 1593 } 1594 } 1595 1596 pub fn find_node(&self, byte_index: u32) -> Option<Located<'_>> { 1597 self.pattern 1598 .iter() 1599 .find_map(|p| p.find_node(byte_index)) 1600 .or_else(|| self.then.find_node(byte_index)) 1601 } 1602 1603 pub fn pattern_location(&self) -> SrcSpan { 1604 let start = self.pattern.first().map(|pattern| pattern.location().start); 1605 1606 let end = if let Some(last_pattern) = self 1607 .alternative_patterns 1608 .last() 1609 .and_then(|patterns| patterns.last()) 1610 { 1611 Some(last_pattern.location().end) 1612 } else { 1613 self.pattern.last().map(|pattern| pattern.location().end) 1614 }; 1615 1616 SrcSpan::new(start.unwrap_or_default(), end.unwrap_or_default()) 1617 } 1618} 1619 1620pub type UntypedClauseGuard = ClauseGuard<(), ()>; 1621pub type TypedClauseGuard = ClauseGuard<Arc<Type>, EcoString>; 1622 1623#[derive(Debug, Clone, PartialEq, Eq)] 1624pub enum ClauseGuard<Type, RecordTag> { 1625 Equals { 1626 location: SrcSpan, 1627 left: Box<Self>, 1628 right: Box<Self>, 1629 }, 1630 1631 NotEquals { 1632 location: SrcSpan, 1633 left: Box<Self>, 1634 right: Box<Self>, 1635 }, 1636 1637 GtInt { 1638 location: SrcSpan, 1639 left: Box<Self>, 1640 right: Box<Self>, 1641 }, 1642 1643 GtEqInt { 1644 location: SrcSpan, 1645 left: Box<Self>, 1646 right: Box<Self>, 1647 }, 1648 1649 LtInt { 1650 location: SrcSpan, 1651 left: Box<Self>, 1652 right: Box<Self>, 1653 }, 1654 1655 LtEqInt { 1656 location: SrcSpan, 1657 left: Box<Self>, 1658 right: Box<Self>, 1659 }, 1660 1661 GtFloat { 1662 location: SrcSpan, 1663 left: Box<Self>, 1664 right: Box<Self>, 1665 }, 1666 1667 GtEqFloat { 1668 location: SrcSpan, 1669 left: Box<Self>, 1670 right: Box<Self>, 1671 }, 1672 1673 LtFloat { 1674 location: SrcSpan, 1675 left: Box<Self>, 1676 right: Box<Self>, 1677 }, 1678 1679 LtEqFloat { 1680 location: SrcSpan, 1681 left: Box<Self>, 1682 right: Box<Self>, 1683 }, 1684 1685 AddInt { 1686 location: SrcSpan, 1687 left: Box<Self>, 1688 right: Box<Self>, 1689 }, 1690 1691 AddFloat { 1692 location: SrcSpan, 1693 left: Box<Self>, 1694 right: Box<Self>, 1695 }, 1696 1697 SubInt { 1698 location: SrcSpan, 1699 left: Box<Self>, 1700 right: Box<Self>, 1701 }, 1702 1703 SubFloat { 1704 location: SrcSpan, 1705 left: Box<Self>, 1706 right: Box<Self>, 1707 }, 1708 1709 MultInt { 1710 location: SrcSpan, 1711 left: Box<Self>, 1712 right: Box<Self>, 1713 }, 1714 1715 MultFloat { 1716 location: SrcSpan, 1717 left: Box<Self>, 1718 right: Box<Self>, 1719 }, 1720 1721 DivInt { 1722 location: SrcSpan, 1723 left: Box<Self>, 1724 right: Box<Self>, 1725 }, 1726 1727 DivFloat { 1728 location: SrcSpan, 1729 left: Box<Self>, 1730 right: Box<Self>, 1731 }, 1732 1733 RemainderInt { 1734 location: SrcSpan, 1735 left: Box<Self>, 1736 right: Box<Self>, 1737 }, 1738 1739 Or { 1740 location: SrcSpan, 1741 left: Box<Self>, 1742 right: Box<Self>, 1743 }, 1744 1745 And { 1746 location: SrcSpan, 1747 left: Box<Self>, 1748 right: Box<Self>, 1749 }, 1750 1751 Not { 1752 location: SrcSpan, 1753 expression: Box<Self>, 1754 }, 1755 1756 Var { 1757 location: SrcSpan, 1758 type_: Type, 1759 name: EcoString, 1760 definition_location: SrcSpan, 1761 }, 1762 1763 TupleIndex { 1764 location: SrcSpan, 1765 index: u64, 1766 type_: Type, 1767 tuple: Box<Self>, 1768 }, 1769 1770 FieldAccess { 1771 location: SrcSpan, 1772 index: Option<u64>, 1773 label: EcoString, 1774 type_: Type, 1775 container: Box<Self>, 1776 }, 1777 1778 ModuleSelect { 1779 location: SrcSpan, 1780 type_: Type, 1781 label: EcoString, 1782 module_name: EcoString, 1783 module_alias: EcoString, 1784 literal: Constant<Type, RecordTag>, 1785 }, 1786 1787 Constant(Constant<Type, RecordTag>), 1788} 1789 1790impl<A, B> ClauseGuard<A, B> { 1791 pub fn location(&self) -> SrcSpan { 1792 match self { 1793 ClauseGuard::Constant(constant) => constant.location(), 1794 ClauseGuard::Or { location, .. } 1795 | ClauseGuard::And { location, .. } 1796 | ClauseGuard::Not { location, .. } 1797 | ClauseGuard::Var { location, .. } 1798 | ClauseGuard::TupleIndex { location, .. } 1799 | ClauseGuard::Equals { location, .. } 1800 | ClauseGuard::NotEquals { location, .. } 1801 | ClauseGuard::GtInt { location, .. } 1802 | ClauseGuard::GtEqInt { location, .. } 1803 | ClauseGuard::LtInt { location, .. } 1804 | ClauseGuard::LtEqInt { location, .. } 1805 | ClauseGuard::GtFloat { location, .. } 1806 | ClauseGuard::GtEqFloat { location, .. } 1807 | ClauseGuard::LtFloat { location, .. } 1808 | ClauseGuard::AddInt { location, .. } 1809 | ClauseGuard::AddFloat { location, .. } 1810 | ClauseGuard::SubInt { location, .. } 1811 | ClauseGuard::SubFloat { location, .. } 1812 | ClauseGuard::MultInt { location, .. } 1813 | ClauseGuard::MultFloat { location, .. } 1814 | ClauseGuard::DivInt { location, .. } 1815 | ClauseGuard::DivFloat { location, .. } 1816 | ClauseGuard::RemainderInt { location, .. } 1817 | ClauseGuard::FieldAccess { location, .. } 1818 | ClauseGuard::LtEqFloat { location, .. } 1819 | ClauseGuard::ModuleSelect { location, .. } => *location, 1820 } 1821 } 1822 1823 pub fn precedence(&self) -> u8 { 1824 // Ensure that this matches the other precedence function for guards 1825 match self.bin_op_name() { 1826 Some(name) => name.precedence(), 1827 None => u8::MAX, 1828 } 1829 } 1830 1831 pub fn bin_op_name(&self) -> Option<BinOp> { 1832 match self { 1833 ClauseGuard::Or { .. } => Some(BinOp::Or), 1834 ClauseGuard::And { .. } => Some(BinOp::And), 1835 ClauseGuard::Equals { .. } => Some(BinOp::Eq), 1836 ClauseGuard::NotEquals { .. } => Some(BinOp::NotEq), 1837 ClauseGuard::GtInt { .. } => Some(BinOp::GtInt), 1838 ClauseGuard::GtEqInt { .. } => Some(BinOp::GtEqInt), 1839 ClauseGuard::LtInt { .. } => Some(BinOp::LtInt), 1840 ClauseGuard::LtEqInt { .. } => Some(BinOp::LtEqInt), 1841 ClauseGuard::GtFloat { .. } => Some(BinOp::GtFloat), 1842 ClauseGuard::GtEqFloat { .. } => Some(BinOp::GtEqFloat), 1843 ClauseGuard::LtFloat { .. } => Some(BinOp::LtFloat), 1844 ClauseGuard::LtEqFloat { .. } => Some(BinOp::LtEqFloat), 1845 ClauseGuard::AddInt { .. } => Some(BinOp::AddInt), 1846 ClauseGuard::AddFloat { .. } => Some(BinOp::AddFloat), 1847 ClauseGuard::SubInt { .. } => Some(BinOp::SubInt), 1848 ClauseGuard::SubFloat { .. } => Some(BinOp::SubFloat), 1849 ClauseGuard::MultInt { .. } => Some(BinOp::MultInt), 1850 ClauseGuard::MultFloat { .. } => Some(BinOp::MultFloat), 1851 ClauseGuard::DivInt { .. } => Some(BinOp::DivInt), 1852 ClauseGuard::DivFloat { .. } => Some(BinOp::DivFloat), 1853 ClauseGuard::RemainderInt { .. } => Some(BinOp::RemainderInt), 1854 1855 ClauseGuard::Constant(_) 1856 | ClauseGuard::Var { .. } 1857 | ClauseGuard::Not { .. } 1858 | ClauseGuard::TupleIndex { .. } 1859 | ClauseGuard::FieldAccess { .. } 1860 | ClauseGuard::ModuleSelect { .. } => None, 1861 } 1862 } 1863} 1864 1865impl TypedClauseGuard { 1866 pub fn type_(&self) -> Arc<Type> { 1867 match self { 1868 ClauseGuard::Var { type_, .. } => type_.clone(), 1869 ClauseGuard::TupleIndex { type_, .. } => type_.clone(), 1870 ClauseGuard::FieldAccess { type_, .. } => type_.clone(), 1871 ClauseGuard::ModuleSelect { type_, .. } => type_.clone(), 1872 ClauseGuard::Constant(constant) => constant.type_(), 1873 1874 ClauseGuard::AddInt { .. } 1875 | ClauseGuard::SubInt { .. } 1876 | ClauseGuard::MultInt { .. } 1877 | ClauseGuard::DivInt { .. } 1878 | ClauseGuard::RemainderInt { .. } => type_::int(), 1879 1880 ClauseGuard::AddFloat { .. } 1881 | ClauseGuard::SubFloat { .. } 1882 | ClauseGuard::MultFloat { .. } 1883 | ClauseGuard::DivFloat { .. } => type_::float(), 1884 1885 ClauseGuard::Or { .. } 1886 | ClauseGuard::Not { .. } 1887 | ClauseGuard::And { .. } 1888 | ClauseGuard::Equals { .. } 1889 | ClauseGuard::NotEquals { .. } 1890 | ClauseGuard::GtInt { .. } 1891 | ClauseGuard::GtEqInt { .. } 1892 | ClauseGuard::LtInt { .. } 1893 | ClauseGuard::LtEqInt { .. } 1894 | ClauseGuard::GtFloat { .. } 1895 | ClauseGuard::GtEqFloat { .. } 1896 | ClauseGuard::LtFloat { .. } 1897 | ClauseGuard::LtEqFloat { .. } => type_::bool(), 1898 } 1899 } 1900 1901 pub(crate) fn referenced_variables(&self) -> im::HashSet<&EcoString> { 1902 match self { 1903 ClauseGuard::Var { name, .. } => im::hashset![name], 1904 1905 ClauseGuard::Not { expression, .. } => expression.referenced_variables(), 1906 ClauseGuard::TupleIndex { tuple, .. } => tuple.referenced_variables(), 1907 ClauseGuard::FieldAccess { container, .. } => container.referenced_variables(), 1908 ClauseGuard::Constant(constant) => constant.referenced_variables(), 1909 ClauseGuard::ModuleSelect { .. } => im::HashSet::new(), 1910 1911 ClauseGuard::Equals { left, right, .. } 1912 | ClauseGuard::NotEquals { left, right, .. } 1913 | ClauseGuard::GtInt { left, right, .. } 1914 | ClauseGuard::GtEqInt { left, right, .. } 1915 | ClauseGuard::LtInt { left, right, .. } 1916 | ClauseGuard::LtEqInt { left, right, .. } 1917 | ClauseGuard::GtFloat { left, right, .. } 1918 | ClauseGuard::GtEqFloat { left, right, .. } 1919 | ClauseGuard::LtFloat { left, right, .. } 1920 | ClauseGuard::LtEqFloat { left, right, .. } 1921 | ClauseGuard::AddInt { left, right, .. } 1922 | ClauseGuard::AddFloat { left, right, .. } 1923 | ClauseGuard::SubInt { left, right, .. } 1924 | ClauseGuard::SubFloat { left, right, .. } 1925 | ClauseGuard::MultInt { left, right, .. } 1926 | ClauseGuard::MultFloat { left, right, .. } 1927 | ClauseGuard::DivInt { left, right, .. } 1928 | ClauseGuard::DivFloat { left, right, .. } 1929 | ClauseGuard::RemainderInt { left, right, .. } 1930 | ClauseGuard::And { left, right, .. } 1931 | ClauseGuard::Or { left, right, .. } => left 1932 .referenced_variables() 1933 .union(right.referenced_variables()), 1934 } 1935 } 1936} 1937 1938#[derive( 1939 Debug, 1940 PartialEq, 1941 Eq, 1942 PartialOrd, 1943 Ord, 1944 Default, 1945 Clone, 1946 Copy, 1947 serde::Serialize, 1948 serde::Deserialize, 1949)] 1950pub struct SrcSpan { 1951 pub start: u32, 1952 pub end: u32, 1953} 1954 1955impl SrcSpan { 1956 pub fn new(start: u32, end: u32) -> Self { 1957 Self { start, end } 1958 } 1959 1960 pub fn contains(&self, byte_index: u32) -> bool { 1961 byte_index >= self.start && byte_index <= self.end 1962 } 1963 1964 /// Merges two spans into a new one that starts at the start of the smaller 1965 /// one and ends at the end of the bigger one. For example: 1966 /// 1967 /// ```txt 1968 /// wibble wobble 1969 /// ─┬──── ─┬──── 1970 /// │ ╰─ one span 1971 /// ╰─ the other span 1972 /// ─┬────────────── 1973 /// ╰─ the span you get by merging the two 1974 /// ``` 1975 pub fn merge(&self, with: &SrcSpan) -> SrcSpan { 1976 Self { 1977 start: self.start.min(with.start), 1978 end: self.end.max(with.end), 1979 } 1980 } 1981} 1982 1983#[derive(Debug, PartialEq, Eq, Clone)] 1984pub struct DefinitionLocation { 1985 pub module: Option<EcoString>, 1986 pub span: SrcSpan, 1987} 1988 1989pub type UntypedPattern = Pattern<()>; 1990pub type TypedPattern = Pattern<Arc<Type>>; 1991 1992#[derive(Debug, Clone, PartialEq, Eq)] 1993pub enum Pattern<Type> { 1994 Int { 1995 location: SrcSpan, 1996 value: EcoString, 1997 int_value: BigInt, 1998 }, 1999 2000 Float { 2001 location: SrcSpan, 2002 value: EcoString, 2003 }, 2004 2005 String { 2006 location: SrcSpan, 2007 value: EcoString, 2008 }, 2009 2010 /// The creation of a variable. 2011 /// e.g. `assert [this_is_a_var, .._] = x` 2012 Variable { 2013 location: SrcSpan, 2014 name: EcoString, 2015 type_: Type, 2016 origin: VariableOrigin, 2017 }, 2018 2019 /// The specified size of a bit array. This can either be a literal integer, 2020 /// a reference to a variable, or a maths expression. 2021 /// e.g. `let assert <<y:size(somevar)>> = x` 2022 BitArraySize(BitArraySize<Type>), 2023 2024 /// A name given to a sub-pattern using the `as` keyword. 2025 /// e.g. `assert #(1, [_, _] as the_list) = x` 2026 Assign { 2027 name: EcoString, 2028 location: SrcSpan, 2029 pattern: Box<Self>, 2030 }, 2031 2032 /// A pattern that binds to any value but does not assign a variable. 2033 /// Always starts with an underscore. 2034 Discard { 2035 name: EcoString, 2036 location: SrcSpan, 2037 type_: Type, 2038 }, 2039 2040 List { 2041 location: SrcSpan, 2042 elements: Vec<Self>, 2043 tail: Option<Box<Self>>, 2044 type_: Type, 2045 }, 2046 2047 /// The constructor for a custom type. Starts with an uppercase letter. 2048 Constructor { 2049 location: SrcSpan, 2050 name_location: SrcSpan, 2051 name: EcoString, 2052 arguments: Vec<CallArg<Self>>, 2053 module: Option<(EcoString, SrcSpan)>, 2054 constructor: Inferred<PatternConstructor>, 2055 spread: Option<SrcSpan>, 2056 type_: Type, 2057 }, 2058 2059 Tuple { 2060 location: SrcSpan, 2061 elements: Vec<Self>, 2062 }, 2063 2064 BitArray { 2065 location: SrcSpan, 2066 segments: Vec<BitArraySegment<Self, Type>>, 2067 }, 2068 2069 // "prefix" <> variable 2070 StringPrefix { 2071 location: SrcSpan, 2072 left_location: SrcSpan, 2073 left_side_assignment: Option<(EcoString, SrcSpan)>, 2074 right_location: SrcSpan, 2075 left_side_string: EcoString, 2076 /// The variable on the right hand side of the `<>`. 2077 right_side_assignment: AssignName, 2078 }, 2079 2080 /// A placeholder pattern used to allow module analysis to continue 2081 /// even when there are type errors. Should never end up in generated code. 2082 Invalid { 2083 location: SrcSpan, 2084 type_: Type, 2085 }, 2086} 2087 2088pub type TypedBitArraySize = BitArraySize<Arc<Type>>; 2089 2090#[derive(Debug, Clone, PartialEq, Eq)] 2091pub enum BitArraySize<Type> { 2092 Int { 2093 location: SrcSpan, 2094 value: EcoString, 2095 int_value: BigInt, 2096 }, 2097 2098 Variable { 2099 location: SrcSpan, 2100 name: EcoString, 2101 constructor: Option<Box<ValueConstructor>>, 2102 type_: Type, 2103 }, 2104 2105 BinaryOperator { 2106 location: SrcSpan, 2107 operator: IntOperator, 2108 left: Box<Self>, 2109 right: Box<Self>, 2110 }, 2111 2112 Block { 2113 location: SrcSpan, 2114 inner: Box<Self>, 2115 }, 2116} 2117 2118#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 2119pub enum IntOperator { 2120 Add, 2121 Subtract, 2122 Multiply, 2123 Divide, 2124 Remainder, 2125} 2126 2127impl IntOperator { 2128 pub fn precedence(&self) -> u8 { 2129 match self { 2130 Self::Add | Self::Subtract => 7, 2131 2132 Self::Multiply | Self::Divide | Self::Remainder => 8, 2133 } 2134 } 2135 2136 pub fn to_bin_op(&self) -> BinOp { 2137 match self { 2138 IntOperator::Add => BinOp::AddInt, 2139 IntOperator::Subtract => BinOp::SubInt, 2140 IntOperator::Multiply => BinOp::MultInt, 2141 IntOperator::Divide => BinOp::DivInt, 2142 IntOperator::Remainder => BinOp::RemainderInt, 2143 } 2144 } 2145} 2146 2147impl<T> BitArraySize<T> { 2148 pub fn location(&self) -> SrcSpan { 2149 match self { 2150 BitArraySize::Int { location, .. } 2151 | BitArraySize::Variable { location, .. } 2152 | BitArraySize::BinaryOperator { location, .. } 2153 | BitArraySize::Block { location, .. } => *location, 2154 } 2155 } 2156 2157 pub fn non_zero_compile_time_number(&self) -> bool { 2158 match self { 2159 BitArraySize::Int { int_value, .. } => !int_value.is_zero(), 2160 BitArraySize::Block { inner, .. } => inner.non_zero_compile_time_number(), 2161 BitArraySize::Variable { .. } | BitArraySize::BinaryOperator { .. } => false, 2162 } 2163 } 2164} 2165 2166impl Default for Inferred<()> { 2167 fn default() -> Self { 2168 Self::Unknown 2169 } 2170} 2171 2172#[derive(Debug, Clone, PartialEq, Eq, Hash)] 2173pub enum AssignName { 2174 Variable(EcoString), 2175 Discard(EcoString), 2176} 2177 2178impl AssignName { 2179 pub fn name(&self) -> &EcoString { 2180 match self { 2181 AssignName::Variable(name) | AssignName::Discard(name) => name, 2182 } 2183 } 2184 2185 pub fn to_arg_names(self, location: SrcSpan) -> ArgNames { 2186 match self { 2187 AssignName::Variable(name) => ArgNames::Named { name, location }, 2188 AssignName::Discard(name) => ArgNames::Discard { name, location }, 2189 } 2190 } 2191 2192 pub fn assigned_name(&self) -> Option<&str> { 2193 match self { 2194 AssignName::Variable(name) => Some(name), 2195 AssignName::Discard(_) => None, 2196 } 2197 } 2198} 2199 2200impl<A> Pattern<A> { 2201 pub fn location(&self) -> SrcSpan { 2202 match self { 2203 Pattern::Assign { 2204 pattern, location, .. 2205 } => SrcSpan::new(pattern.location().start, location.end), 2206 Pattern::Int { location, .. } 2207 | Pattern::Variable { location, .. } 2208 | Pattern::List { location, .. } 2209 | Pattern::Float { location, .. } 2210 | Pattern::Discard { location, .. } 2211 | Pattern::String { location, .. } 2212 | Pattern::Tuple { location, .. } 2213 | Pattern::Constructor { location, .. } 2214 | Pattern::StringPrefix { location, .. } 2215 | Pattern::BitArray { location, .. } 2216 | Pattern::Invalid { location, .. } => *location, 2217 Pattern::BitArraySize(size) => size.location(), 2218 } 2219 } 2220 2221 /// Returns `true` if the pattern is [`Discard`]. 2222 /// 2223 /// [`Discard`]: Pattern::Discard 2224 #[must_use] 2225 pub fn is_discard(&self) -> bool { 2226 matches!(self, Self::Discard { .. }) 2227 } 2228 2229 #[must_use] 2230 pub fn is_variable(&self) -> bool { 2231 match self { 2232 Pattern::Variable { .. } => true, 2233 _ => false, 2234 } 2235 } 2236 2237 #[must_use] 2238 pub fn is_string(&self) -> bool { 2239 matches!(self, Self::String { .. }) 2240 } 2241} 2242 2243impl TypedPattern { 2244 pub fn definition_location(&self) -> Option<DefinitionLocation> { 2245 match self { 2246 Pattern::Int { .. } 2247 | Pattern::Float { .. } 2248 | Pattern::String { .. } 2249 | Pattern::Variable { .. } 2250 | Pattern::BitArraySize { .. } 2251 | Pattern::Assign { .. } 2252 | Pattern::Discard { .. } 2253 | Pattern::List { .. } 2254 | Pattern::Tuple { .. } 2255 | Pattern::BitArray { .. } 2256 | Pattern::StringPrefix { .. } 2257 | Pattern::Invalid { .. } => None, 2258 2259 Pattern::Constructor { constructor, .. } => constructor.definition_location(), 2260 } 2261 } 2262 2263 pub fn get_documentation(&self) -> Option<&str> { 2264 match self { 2265 Pattern::Int { .. } 2266 | Pattern::Float { .. } 2267 | Pattern::String { .. } 2268 | Pattern::Variable { .. } 2269 | Pattern::BitArraySize { .. } 2270 | Pattern::Assign { .. } 2271 | Pattern::Discard { .. } 2272 | Pattern::List { .. } 2273 | Pattern::Tuple { .. } 2274 | Pattern::BitArray { .. } 2275 | Pattern::StringPrefix { .. } 2276 | Pattern::Invalid { .. } => None, 2277 2278 Pattern::Constructor { constructor, .. } => constructor.get_documentation(), 2279 } 2280 } 2281 2282 pub fn type_(&self) -> Arc<Type> { 2283 match self { 2284 Pattern::Int { .. } => type_::int(), 2285 Pattern::Float { .. } => type_::float(), 2286 Pattern::String { .. } => type_::string(), 2287 Pattern::BitArray { .. } => type_::bit_array(), 2288 Pattern::StringPrefix { .. } => type_::string(), 2289 2290 Pattern::Variable { type_, .. } 2291 | Pattern::List { type_, .. } 2292 | Pattern::Constructor { type_, .. } 2293 | Pattern::Invalid { type_, .. } => type_.clone(), 2294 2295 Pattern::Assign { pattern, .. } => pattern.type_(), 2296 2297 // Bit array sizes should always be integers 2298 Pattern::BitArraySize(_) => type_::int(), 2299 2300 Pattern::Discard { type_, .. } => type_.clone(), 2301 2302 Pattern::Tuple { elements, .. } => { 2303 type_::tuple(elements.iter().map(|p| p.type_()).collect()) 2304 } 2305 } 2306 } 2307 2308 fn find_node(&self, byte_index: u32) -> Option<Located<'_>> { 2309 if !self.location().contains(byte_index) { 2310 return None; 2311 } 2312 2313 if let Pattern::Variable { name, .. } = self { 2314 // For pipes the pattern can't be pointed to 2315 if name.as_str().eq(PIPE_VARIABLE) { 2316 return None; 2317 } 2318 } 2319 2320 match self { 2321 Pattern::Int { .. } 2322 | Pattern::Float { .. } 2323 | Pattern::String { .. } 2324 | Pattern::Variable { .. } 2325 | Pattern::BitArraySize { .. } 2326 | Pattern::Assign { .. } 2327 | Pattern::Discard { .. } 2328 | Pattern::StringPrefix { .. } 2329 | Pattern::Invalid { .. } => Some(Located::Pattern(self)), 2330 2331 Pattern::Constructor { 2332 arguments, spread, .. 2333 } => match spread { 2334 Some(spread_location) if spread_location.contains(byte_index) => { 2335 Some(Located::PatternSpread { 2336 spread_location: *spread_location, 2337 pattern: self, 2338 }) 2339 } 2340 2341 Some(_) | None => arguments.iter().find_map(|arg| arg.find_node(byte_index)), 2342 }, 2343 Pattern::List { elements, tail, .. } => elements 2344 .iter() 2345 .find_map(|p| p.find_node(byte_index)) 2346 .or_else(|| tail.as_ref().and_then(|p| p.find_node(byte_index))), 2347 2348 Pattern::Tuple { elements, .. } => { 2349 elements.iter().find_map(|p| p.find_node(byte_index)) 2350 } 2351 2352 Pattern::BitArray { segments, .. } => segments 2353 .iter() 2354 .find_map(|segment| segment.find_node(byte_index)) 2355 .or(Some(Located::Pattern(self))), 2356 } 2357 .or(Some(Located::Pattern(self))) 2358 } 2359 2360 /// If the pattern is a `Constructor` with a spread, it returns a tuple with 2361 /// all the ignored fields. Split in unlabelled and labelled ones. 2362 /// 2363 pub(crate) fn unused_arguments(&self) -> Option<PatternUnusedArguments> { 2364 let TypedPattern::Constructor { 2365 arguments, 2366 spread: Some(_), 2367 .. 2368 } = self 2369 else { 2370 return None; 2371 }; 2372 2373 let mut positional = vec![]; 2374 let mut labelled = vec![]; 2375 for argument in arguments { 2376 // We only want to display the arguments that were ignored using `..`. 2377 // Any argument ignored that way is marked as implicit, so if it is 2378 // not implicit we just ignore it. 2379 if !argument.is_implicit() { 2380 continue; 2381 } 2382 let type_ = argument.value.type_(); 2383 match &argument.label { 2384 Some(label) => labelled.push((label.clone(), type_)), 2385 None => positional.push(type_), 2386 } 2387 } 2388 2389 Some(PatternUnusedArguments { 2390 positional, 2391 labelled, 2392 }) 2393 } 2394 2395 /// Whether the pattern always matches. For example, a tuple or simple 2396 /// variable assignment always match and can never fail. 2397 #[must_use] 2398 pub fn always_matches(&self) -> bool { 2399 match self { 2400 Pattern::Variable { .. } | Pattern::Discard { .. } => true, 2401 Pattern::Assign { pattern, .. } => pattern.always_matches(), 2402 Pattern::Tuple { elements, .. } => { 2403 elements.iter().all(|element| element.always_matches()) 2404 } 2405 Pattern::Int { .. } 2406 | Pattern::Float { .. } 2407 | Pattern::String { .. } 2408 | Pattern::BitArraySize { .. } 2409 | Pattern::List { .. } 2410 | Pattern::Constructor { .. } 2411 | Pattern::BitArray { .. } 2412 | Pattern::StringPrefix { .. } 2413 | Pattern::Invalid { .. } => false, 2414 } 2415 } 2416 2417 pub fn bound_variables(&self) -> Vec<EcoString> { 2418 let mut variables = Vec::new(); 2419 self.collect_bound_variables(&mut variables); 2420 variables 2421 } 2422 2423 fn collect_bound_variables(&self, variables: &mut Vec<EcoString>) { 2424 match self { 2425 Pattern::Int { .. } 2426 | Pattern::Float { .. } 2427 | Pattern::String { .. } 2428 | Pattern::Discard { .. } 2429 | Pattern::Invalid { .. } => {} 2430 2431 Pattern::Variable { name, .. } => variables.push(name.clone()), 2432 Pattern::BitArraySize { .. } => {} 2433 Pattern::Assign { name, pattern, .. } => { 2434 variables.push(name.clone()); 2435 pattern.collect_bound_variables(variables); 2436 } 2437 Pattern::List { elements, tail, .. } => { 2438 for element in elements { 2439 element.collect_bound_variables(variables); 2440 } 2441 if let Some(tail) = tail { 2442 tail.collect_bound_variables(variables); 2443 } 2444 } 2445 Pattern::Constructor { arguments, .. } => { 2446 for argument in arguments { 2447 argument.value.collect_bound_variables(variables); 2448 } 2449 } 2450 Pattern::Tuple { elements, .. } => { 2451 for element in elements { 2452 element.collect_bound_variables(variables); 2453 } 2454 } 2455 Pattern::BitArray { segments, .. } => { 2456 for segment in segments { 2457 segment.value.collect_bound_variables(variables); 2458 } 2459 } 2460 Pattern::StringPrefix { 2461 left_side_assignment, 2462 right_side_assignment, 2463 .. 2464 } => { 2465 if let Some((left_variable, _)) = left_side_assignment { 2466 variables.push(left_variable.clone()); 2467 } 2468 match right_side_assignment { 2469 AssignName::Variable(name) => variables.push(name.clone()), 2470 AssignName::Discard(_) => {} 2471 } 2472 } 2473 } 2474 } 2475} 2476 2477#[derive(Debug, Default)] 2478pub struct PatternUnusedArguments { 2479 pub positional: Vec<Arc<Type>>, 2480 pub labelled: Vec<(EcoString, Arc<Type>)>, 2481} 2482 2483impl<A> HasLocation for Pattern<A> { 2484 fn location(&self) -> SrcSpan { 2485 self.location() 2486 } 2487} 2488 2489#[derive(Debug, Clone, PartialEq, Eq)] 2490pub enum AssignmentKind<Expression> { 2491 /// let x = ... 2492 Let, 2493 /// This is a let assignment generated by the compiler for intermediate variables 2494 /// needed by record updates and `use`. 2495 /// Like a regular `Let` assignment this can never fail. 2496 /// 2497 Generated, 2498 /// let assert x = ... 2499 Assert { 2500 /// The src byte span of the `let assert` 2501 /// 2502 /// ```gleam 2503 /// let assert Wibble = todo 2504 /// ^^^^^^^^^^ 2505 /// ``` 2506 location: SrcSpan, 2507 2508 /// The byte index of the start of `assert` 2509 /// 2510 /// ```gleam 2511 /// let assert Wibble = todo 2512 /// ^ 2513 /// ``` 2514 assert_keyword_start: u32, 2515 2516 /// The message given to the assertion: 2517 /// 2518 /// ```gleam 2519 /// let asset Ok(a) = something() as "This will never fail" 2520 /// ^^^^^^^^^^^^^^^^^^^^^^ 2521 /// ``` 2522 message: Option<Expression>, 2523 }, 2524} 2525 2526impl<Expression> AssignmentKind<Expression> { 2527 /// Returns `true` if the assignment kind is [`Assert`]. 2528 /// 2529 /// [`Assert`]: AssignmentKind::Assert 2530 #[must_use] 2531 pub fn is_assert(&self) -> bool { 2532 match self { 2533 Self::Assert { .. } => true, 2534 Self::Let | Self::Generated => false, 2535 } 2536 } 2537} 2538 2539// BitArrays 2540 2541pub type UntypedExprBitArraySegment = BitArraySegment<UntypedExpr, ()>; 2542pub type TypedExprBitArraySegment = BitArraySegment<TypedExpr, Arc<Type>>; 2543 2544pub type UntypedConstantBitArraySegment = BitArraySegment<UntypedConstant, ()>; 2545pub type TypedConstantBitArraySegment = BitArraySegment<TypedConstant, Arc<Type>>; 2546 2547pub type UntypedPatternBitArraySegment = BitArraySegment<UntypedPattern, ()>; 2548pub type TypedPatternBitArraySegment = BitArraySegment<TypedPattern, Arc<Type>>; 2549 2550#[derive(Debug, Clone, PartialEq, Eq)] 2551pub struct BitArraySegment<Value, Type> { 2552 pub location: SrcSpan, 2553 pub value: Box<Value>, 2554 pub options: Vec<BitArrayOption<Value>>, 2555 pub type_: Type, 2556} 2557 2558#[derive(Debug, PartialEq, Eq, Copy, Clone, Hash)] 2559pub enum Endianness { 2560 Big, 2561 Little, 2562} 2563 2564impl Endianness { 2565 pub fn is_big(&self) -> bool { 2566 *self == Endianness::Big 2567 } 2568} 2569 2570impl<Type> BitArraySegment<Pattern<Type>, Type> { 2571 /// Returns the value of the pattern unwrapping any assign pattern. 2572 /// 2573 pub fn value_unwrapping_assign(&self) -> &Pattern<Type> { 2574 match self.value.as_ref() { 2575 Pattern::Assign { pattern, .. } => pattern, 2576 Pattern::Int { .. } 2577 | Pattern::Float { .. } 2578 | Pattern::String { .. } 2579 | Pattern::Variable { .. } 2580 | Pattern::BitArraySize { .. } 2581 | Pattern::Discard { .. } 2582 | Pattern::List { .. } 2583 | Pattern::Constructor { .. } 2584 | Pattern::Tuple { .. } 2585 | Pattern::BitArray { .. } 2586 | Pattern::StringPrefix { .. } 2587 | Pattern::Invalid { .. } => self.value.as_ref(), 2588 } 2589 } 2590} 2591 2592impl<Value, Type> BitArraySegment<Value, Type> { 2593 #[must_use] 2594 pub fn has_native_option(&self) -> bool { 2595 self.options 2596 .iter() 2597 .any(|x| matches!(x, BitArrayOption::Native { .. })) 2598 } 2599 2600 #[must_use] 2601 pub fn has_utf16_codepoint_option(&self) -> bool { 2602 self.options 2603 .iter() 2604 .any(|x| matches!(x, BitArrayOption::Utf16Codepoint { .. })) 2605 } 2606 2607 #[must_use] 2608 pub fn has_utf32_codepoint_option(&self) -> bool { 2609 self.options 2610 .iter() 2611 .any(|x| matches!(x, BitArrayOption::Utf32Codepoint { .. })) 2612 } 2613 2614 #[must_use] 2615 pub fn has_utf16_option(&self) -> bool { 2616 self.options 2617 .iter() 2618 .any(|x| matches!(x, BitArrayOption::Utf16 { .. })) 2619 } 2620 2621 #[must_use] 2622 pub fn has_utf32_option(&self) -> bool { 2623 self.options 2624 .iter() 2625 .any(|x| matches!(x, BitArrayOption::Utf32 { .. })) 2626 } 2627 2628 pub fn endianness(&self) -> Endianness { 2629 if self 2630 .options 2631 .iter() 2632 .any(|x| matches!(x, BitArrayOption::Little { .. })) 2633 { 2634 Endianness::Little 2635 } else { 2636 Endianness::Big 2637 } 2638 } 2639 2640 pub(crate) fn signed(&self) -> bool { 2641 self.options 2642 .iter() 2643 .any(|x| matches!(x, BitArrayOption::Signed { .. })) 2644 } 2645 2646 pub fn size(&self) -> Option<&Value> { 2647 self.options.iter().find_map(|x| match x { 2648 BitArrayOption::Size { value, .. } => Some(value.as_ref()), 2649 _ => None, 2650 }) 2651 } 2652 2653 pub fn unit(&self) -> u8 { 2654 self.options 2655 .iter() 2656 .find_map(|option| match option { 2657 BitArrayOption::Unit { value, .. } => Some(*value), 2658 BitArrayOption::Bytes { .. } => Some(8), 2659 _ => None, 2660 }) 2661 .unwrap_or(1) 2662 } 2663 2664 pub(crate) fn has_bits_option(&self) -> bool { 2665 self.options.iter().any(|option| match option { 2666 BitArrayOption::Bits { .. } => true, 2667 _ => false, 2668 }) 2669 } 2670 2671 pub(crate) fn has_bytes_option(&self) -> bool { 2672 self.options.iter().any(|option| match option { 2673 BitArrayOption::Bytes { .. } => true, 2674 _ => false, 2675 }) 2676 } 2677} 2678 2679impl<Value, Type> BitArraySegment<Value, Type> { 2680 #[must_use] 2681 pub(crate) fn has_type_option(&self) -> bool { 2682 self.options.iter().any(|option| option.is_type_option()) 2683 } 2684} 2685 2686impl TypedExprBitArraySegment { 2687 pub fn find_node(&self, byte_index: u32) -> Option<Located<'_>> { 2688 self.value.find_node(byte_index) 2689 } 2690} 2691 2692impl<TypedValue> BitArraySegment<TypedValue, Arc<Type>> 2693where 2694 TypedValue: HasType + HasLocation + Clone + bit_array::GetLiteralValue, 2695{ 2696 pub(crate) fn check_for_truncated_value(&self) -> Option<BitArraySegmentTruncation> { 2697 // Both the size and the value must be two compile-time known constants. 2698 let segment_bits = self.bits_size()?.to_i64()?; 2699 let literal_value = self.value.as_int_literal()?; 2700 if segment_bits <= 0 { 2701 return None; 2702 } 2703 2704 let safe_range = match literal_value.sign() { 2705 Sign::NoSign => return None, 2706 Sign::Minus => { 2707 (-(BigInt::one() << (segment_bits - 1))) 2708 ..((BigInt::one() << (segment_bits - 1)) - 1) 2709 } 2710 Sign::Plus => BigInt::ZERO..(BigInt::one() << segment_bits), 2711 }; 2712 2713 if !safe_range.contains(&literal_value) { 2714 Some(BitArraySegmentTruncation { 2715 truncated_value: literal_value.clone(), 2716 truncated_into: truncate(&literal_value, segment_bits), 2717 value_location: self.value.location(), 2718 segment_bits, 2719 }) 2720 } else { 2721 None 2722 } 2723 } 2724 2725 /// If the segment size is a compile-time known constant this returns the 2726 /// segment size in bits, taking the segment's unit into consideration! 2727 /// 2728 fn bits_size(&self) -> Option<BigInt> { 2729 let size = match self.size() { 2730 None if self.type_.is_int() => 8.into(), 2731 None => 64.into(), 2732 Some(value) => value.as_int_literal()?, 2733 }; 2734 2735 let unit = self.unit(); 2736 Some(size * unit) 2737 } 2738} 2739 2740/// As Björn said, when a value is smaller than the segment's size it will be 2741/// truncated, only taking the first `n` bits: 2742/// 2743/// > It will be silently truncated. In general, when storing value an integer 2744/// > `I` into a segment of size `N`, the actual value stored will be 2745/// > `I band ((1 bsl N) - 1)`. 2746/// 2747/// <https://erlangforums.com/t/what-happens-when-a-bit-array-segment-size-is-smaller-than-its-value/4650/2?u=giacomocavalieri> 2748/// 2749/// Thank you Björn! 2750/// 2751fn truncate(literal_value: &BigInt, segment_bits: i64) -> BigInt { 2752 literal_value & ((BigInt::one() << segment_bits) - BigInt::one()) 2753} 2754 2755#[derive(serde::Deserialize, serde::Serialize, Eq, PartialEq, Clone, Debug)] 2756pub struct BitArraySegmentTruncation { 2757 /// The value that would end up being truncated. 2758 pub truncated_value: BigInt, 2759 /// What the value would be truncated into. 2760 pub truncated_into: BigInt, 2761 /// The span of the segment's value being truncated. 2762 pub value_location: SrcSpan, 2763 /// The size of the segment. 2764 pub segment_bits: i64, 2765} 2766 2767impl TypedPatternBitArraySegment { 2768 pub fn find_node(&self, byte_index: u32) -> Option<Located<'_>> { 2769 self.value.find_node(byte_index).or_else(|| { 2770 self.options 2771 .iter() 2772 .find_map(|option| option.find_node(byte_index)) 2773 }) 2774 } 2775} 2776 2777impl TypedConstantBitArraySegment { 2778 pub fn find_node(&self, byte_index: u32) -> Option<Located<'_>> { 2779 self.value.find_node(byte_index).or_else(|| { 2780 self.options 2781 .iter() 2782 .find_map(|option| option.find_node(byte_index)) 2783 }) 2784 } 2785} 2786 2787pub type TypedConstantBitArraySegmentOption = BitArrayOption<TypedConstant>; 2788 2789#[derive(Debug, PartialEq, Eq, Clone)] 2790pub enum BitArrayOption<Value> { 2791 Bytes { 2792 location: SrcSpan, 2793 }, 2794 2795 Int { 2796 location: SrcSpan, 2797 }, 2798 2799 Float { 2800 location: SrcSpan, 2801 }, 2802 2803 Bits { 2804 location: SrcSpan, 2805 }, 2806 2807 Utf8 { 2808 location: SrcSpan, 2809 }, 2810 2811 Utf16 { 2812 location: SrcSpan, 2813 }, 2814 2815 Utf32 { 2816 location: SrcSpan, 2817 }, 2818 2819 Utf8Codepoint { 2820 location: SrcSpan, 2821 }, 2822 2823 Utf16Codepoint { 2824 location: SrcSpan, 2825 }, 2826 2827 Utf32Codepoint { 2828 location: SrcSpan, 2829 }, 2830 2831 Signed { 2832 location: SrcSpan, 2833 }, 2834 2835 Unsigned { 2836 location: SrcSpan, 2837 }, 2838 2839 Big { 2840 location: SrcSpan, 2841 }, 2842 2843 Little { 2844 location: SrcSpan, 2845 }, 2846 2847 Native { 2848 location: SrcSpan, 2849 }, 2850 2851 Size { 2852 location: SrcSpan, 2853 value: Box<Value>, 2854 short_form: bool, 2855 }, 2856 2857 Unit { 2858 location: SrcSpan, 2859 value: u8, 2860 }, 2861} 2862 2863impl<A> BitArrayOption<A> { 2864 pub fn value(&self) -> Option<&A> { 2865 match self { 2866 BitArrayOption::Size { value, .. } => Some(value), 2867 _ => None, 2868 } 2869 } 2870 2871 pub fn location(&self) -> SrcSpan { 2872 match self { 2873 BitArrayOption::Bytes { location } 2874 | BitArrayOption::Int { location } 2875 | BitArrayOption::Float { location } 2876 | BitArrayOption::Bits { location } 2877 | BitArrayOption::Utf8 { location } 2878 | BitArrayOption::Utf16 { location } 2879 | BitArrayOption::Utf32 { location } 2880 | BitArrayOption::Utf8Codepoint { location } 2881 | BitArrayOption::Utf16Codepoint { location } 2882 | BitArrayOption::Utf32Codepoint { location } 2883 | BitArrayOption::Signed { location } 2884 | BitArrayOption::Unsigned { location } 2885 | BitArrayOption::Big { location } 2886 | BitArrayOption::Little { location } 2887 | BitArrayOption::Native { location } 2888 | BitArrayOption::Size { location, .. } 2889 | BitArrayOption::Unit { location, .. } => *location, 2890 } 2891 } 2892 2893 pub fn label(&self) -> EcoString { 2894 match self { 2895 BitArrayOption::Bytes { .. } => "bytes".into(), 2896 BitArrayOption::Int { .. } => "int".into(), 2897 BitArrayOption::Float { .. } => "float".into(), 2898 BitArrayOption::Bits { .. } => "bits".into(), 2899 BitArrayOption::Utf8 { .. } => "utf8".into(), 2900 BitArrayOption::Utf16 { .. } => "utf16".into(), 2901 BitArrayOption::Utf32 { .. } => "utf32".into(), 2902 BitArrayOption::Utf8Codepoint { .. } => "utf8_codepoint".into(), 2903 BitArrayOption::Utf16Codepoint { .. } => "utf16_codepoint".into(), 2904 BitArrayOption::Utf32Codepoint { .. } => "utf32_codepoint".into(), 2905 BitArrayOption::Signed { .. } => "signed".into(), 2906 BitArrayOption::Unsigned { .. } => "unsigned".into(), 2907 BitArrayOption::Big { .. } => "big".into(), 2908 BitArrayOption::Little { .. } => "little".into(), 2909 BitArrayOption::Native { .. } => "native".into(), 2910 BitArrayOption::Size { .. } => "size".into(), 2911 BitArrayOption::Unit { .. } => "unit".into(), 2912 } 2913 } 2914 2915 fn is_type_option(&self) -> bool { 2916 match self { 2917 BitArrayOption::Bytes { .. } 2918 | BitArrayOption::Int { .. } 2919 | BitArrayOption::Float { .. } 2920 | BitArrayOption::Bits { .. } 2921 | BitArrayOption::Utf8 { .. } 2922 | BitArrayOption::Utf16 { .. } 2923 | BitArrayOption::Utf32 { .. } 2924 | BitArrayOption::Utf8Codepoint { .. } 2925 | BitArrayOption::Utf16Codepoint { .. } 2926 | BitArrayOption::Utf32Codepoint { .. } => true, 2927 2928 BitArrayOption::Signed { .. } 2929 | BitArrayOption::Unsigned { .. } 2930 | BitArrayOption::Big { .. } 2931 | BitArrayOption::Little { .. } 2932 | BitArrayOption::Native { .. } 2933 | BitArrayOption::Size { .. } 2934 | BitArrayOption::Unit { .. } => false, 2935 } 2936 } 2937} 2938 2939impl BitArrayOption<TypedConstant> { 2940 fn referenced_variables(&self) -> im::HashSet<&EcoString> { 2941 match self { 2942 BitArrayOption::Bytes { .. } 2943 | BitArrayOption::Int { .. } 2944 | BitArrayOption::Float { .. } 2945 | BitArrayOption::Bits { .. } 2946 | BitArrayOption::Utf8 { .. } 2947 | BitArrayOption::Utf16 { .. } 2948 | BitArrayOption::Utf32 { .. } 2949 | BitArrayOption::Utf8Codepoint { .. } 2950 | BitArrayOption::Utf16Codepoint { .. } 2951 | BitArrayOption::Utf32Codepoint { .. } 2952 | BitArrayOption::Signed { .. } 2953 | BitArrayOption::Unsigned { .. } 2954 | BitArrayOption::Big { .. } 2955 | BitArrayOption::Little { .. } 2956 | BitArrayOption::Unit { .. } 2957 | BitArrayOption::Native { .. } => im::hashset![], 2958 2959 BitArrayOption::Size { value, .. } => value.referenced_variables(), 2960 } 2961 } 2962} 2963 2964impl BitArrayOption<TypedPattern> { 2965 pub fn find_node(&self, byte_index: u32) -> Option<Located<'_>> { 2966 match self { 2967 BitArrayOption::Bytes { .. } 2968 | BitArrayOption::Int { .. } 2969 | BitArrayOption::Float { .. } 2970 | BitArrayOption::Bits { .. } 2971 | BitArrayOption::Utf8 { .. } 2972 | BitArrayOption::Utf16 { .. } 2973 | BitArrayOption::Utf32 { .. } 2974 | BitArrayOption::Utf8Codepoint { .. } 2975 | BitArrayOption::Utf16Codepoint { .. } 2976 | BitArrayOption::Utf32Codepoint { .. } 2977 | BitArrayOption::Signed { .. } 2978 | BitArrayOption::Unsigned { .. } 2979 | BitArrayOption::Big { .. } 2980 | BitArrayOption::Little { .. } 2981 | BitArrayOption::Native { .. } 2982 | BitArrayOption::Unit { .. } => None, 2983 BitArrayOption::Size { value, .. } => value.find_node(byte_index), 2984 } 2985 } 2986} 2987 2988impl BitArrayOption<TypedConstant> { 2989 pub fn find_node(&self, byte_index: u32) -> Option<Located<'_>> { 2990 match self { 2991 BitArrayOption::Bytes { .. } 2992 | BitArrayOption::Int { .. } 2993 | BitArrayOption::Float { .. } 2994 | BitArrayOption::Bits { .. } 2995 | BitArrayOption::Utf8 { .. } 2996 | BitArrayOption::Utf16 { .. } 2997 | BitArrayOption::Utf32 { .. } 2998 | BitArrayOption::Utf8Codepoint { .. } 2999 | BitArrayOption::Utf16Codepoint { .. } 3000 | BitArrayOption::Utf32Codepoint { .. } 3001 | BitArrayOption::Signed { .. } 3002 | BitArrayOption::Unsigned { .. } 3003 | BitArrayOption::Big { .. } 3004 | BitArrayOption::Little { .. } 3005 | BitArrayOption::Native { .. } 3006 | BitArrayOption::Unit { .. } => None, 3007 BitArrayOption::Size { value, .. } => value.find_node(byte_index), 3008 } 3009 } 3010} 3011 3012#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)] 3013pub enum TodoKind { 3014 Keyword, 3015 EmptyFunction { function_location: SrcSpan }, 3016 IncompleteUse, 3017 EmptyBlock, 3018} 3019 3020#[derive(Debug, Default)] 3021pub struct GroupedDefinitions { 3022 pub functions: Vec<UntypedFunction>, 3023 pub constants: Vec<UntypedModuleConstant>, 3024 pub custom_types: Vec<UntypedCustomType>, 3025 pub imports: Vec<UntypedImport>, 3026 pub type_aliases: Vec<UntypedTypeAlias>, 3027} 3028 3029impl GroupedDefinitions { 3030 pub fn new(definitions: impl IntoIterator<Item = UntypedDefinition>) -> Self { 3031 let mut this = Self::default(); 3032 3033 for definition in definitions { 3034 this.add(definition) 3035 } 3036 3037 this 3038 } 3039 3040 pub fn is_empty(&self) -> bool { 3041 self.len() == 0 3042 } 3043 3044 pub fn len(&self) -> usize { 3045 let Self { 3046 custom_types, 3047 functions, 3048 constants, 3049 imports, 3050 type_aliases, 3051 } = self; 3052 functions.len() + constants.len() + imports.len() + custom_types.len() + type_aliases.len() 3053 } 3054 3055 fn add(&mut self, statement: UntypedDefinition) { 3056 match statement { 3057 Definition::Import(import) => self.imports.push(import), 3058 Definition::Function(function) => self.functions.push(function), 3059 Definition::TypeAlias(type_alias) => self.type_aliases.push(type_alias), 3060 Definition::CustomType(custom_type) => self.custom_types.push(custom_type), 3061 Definition::ModuleConstant(constant) => self.constants.push(constant), 3062 } 3063 } 3064} 3065 3066/// A statement with in a function body. 3067#[derive(Debug, Clone, PartialEq, Eq)] 3068pub enum Statement<TypeT, ExpressionT> { 3069 /// A bare expression that is not assigned to any variable. 3070 Expression(ExpressionT), 3071 /// Assigning an expression to variables using a pattern. 3072 Assignment(Box<Assignment<TypeT, ExpressionT>>), 3073 /// A `use` expression. 3074 Use(Use<TypeT, ExpressionT>), 3075 /// A bool assertion. 3076 Assert(Assert<ExpressionT>), 3077} 3078 3079pub type UntypedUse = Use<(), UntypedExpr>; 3080pub type TypedUse = Use<Arc<Type>, TypedExpr>; 3081 3082#[derive(Debug, Clone, PartialEq, Eq)] 3083pub struct Use<TypeT, ExpressionT> { 3084 /// In an untyped use this is the expression with the untyped code of the 3085 /// callback function. 3086 /// 3087 /// In a typed use this is the typed function call the use expression 3088 /// desugars to. 3089 /// 3090 pub call: Box<ExpressionT>, 3091 3092 /// This is the location of the whole use line, starting from the `use` 3093 /// keyword and ending with the function call on the right hand side of 3094 /// `<-`. 3095 /// 3096 /// ```gleam 3097 /// use a <- result.try(result) 3098 /// ^^^^^^^^^^^^^^^^^^^^^^^^^^^ 3099 /// ``` 3100 /// 3101 pub location: SrcSpan, 3102 3103 /// This is the location of the expression on the right hand side of the use 3104 /// arrow. 3105 /// 3106 /// ```gleam 3107 /// use a <- result.try(result) 3108 /// ^^^^^^^^^^^^^^^^^^ 3109 /// ``` 3110 /// 3111 pub right_hand_side_location: SrcSpan, 3112 3113 /// This is the SrcSpan of the patterns you find on the left hand side of 3114 /// `<-` in a use expression. 3115 /// 3116 /// ```gleam 3117 /// use pattern1, pattern2 <- todo 3118 /// ^^^^^^^^^^^^^^^^^^ 3119 /// ``` 3120 /// 3121 /// In case there's no patterns it will be corresponding to the SrcSpan of 3122 /// the `use` keyword itself. 3123 /// 3124 pub assignments_location: SrcSpan, 3125 3126 /// The patterns on the left hand side of `<-` in a use expression. 3127 /// 3128 pub assignments: Vec<UseAssignment<TypeT>>, 3129} 3130 3131pub type UntypedUseAssignment = UseAssignment<()>; 3132pub type TypedUseAssignment = UseAssignment<Arc<Type>>; 3133 3134#[derive(Debug, Clone, PartialEq, Eq)] 3135pub struct UseAssignment<TypeT> { 3136 pub location: SrcSpan, 3137 pub pattern: Pattern<TypeT>, 3138 pub annotation: Option<TypeAst>, 3139} 3140 3141impl TypedUse { 3142 pub fn find_node(&self, byte_index: u32) -> Option<Located<'_>> { 3143 for assignment in self.assignments.iter() { 3144 if let Some(found) = assignment.pattern.find_node(byte_index) { 3145 return Some(found); 3146 } 3147 if let Some(found) = assignment 3148 .annotation 3149 .as_ref() 3150 .and_then(|annotation| annotation.find_node(byte_index, assignment.pattern.type_())) 3151 { 3152 return Some(found); 3153 } 3154 } 3155 self.call.find_node(byte_index) 3156 } 3157 3158 pub fn callback_arguments(&self) -> Option<&Vec<TypedArg>> { 3159 let TypedExpr::Call { args, .. } = self.call.as_ref() else { 3160 return None; 3161 }; 3162 let callback = args.iter().last()?; 3163 let TypedExpr::Fn { args, .. } = &callback.value else { 3164 // The expression might be invalid so we have to return a None here 3165 return None; 3166 }; 3167 Some(args) 3168 } 3169} 3170 3171pub type TypedStatement = Statement<Arc<Type>, TypedExpr>; 3172pub type UntypedStatement = Statement<(), UntypedExpr>; 3173 3174impl<T, E> Statement<T, E> { 3175 /// Returns `true` if the statement is [`Expression`]. 3176 /// 3177 /// [`Expression`]: Statement::Expression 3178 #[must_use] 3179 pub fn is_expression(&self) -> bool { 3180 matches!(self, Self::Expression(..)) 3181 } 3182 3183 #[must_use] 3184 pub(crate) fn is_use(&self) -> bool { 3185 match self { 3186 Self::Use(_) => true, 3187 _ => false, 3188 } 3189 } 3190} 3191 3192impl UntypedStatement { 3193 pub fn location(&self) -> SrcSpan { 3194 match self { 3195 Statement::Expression(expression) => expression.location(), 3196 Statement::Assignment(assignment) => assignment.location, 3197 Statement::Use(use_) => use_.location, 3198 Statement::Assert(assert) => assert.location, 3199 } 3200 } 3201 3202 pub fn start_byte_index(&self) -> u32 { 3203 match self { 3204 Statement::Expression(expression) => expression.start_byte_index(), 3205 Statement::Assignment(assignment) => assignment.location.start, 3206 Statement::Use(use_) => use_.location.start, 3207 Statement::Assert(assert) => assert.location.start, 3208 } 3209 } 3210 3211 pub fn is_placeholder(&self) -> bool { 3212 match self { 3213 Statement::Expression(expression) => expression.is_placeholder(), 3214 Statement::Assignment(_) | Statement::Use(_) | Statement::Assert(_) => false, 3215 } 3216 } 3217} 3218 3219impl TypedStatement { 3220 pub fn is_println(&self) -> bool { 3221 match self { 3222 Statement::Expression(e) => e.is_println(), 3223 Statement::Assignment(_) => false, 3224 Statement::Use(_) => false, 3225 Statement::Assert(_) => false, 3226 } 3227 } 3228 3229 pub fn location(&self) -> SrcSpan { 3230 match self { 3231 Statement::Expression(expression) => expression.location(), 3232 Statement::Assignment(assignment) => assignment.location, 3233 Statement::Use(use_) => use_.location, 3234 Statement::Assert(assert) => assert.location, 3235 } 3236 } 3237 3238 /// Returns the location of the last element of a statement. This means that 3239 /// if the statement is a use you'll get the location of the last item at 3240 /// the end of its block. 3241 pub fn last_location(&self) -> SrcSpan { 3242 match self { 3243 Statement::Expression(expression) => expression.last_location(), 3244 Statement::Assignment(assignment) => assignment.value.last_location(), 3245 Statement::Use(use_) => use_.call.last_location(), 3246 Statement::Assert(assert) => assert.value.last_location(), 3247 } 3248 } 3249 3250 pub fn type_(&self) -> Arc<Type> { 3251 match self { 3252 Statement::Expression(expression) => expression.type_(), 3253 Statement::Assignment(assignment) => assignment.type_(), 3254 Statement::Use(use_) => use_.call.type_(), 3255 Statement::Assert(_) => nil(), 3256 } 3257 } 3258 3259 pub fn definition_location(&self) -> Option<DefinitionLocation> { 3260 match self { 3261 Statement::Expression(expression) => expression.definition_location(), 3262 Statement::Assignment(_) => None, 3263 Statement::Use(use_) => use_.call.definition_location(), 3264 Statement::Assert(_) => None, 3265 } 3266 } 3267 3268 pub fn find_node(&self, byte_index: u32) -> Option<Located<'_>> { 3269 match self { 3270 Statement::Use(use_) => use_.find_node(byte_index), 3271 Statement::Expression(expression) => expression.find_node(byte_index), 3272 Statement::Assignment(assignment) => assignment.find_node(byte_index).or_else(|| { 3273 if assignment.location.contains(byte_index) { 3274 Some(Located::Statement(self)) 3275 } else { 3276 None 3277 } 3278 }), 3279 Statement::Assert(assert) => assert.find_node(byte_index).or_else(|| { 3280 if assert.location.contains(byte_index) { 3281 Some(Located::Statement(self)) 3282 } else { 3283 None 3284 } 3285 }), 3286 } 3287 } 3288 3289 pub fn find_statement(&self, byte_index: u32) -> Option<&TypedStatement> { 3290 match self { 3291 Statement::Use(use_) => use_.call.find_statement(byte_index), 3292 Statement::Expression(expression) => expression.find_statement(byte_index), 3293 Statement::Assignment(assignment) => { 3294 assignment.value.find_statement(byte_index).or_else(|| { 3295 if assignment.location.contains(byte_index) { 3296 Some(self) 3297 } else { 3298 None 3299 } 3300 }) 3301 } 3302 Statement::Assert(assert) => assert.value.find_statement(byte_index).or_else(|| { 3303 if assert.location.contains(byte_index) { 3304 Some(self) 3305 } else { 3306 None 3307 } 3308 }), 3309 } 3310 } 3311 3312 pub fn type_defining_location(&self) -> SrcSpan { 3313 match self { 3314 Statement::Expression(expression) => expression.type_defining_location(), 3315 Statement::Assignment(assignment) => assignment.location, 3316 Statement::Use(use_) => use_.location, 3317 Statement::Assert(assert) => assert.location, 3318 } 3319 } 3320 3321 fn is_pure_value_constructor(&self) -> bool { 3322 match self { 3323 Statement::Expression(expression) => expression.is_pure_value_constructor(), 3324 Statement::Assignment(assignment) => { 3325 // A let assert is not considered a pure value constructor 3326 // as it could crash the program! 3327 !assignment.kind.is_assert() && assignment.value.is_pure_value_constructor() 3328 } 3329 Statement::Use(Use { call, .. }) => call.is_pure_value_constructor(), 3330 // Assert statements by definition are not pure 3331 Statement::Assert(_) => false, 3332 } 3333 } 3334} 3335 3336#[derive(Debug, Clone, PartialEq, Eq)] 3337pub struct Assignment<TypeT, ExpressionT> { 3338 pub location: SrcSpan, 3339 pub value: ExpressionT, 3340 pub pattern: Pattern<TypeT>, 3341 pub kind: AssignmentKind<ExpressionT>, 3342 pub compiled_case: CompiledCase, 3343 /// This will be true for assignments that are automatically generated by 3344 /// the compiler. 3345 pub annotation: Option<TypeAst>, 3346} 3347 3348pub type TypedAssignment = Assignment<Arc<Type>, TypedExpr>; 3349pub type UntypedAssignment = Assignment<(), UntypedExpr>; 3350 3351impl TypedAssignment { 3352 pub fn find_node(&self, byte_index: u32) -> Option<Located<'_>> { 3353 if let Some(annotation) = &self.annotation { 3354 if let Some(l) = annotation.find_node(byte_index, self.pattern.type_()) { 3355 return Some(l); 3356 } 3357 } 3358 self.pattern 3359 .find_node(byte_index) 3360 .or_else(|| self.value.find_node(byte_index)) 3361 } 3362 3363 pub fn type_(&self) -> Arc<Type> { 3364 self.value.type_() 3365 } 3366} 3367 3368pub type TypedAssert = Assert<TypedExpr>; 3369pub type UntypedAssert = Assert<UntypedExpr>; 3370 3371#[derive(Debug, Clone, PartialEq, Eq)] 3372pub struct Assert<Expression> { 3373 pub location: SrcSpan, 3374 pub value: Expression, 3375 pub message: Option<Expression>, 3376} 3377 3378impl TypedAssert { 3379 pub fn find_node(&self, byte_index: u32) -> Option<Located<'_>> { 3380 if let Some(found) = self.value.find_node(byte_index) { 3381 return Some(found); 3382 } 3383 if let Some(message) = &self.message { 3384 if let Some(found) = message.find_node(byte_index) { 3385 return Some(found); 3386 } 3387 } 3388 None 3389 } 3390} 3391 3392/// A pipeline is desugared to a series of assignments: 3393/// 3394/// ```gleam 3395/// wibble |> wobble |> woo 3396/// ``` 3397/// 3398/// Becomes: 3399/// 3400/// ```erl 3401/// Pipe1 = wibble 3402/// Pipe2 = wobble(Pipe1) 3403/// woo(Pipe2) 3404/// ``` 3405/// 3406/// This represents one of such assignments once the pipeline has been desugared 3407/// and each step has been typed. 3408/// 3409/// > We're not using a more general `TypedAssignment` node since that has much 3410/// > more informations to carry around. This one is limited since we know it 3411/// > will always be in the form `VarName = <Expr>`, with no patterns on the 3412/// > left hand side of the assignment. 3413/// > Being more constrained simplifies code generation for pipelines! 3414/// 3415#[derive(Debug, Clone, PartialEq, Eq)] 3416pub struct TypedPipelineAssignment { 3417 pub location: SrcSpan, 3418 pub name: EcoString, 3419 pub value: Box<TypedExpr>, 3420} 3421 3422impl TypedPipelineAssignment { 3423 pub fn find_node(&self, byte_index: u32) -> Option<Located<'_>> { 3424 self.value.find_node(byte_index) 3425 } 3426 3427 pub fn find_statement(&self, byte_index: u32) -> Option<&TypedStatement> { 3428 self.value.find_statement(byte_index) 3429 } 3430 3431 pub fn type_(&self) -> Arc<Type> { 3432 self.value.type_() 3433 } 3434} 3435 3436/// The kind of desugaring that might take place when rewriting a pipeline to 3437/// regular assignments. 3438/// 3439#[derive(Debug, Clone, Copy, PartialEq, Eq)] 3440pub enum PipelineAssignmentKind { 3441 /// In case `a |> b(c)` is desugared to `b(a, c)`. 3442 FirstArgument { 3443 /// The location of the second argument of the call, in case there's any: 3444 /// - `a |> b(c, d)`: here it's `Some` wrapping the location of `c`. 3445 /// - `a |> b()`: here it's `None`. 3446 second_argument: Option<SrcSpan>, 3447 }, 3448 3449 /// In case there's an explicit hole and `a |> b(_, c)` is desugared to 3450 /// `b(a, c)`. 3451 Hole { hole: SrcSpan }, 3452 3453 /// In case `a |> b(c)` is desugared to `b(c)(a)` 3454 FunctionCall, 3455 3456 /// In case there's an echo in the middle of a pipeline `a |> echo` 3457 Echo, 3458}