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

Configure Feed

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

Begin translating expressions to the mir

author
Danielle Maywood
committer
nandi
date (Jul 26, 2026, 12:11 PM -0700) commit 831ff127 parent b07e9632 change-id ompvrpqx
+406 -5
+402 -4
compiler-core/src/cranelift/mir.rs
··· 1 - use ecow::EcoString; 1 + use std::ops::Deref; 2 + 3 + use ecow::{EcoString, eco_format}; 4 + use im::HashSet; 5 + use num_bigint::BigInt; 6 + use vec1::Vec1; 2 7 3 - use crate::{ast, type_}; 8 + use crate::{ast, exhaustiveness, parse, type_}; 4 9 5 10 #[derive(Debug, Default)] 6 11 pub struct Module { ··· 10 15 #[derive(Debug)] 11 16 pub struct Function { 12 17 pub name: EcoString, 18 + pub return_type: Type, 13 19 pub parameters: Vec<FunctionParameter>, 20 + pub body: Expression, 14 21 } 15 22 16 23 #[derive(Debug)] ··· 28 35 pub enum Type { 29 36 Int, 30 37 Float, 38 + Bool, 39 + Generic, 40 + } 41 + 42 + #[derive(Debug)] 43 + pub 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 + }, 31 74 } 32 75 33 76 impl Translator { ··· 52 95 fn translate_function(function: &ast::TypedFunction) -> Function { 53 96 let (_, name) = function.name.clone().expect("function should have a name"); 54 97 98 + let return_type = Self::translate_type(&function.return_type); 99 + 55 100 let parameters = Iterator::collect(function.arguments.iter().map(|argument| { 56 101 let name = argument.get_variable_name().cloned(); 57 102 let type_ = Self::translate_type(&argument.type_); ··· 59 104 FunctionParameter { name, type_ } 60 105 })); 61 106 62 - Function { name, parameters } 107 + let body = BodyTranslator::default().translate(&function.body); 108 + 109 + Function { 110 + name, 111 + body, 112 + return_type, 113 + parameters, 114 + } 63 115 } 64 116 65 117 fn translate_type(type_: &type_::Type) -> Type { ··· 74 126 } => match (module.as_str(), name.as_str()) { 75 127 ("gleam", "Int") => Type::Int, 76 128 ("gleam", "Float") => Type::Float, 129 + ("gleam", "Bool") => Type::Bool, 77 130 (_, _) => todo!(), 78 131 }, 79 132 type_::Type::Fn { 80 133 arguments: _, 81 134 return_: _, 82 135 } => todo!(), 83 - type_::Type::Var { type_: _ } => 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 + }, 84 142 type_::Type::Tuple { elements: _ } => todo!(), 85 143 } 86 144 } 87 145 } 146 + 147 + #[derive(Debug, Default)] 148 + pub struct BodyTranslator { 149 + variables: HashSet<EcoString>, 150 + variable_count: usize, 151 + } 152 + 153 + impl 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 + }
+4 -1
test/project_cranelift/src/project_cranelift.gleam
··· 1 1 pub fn add(lhs: Int, rhs: Int) -> Int { 2 - lhs + rhs 2 + case lhs { 3 + 0 -> 10 4 + _ -> rhs 5 + } 3 6 }