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 / metadata / module_encoder.rs
21 kB 527 lines
1use ecow::EcoString; 2 3use crate::{ 4 ast::{ 5 Constant, Publicity, SrcSpan, TypedConstant, TypedConstantBitArraySegment, 6 TypedConstantBitArraySegmentOption, 7 }, 8 schema_capnp::{self as schema, *}, 9 type_::{ 10 self, expression::Implementations, AccessorsMap, Deprecation, FieldMap, RecordAccessor, 11 Type, TypeConstructor, TypeValueConstructor, TypeVar, TypeVariantConstructors, 12 ValueConstructor, ValueConstructorVariant, 13 }, 14}; 15use std::{collections::HashMap, ops::Deref, sync::Arc}; 16 17#[derive(Debug)] 18pub struct ModuleEncoder<'a> { 19 data: &'a type_::ModuleInterface, 20 next_type_var_id: u64, 21 type_var_id_map: HashMap<u64, u64>, 22} 23 24impl<'a> ModuleEncoder<'a> { 25 pub fn new(data: &'a type_::ModuleInterface) -> Self { 26 Self { 27 data, 28 next_type_var_id: 0, 29 type_var_id_map: HashMap::new(), 30 } 31 } 32 33 pub fn encode(mut self) -> crate::Result<Vec<u8>> { 34 let span = tracing::info_span!("metadata"); 35 let _enter = span.enter(); 36 let mut buffer = Vec::new(); 37 38 let mut message = capnp::message::Builder::new_default(); 39 40 let mut module = message.init_root::<module::Builder<'_>>(); 41 module.set_name(&self.data.name); 42 module.set_package(&self.data.package); 43 module.set_contains_todo(self.data.contains_todo); 44 self.set_module_types(&mut module); 45 self.set_module_values(&mut module); 46 self.set_module_accessors(&mut module); 47 self.set_module_types_constructors(&mut module); 48 self.set_unused_imports(&mut module); 49 self.set_line_numbers(&mut module); 50 51 capnp::serialize_packed::write_message(&mut buffer, &message).expect("capnp encode"); 52 Ok(buffer) 53 } 54 55 fn set_line_numbers(&mut self, module: &mut module::Builder<'_>) { 56 let mut line_numbers = module.reborrow().init_line_numbers(); 57 line_numbers.set_length(self.data.line_numbers.length); 58 let line_starts = 59 line_numbers.init_line_starts(self.data.line_numbers.line_starts.len() as u32); 60 for (i, l) in self.data.line_numbers.line_starts.iter().enumerate() { 61 line_starts.reborrow().set(i as u32, *l); 62 } 63 } 64 65 fn set_unused_imports(&mut self, module: &mut module::Builder<'_>) { 66 let mut unused_imports = module 67 .reborrow() 68 .init_unused_imports(self.data.unused_imports.len() as u32); 69 for (i, span) in self.data.unused_imports.iter().enumerate() { 70 let unused_import = unused_imports.reborrow().get(i as u32); 71 self.build_src_span(unused_import, *span) 72 } 73 } 74 75 fn set_module_accessors(&mut self, module: &mut module::Builder<'_>) { 76 tracing::trace!("Writing module metadata accessors"); 77 let mut builder = module 78 .reborrow() 79 .init_accessors(self.data.accessors.len() as u32); 80 for (i, (key, map)) in self.data.accessors.iter().enumerate() { 81 let mut property = builder.reborrow().get(i as u32); 82 property.set_key(key); 83 self.build_accessors_map(property.init_value(), map); 84 } 85 } 86 87 fn build_accessors_map( 88 &mut self, 89 mut builder: accessors_map::Builder<'_>, 90 accessors: &AccessorsMap, 91 ) { 92 self.build_type(builder.reborrow().init_type(), &accessors.type_); 93 let mut builder = builder.init_accessors(accessors.accessors.len() as u32); 94 for (i, (name, accessor)) in accessors.accessors.iter().enumerate() { 95 let mut property = builder.reborrow().get(i as u32); 96 property.set_key(name); 97 self.build_record_accessor(property.init_value(), accessor) 98 } 99 } 100 101 fn build_record_accessor( 102 &mut self, 103 mut builder: record_accessor::Builder<'_>, 104 accessor: &RecordAccessor, 105 ) { 106 self.build_type(builder.reborrow().init_type(), &accessor.type_); 107 builder.reborrow().set_label(&accessor.label); 108 builder.set_index(accessor.index as u16); 109 } 110 111 fn set_module_types(&mut self, module: &mut module::Builder<'_>) { 112 tracing::trace!("Writing module metadata types"); 113 let mut types = module.reborrow().init_types(self.data.types.len() as u32); 114 for (i, (name, type_)) in self.data.types.iter().enumerate() { 115 let mut property = types.reborrow().get(i as u32); 116 property.set_key(name); 117 self.build_type_constructor(property.init_value(), type_) 118 } 119 } 120 121 fn set_module_types_constructors(&mut self, module: &mut module::Builder<'_>) { 122 tracing::trace!("Writing module metadata types to constructors mapping"); 123 let mut types_constructors = module 124 .reborrow() 125 .init_types_constructors(self.data.types_value_constructors.len() as u32); 126 for (i, (name, data)) in self.data.types_value_constructors.iter().enumerate() { 127 let mut property = types_constructors.reborrow().get(i as u32); 128 property.set_key(name); 129 self.build_type_variant_constructors(property.init_value(), data) 130 } 131 } 132 133 fn build_type_variant_constructors( 134 &mut self, 135 mut builder: types_variant_constructors::Builder<'_>, 136 data: &TypeVariantConstructors, 137 ) { 138 { 139 let mut builder = builder 140 .reborrow() 141 .init_type_parameters_ids(data.type_parameters_ids.len() as u32); 142 for (i, id) in data.type_parameters_ids.iter().enumerate() { 143 let id = self.get_or_insert_type_var_id(*id); 144 builder.set(i as u32, id as u16); 145 } 146 } 147 let mut builder = builder.init_variants(data.variants.len() as u32); 148 for (i, constructor) in data.variants.iter().enumerate() { 149 self.build_type_value_constructor(builder.reborrow().get(i as u32), constructor); 150 } 151 } 152 153 fn set_module_values(&mut self, module: &mut module::Builder<'_>) { 154 tracing::trace!("Writing module metadata values"); 155 let mut values = module.reborrow().init_values(self.data.values.len() as u32); 156 for (i, (name, value)) in self.data.values.iter().enumerate() { 157 let mut property = values.reborrow().get(i as u32); 158 property.set_key(name); 159 self.build_value_constructor(property.init_value(), value) 160 } 161 } 162 163 fn build_type_constructor( 164 &mut self, 165 mut builder: type_constructor::Builder<'_>, 166 constructor: &TypeConstructor, 167 ) { 168 builder.set_module(&constructor.module); 169 builder.set_deprecated(match &constructor.deprecation { 170 Deprecation::NotDeprecated => "", 171 Deprecation::Deprecated { message } => message, 172 }); 173 builder.set_publicity(self.publicity(constructor.publicity)); 174 let type_builder = builder.reborrow().init_type(); 175 self.build_type(type_builder, &constructor.typ); 176 self.build_types( 177 builder 178 .reborrow() 179 .init_parameters(constructor.parameters.len() as u32), 180 &constructor.parameters, 181 ); 182 } 183 184 fn build_type_value_constructor( 185 &mut self, 186 mut builder: type_value_constructor::Builder<'_>, 187 constructor: &TypeValueConstructor, 188 ) { 189 builder.set_name(&constructor.name); 190 let mut builder = builder.init_parameters(constructor.parameters.len() as u32); 191 for (i, parameter) in constructor.parameters.iter().enumerate() { 192 self.build_type_value_constructor_parameter( 193 builder.reborrow().get(i as u32), 194 parameter, 195 ); 196 } 197 } 198 199 fn build_type_value_constructor_parameter( 200 &mut self, 201 builder: type_value_constructor_parameter::Builder<'_>, 202 parameter: &type_::TypeValueConstructorField, 203 ) { 204 self.build_type(builder.init_type(), parameter.type_.as_ref()) 205 } 206 207 fn build_value_constructor( 208 &mut self, 209 mut builder: value_constructor::Builder<'_>, 210 constructor: &ValueConstructor, 211 ) { 212 builder.set_deprecated(match &constructor.deprecation { 213 Deprecation::NotDeprecated => "", 214 Deprecation::Deprecated { message } => message, 215 }); 216 builder.set_publicity(self.publicity(constructor.publicity)); 217 self.build_type(builder.reborrow().init_type(), &constructor.type_); 218 self.build_value_constructor_variant(builder.init_variant(), &constructor.variant); 219 } 220 221 fn publicity(&self, publicity: Publicity) -> crate::schema_capnp::Publicity { 222 match publicity { 223 Publicity::Public => crate::schema_capnp::Publicity::Public, 224 Publicity::Private => crate::schema_capnp::Publicity::Private, 225 Publicity::Internal => crate::schema_capnp::Publicity::Internal, 226 } 227 } 228 229 fn build_src_span(&mut self, mut builder: src_span::Builder<'_>, span: SrcSpan) { 230 builder.set_start(span.start); 231 builder.set_end(span.end); 232 } 233 234 fn build_value_constructor_variant( 235 &mut self, 236 builder: value_constructor_variant::Builder<'_>, 237 constructor: &ValueConstructorVariant, 238 ) { 239 match constructor { 240 ValueConstructorVariant::LocalVariable { .. } => { 241 panic!("Unexpected local variable value constructor in module interface",) 242 } 243 244 ValueConstructorVariant::LocalConstant { .. } => { 245 panic!("Unexpected local constant value constructor in module interface",) 246 } 247 248 ValueConstructorVariant::ModuleConstant { 249 literal, 250 location, 251 module, 252 documentation: doc, 253 implementations, 254 } => { 255 let mut builder = builder.init_module_constant(); 256 builder.set_documentation(doc.as_ref().map(EcoString::as_str).unwrap_or_default()); 257 self.build_src_span(builder.reborrow().init_location(), *location); 258 self.build_constant(builder.reborrow().init_literal(), literal); 259 builder.reborrow().set_module(module); 260 self.build_implementations(builder.init_implementations(), *implementations) 261 } 262 263 ValueConstructorVariant::Record { 264 name, 265 field_map, 266 arity, 267 location, 268 module, 269 constructors_count, 270 constructor_index, 271 documentation: doc, 272 } => { 273 let mut builder = builder.init_record(); 274 builder.set_name(name); 275 builder.set_module(module); 276 builder.set_arity(*arity); 277 builder.set_documentation(doc.as_ref().map(EcoString::as_str).unwrap_or_default()); 278 builder.set_constructors_count(*constructors_count); 279 builder.set_constructor_index(*constructor_index); 280 self.build_optional_field_map(builder.reborrow().init_field_map(), field_map); 281 self.build_src_span(builder.init_location(), *location); 282 } 283 284 ValueConstructorVariant::ModuleFn { 285 arity, 286 field_map, 287 module, 288 name, 289 location, 290 documentation: doc, 291 implementations, 292 } => { 293 let mut builder = builder.init_module_fn(); 294 builder.set_name(name); 295 builder.set_module(module); 296 builder.set_arity(*arity as u16); 297 builder.set_documentation(doc.as_ref().map(EcoString::as_str).unwrap_or_default()); 298 self.build_optional_field_map(builder.reborrow().init_field_map(), field_map); 299 self.build_src_span(builder.reborrow().init_location(), *location); 300 self.build_implementations(builder.init_implementations(), *implementations); 301 } 302 } 303 } 304 305 fn build_optional_field_map( 306 &mut self, 307 mut builder: option::Builder<'_, field_map::Owned>, 308 field_map: &Option<FieldMap>, 309 ) { 310 match field_map { 311 Some(field_map) => self.build_field_map(builder.init_some(), field_map), 312 None => builder.set_none(()), 313 }; 314 } 315 316 fn build_field_map(&mut self, mut builder: field_map::Builder<'_>, field_map: &FieldMap) { 317 builder.set_arity(field_map.arity); 318 let mut builder = builder.init_fields(field_map.fields.len() as u32); 319 for (i, (name, &position)) in field_map.fields.iter().enumerate() { 320 let mut field = builder.reborrow().get(i as u32); 321 field.set_key(name); 322 field.init_value().set_value(position); 323 } 324 } 325 326 fn build_constant(&mut self, mut builder: constant::Builder<'_>, constant: &TypedConstant) { 327 match constant { 328 Constant::Int { value, .. } => builder.set_int(value), 329 Constant::Float { value, .. } => builder.set_float(value), 330 Constant::String { value, .. } => builder.set_string(value), 331 332 Constant::Tuple { elements, .. } => { 333 self.build_constants(builder.init_tuple(elements.len() as u32), elements) 334 } 335 336 Constant::List { elements, typ, .. } => { 337 let mut builder = builder.init_list(); 338 self.build_constants( 339 builder.reborrow().init_elements(elements.len() as u32), 340 elements, 341 ); 342 self.build_type(builder.init_type(), typ); 343 } 344 345 Constant::BitArray { segments, .. } => { 346 let mut builder = builder.init_bit_array(segments.len() as u32); 347 for (i, segment) in segments.iter().enumerate() { 348 self.build_bit_array_segment(builder.reborrow().get(i as u32), segment); 349 } 350 } 351 352 Constant::Record { args, tag, typ, .. } => { 353 let mut builder = builder.init_record(); 354 { 355 let mut builder = builder.reborrow().init_args(args.len() as u32); 356 for (i, arg) in args.iter().enumerate() { 357 self.build_constant(builder.reborrow().get(i as u32), &arg.value); 358 } 359 } 360 builder.reborrow().set_tag(tag); 361 self.build_type(builder.reborrow().init_typ(), typ); 362 } 363 364 Constant::Var { 365 module, 366 name, 367 typ, 368 constructor, 369 .. 370 } => { 371 let mut builder = builder.init_var(); 372 match module { 373 Some(name) => builder.set_module(name), 374 None => builder.set_module(""), 375 }; 376 builder.set_name(name); 377 self.build_type(builder.reborrow().init_typ(), typ); 378 self.build_value_constructor( 379 builder.reborrow().init_constructor(), 380 constructor 381 .as_ref() 382 .expect("This is guaranteed to hold a value."), 383 ); 384 } 385 } 386 } 387 388 fn build_constants( 389 &mut self, 390 mut builder: capnp::struct_list::Builder<'_, constant::Owned>, 391 constant: &[TypedConstant], 392 ) { 393 for (i, constant) in constant.iter().enumerate() { 394 self.build_constant(builder.reborrow().get(i as u32), constant); 395 } 396 } 397 398 fn build_bit_array_segment( 399 &mut self, 400 mut builder: bit_array_segment::Builder<'_>, 401 segment: &TypedConstantBitArraySegment, 402 ) { 403 self.build_constant(builder.reborrow().init_value(), &segment.value); 404 { 405 let mut builder = builder 406 .reborrow() 407 .init_options(segment.options.len() as u32); 408 for (i, option) in segment.options.iter().enumerate() { 409 self.build_bit_array_segment_option(builder.reborrow().get(i as u32), option); 410 } 411 } 412 self.build_type(builder.init_type(), &segment.type_); 413 } 414 415 fn build_bit_array_segment_option( 416 &mut self, 417 mut builder: bit_array_segment_option::Builder<'_>, 418 option: &TypedConstantBitArraySegmentOption, 419 ) { 420 use crate::ast::TypedConstantBitArraySegmentOption as Opt; 421 match option { 422 Opt::Bytes { .. } => builder.set_bytes(()), 423 Opt::Int { .. } => builder.set_integer(()), 424 Opt::Float { .. } => builder.set_float(()), 425 Opt::Bits { .. } => builder.set_bits(()), 426 Opt::Utf8 { .. } => builder.set_utf8(()), 427 Opt::Utf16 { .. } => builder.set_utf16(()), 428 Opt::Utf32 { .. } => builder.set_utf32(()), 429 Opt::Utf8Codepoint { .. } => builder.set_utf8_codepoint(()), 430 Opt::Utf16Codepoint { .. } => builder.set_utf16_codepoint(()), 431 Opt::Utf32Codepoint { .. } => builder.set_utf32_codepoint(()), 432 Opt::Signed { .. } => builder.set_signed(()), 433 Opt::Unsigned { .. } => builder.set_unsigned(()), 434 Opt::Big { .. } => builder.set_big(()), 435 Opt::Little { .. } => builder.set_little(()), 436 Opt::Native { .. } => builder.set_native(()), 437 438 Opt::Size { 439 value, short_form, .. 440 } => { 441 let mut builder = builder.init_size(); 442 self.build_constant(builder.reborrow().init_value(), value); 443 builder.set_short_form(*short_form); 444 } 445 446 Opt::Unit { value, .. } => { 447 let mut builder = builder.init_unit(); 448 builder.set_value(*value); 449 } 450 } 451 } 452 453 fn build_type(&mut self, builder: schema::type_::Builder<'_>, type_: &Type) { 454 match type_ { 455 Type::Fn { args, retrn } => { 456 let mut fun = builder.init_fn(); 457 self.build_types(fun.reborrow().init_arguments(args.len() as u32), args); 458 self.build_type(fun.init_return(), retrn) 459 } 460 461 Type::Named { 462 name, 463 args, 464 module, 465 package, 466 .. 467 } => { 468 let mut app = builder.init_app(); 469 app.set_name(name); 470 app.set_module(module); 471 app.set_package(package); 472 self.build_types(app.reborrow().init_parameters(args.len() as u32), args); 473 } 474 475 Type::Tuple { elems } => self.build_types( 476 builder.init_tuple().init_elements(elems.len() as u32), 477 elems, 478 ), 479 480 Type::Var { type_: typ } => match typ.borrow().deref() { 481 TypeVar::Link { type_: typ } => self.build_type(builder, typ), 482 TypeVar::Unbound { id, .. } | TypeVar::Generic { id } => { 483 self.build_type_var(builder.init_var(), *id) 484 } 485 }, 486 } 487 } 488 489 fn build_types( 490 &mut self, 491 mut builder: capnp::struct_list::Builder<'_, schema::type_::Owned>, 492 types: &[Arc<Type>], 493 ) { 494 for (i, type_) in types.iter().enumerate() { 495 self.build_type(builder.reborrow().get(i as u32), type_); 496 } 497 } 498 499 fn build_type_var(&mut self, mut builder: schema::type_::var::Builder<'_>, id: u64) { 500 let serialised_id = self.get_or_insert_type_var_id(id); 501 builder.set_id(serialised_id); 502 } 503 504 fn get_or_insert_type_var_id(&mut self, id: u64) -> u64 { 505 match self.type_var_id_map.get(&id) { 506 Some(&id) => id, 507 None => { 508 let new_id = self.next_type_var_id; 509 self.next_type_var_id += 1; 510 let _ = self.type_var_id_map.insert(id, new_id); 511 new_id 512 } 513 } 514 } 515 516 fn build_implementations( 517 &self, 518 mut builder: implementations::Builder<'_>, 519 implementations: Implementations, 520 ) { 521 builder.set_gleam(implementations.gleam); 522 builder.set_uses_erlang_externals(implementations.uses_erlang_externals); 523 builder.set_uses_javascript_externals(implementations.uses_javascript_externals); 524 builder.set_can_run_on_erlang(implementations.can_run_on_erlang); 525 builder.set_can_run_on_javascript(implementations.can_run_on_javascript); 526 } 527}