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 <ir/base/scriptFunction.h>
17 #include <ir/expressions/arrayExpression.h>
18 #include <ir/expressions/callExpression.h>
19 #include <ir/expressions/functionExpression.h>
20 #include <ir/expressions/memberExpression.h>
21 #include <ir/statements/expressionStatement.h>
22 #include <ir/statements/blockStatement.h>
23
24 #include "parserImpl.h"
25
26 namespace panda::es2panda::parser {
27 static std::vector<std::string_view> cjsMandatoryParams = {binder::Binder::CJS_MANDATORY_PARAM_EXPORTS,
28 binder::Binder::CJS_MANDATORY_PARAM_REQUIRE,
29 binder::Binder::CJS_MANDATORY_PARAM_MODULE,
30 binder::Binder::CJS_MANDATORY_PARAM_FILENAME,
31 binder::Binder::CJS_MANDATORY_PARAM_DIRNAME};
32
AddCommonjsParams(ArenaVector<ir::Expression * > & params)33 void ParserImpl::AddCommonjsParams(ArenaVector<ir::Expression *> ¶ms)
34 {
35 for (auto paramName : cjsMandatoryParams) {
36 ir::Expression *param = AllocNode<ir::Identifier>(paramName);
37 param->AsIdentifier()->SetReference();
38 Binder()->AddParamDecl(param);
39 params.push_back(param);
40 }
41 }
42
AddReflectApplyArgs(ArenaVector<ir::Expression * > & args,ir::FunctionExpression * wrapper)43 void ParserImpl::AddReflectApplyArgs(ArenaVector<ir::Expression *> &args, ir::FunctionExpression *wrapper)
44 {
45 ASSERT(wrapper != nullptr);
46 // wrapper
47 args.push_back(wrapper);
48 // thisValue
49 ir::Expression *thisValue = AllocNode<ir::Identifier>(binder::Binder::CJS_MANDATORY_PARAM_EXPORTS);
50 thisValue->AsIdentifier()->SetReference();
51 args.push_back(thisValue);
52 // wrapper's arguments
53 ArenaVector<ir::Expression *> elements(Allocator()->Adapter());
54 for (auto argName : cjsMandatoryParams) {
55 ir::Expression *arg = AllocNode<ir::Identifier>(argName);
56 arg->AsIdentifier()->SetReference();
57 elements.push_back(arg);
58 }
59 ir::ArrayExpression *wrapperArgsArray =
60 AllocNode<ir::ArrayExpression>(ir::AstNodeType::ARRAY_EXPRESSION, std::move(elements), false);
61 args.push_back(wrapperArgsArray);
62 }
63
ParseCommonjs()64 void ParserImpl::ParseCommonjs()
65 {
66 // create FunctionExpression as callee
67 ir::FunctionExpression *wrapper = nullptr;
68 {
69 FunctionContext functionContext(this, ParserStatus::FUNCTION | ParserStatus::ALLOW_NEW_TARGET);
70 FunctionParameterContext funcParamContext(&context_, Binder());
71 auto *funcParamScope = funcParamContext.LexicalScope().GetScope();
72
73 ArenaVector<ir::Expression *> params(Allocator()->Adapter());
74 AddCommonjsParams(params);
75
76 auto functionCtx = binder::LexicalScope<binder::FunctionScope>(Binder());
77 auto *functionScope = functionCtx.GetScope();
78 functionScope->BindParamScope(funcParamScope);
79 funcParamScope->BindFunctionScope(functionScope);
80
81 ParseProgram(ScriptKind::COMMONJS);
82
83 auto *funcNode =
84 AllocNode<ir::ScriptFunction>(functionScope, std::move(params), nullptr, program_.Ast(), nullptr,
85 functionContext.Flags(), false, Extension() == ScriptExtension::TS);
86 functionScope->BindNode(funcNode);
87 funcParamScope->BindNode(funcNode);
88
89 wrapper = AllocNode<ir::FunctionExpression>(funcNode);
90 }
91
92 // create CallExpression
93 ArenaVector<ir::Expression *> arguments(Allocator()->Adapter());
94 AddReflectApplyArgs(arguments, wrapper);
95
96 auto *apply = AllocNode<ir::Identifier>("apply");
97 auto *reflect = AllocNode<ir::Identifier>("Reflect");
98 auto *reflectApply = AllocNode<ir::MemberExpression>(reflect, apply,
99 ir::MemberExpression::MemberExpressionKind::PROPERTY_ACCESS, false, false);
100
101 auto *callExpr = AllocNode<ir::CallExpression>(reflectApply, std::move(arguments), nullptr, false);
102 // create ExpressionStatement
103 auto *exprStatementNode = AllocNode<ir::ExpressionStatement>(callExpr);
104
105 ArenaVector<ir::Statement *> statements(Allocator()->Adapter());
106 statements.push_back(exprStatementNode);
107
108 auto *blockStmt = AllocNode<ir::BlockStatement>(Binder()->GetScope(), std::move(statements));
109 Binder()->GetScope()->BindNode(blockStmt);
110
111 program_.SetAst(blockStmt);
112 }
113 } // namespace panda::es2panda::parser