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

Configure Feed

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

1use std::ops::Deref; 2 3use ecow::{EcoString, eco_format}; 4use im::HashSet; 5use num_bigint::BigInt; 6use vec1::Vec1; 7 8use crate::{ast, exhaustiveness, parse, type_}; 9 10#[derive(Debug, Default)] 11pub struct Module { 12 functions: Vec<Function>, 13} 14 15#[derive(Debug)] 16pub struct Function { 17 pub name: EcoString, 18 pub return_type: Type, 19 pub parameters: Vec<FunctionParameter>, 20 pub body: Expression, 21} 22 23#[derive(Debug)] 24pub struct FunctionParameter { 25 pub type_: Type, 26 pub name: Option<EcoString>, 27} 28 29#[derive(Debug, Default)] 30pub struct Translator { 31 module: Module, 32} 33 34#[derive(Debug, Clone, Copy)] 35pub enum Type { 36 Int, 37 Float, 38 Bool, 39 Generic, 40} 41 42#[derive(Debug)] 43pub enum Expression { 44 Block(Vec<Expression>), 45 46 Var { 47 name: EcoString, 48 }, 49 50 Int { 51 value: BigInt, 52 }, 53 54 Equals { 55 lhs: Box<Expression>, 56 rhs: Box<Expression>, 57 }, 58 59 IntAdd { 60 lhs: Box<Expression>, 61 rhs: Box<Expression>, 62 }, 63 64 Set { 65 name: EcoString, 66 value: Box<Expression>, 67 }, 68 69 If { 70 cond: Box<Expression>, 71 then: Box<Expression>, 72 else_: Box<Expression>, 73 }, 74} 75 76impl Translator { 77 pub fn translate(mut self, module: &ast::TypedModule) -> Module { 78 for definition in &module.definitions { 79 match definition { 80 ast::Definition::Function(function) => { 81 self.module 82 .functions 83 .push(Self::translate_function(function)); 84 } 85 ast::Definition::TypeAlias(_type_alias) => todo!(), 86 ast::Definition::CustomType(_custom_type) => todo!(), 87 ast::Definition::Import(_import) => todo!(), 88 ast::Definition::ModuleConstant(_module_constant) => todo!(), 89 } 90 } 91 92 self.module 93 } 94 95 fn translate_function(function: &ast::TypedFunction) -> Function { 96 let (_, name) = function.name.clone().expect("function should have a name"); 97 98 let return_type = Self::translate_type(&function.return_type); 99 100 let parameters = Iterator::collect(function.arguments.iter().map(|argument| { 101 let name = argument.get_variable_name().cloned(); 102 let type_ = Self::translate_type(&argument.type_); 103 104 FunctionParameter { name, type_ } 105 })); 106 107 let body = BodyTranslator::default().translate(&function.body); 108 109 Function { 110 name, 111 body, 112 return_type, 113 parameters, 114 } 115 } 116 117 fn translate_type(type_: &type_::Type) -> Type { 118 match type_ { 119 type_::Type::Named { 120 publicity: _, 121 package: _, 122 module, 123 name, 124 arguments: _, 125 inferred_variant: _, 126 } => match (module.as_str(), name.as_str()) { 127 ("gleam", "Int") => Type::Int, 128 ("gleam", "Float") => Type::Float, 129 ("gleam", "Bool") => Type::Bool, 130 (_, _) => todo!(), 131 }, 132 type_::Type::Fn { 133 arguments: _, 134 return_: _, 135 } => todo!(), 136 type_::Type::Var { type_ } => match type_.borrow().deref() { 137 type_::TypeVar::Link { type_ } => Self::translate_type(type_), 138 type_::TypeVar::Unbound { id: _ } | type_::TypeVar::Generic { id: _ } => { 139 Type::Generic 140 } 141 }, 142 type_::Type::Tuple { elements: _ } => todo!(), 143 } 144 } 145} 146 147#[derive(Debug, Default)] 148pub struct BodyTranslator { 149 variables: HashSet<EcoString>, 150 variable_count: usize, 151} 152 153impl BodyTranslator { 154 fn translate(mut self, body: &Vec1<ast::TypedStatement>) -> Expression { 155 Expression::Block(Iterator::collect( 156 body.iter().map(|stmt| self.translate_statement(stmt)), 157 )) 158 } 159 160 fn translate_statement(&mut self, statement: &ast::TypedStatement) -> Expression { 161 match statement { 162 ast::Statement::Expression(expression) => self.translate_expression(expression), 163 ast::Statement::Assignment(assignment) => self.translate_assignment(assignment), 164 ast::Statement::Use(_) => todo!(), 165 ast::Statement::Assert(_) => todo!(), 166 } 167 } 168 169 fn translate_expression(&mut self, expression: &ast::TypedExpr) -> Expression { 170 match expression { 171 ast::TypedExpr::Int { 172 location: _, 173 type_: _, 174 value: _, 175 int_value, 176 } => Expression::Int { 177 value: int_value.clone(), 178 }, 179 ast::TypedExpr::Float { 180 location: _, 181 type_: _, 182 value: _, 183 } => todo!(), 184 ast::TypedExpr::String { 185 location: _, 186 type_: _, 187 value: _, 188 } => todo!(), 189 ast::TypedExpr::Block { 190 location: _, 191 statements: _, 192 } => todo!(), 193 ast::TypedExpr::Pipeline { 194 location: _, 195 first_value: _, 196 assignments: _, 197 finally: _, 198 finally_kind: _, 199 } => todo!(), 200 ast::TypedExpr::Var { 201 location: _, 202 constructor: _, 203 name, 204 } => Expression::Var { name: name.clone() }, 205 ast::TypedExpr::Fn { 206 location: _, 207 type_: _, 208 kind: _, 209 arguments: _, 210 body: _, 211 return_annotation: _, 212 purity: _, 213 } => todo!(), 214 ast::TypedExpr::List { 215 location: _, 216 type_: _, 217 elements: _, 218 tail: _, 219 } => todo!(), 220 ast::TypedExpr::Call { 221 location: _, 222 type_: _, 223 fun: _, 224 arguments: _, 225 } => todo!(), 226 ast::TypedExpr::BinOp { 227 location: _, 228 type_: _, 229 name, 230 name_location: _, 231 left, 232 right, 233 } => { 234 let lhs = Box::new(self.translate_expression(left)); 235 let rhs = Box::new(self.translate_expression(right)); 236 237 match name { 238 ast::BinOp::And => todo!(), 239 ast::BinOp::Or => todo!(), 240 ast::BinOp::Eq => Expression::Equals { lhs, rhs }, 241 ast::BinOp::NotEq => todo!(), 242 ast::BinOp::LtInt => todo!(), 243 ast::BinOp::LtEqInt => todo!(), 244 ast::BinOp::LtFloat => todo!(), 245 ast::BinOp::LtEqFloat => todo!(), 246 ast::BinOp::GtEqInt => todo!(), 247 ast::BinOp::GtInt => todo!(), 248 ast::BinOp::GtEqFloat => todo!(), 249 ast::BinOp::GtFloat => todo!(), 250 ast::BinOp::AddInt => Expression::IntAdd { lhs, rhs }, 251 ast::BinOp::AddFloat => todo!(), 252 ast::BinOp::SubInt => todo!(), 253 ast::BinOp::SubFloat => todo!(), 254 ast::BinOp::MultInt => todo!(), 255 ast::BinOp::MultFloat => todo!(), 256 ast::BinOp::DivInt => todo!(), 257 ast::BinOp::DivFloat => todo!(), 258 ast::BinOp::RemainderInt => todo!(), 259 ast::BinOp::Concatenate => todo!(), 260 } 261 } 262 ast::TypedExpr::Case { 263 location: _, 264 type_: _, 265 subjects, 266 clauses, 267 compiled_case, 268 } => { 269 let mut block = vec![]; 270 271 let subject_vars: Vec<_> = Iterator::collect(subjects.iter().map(|subject| { 272 let name = self.make_tmp_var(); 273 let value = self.translate_expression(subject); 274 275 block.push(Expression::Set { 276 name: name.clone(), 277 value: Box::new(value), 278 }); 279 280 return name; 281 })); 282 283 block.push(self.translate_decision(&subject_vars, clauses, &compiled_case.tree)); 284 285 Expression::Block(block) 286 } 287 ast::TypedExpr::RecordAccess { 288 location: _, 289 field_start: _, 290 type_: _, 291 label: _, 292 index: _, 293 record: _, 294 } => todo!(), 295 ast::TypedExpr::ModuleSelect { 296 location: _, 297 field_start: _, 298 type_: _, 299 label: _, 300 module_name: _, 301 module_alias: _, 302 constructor: _, 303 } => todo!(), 304 ast::TypedExpr::Tuple { 305 location: _, 306 type_: _, 307 elements: _, 308 } => todo!(), 309 ast::TypedExpr::TupleIndex { 310 location: _, 311 type_: _, 312 index: _, 313 tuple: _, 314 } => todo!(), 315 ast::TypedExpr::Todo { 316 location: _, 317 message: _, 318 kind: _, 319 type_: _, 320 } => todo!(), 321 ast::TypedExpr::Panic { 322 location: _, 323 message: _, 324 type_: _, 325 } => todo!(), 326 ast::TypedExpr::Echo { 327 location: _, 328 type_: _, 329 expression: _, 330 message: _, 331 } => todo!(), 332 ast::TypedExpr::BitArray { 333 location: _, 334 type_: _, 335 segments: _, 336 } => todo!(), 337 ast::TypedExpr::RecordUpdate { 338 location: _, 339 type_: _, 340 record_assignment: _, 341 constructor: _, 342 arguments: _, 343 } => todo!(), 344 ast::TypedExpr::NegateBool { 345 location: _, 346 value: _, 347 } => todo!(), 348 ast::TypedExpr::NegateInt { 349 location: _, 350 value: _, 351 } => todo!(), 352 ast::TypedExpr::Invalid { 353 location: _, 354 type_: _, 355 } => todo!(), 356 } 357 } 358 359 fn translate_assignment(&mut self, assignment: &ast::TypedAssignment) -> Expression { 360 dbg!(&assignment.compiled_case); 361 362 todo!() 363 } 364 365 fn make_tmp_var(&mut self) -> EcoString { 366 let variable_count = self.variable_count; 367 self.make_var(eco_format!("_tmp{variable_count}")) 368 } 369 370 fn make_var(&mut self, name: EcoString) -> EcoString { 371 self.variable_count += 1; 372 _ = self.variables.insert(name.clone()); 373 name 374 } 375 376 fn translate_decision( 377 &mut self, 378 subjects: &[EcoString], 379 clauses: &[ast::TypedClause], 380 decision: &exhaustiveness::Decision, 381 ) -> Expression { 382 match decision { 383 exhaustiveness::Decision::Run { body } => { 384 let mut block = vec![]; 385 386 for (binding, value) in &body.bindings { 387 block.push(self.translate_binding(subjects, binding.clone(), value)); 388 } 389 390 block.push(self.translate_expression(&clauses[body.clause_index].then)); 391 392 Expression::Block(block) 393 } 394 exhaustiveness::Decision::Guard { 395 guard: _, 396 if_true: _, 397 if_false: _, 398 } => { 399 todo!() 400 } 401 exhaustiveness::Decision::Switch { 402 var, 403 choices, 404 fallback, 405 fallback_check: _, 406 } => { 407 let fallback = self.translate_decision(subjects, clauses, fallback); 408 409 choices 410 .iter() 411 .rfold(fallback, |fallback, (check, then)| Expression::If { 412 cond: Box::new(self.translate_runtime_check( 413 check, 414 Expression::Var { 415 name: subjects[var.id].clone(), 416 }, 417 )), 418 then: Box::new(self.translate_decision(subjects, clauses, then)), 419 else_: Box::new(fallback), 420 }) 421 } 422 exhaustiveness::Decision::Fail => todo!(), 423 } 424 } 425 426 fn translate_binding( 427 &mut self, 428 subjects: &[EcoString], 429 binding: EcoString, 430 value: &exhaustiveness::BoundValue, 431 ) -> Expression { 432 let value = match value { 433 exhaustiveness::BoundValue::Variable(variable) => Expression::Var { 434 name: subjects[variable.id].clone(), 435 }, 436 exhaustiveness::BoundValue::LiteralString(_eco_string) => todo!(), 437 exhaustiveness::BoundValue::LiteralInt(big_int) => Expression::Int { 438 value: big_int.clone(), 439 }, 440 exhaustiveness::BoundValue::LiteralFloat(_eco_string) => todo!(), 441 exhaustiveness::BoundValue::BitArraySlice { 442 bit_array: _, 443 read_action: _, 444 } => todo!(), 445 }; 446 447 Expression::Set { 448 name: binding, 449 value: Box::new(value), 450 } 451 } 452 453 fn translate_runtime_check( 454 &mut self, 455 check: &exhaustiveness::RuntimeCheck, 456 against: Expression, 457 ) -> Expression { 458 match check { 459 exhaustiveness::RuntimeCheck::Int { value } => { 460 let value = parse::parse_int_value(&value).expect("unable to parse integer value"); 461 462 Expression::Equals { 463 lhs: Box::new(against), 464 rhs: Box::new(Expression::Int { value }), 465 } 466 } 467 exhaustiveness::RuntimeCheck::Float { value: _ } => todo!(), 468 exhaustiveness::RuntimeCheck::String { value: _ } => todo!(), 469 exhaustiveness::RuntimeCheck::StringPrefix { prefix: _, rest: _ } => todo!(), 470 exhaustiveness::RuntimeCheck::Tuple { 471 size: _, 472 elements: _, 473 } => todo!(), 474 exhaustiveness::RuntimeCheck::BitArray { test: _ } => todo!(), 475 exhaustiveness::RuntimeCheck::Variant { 476 match_: _, 477 index: _, 478 labels: _, 479 fields: _, 480 } => todo!(), 481 exhaustiveness::RuntimeCheck::NonEmptyList { first: _, rest: _ } => todo!(), 482 exhaustiveness::RuntimeCheck::EmptyList => todo!(), 483 } 484 } 485}