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 "es2panda.h"
17
18 #include <compiler/core/compileQueue.h>
19 #include <compiler/core/compilerContext.h>
20 #include <compiler/core/compilerImpl.h>
21 #include <compiler/core/emitter/emitter.h>
22 #include <parser/parserImpl.h>
23 #include <parser/program/program.h>
24 #include <parser/transformer/transformer.h>
25 #include <typescript/checker.h>
26 #include <util/helpers.h>
27
28 #include <iostream>
29
30 namespace panda::es2panda {
31 // Compiler
32
33 constexpr size_t DEFAULT_THREAD_COUNT = 2;
34
Compiler(ScriptExtension ext)35 Compiler::Compiler(ScriptExtension ext) : Compiler(ext, DEFAULT_THREAD_COUNT) {}
36
Compiler(ScriptExtension ext,size_t threadCount)37 Compiler::Compiler(ScriptExtension ext, size_t threadCount)
38 : parser_(new parser::ParserImpl(ext)), compiler_(new compiler::CompilerImpl(threadCount))
39 {
40 if (parser_->Extension() == ScriptExtension::TS) {
41 transformer_ = std::make_unique<parser::Transformer>(parser_->Allocator());
42 }
43 }
44
~Compiler()45 Compiler::~Compiler()
46 {
47 delete parser_;
48 delete compiler_;
49 }
50
CreateJsonContentProgram(std::string src,std::string rname,util::Hotfix * hotfixHelper)51 panda::pandasm::Program *CreateJsonContentProgram(std::string src, std::string rname, util::Hotfix *hotfixHelper)
52 {
53 panda::es2panda::compiler::CompilerContext context(nullptr, false, false, false, false, true,
54 src, "", util::StringView(rname), hotfixHelper);
55 return context.GetEmitter()->Finalize(false, nullptr);
56 }
57
Compile(const SourceFile & input,const CompilerOptions & options,util::SymbolTable * symbolTable)58 panda::pandasm::Program *Compiler::Compile(const SourceFile &input, const CompilerOptions &options,
59 util::SymbolTable *symbolTable)
60 {
61 /* TODO(dbatyai): pass string view */
62 std::string fname(input.fileName);
63 std::string src(input.source);
64 std::string rname(input.recordName);
65 std::string sourcefile(input.sourcefile);
66 std::string pkgName(input.pkgName);
67 parser::ScriptKind kind(input.scriptKind);
68
69 auto *hotfixHelper = InitHotfixHelper(input, options, symbolTable);
70
71 if (fname.substr(fname.find_last_of(".") + 1) == "json") {
72 return CreateJsonContentProgram(src, rname, hotfixHelper);
73 }
74
75 try {
76 auto ast = parser_->Parse(fname, src, rname, kind);
77 ast.Binder()->SetProgram(&ast);
78
79 if (options.dumpAst) {
80 std::cout << ast.Dump() << std::endl;
81 }
82
83 if (ast.Extension() == ScriptExtension::TS && options.enableTypeCheck) {
84 ArenaAllocator localAllocator(SpaceType::SPACE_TYPE_COMPILER, nullptr, true);
85 auto checker = std::make_unique<checker::Checker>(&localAllocator, ast.Binder());
86 checker->StartChecker();
87 }
88
89 if (ast.Extension() == ScriptExtension::TS) {
90 transformer_->Transform(&ast);
91 ast.Binder()->IdentifierAnalysis(binder::ResolveBindingFlags::ALL);
92 }
93
94 if (options.parseOnly) {
95 return nullptr;
96 }
97
98 std::string debugInfoSourceFile = options.debugInfoSourceFile.empty() ?
99 sourcefile : options.debugInfoSourceFile;
100 auto *prog = compiler_->Compile(&ast, options, debugInfoSourceFile, pkgName);
101
102 CleanHotfixHelper(hotfixHelper);
103 return prog;
104 } catch (const class Error &e) {
105 error_ = e;
106
107 CleanHotfixHelper(hotfixHelper);
108 return nullptr;
109 }
110 }
111
InitHotfixHelper(const SourceFile & input,const CompilerOptions & options,util::SymbolTable * symbolTable)112 util::Hotfix *Compiler::InitHotfixHelper(const SourceFile &input, const CompilerOptions &options,
113 util::SymbolTable *symbolTable)
114 {
115 bool needDumpSymbolFile = !options.hotfixOptions.dumpSymbolTable.empty();
116 bool needGeneratePatch = options.hotfixOptions.generatePatch && !options.hotfixOptions.symbolTable.empty();
117 bool isHotReload = options.hotfixOptions.hotReload;
118 util::Hotfix *hotfixHelper = nullptr;
119 if (symbolTable && (needDumpSymbolFile || needGeneratePatch || isHotReload)) {
120 hotfixHelper = new util::Hotfix(needDumpSymbolFile, needGeneratePatch, isHotReload,
121 input.recordName, symbolTable);
122 parser_->AddHotfixHelper(hotfixHelper);
123 compiler_->AddHotfixHelper(hotfixHelper);
124 }
125 return hotfixHelper;
126 }
127
CleanHotfixHelper(const util::Hotfix * hotfixHelper)128 void Compiler::CleanHotfixHelper(const util::Hotfix *hotfixHelper)
129 {
130 if (hotfixHelper) {
131 delete hotfixHelper;
132 hotfixHelper = nullptr;
133 }
134 }
135
DumpAsm(const panda::pandasm::Program * prog)136 void Compiler::DumpAsm(const panda::pandasm::Program *prog)
137 {
138 compiler::CompilerImpl::DumpAsm(prog);
139 }
140
CompileFiles(CompilerOptions & options,std::map<std::string,panda::es2panda::util::ProgramCache * > & progsInfo,panda::ArenaAllocator * allocator)141 int Compiler::CompileFiles(CompilerOptions &options,
142 std::map<std::string, panda::es2panda::util::ProgramCache*> &progsInfo, panda::ArenaAllocator *allocator)
143 {
144 util::SymbolTable *symbolTable = nullptr;
145 if (!options.hotfixOptions.symbolTable.empty() || !options.hotfixOptions.dumpSymbolTable.empty()) {
146 symbolTable = new util::SymbolTable(options.hotfixOptions.symbolTable, options.hotfixOptions.dumpSymbolTable);
147 if (!symbolTable->Initialize()) {
148 std::cerr << "Exits due to hot fix initialize failed!" << std::endl;
149 return 1;
150 }
151 }
152
153 bool failed = false;
154 auto queue = new compiler::CompileFileQueue(options.fileThreadCount, &options, progsInfo, symbolTable, allocator);
155
156 try {
157 queue->Schedule();
158 queue->Consume();
159 queue->Wait();
160 } catch (const class Error &e) {
161 failed = true;
162 }
163
164 delete queue;
165 queue = nullptr;
166
167 if (symbolTable) {
168 delete symbolTable;
169 symbolTable = nullptr;
170 }
171
172 return failed ? 1 : 0;
173 }
174
CompileFile(const CompilerOptions & options,SourceFile * src,util::SymbolTable * symbolTable)175 panda::pandasm::Program *Compiler::CompileFile(const CompilerOptions &options, SourceFile *src,
176 util::SymbolTable *symbolTable)
177 {
178 if (src->source.empty()) {
179 return nullptr;
180 }
181
182 auto *program = Compile(*src, options, symbolTable);
183 if (!program) {
184 const auto &err = GetError();
185
186 if (err.Message().empty() && options.parseOnly) {
187 return nullptr;
188 }
189
190 std::cerr << err.TypeString() << ": " << err.Message();
191 std::cerr << " [" << util::Helpers::BaseName(src->fileName) << ":"
192 << err.Line() << ":" << err.Col() << "]" << std::endl;
193 throw err;
194 }
195 return program;
196 }
197
198 } // namespace panda::es2panda
199