1 /**
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "binaryExpression.h"
17
18 #include <binder/variable.h>
19 #include <compiler/core/pandagen.h>
20 #include <compiler/core/regScope.h>
21 #include <typescript/checker.h>
22 #include <ir/astDump.h>
23 #include <ir/base/classDefinition.h>
24 #include <ir/expressions/privateIdentifier.h>
25 #include <lexer/token/tokenType.h>
26
27 namespace panda::es2panda::ir {
28
Iterate(const NodeTraverser &cb) const29 void BinaryExpression::Iterate(const NodeTraverser &cb) const
30 {
31 cb(left_);
32 cb(right_);
33 }
34
Dump(ir::AstDumper *dumper) const35 void BinaryExpression::Dump(ir::AstDumper *dumper) const
36 {
37 dumper->Add({{"type", IsLogical() ? "LogicalExpression" : "BinaryExpression"},
38 {"operator", operator_},
39 {"left", left_},
40 {"right", right_}});
41 }
42
CompileLogical(compiler::PandaGen *pg) const43 void BinaryExpression::CompileLogical(compiler::PandaGen *pg) const
44 {
45 compiler::RegScope rs(pg);
46 compiler::VReg lhs = pg->AllocReg();
47
48 ASSERT(operator_ == lexer::TokenType::PUNCTUATOR_LOGICAL_AND ||
49 operator_ == lexer::TokenType::PUNCTUATOR_LOGICAL_OR ||
50 operator_ == lexer::TokenType::PUNCTUATOR_NULLISH_COALESCING);
51 auto *skipRight = pg->AllocLabel();
52 auto *endLabel = pg->AllocLabel();
53
54 // left -> acc -> lhs -> toboolean -> acc -> bool_lhs
55 left_->Compile(pg);
56 pg->StoreAccumulator(this, lhs);
57
58 if (operator_ == lexer::TokenType::PUNCTUATOR_LOGICAL_AND) {
59 pg->BranchIfFalse(this, skipRight);
60 } else if (operator_ == lexer::TokenType::PUNCTUATOR_LOGICAL_OR) {
61 pg->BranchIfTrue(this, skipRight);
62 } else {
63 ASSERT(operator_ == lexer::TokenType::PUNCTUATOR_NULLISH_COALESCING);
64 auto *nullish = pg->AllocLabel();
65 // if lhs === null
66 pg->BranchIfStrictNull(this, nullish);
67 pg->LoadAccumulator(this, lhs);
68 // if lhs === undefined
69 pg->BranchIfStrictNotUndefined(this, skipRight);
70 pg->SetLabel(this, nullish);
71 }
72
73 // left is true/false(and/or) then right -> acc
74 right_->Compile(pg);
75 pg->Branch(this, endLabel);
76
77 // left is false/true(and/or) then lhs -> acc
78 pg->SetLabel(this, skipRight);
79 pg->LoadAccumulator(this, lhs);
80 pg->SetLabel(this, endLabel);
81 }
82
CompilePrivateIn(compiler::PandaGen *pg) const83 void BinaryExpression::CompilePrivateIn(compiler::PandaGen *pg) const
84 {
85 ASSERT(operator_ == lexer::TokenType::KEYW_IN);
86 auto name = left_->AsPrivateIdentifier()->Name();
87 auto result = pg->Scope()->FindPrivateName(name);
88
89 right_->Compile(pg);
90 if (!result.result.isMethod) {
91 pg->TestIn(this, result.lexLevel, result.result.slot);
92 return;
93 }
94 // Instance private method check symbol("#method")
95 if (!result.result.isStatic) {
96 pg->TestIn(this, result.lexLevel, result.result.validateMethodSlot);
97 return;
98 }
99 // Static private method check whether equals the class object
100 compiler::RegScope rs(pg);
101 compiler::VReg rhs = pg->AllocReg();
102 pg->StoreAccumulator(right_, rhs);
103 pg->LoadLexicalVar(this, result.lexLevel, result.result.validateMethodSlot);
104 pg->Equal(this, rhs);
105 }
106
Compile(compiler::PandaGen *pg) const107 void BinaryExpression::Compile(compiler::PandaGen *pg) const
108 {
109 if (left_->IsPrivateIdentifier()) {
110 CompilePrivateIn(pg);
111 return;
112 }
113
114 if (IsLogical()) {
115 CompileLogical(pg);
116 return;
117 }
118
119 compiler::RegScope rs(pg);
120 compiler::VReg lhs = pg->AllocReg();
121
122 left_->Compile(pg);
123 pg->StoreAccumulator(right_, lhs);
124 right_->Compile(pg);
125
126 pg->Binary(right_, operator_, lhs);
127 }
128
Check(checker::Checker *checker) const129 checker::Type *BinaryExpression::Check(checker::Checker *checker) const
130 {
131 auto *leftType = left_->Check(checker);
132 auto *rightType = right_->Check(checker);
133
134 switch (operator_) {
135 case lexer::TokenType::PUNCTUATOR_MULTIPLY:
136 case lexer::TokenType::PUNCTUATOR_EXPONENTIATION:
137 case lexer::TokenType::PUNCTUATOR_DIVIDE:
138 case lexer::TokenType::PUNCTUATOR_MOD:
139 case lexer::TokenType::PUNCTUATOR_MINUS:
140 case lexer::TokenType::PUNCTUATOR_LEFT_SHIFT:
141 case lexer::TokenType::PUNCTUATOR_RIGHT_SHIFT:
142 case lexer::TokenType::PUNCTUATOR_UNSIGNED_RIGHT_SHIFT:
143 case lexer::TokenType::PUNCTUATOR_BITWISE_AND:
144 case lexer::TokenType::PUNCTUATOR_BITWISE_XOR:
145 case lexer::TokenType::PUNCTUATOR_BITWISE_OR: {
146 return checker->CheckBinaryOperator(leftType, rightType, left_, right_, this, operator_);
147 }
148 case lexer::TokenType::PUNCTUATOR_PLUS: {
149 return checker->CheckPlusOperator(leftType, rightType, left_, right_, this, operator_);
150 }
151 case lexer::TokenType::PUNCTUATOR_LESS_THAN:
152 case lexer::TokenType::PUNCTUATOR_GREATER_THAN: {
153 return checker->CheckCompareOperator(leftType, rightType, left_, right_, this, operator_);
154 }
155 case lexer::TokenType::PUNCTUATOR_EQUAL:
156 case lexer::TokenType::PUNCTUATOR_NOT_EQUAL:
157 case lexer::TokenType::PUNCTUATOR_STRICT_EQUAL:
158 case lexer::TokenType::PUNCTUATOR_NOT_STRICT_EQUAL: {
159 if (checker->IsTypeEqualityComparableTo(leftType, rightType) ||
160 checker->IsTypeEqualityComparableTo(rightType, leftType)) {
161 return checker->GlobalBooleanType();
162 }
163
164 checker->ThrowBinaryLikeError(operator_, leftType, rightType, Start());
165 }
166 case lexer::TokenType::KEYW_INSTANCEOF: {
167 return checker->CheckInstanceofExpression(leftType, rightType, right_, this);
168 }
169 case lexer::TokenType::KEYW_IN: {
170 return checker->CheckInExpression(leftType, rightType, left_, right_, this);
171 }
172 case lexer::TokenType::PUNCTUATOR_LOGICAL_AND: {
173 return checker->CheckAndOperator(leftType, rightType, left_);
174 }
175 case lexer::TokenType::PUNCTUATOR_LOGICAL_OR: {
176 return checker->CheckOrOperator(leftType, rightType, left_);
177 }
178 case lexer::TokenType::PUNCTUATOR_NULLISH_COALESCING: {
179 // TODO(Csaba Repasi): Implement checker for nullish coalescing
180 return checker->GlobalAnyType();
181 }
182 case lexer::TokenType::PUNCTUATOR_SUBSTITUTION: {
183 checker->CheckAssignmentOperator(operator_, left_, leftType, rightType);
184 return rightType;
185 }
186 default: {
187 UNREACHABLE();
188 break;
189 }
190 }
191
192 return nullptr;
193 }
194
UpdateSelf(const NodeUpdater &cb, [[maybe_unused]] binder::Binder *binder)195 void BinaryExpression::UpdateSelf(const NodeUpdater &cb, [[maybe_unused]] binder::Binder *binder)
196 {
197 left_ = std::get<ir::AstNode *>(cb(left_))->AsExpression();
198 right_ = std::get<ir::AstNode *>(cb(right_))->AsExpression();
199 }
200
201 } // namespace panda::es2panda::ir
202