From c59ac387aed46c90199f1bc9e057c1a09b4a0a6d Mon Sep 17 00:00:00 2001 From: Joe Savona Date: Thu, 6 Jul 2023 09:24:51 +0900 Subject: [PATCH] [rust] Assignment expressions --- compiler/forget/crates/build-hir/src/build.rs | 49 +++++++++++++------ compiler/forget/crates/estree-swc/src/lib.rs | 31 ++++++++++-- .../fixtures/tests/fixtures/identifiers.js | 1 + ...ixtures_test__fixtures@identifiers.js.snap | 13 +++-- 4 files changed, 68 insertions(+), 26 deletions(-) diff --git a/compiler/forget/crates/build-hir/src/build.rs b/compiler/forget/crates/build-hir/src/build.rs index 12c18a4e11..7e10e94278 100644 --- a/compiler/forget/crates/build-hir/src/build.rs +++ b/compiler/forget/crates/build-hir/src/build.rs @@ -1,7 +1,7 @@ use bumpalo::collections::{CollectIn, String}; use estree::{ - ExpressionLike, FunctionDeclaration, Literal, LiteralValue, Pattern, Statement, - VariableDeclarationKind, + AssignmentTarget, ExpressionLike, FunctionDeclaration, Literal, LiteralValue, Pattern, + Statement, VariableDeclarationKind, }; use hir::{ ArrayElement, BlockKind, Environment, Function, GotoKind, Identifier, InstructionKind, @@ -114,7 +114,13 @@ fn lower_statement<'a>( for declaration in stmt.declarations { if let Some(init) = declaration.init { let value = lower_expression_to_temporary(env, builder, init); - lower_assignment(env, builder, kind, declaration.id, value); + lower_assignment( + env, + builder, + kind, + AssignmentTarget::Pattern(declaration.id.into()), + value, + ); } else { if let Pattern::Identifier(id) = declaration.id { // TODO: handle unbound variables @@ -195,6 +201,14 @@ fn lower_expression<'a>( .collect_in(env.allocator); InstructionValue::Array(hir::Array { elements }) } + ExpressionLike::AssignmentExpression(expr) => match expr.operator { + estree::AssignmentOperator::Equals => { + let right = lower_expression_to_temporary(env, builder, expr.right); + lower_assignment(env, builder, InstructionKind::Reassign, expr.left, right) + } + _ => todo!("lower assignment expr {:#?}", expr), + }, + // Cases that cannot appear in expression position but which are included in ExpressionLike // to make serialization easier ExpressionLike::SpreadElement(_) => { @@ -208,22 +222,25 @@ fn lower_assignment<'a>( env: &'a Environment<'a>, builder: &mut Builder<'a>, kind: InstructionKind, - lvalue: Pattern, + lvalue: AssignmentTarget, value: Place<'a>, ) -> InstructionValue<'a> { match lvalue { - Pattern::Identifier(lvalue) => { - let place = lower_identifier_for_assignment(env, builder, kind, *lvalue).unwrap(); - let temporary = lower_value_to_temporary( - env, - builder, - InstructionValue::StoreLocal(hir::StoreLocal { - lvalue: LValue { place, kind }, - value, - }), - ); - InstructionValue::LoadLocal(LoadLocal { place: temporary }) - } + AssignmentTarget::Pattern(lvalue) => match *lvalue { + Pattern::Identifier(lvalue) => { + let place = lower_identifier_for_assignment(env, builder, kind, *lvalue).unwrap(); + let temporary = lower_value_to_temporary( + env, + builder, + InstructionValue::StoreLocal(hir::StoreLocal { + lvalue: LValue { place, kind }, + value, + }), + ); + InstructionValue::LoadLocal(LoadLocal { place: temporary }) + } + _ => todo!("lower assignment pattern for {:#?}", lvalue), + }, _ => todo!("lower assignment for {:#?}", lvalue), } } diff --git a/compiler/forget/crates/estree-swc/src/lib.rs b/compiler/forget/crates/estree-swc/src/lib.rs index 99de60e1dd..b9406f9160 100644 --- a/compiler/forget/crates/estree-swc/src/lib.rs +++ b/compiler/forget/crates/estree-swc/src/lib.rs @@ -6,8 +6,8 @@ use swc_core::common::errors::Handler; use swc_core::common::source_map::Pos; use swc_core::common::{FileName, FilePathMapping, Mark, SourceMap, Span, SyntaxContext, GLOBALS}; use swc_core::ecma::ast::{ - AssignOp, BinaryOp, BlockStmt, Decl, EsVersion, Expr, Ident, Lit, ModuleItem, Pat, PatOrExpr, - Program, Stmt, UnaryOp, VarDecl, VarDeclKind, VarDeclOrExpr, + AssignOp, BinaryOp, BlockStmt, Decl, EsVersion, Expr, Ident, Lit, MemberExpr, ModuleItem, Pat, + PatOrExpr, Program, Stmt, UnaryOp, VarDecl, VarDeclKind, VarDeclOrExpr, }; use swc_core::ecma::parser::Syntax; use swc_core::ecma::transforms::base::resolver; @@ -360,7 +360,7 @@ fn convert_expression(cx: &Context, expr: &Expr) -> estree::ExpressionLike { Expr::Assign(expr) => { estree::ExpressionLike::AssignmentExpression(Box::new(estree::AssignmentExpression { operator: convert_assignment_operator(expr.op), - left: convert_assignment_target(&expr.left), + left: convert_assignment_target(cx, &expr.left), right: convert_expression(cx, &expr.right), loc: None, range: convert_span(&expr.span), @@ -370,8 +370,28 @@ fn convert_expression(cx: &Context, expr: &Expr) -> estree::ExpressionLike { } } -fn convert_assignment_target(_target: &PatOrExpr) -> estree::AssignmentTarget { - todo!("translate assignment target") +fn convert_assignment_target(cx: &Context, target: &PatOrExpr) -> estree::AssignmentTarget { + match target { + PatOrExpr::Pat(target) => { + estree::AssignmentTarget::Pattern(Box::new(convert_pattern(cx, target))) + } + PatOrExpr::Expr(target) => { + if let Expr::Member(target) = target.as_ref() { + estree::AssignmentTarget::MemberExpression(Box::new(convert_member_expression( + cx, target, + ))) + } else { + panic!( + "Invalid input, expected either a pattern or member expression, got {:#?}", + target + ) + } + } + } +} + +fn convert_member_expression(cx: &Context, expr: &MemberExpr) -> estree::MemberExpression { + todo!("convert member expression") } fn convert_unary_operator(op: UnaryOp) -> estree::UnaryOperator { @@ -388,6 +408,7 @@ fn convert_unary_operator(op: UnaryOp) -> estree::UnaryOperator { fn convert_assignment_operator(op: AssignOp) -> estree::AssignmentOperator { match op { + AssignOp::Assign => estree::AssignmentOperator::Equals, AssignOp::AddAssign => estree::AssignmentOperator::PlusEquals, _ => todo!("translate assignment operator"), } diff --git a/compiler/forget/crates/fixtures/tests/fixtures/identifiers.js b/compiler/forget/crates/fixtures/tests/fixtures/identifiers.js index 5c1e3b02f9..def546ffd3 100644 --- a/compiler/forget/crates/fixtures/tests/fixtures/identifiers.js +++ b/compiler/forget/crates/fixtures/tests/fixtures/identifiers.js @@ -8,6 +8,7 @@ function id(x) { Math; id; let y = true; + y = false; y; let z; z; diff --git a/compiler/forget/crates/fixtures/tests/snapshots/fixtures_test__fixtures@identifiers.js.snap b/compiler/forget/crates/fixtures/tests/snapshots/fixtures_test__fixtures@identifiers.js.snap index c20e69fb58..e2af692274 100644 --- a/compiler/forget/crates/fixtures/tests/snapshots/fixtures_test__fixtures@identifiers.js.snap +++ b/compiler/forget/crates/fixtures/tests/snapshots/fixtures_test__fixtures@identifiers.js.snap @@ -14,6 +14,7 @@ function id(x) { Math; id; let y = true; + y = false; y; let z; z; @@ -28,9 +29,11 @@ bb0 [1] unknown $2 = LoadGlobal id [2] unknown $3 = true [3] unknown $5 = StoreLocal Let unknown y$4 = unknown $3 - [4] unknown $6 = LoadLocal unknown y$4 - [5] unknown $8 = DeclareLocal Let unknown z$7 - [6] unknown $9 = LoadLocal unknown z$7 - [7] unknown $11 = LoadLocal unknown x$10 - [8] Return unknown $11 + [4] unknown $6 = false + [5] unknown $7 = StoreLocal Reassign unknown y$4 = unknown $6 + [6] unknown $8 = LoadLocal unknown y$4 + [7] unknown $10 = DeclareLocal Let unknown z$9 + [8] unknown $11 = LoadLocal unknown z$9 + [9] unknown $13 = LoadLocal unknown x$12 + [10] Return unknown $13