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 / constant.rs
16 kB 481 lines
1use super::*; 2use crate::analyse::Inferred; 3use crate::type_::{FieldMap, HasType}; 4 5pub type TypedConstant = Constant<Arc<Type>, EcoString>; 6pub type UntypedConstant = Constant<(), ()>; 7 8// TODO: remove RecordTag paramter 9#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] 10pub enum Constant<T, RecordTag> { 11 Int { 12 location: SrcSpan, 13 value: EcoString, 14 int_value: BigInt, 15 }, 16 17 Float { 18 location: SrcSpan, 19 value: EcoString, 20 float_value: LiteralFloatValue, 21 }, 22 23 String { 24 location: SrcSpan, 25 value: EcoString, 26 }, 27 28 Tuple { 29 location: SrcSpan, 30 elements: Vec<Self>, 31 type_: T, 32 }, 33 34 List { 35 location: SrcSpan, 36 elements: Vec<Self>, 37 type_: T, 38 tail: Option<Box<Self>>, 39 }, 40 41 Record { 42 location: SrcSpan, 43 module: Option<(EcoString, SrcSpan)>, 44 name: EcoString, 45 arguments: Vec<CallArg<Self>>, 46 tag: RecordTag, 47 type_: T, 48 field_map: Inferred<FieldMap>, 49 record_constructor: Option<Box<ValueConstructor>>, 50 }, 51 52 RecordUpdate { 53 location: SrcSpan, 54 constructor_location: SrcSpan, 55 module: Option<(EcoString, SrcSpan)>, 56 name: EcoString, 57 record: RecordBeingUpdated<Self>, 58 arguments: Vec<RecordUpdateArg<Self>>, 59 tag: RecordTag, 60 type_: T, 61 field_map: Inferred<FieldMap>, 62 }, 63 64 BitArray { 65 location: SrcSpan, 66 segments: Vec<BitArraySegment<Self, T>>, 67 }, 68 69 Var { 70 location: SrcSpan, 71 module: Option<(EcoString, SrcSpan)>, 72 name: EcoString, 73 constructor: Option<Box<ValueConstructor>>, 74 type_: T, 75 }, 76 77 StringConcatenation { 78 location: SrcSpan, 79 left: Box<Self>, 80 right: Box<Self>, 81 }, 82 83 /// A placeholder constant used to allow module analysis to continue 84 /// even when there are type errors. Should never end up in generated code. 85 Invalid { 86 location: SrcSpan, 87 type_: T, 88 /// Extra information about the invalid expression, useful for providing 89 /// addition help or information, such as code actions to fix invalid 90 /// states. 91 extra_information: Option<InvalidExpression>, 92 }, 93} 94 95impl TypedConstant { 96 pub fn type_(&self) -> Arc<Type> { 97 match self { 98 Constant::Int { .. } => type_::int(), 99 Constant::Float { .. } => type_::float(), 100 Constant::String { .. } | Constant::StringConcatenation { .. } => type_::string(), 101 Constant::BitArray { .. } => type_::bit_array(), 102 103 Constant::List { type_, .. } 104 | Constant::Tuple { type_, .. } 105 | Constant::Record { type_, .. } 106 | Constant::RecordUpdate { type_, .. } 107 | Constant::Var { type_, .. } 108 | Constant::Invalid { type_, .. } => type_.clone(), 109 } 110 } 111 112 pub fn find_node(&self, byte_index: u32) -> Option<Located<'_>> { 113 if !self.location().contains(byte_index) { 114 return None; 115 } 116 Some(match self { 117 Constant::Int { .. } 118 | Constant::Float { .. } 119 | Constant::String { .. } 120 | Constant::Invalid { .. } => Located::Constant(self), 121 Constant::Var { 122 module: Some((module_alias, location)), 123 constructor: Some(constructor), 124 .. 125 } 126 | Constant::Record { 127 module: Some((module_alias, location)), 128 record_constructor: Some(constructor), 129 .. 130 } if location.contains(byte_index) => match &constructor.variant { 131 ValueConstructorVariant::ModuleConstant { module, .. } 132 | ValueConstructorVariant::ModuleFn { module, .. } 133 | ValueConstructorVariant::Record { module, .. } => Located::ModuleName { 134 location: *location, 135 module_name: module.clone(), 136 module_alias: module_alias.clone(), 137 layer: Layer::Value, 138 }, 139 ValueConstructorVariant::LocalVariable { .. } => Located::Constant(self), 140 }, 141 Constant::Var { .. } => Located::Constant(self), 142 Constant::Tuple { elements, .. } => elements 143 .iter() 144 .find_map(|element| element.find_node(byte_index)) 145 .unwrap_or(Located::Constant(self)), 146 Constant::List { elements, tail, .. } => elements 147 .iter() 148 .find_map(|element| element.find_node(byte_index)) 149 .or_else(|| tail.as_deref().and_then(|tail| tail.find_node(byte_index))) 150 .unwrap_or(Located::Constant(self)), 151 Constant::Record { arguments, .. } => arguments 152 .iter() 153 .find_map(|argument| argument.find_node(byte_index)) 154 .unwrap_or(Located::Constant(self)), 155 Constant::RecordUpdate { 156 record, arguments, .. 157 } => record 158 .base 159 .find_node(byte_index) 160 .or_else(|| { 161 arguments 162 .iter() 163 .find_map(|arg| arg.value.find_node(byte_index)) 164 }) 165 .unwrap_or(Located::Constant(self)), 166 Constant::BitArray { segments, .. } => segments 167 .iter() 168 .find_map(|segment| segment.find_node(byte_index)) 169 .unwrap_or(Located::Constant(self)), 170 Constant::StringConcatenation { left, right, .. } => left 171 .find_node(byte_index) 172 .or_else(|| right.find_node(byte_index)) 173 .unwrap_or(Located::Constant(self)), 174 }) 175 } 176 177 pub fn definition_location(&self) -> Option<DefinitionLocation> { 178 match self { 179 Constant::Int { .. } 180 | Constant::Float { .. } 181 | Constant::String { .. } 182 | Constant::Tuple { .. } 183 | Constant::List { .. } 184 | Constant::BitArray { .. } 185 | Constant::StringConcatenation { .. } 186 | Constant::Invalid { .. } => None, 187 Constant::Record { 188 record_constructor: value_constructor, 189 .. 190 } 191 | Constant::Var { 192 constructor: value_constructor, 193 .. 194 } => value_constructor 195 .as_ref() 196 .map(|constructor| constructor.definition_location()), 197 Constant::RecordUpdate { .. } => None, 198 } 199 } 200 201 pub(crate) fn referenced_variables(&self) -> im::HashSet<&EcoString> { 202 match self { 203 Constant::Var { name, .. } => im::hashset![name], 204 205 Constant::Invalid { .. } 206 | Constant::Int { .. } 207 | Constant::Float { .. } 208 | Constant::String { .. } => im::hashset![], 209 210 Constant::List { elements, .. } | Constant::Tuple { elements, .. } => elements 211 .iter() 212 .map(|element| element.referenced_variables()) 213 .fold(im::hashset![], im::HashSet::union), 214 215 Constant::Record { arguments, .. } => arguments 216 .iter() 217 .map(|argument| argument.value.referenced_variables()) 218 .fold(im::hashset![], im::HashSet::union), 219 220 Constant::RecordUpdate { 221 record, arguments, .. 222 } => record.base.referenced_variables().union( 223 arguments 224 .iter() 225 .map(|arg| arg.value.referenced_variables()) 226 .fold(im::hashset![], im::HashSet::union), 227 ), 228 229 Constant::BitArray { segments, .. } => segments 230 .iter() 231 .map(|segment| { 232 segment 233 .options 234 .iter() 235 .map(|option| option.referenced_variables()) 236 .fold(segment.value.referenced_variables(), im::HashSet::union) 237 }) 238 .fold(im::hashset![], im::HashSet::union), 239 240 Constant::StringConcatenation { left, right, .. } => left 241 .referenced_variables() 242 .union(right.referenced_variables()), 243 } 244 } 245 246 pub(crate) fn syntactically_eq(&self, other: &Self) -> bool { 247 match (self, other) { 248 (Constant::Int { int_value: n, .. }, Constant::Int { int_value: m, .. }) => n == m, 249 (Constant::Int { .. }, _) => false, 250 251 (Constant::Float { float_value: n, .. }, Constant::Float { float_value: m, .. }) => { 252 n == m 253 } 254 (Constant::Float { .. }, _) => false, 255 256 ( 257 Constant::String { value, .. }, 258 Constant::String { 259 value: other_value, .. 260 }, 261 ) => value == other_value, 262 (Constant::String { .. }, _) => false, 263 264 ( 265 Constant::Tuple { elements, .. }, 266 Constant::Tuple { 267 elements: other_elements, 268 .. 269 }, 270 ) => pairwise_all(elements, other_elements, |(one, other)| { 271 one.syntactically_eq(other) 272 }), 273 (Constant::Tuple { .. }, _) => false, 274 275 ( 276 Constant::List { elements, .. }, 277 Constant::List { 278 elements: other_elements, 279 .. 280 }, 281 ) => pairwise_all(elements, other_elements, |(one, other)| { 282 one.syntactically_eq(other) 283 }), 284 (Constant::List { .. }, _) => false, 285 286 ( 287 Constant::Record { 288 module, 289 name, 290 arguments, 291 .. 292 }, 293 Constant::Record { 294 module: other_module, 295 name: other_name, 296 arguments: other_arguments, 297 .. 298 }, 299 ) => { 300 let modules_are_equal = match (module, other_module) { 301 (None, None) => true, 302 (None, Some(_)) | (Some(_), None) => false, 303 (Some((one, _)), Some((other, _))) => one == other, 304 }; 305 306 modules_are_equal 307 && name == other_name 308 && pairwise_all(arguments, other_arguments, |(one, other)| { 309 one.label == other.label && one.value.syntactically_eq(&other.value) 310 }) 311 } 312 (Constant::Record { .. }, _) => false, 313 314 ( 315 Constant::RecordUpdate { 316 module, 317 name, 318 record, 319 arguments, 320 .. 321 }, 322 Constant::RecordUpdate { 323 module: other_module, 324 name: other_name, 325 record: other_record, 326 arguments: other_arguments, 327 .. 328 }, 329 ) => { 330 let modules_are_equal = match (module, other_module) { 331 (None, None) => true, 332 (None, Some(_)) | (Some(_), None) => false, 333 (Some((one, _)), Some((other, _))) => one == other, 334 }; 335 336 modules_are_equal 337 && name == other_name 338 && record.base.syntactically_eq(&other_record.base) 339 && pairwise_all(arguments, other_arguments, |(one, other)| { 340 one.label == other.label && one.value.syntactically_eq(&other.value) 341 }) 342 } 343 (Constant::RecordUpdate { .. }, _) => false, 344 345 ( 346 Constant::BitArray { segments, .. }, 347 Constant::BitArray { 348 segments: other_segments, 349 .. 350 }, 351 ) => pairwise_all(segments, other_segments, |(one, other)| { 352 one.syntactically_eq(other) 353 }), 354 (Constant::BitArray { .. }, _) => false, 355 356 ( 357 Constant::Var { module, name, .. }, 358 Constant::Var { 359 module: other_module, 360 name: other_name, 361 .. 362 }, 363 ) => { 364 let modules_are_equal = match (module, other_module) { 365 (None, None) => true, 366 (None, Some(_)) | (Some(_), None) => false, 367 (Some((one, _)), Some((other, _))) => one == other, 368 }; 369 370 modules_are_equal && name == other_name 371 } 372 (Constant::Var { .. }, _) => false, 373 374 ( 375 Constant::StringConcatenation { left, right, .. }, 376 Constant::StringConcatenation { 377 left: other_left, 378 right: other_right, 379 .. 380 }, 381 ) => left.syntactically_eq(other_left) && right.syntactically_eq(other_right), 382 (Constant::StringConcatenation { .. }, _) => false, 383 384 (Constant::Invalid { .. }, _) => false, 385 } 386 } 387 388 pub fn list_elements(&self) -> Option<Vec<&Self>> { 389 match self { 390 Constant::List { elements, tail, .. } => Some( 391 elements 392 .iter() 393 .chain( 394 tail.as_deref() 395 .and_then(|tail| tail.list_elements()) 396 .unwrap_or_default() 397 .into_iter(), 398 ) 399 .collect(), 400 ), 401 Constant::Var { 402 constructor: Some(constructor), 403 .. 404 } => match &constructor.variant { 405 ValueConstructorVariant::ModuleConstant { literal, .. } => literal.list_elements(), 406 ValueConstructorVariant::LocalVariable { .. } 407 | ValueConstructorVariant::ModuleFn { .. } 408 | ValueConstructorVariant::Record { .. } => None, 409 }, 410 411 Constant::Int { .. } 412 | Constant::Float { .. } 413 | Constant::String { .. } 414 | Constant::Tuple { .. } 415 | Constant::Record { .. } 416 | Constant::RecordUpdate { .. } 417 | Constant::BitArray { .. } 418 | Constant::StringConcatenation { .. } 419 | Constant::Var { .. } 420 | Constant::Invalid { .. } => None, 421 } 422 } 423} 424 425impl HasType for TypedConstant { 426 fn type_(&self) -> Arc<Type> { 427 self.type_() 428 } 429} 430 431impl<A, B> Constant<A, B> { 432 pub fn location(&self) -> SrcSpan { 433 match self { 434 Constant::Int { location, .. } 435 | Constant::List { location, .. } 436 | Constant::Float { location, .. } 437 | Constant::Tuple { location, .. } 438 | Constant::String { location, .. } 439 | Constant::Record { location, .. } 440 | Constant::RecordUpdate { location, .. } 441 | Constant::BitArray { location, .. } 442 | Constant::Var { location, .. } 443 | Constant::Invalid { location, .. } 444 | Constant::StringConcatenation { location, .. } => *location, 445 } 446 } 447 448 #[must_use] 449 pub fn can_have_multiple_per_line(&self) -> bool { 450 match self { 451 Constant::Int { .. } 452 | Constant::Float { .. } 453 | Constant::String { .. } 454 | Constant::Var { .. } => true, 455 456 Constant::Tuple { .. } 457 | Constant::List { .. } 458 | Constant::Record { .. } 459 | Constant::RecordUpdate { .. } 460 | Constant::BitArray { .. } 461 | Constant::StringConcatenation { .. } 462 | Constant::Invalid { .. } => false, 463 } 464 } 465} 466 467impl<A, B> HasLocation for Constant<A, B> { 468 fn location(&self) -> SrcSpan { 469 self.location() 470 } 471} 472 473impl<A, B> bit_array::GetLiteralValue for Constant<A, B> { 474 fn as_int_literal(&self) -> Option<BigInt> { 475 if let Constant::Int { int_value, .. } = self { 476 Some(int_value.clone()) 477 } else { 478 None 479 } 480 } 481}