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::PatchFix * patchFixHelper)51 panda::pandasm::Program *CreateJsonContentProgram(std::string src, std::string rname, util::PatchFix *patchFixHelper)
52 {
53 panda::es2panda::compiler::CompilerContext context(nullptr, false, false, false, false, true,
54 src, "", util::StringView(rname), patchFixHelper);
55 context.GetEmitter()->GenRecordNameInfo();
56 return context.GetEmitter()->Finalize(false, nullptr);
57 }
58
Compile(const SourceFile & input,const CompilerOptions & options,util::SymbolTable * symbolTable)59 panda::pandasm::Program *Compiler::Compile(const SourceFile &input, const CompilerOptions &options,
60 util::SymbolTable *symbolTable)
61 {
62 /* TODO(dbatyai): pass string view */
63 std::string fname(input.fileName);
64 std::string src(input.source);
65 std::string rname(input.recordName);
66 std::string sourcefile(input.sourcefile);
67 std::string pkgName(input.pkgName);
68 parser::ScriptKind kind(input.scriptKind);
69
70 auto *patchFixHelper = InitPatchFixHelper(input, options, symbolTable);
71
72 if (fname.substr(fname.find_last_of(".") + 1) == "json") {
73 return CreateJsonContentProgram(src, rname, patchFixHelper);
74 }
75
76 try {
77 parser_->SetDebug(options.isDebug);
78 auto ast = parser_->Parse(fname, src, rname, kind);
79 ast.Binder()->SetProgram(&ast);
80
81 if (options.dumpAst) {
82 std::cout << ast.Dump() << std::endl;
83 }
84
85 if (ast.Extension() == ScriptExtension::TS && options.enableTypeCheck) {
86 ArenaAllocator localAllocator(SpaceType::SPACE_TYPE_COMPILER, nullptr, true);
87 auto checker = std::make_unique<checker::Checker>(&localAllocator, ast.Binder());
88 checker->StartChecker();
89 }
90
91 if (ast.Extension() == ScriptExtension::TS) {
92 transformer_->Transform(&ast);
93 ast.Binder()->IdentifierAnalysis(binder::ResolveBindingFlags::ALL);
94 if (options.dumpTransformedAst) {
95 std::cout << ast.Dump() << std::endl;
96 }
97 if (options.checkTransformedAstStructure) {
98 transformer_->CheckTransformedAstStructure(&ast);
99 }
100 }
101
102 if (options.parseOnly) {
103 return nullptr;
104 }
105
106 std::string debugInfoSourceFile = options.debugInfoSourceFile.empty() ?
107 sourcefile : options.debugInfoSourceFile;
108 auto *prog = compiler_->Compile(&ast, options, debugInfoSourceFile, pkgName);
109
110 CleanPatchFixHelper(patchFixHelper);
111 return prog;
112 } catch (const class Error &e) {
113 error_ = e;
114
115 CleanPatchFixHelper(patchFixHelper);
116 return nullptr;
117 }
118 }
119
InitPatchFixHelper(const SourceFile & input,const CompilerOptions & options,util::SymbolTable * symbolTable)120 util::PatchFix *Compiler::InitPatchFixHelper(const SourceFile &input, const CompilerOptions &options,
121 util::SymbolTable *symbolTable)
122 {
123 util::PatchFix *patchFixHelper = nullptr;
124 bool needDumpSymbolFile = !options.patchFixOptions.dumpSymbolTable.empty();
125 bool needGeneratePatch = options.patchFixOptions.generatePatch && !options.patchFixOptions.symbolTable.empty();
126 bool isHotReload = options.patchFixOptions.hotReload;
127 bool isColdFix = options.patchFixOptions.coldFix;
128 if (symbolTable && (needDumpSymbolFile || needGeneratePatch || isHotReload)) {
129 util::PatchFixKind patchFixKind = util::PatchFixKind::DUMPSYMBOLTABLE;
130 if (needGeneratePatch) {
131 patchFixKind = isColdFix ? util::PatchFixKind::COLDFIX : util::PatchFixKind::HOTFIX;
132 }
133 if (isHotReload) {
134 patchFixKind = util::PatchFixKind::HOTRELOAD;
135 }
136 patchFixHelper = new util::PatchFix(needDumpSymbolFile, needGeneratePatch, patchFixKind, input.recordName,
137 symbolTable);
138 parser_->AddPatchFixHelper(patchFixHelper);
139 compiler_->AddPatchFixHelper(patchFixHelper);
140 }
141 return patchFixHelper;
142 }
143
CleanPatchFixHelper(const util::PatchFix * patchFixHelper)144 void Compiler::CleanPatchFixHelper(const util::PatchFix *patchFixHelper)
145 {
146 if (patchFixHelper) {
147 delete patchFixHelper;
148 patchFixHelper = nullptr;
149 }
150 }
151
DumpAsm(const panda::pandasm::Program * prog)152 void Compiler::DumpAsm(const panda::pandasm::Program *prog)
153 {
154 compiler::CompilerImpl::DumpAsm(prog);
155 }
156
CompileFiles(CompilerOptions & options,std::map<std::string,panda::es2panda::util::ProgramCache * > & progsInfo,panda::ArenaAllocator * allocator)157 int Compiler::CompileFiles(CompilerOptions &options,
158 std::map<std::string, panda::es2panda::util::ProgramCache*> &progsInfo, panda::ArenaAllocator *allocator)
159 {
160 util::SymbolTable *symbolTable = nullptr;
161 if (!options.patchFixOptions.symbolTable.empty() || !options.patchFixOptions.dumpSymbolTable.empty()) {
162 symbolTable = new util::SymbolTable(options.patchFixOptions.symbolTable,
163 options.patchFixOptions.dumpSymbolTable);
164 if (!symbolTable->Initialize()) {
165 std::cerr << "Exits due to hot fix initialize failed!" << std::endl;
166 return 1;
167 }
168 }
169
170 bool failed = false;
171 auto queue = new compiler::CompileFileQueue(options.fileThreadCount, &options, progsInfo, symbolTable, allocator);
172
173 try {
174 queue->Schedule();
175 queue->Consume();
176 queue->Wait();
177 } catch (const class Error &e) {
178 failed = true;
179 }
180
181 delete queue;
182 queue = nullptr;
183
184 if (symbolTable) {
185 delete symbolTable;
186 symbolTable = nullptr;
187 }
188
189 return failed ? 1 : 0;
190 }
191
CompileFile(const CompilerOptions & options,SourceFile * src,util::SymbolTable * symbolTable)192 panda::pandasm::Program *Compiler::CompileFile(const CompilerOptions &options, SourceFile *src,
193 util::SymbolTable *symbolTable)
194 {
195 auto *program = Compile(*src, options, symbolTable);
196 if (!program) {
197 const auto &err = GetError();
198
199 if (err.Message().empty() && options.parseOnly) {
200 return nullptr;
201 }
202
203 std::cerr << err.TypeString() << ": " << err.Message();
204 std::cerr << " [" << util::Helpers::BaseName(src->fileName) << ":"
205 << err.Line() << ":" << err.Col() << "]" << std::endl;
206 throw err;
207 }
208 return program;
209 }
210
211 } // namespace panda::es2panda
212