1 Star 0 Fork 153

klooer/sig_arkcompiler_ets_frontend

加入 Gitee
与超过 1400万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
ETSparser.cpp 123.01 KB
一键复制 编辑 原始数据 按行查看 历史
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270
/**
* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "ETSparser.h"
#include "plugins/ecmascript/es2panda/parser/parserFlags.h"
#include "plugins/ecmascript/es2panda/util/arktsconfig.h"
#include "plugins/ecmascript/es2panda/util/helpers.h"
#include "plugins/ecmascript/es2panda/binder/privateBinding.h"
#include "plugins/ecmascript/es2panda/binder/scope.h"
#include "plugins/ecmascript/es2panda/binder/ETSBinder.h"
#include "plugins/ecmascript/es2panda/lexer/lexer.h"
#include "plugins/ecmascript/es2panda/lexer/ETSLexer.h"
#include "plugins/ecmascript/es2panda/ir/astNode.h"
#include "plugins/ecmascript/es2panda/ir/base/classDefinition.h"
#include "plugins/ecmascript/es2panda/ir/base/decorator.h"
#include "plugins/ecmascript/es2panda/ir/base/catchClause.h"
#include "plugins/ecmascript/es2panda/ir/base/classProperty.h"
#include "plugins/ecmascript/es2panda/ir/base/scriptFunction.h"
#include "plugins/ecmascript/es2panda/ir/base/methodDefinition.h"
#include "plugins/ecmascript/es2panda/ir/base/classStaticBlock.h"
#include "plugins/ecmascript/es2panda/ir/base/spreadElement.h"
#include "plugins/ecmascript/es2panda/ir/module/exportNamedDeclaration.h"
#include "plugins/ecmascript/es2panda/ir/expressions/identifier.h"
#include "plugins/ecmascript/es2panda/ir/expressions/functionExpression.h"
#include "plugins/ecmascript/es2panda/ir/statements/functionDeclaration.h"
#include "plugins/ecmascript/es2panda/ir/statements/expressionStatement.h"
#include "plugins/ecmascript/es2panda/ir/statements/classDeclaration.h"
#include "plugins/ecmascript/es2panda/ir/statements/variableDeclarator.h"
#include "plugins/ecmascript/es2panda/ir/statements/variableDeclaration.h"
#include "plugins/ecmascript/es2panda/ir/expressions/arrayExpression.h"
#include "plugins/ecmascript/es2panda/ir/expressions/assignmentExpression.h"
#include "plugins/ecmascript/es2panda/ir/expressions/sequenceExpression.h"
#include "plugins/ecmascript/es2panda/ir/expressions/callExpression.h"
#include "plugins/ecmascript/es2panda/ir/expressions/thisExpression.h"
#include "plugins/ecmascript/es2panda/ir/expressions/superExpression.h"
#include "plugins/ecmascript/es2panda/ir/expressions/newExpression.h"
#include "plugins/ecmascript/es2panda/ir/expressions/memberExpression.h"
#include "plugins/ecmascript/es2panda/ir/expressions/updateExpression.h"
#include "plugins/ecmascript/es2panda/ir/expressions/arrowFunctionExpression.h"
#include "plugins/ecmascript/es2panda/ir/expressions/unaryExpression.h"
#include "plugins/ecmascript/es2panda/ir/expressions/yieldExpression.h"
#include "plugins/ecmascript/es2panda/ir/expressions/literals/bigIntLiteral.h"
#include "plugins/ecmascript/es2panda/ir/expressions/literals/booleanLiteral.h"
#include "plugins/ecmascript/es2panda/ir/expressions/literals/charLiteral.h"
#include "plugins/ecmascript/es2panda/ir/expressions/literals/nullLiteral.h"
#include "plugins/ecmascript/es2panda/ir/expressions/literals/numberLiteral.h"
#include "plugins/ecmascript/es2panda/ir/expressions/literals/stringLiteral.h"
#include "plugins/ecmascript/es2panda/ir/expressions/objectExpression.h"
#include "plugins/ecmascript/es2panda/ir/module/importDeclaration.h"
#include "plugins/ecmascript/es2panda/ir/module/importSpecifier.h"
#include "plugins/ecmascript/es2panda/ir/statements/assertStatement.h"
#include "plugins/ecmascript/es2panda/ir/statements/deferStatement.h"
#include "plugins/ecmascript/es2panda/ir/statements/panicStatement.h"
#include "plugins/ecmascript/es2panda/ir/statements/blockStatement.h"
#include "plugins/ecmascript/es2panda/ir/ets/etsLaunchExpression.h"
#include "plugins/ecmascript/es2panda/ir/statements/tryStatement.h"
#include "plugins/ecmascript/es2panda/ir/ets/etsClassLiteral.h"
#include "plugins/ecmascript/es2panda/ir/ets/etsPrimitiveType.h"
#include "plugins/ecmascript/es2panda/ir/ets/etsPackageDeclaration.h"
#include "plugins/ecmascript/es2panda/ir/ets/etsWildcardType.h"
#include "plugins/ecmascript/es2panda/ir/ets/etsNewArrayInstanceExpression.h"
#include "plugins/ecmascript/es2panda/ir/ets/etsFunctionType.h"
#include "plugins/ecmascript/es2panda/ir/ets/etsNewClassInstanceExpression.h"
#include "plugins/ecmascript/es2panda/ir/ets/etsNewMultiDimArrayInstanceExpression.h"
#include "plugins/ecmascript/es2panda/ir/ets/etsScript.h"
#include "plugins/ecmascript/es2panda/ir/ets/etsTypeReference.h"
#include "plugins/ecmascript/es2panda/ir/ets/etsTypeReferencePart.h"
#include "plugins/ecmascript/es2panda/ir/ets/etsImportSource.h"
#include "plugins/ecmascript/es2panda/ir/module/importNamespaceSpecifier.h"
#include "plugins/ecmascript/es2panda/ir/ts/tsAsExpression.h"
#include "plugins/ecmascript/es2panda/ir/ts/tsInterfaceDeclaration.h"
#include "plugins/ecmascript/es2panda/ir/ts/tsEnumDeclaration.h"
#include "plugins/ecmascript/es2panda/ir/ts/tsTypeParameterInstantiation.h"
#include "plugins/ecmascript/es2panda/ir/ts/tsInterfaceBody.h"
#include "plugins/ecmascript/es2panda/ir/ts/tsImportEqualsDeclaration.h"
#include "plugins/ecmascript/es2panda/ir/ts/tsArrayType.h"
#include "plugins/ecmascript/es2panda/ir/ts/tsQualifiedName.h"
#include "plugins/ecmascript/es2panda/ir/ts/tsTypeReference.h"
#include "plugins/ecmascript/es2panda/ir/ts/tsTypeParameter.h"
#include "plugins/ecmascript/es2panda/ir/ts/tsIntersectionType.h"
#include "plugins/ecmascript/es2panda/ir/ts/tsInterfaceHeritage.h"
#include "plugins/ecmascript/es2panda/ir/ts/tsFunctionType.h"
#include "plugins/ecmascript/es2panda/ir/ts/tsClassImplements.h"
#include "plugins/ecmascript/es2panda/ir/ts/tsEnumMember.h"
#include "plugins/ecmascript/es2panda/ir/ts/tsTypeAliasDeclaration.h"
#include "plugins/ecmascript/es2panda/ir/ts/tsTypeParameterDeclaration.h"
#include "libpandabase/os/file.h"
#include "libpandabase/utils/json_parser.h"
#include "generated/signatures.h"
#if defined PANDA_TARGET_MOBILE || defined PANDA_TARGET_ARM32
#define USE_UNIX_SYSCALL
#endif
#ifdef USE_UNIX_SYSCALL
#include <dirent.h>
#include <sys/types.h>
#include <unistd.h>
#else
#if __has_include(<filesystem>)
#include <filesystem>
namespace fs = std::filesystem;
#elif __has_include(<experimental/filesystem>)
#include <experimental/filesystem>
namespace fs = std::experimental::filesystem;
#endif
#endif
namespace panda::es2panda::parser {
std::unique_ptr<lexer::Lexer> ETSParser::InitLexer(const SourceFile &source_file)
{
GetProgram()->SetSource(source_file);
auto lexer = std::make_unique<lexer::ETSLexer>(&GetContext());
SetLexer(lexer.get());
return lexer;
}
void ETSParser::ParseProgram(ScriptKind kind)
{
lexer::SourcePosition start_loc = Lexer()->GetToken().Start();
Lexer()->NextToken();
GetProgram()->SetKind(kind);
if (GetProgram()->SourceFile().Utf8()[0] == '@') {
// TODO(user): handle multiple sourceFiles
}
auto statements = PrepareGlobalClass();
ParseDefaultImports();
std::vector<std::string> external_sources = CollectExternalSources();
ParseSources(external_sources, true);
ParseETSGlobalScript(start_loc, statements, external_sources);
}
void ETSParser::ParseETSGlobalScript(lexer::SourcePosition start_loc, ArenaVector<ir::Statement *> &statements,
const std::vector<std::string> &external_sources)
{
auto paths = ParseImportDeclarations(statements);
// remove external sources from paths because already parsed them
paths.erase(remove_if(begin(paths), end(paths),
[external_sources](auto x) {
return find(begin(external_sources), end(external_sources), x) != end(external_sources);
}),
end(paths));
ParseSources(paths, false);
ParseTopLevelDeclaration(statements);
auto *ets_script = AllocNode<ir::ETSScript>(Binder()->GetScope(), std::move(statements), GetProgram());
Binder()->GetScope()->BindNode(ets_script);
ets_script->SetRange({start_loc, Lexer()->GetToken().End()});
GetProgram()->SetAst(ets_script);
}
void ETSParser::CreateGlobalClass()
{
auto *ident = AllocNode<ir::Identifier>(compiler::Signatures::ETS_GLOBAL, Allocator());
auto [decl, var] = Binder()->NewVarDecl<binder::ClassDecl>(ident->Start(), ident->Name());
ident->SetVariable(var);
auto class_ctx = binder::LexicalScope<binder::ClassScope>(Binder());
auto *class_def = AllocNode<ir::ClassDefinition>(Allocator(), class_ctx.GetScope(), ident,
ir::ClassDefinitionModifiers::GLOBAL, ir::ModifierFlags::ABSTRACT);
GetProgram()->SetGlobalClass(class_def);
auto *class_decl = AllocNode<ir::ClassDeclaration>(class_def, Allocator());
class_def->Scope()->BindNode(class_decl);
decl->BindNode(class_decl);
}
ArenaVector<ir::Statement *> ETSParser::PrepareGlobalClass()
{
ArenaVector<ir::Statement *> statements(Allocator()->Adapter());
ParsePackageDeclaration(statements);
CreateGlobalClass();
return statements;
}
ArenaVector<ir::Statement *> ETSParser::PrepareExternalGlobalClass([[maybe_unused]] const SourceFile &source_file)
{
ArenaVector<ir::Statement *> statements(Allocator()->Adapter());
ParsePackageDeclaration(statements);
if (statements.empty()) {
GetProgram()->SetGlobalClass(global_program_->GlobalClass());
}
auto &ext_sources = global_program_->ExternalSources();
const util::StringView name = GetProgram()->SourceFilePath();
auto res = ext_sources.find(name);
if (res == ext_sources.end()) {
Binder()->InitTopScope();
CreateGlobalClass();
auto ins_res = ext_sources.emplace(name, Allocator()->Adapter());
ins_res.first->second.push_back(GetProgram());
} else {
res->second.push_back(GetProgram());
auto *ext_prog = res->second.front();
GetProgram()->SetGlobalClass(ext_prog->GlobalClass());
if (ext_prog->Ast() == nullptr) {
ThrowSyntaxError("Recursive import not allowed");
}
Binder()->ResetTopScope(ext_prog->GlobalScope());
}
return statements;
}
static bool IsCompitableExtension(const std::string &extension)
{
return extension == ".ets" || extension == ".ts";
}
std::vector<std::string> ETSParser::CollectExternalSources()
{
std::vector<std::string> paths;
std::vector<std::string> stdlib = {"std/core", "std/math", "std/containers", "std/time"};
#ifdef USE_UNIX_SYSCALL
for (auto const &path : stdlib) {
auto resolved_path = ResolveImportPath(path);
DIR *dir = opendir(resolved_path.c_str());
if (dir == nullptr) {
ThrowSyntaxError({"Cannot open folder: ", resolved_path});
}
struct dirent *entry;
while ((entry = readdir(dir)) != nullptr) {
if (entry->d_type != DT_REG) {
continue;
}
std::string file_name = entry->d_name;
std::string::size_type pos = file_name.find_last_of('.');
if (pos == std::string::npos || !IsCompitableExtension(file_name.substr(pos))) {
continue;
}
std::string file_path = path + "/" + entry->d_name;
if (file_name == "Object.ets") {
paths.emplace(paths.begin(), file_path);
} else {
paths.emplace_back(file_path);
}
}
closedir(dir);
}
#else
for (auto const &path : stdlib) {
for (auto const &entry : fs::directory_iterator(ResolveImportPath(path))) {
if (!fs::is_regular_file(entry) || !IsCompitableExtension(entry.path().extension().string())) {
continue;
}
std::string base_name = path;
std::size_t pos = entry.path().string().find_last_of(panda::os::file::File::GetPathDelim());
base_name.append(entry.path().string().substr(pos, entry.path().string().size()));
if (entry.path().filename().string() == "Object.ets") {
paths.emplace(paths.begin(), base_name);
} else {
paths.emplace_back(base_name);
}
}
}
#endif
return paths;
}
std::string ETSParser::ResolveImportPath(const std::string &path)
{
char path_delimiter = panda::os::file::File::GetPathDelim().at(0);
if (util::Helpers::IsRelativePath(path)) {
return GetProgram()->SourceFilePath().Mutf8() + path_delimiter + path;
}
std::string base_url;
// Resolve delimeter character to basePath.
if (path.find('/') == 0) {
base_url = ArkTSConfig()->BaseUrl();
base_url.append(path, 0, path.length());
return base_url;
}
// Resolve the root part of the path.
// E.g. root part of std/math is std.
std::string::size_type pos = path.find('/');
bool contains_delim = (pos != std::string::npos);
std::string root_part = contains_delim ? path.substr(0, pos) : path;
if (root_part == "std" && !GetOptions().std_lib.empty()) { // Get std path from CLI if provided
base_url = GetOptions().std_lib;
} else {
auto paths = ArkTSConfig()->Paths();
if (paths.count(root_part) == 0U) {
ThrowSyntaxError({"'", root_part, "' is not defined in ", ArkTSConfig()->ConfigPath()});
}
// FIXME: arktsconfig contains array of paths for each 'root_part', for now just get first one
base_url = paths[root_part][0];
}
if (contains_delim) {
base_url.append(1, path_delimiter);
base_url.append(path, root_part.length() + 1, path.length());
}
return base_url;
}
std::tuple<std::vector<std::string>, bool> ETSParser::CollectUserSources(const std::string &path)
{
std::vector<std::string> user_paths;
const std::string resolved_path = ResolveImportPath(path);
if (!panda::os::file::File::IsDirectory(resolved_path)) {
if (!panda::os::file::File::IsRegularFile(resolved_path)) {
const std::string module_name = resolved_path + ".ets";
if (!panda::os::file::File::IsRegularFile(module_name)) {
ThrowSyntaxError(std::string("Incorrect path: ") + module_name);
}
user_paths.emplace_back(std::string(path + ".ets"));
return {user_paths, true};
}
user_paths.emplace_back(path);
return {user_paths, false};
}
#ifdef USE_UNIX_SYSCALL
DIR *dir = opendir(resolved_path.c_str());
if (dir == nullptr) {
ThrowSyntaxError({"Cannot open folder: ", resolved_path});
}
struct dirent *entry;
while ((entry = readdir(dir)) != nullptr) {
if (entry->d_type != DT_REG) {
continue;
}
std::string file_name = entry->d_name;
std::string::size_type pos = file_name.find_last_of('.');
if (pos == std::string::npos || !IsCompitableExtension(file_name.substr(pos))) {
continue;
}
std::string file_path = path + "/" + entry->d_name;
if (file_name == "Object.ets") {
user_paths.emplace(user_paths.begin(), file_path);
} else {
user_paths.emplace_back(file_path);
}
}
closedir(dir);
#else
for (auto const &entry : fs::directory_iterator(resolved_path)) {
if (!fs::is_regular_file(entry) || !IsCompitableExtension(entry.path().extension().string())) {
continue;
}
std::string base_name = path;
std::size_t pos = entry.path().string().find_last_of(panda::os::file::File::GetPathDelim());
base_name.append(entry.path().string().substr(pos, entry.path().string().size()));
user_paths.emplace_back(base_name);
}
#endif
return {user_paths, false};
}
void ETSParser::ParseSources(const std::vector<std::string> &paths, bool is_external)
{
GetContext().Status() |= is_external ? ParserStatus::IN_EXTERNAL : ParserStatus::IN_IMPORT;
for (auto const &path : paths) {
std::string resolved_path = ResolveImportPath(path);
std::ifstream input_stream(resolved_path.c_str());
if (GetProgram()->SourceFile().Is(resolved_path)) {
break;
}
if (input_stream.fail()) {
ThrowSyntaxError({"Failed to open file: ", resolved_path.c_str()});
}
std::stringstream ss;
ss << input_stream.rdbuf();
auto external_source = ss.str();
ParseSource({path.c_str(), external_source.c_str()});
}
GetContext().Status() &= is_external ? ~ParserStatus::IN_EXTERNAL : ~ParserStatus::IN_IMPORT;
}
void ETSParser::ParseDefaultImports()
{
auto isp = InnerSourceParser(this);
SourceFile source(binder::ETSBinder::DEFAULT_IMPORT_SOURCE_FILE, binder::ETSBinder::DEFAULT_IMPORT_SOURCE);
auto lexer = InitLexer(source);
ArenaVector<ir::Statement *> statements(Allocator()->Adapter());
Lexer()->NextToken();
GetContext().Status() |= ParserStatus::IN_DEFAULT_IMPORTS;
ParseImportDeclarations(statements);
GetContext().Status() &= ~ParserStatus::IN_DEFAULT_IMPORTS;
}
void ETSParser::ParseSource(const SourceFile &source_file)
{
auto *program = Allocator()->New<parser::Program>(Allocator(), Binder());
auto esp = ExternalSourceParser(this, program);
auto lexer = InitLexer(source_file);
lexer::SourcePosition start_loc = Lexer()->GetToken().Start();
Lexer()->NextToken();
auto statements = PrepareExternalGlobalClass(source_file);
ParseETSGlobalScript(start_loc, statements, {});
}
ArenaVector<ir::AstNode *> ETSParser::ParseTopLevelStatements(ArenaVector<ir::Statement *> &statements)
{
ArenaVector<ir::AstNode *> global_properties(Allocator()->Adapter());
ArenaVector<ir::Statement *> exports(Allocator()->Adapter());
while (Lexer()->GetToken().Type() != lexer::TokenType::EOS) {
if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_SEMI_COLON) {
Lexer()->NextToken();
continue;
}
auto current_pos = std::numeric_limits<size_t>::max();
if (Lexer()->GetToken().Type() == lexer::TokenType::KEYW_EXPORT) {
Lexer()->NextToken();
current_pos = global_properties.size();
}
lexer::SourcePosition start_loc = Lexer()->GetToken().Start();
auto member_modifiers = ir::ModifierFlags::STATIC | ir::ModifierFlags::PUBLIC;
switch (Lexer()->GetToken().Type()) {
case lexer::TokenType::KEYW_CONST: {
member_modifiers |= ir::ModifierFlags::CONST;
[[fallthrough]];
}
case lexer::TokenType::KEYW_LET: {
Lexer()->NextToken();
auto *member_name = ExpectIdentifier();
auto class_ctx =
binder::LexicalScope<binder::ClassScope>::Enter(Binder(), GetProgram()->GlobalClassScope());
ParseClassFieldDefiniton(member_name, member_modifiers, &global_properties);
break;
}
case lexer::TokenType::KEYW_ASYNC:
case lexer::TokenType::KEYW_NATIVE: {
bool is_async = Lexer()->GetToken().Type() == lexer::TokenType::KEYW_ASYNC;
if (is_async) {
member_modifiers |= ir::ModifierFlags::ASYNC;
} else {
member_modifiers |= ir::ModifierFlags::NATIVE;
}
Lexer()->NextToken();
if (Lexer()->GetToken().Type() != lexer::TokenType::KEYW_FUNCTION) {
ThrowSyntaxError(
{is_async ? "'async'" : "'native'", " flags must be used for functions at top-level."});
}
[[fallthrough]];
}
case lexer::TokenType::KEYW_FUNCTION: {
Lexer()->NextToken();
auto *member_name = ExpectIdentifier();
auto class_ctx =
binder::LexicalScope<binder::ClassScope>::Enter(Binder(), GetProgram()->GlobalClassScope());
auto *class_method = ParseClassMethodDefinition(member_name, member_modifiers);
class_method->SetStart(start_loc);
if (!class_method->Function()->IsOverload()) {
global_properties.push_back(class_method);
}
break;
}
default: {
ir::Statement *node {};
{
auto class_ctx =
binder::LexicalScope<binder::ClassScope>::Enter(Binder(), GetProgram()->GlobalClassScope());
node = ParseTypeDeclaration();
statements.push_back(node);
}
AddGlobalDeclaration(node);
break;
}
}
while (current_pos < global_properties.size()) {
auto *prop = global_properties[current_pos++];
auto *export_stmt = AllocNodeNoSetParent<ir::ExportNamedDeclaration>(Allocator(), prop);
export_stmt->SetRange(prop->Range());
exports.push_back(export_stmt);
}
}
statements.insert(statements.end(), exports.begin(), exports.end());
return global_properties;
}
void ETSParser::AddGlobalDeclaration(ir::AstNode *node)
{
switch (node->Type()) {
case ir::AstNodeType::CLASS_DECLARATION: {
auto *ident = node->AsClassDeclaration()->Definition()->Ident();
Binder()->TopScope()->Bindings().insert({ident->Name(), ident->Variable()});
if ((GetContext().Status() & ParserStatus::IN_EXTERNAL) != 0) { // IN_EXTERNAL
ident->Variable()->AddFlag(binder::VariableFlags::BUILTIN_TYPE);
}
break;
}
case ir::AstNodeType::TS_INTERFACE_DECLARATION: {
auto *ident = node->AsTSInterfaceDeclaration()->Id();
Binder()->TopScope()->Bindings().insert({ident->Name(), ident->Variable()});
if ((GetContext().Status() & ParserStatus::IN_EXTERNAL) != 0) {
ident->Variable()->AddFlag(binder::VariableFlags::BUILTIN_TYPE);
}
break;
}
case ir::AstNodeType::TS_ENUM_DECLARATION: {
auto *ident = node->AsTSEnumDeclaration()->Key();
Binder()->TopScope()->Bindings().insert({ident->Name(), ident->Variable()});
break;
}
case ir::AstNodeType::TS_TYPE_ALIAS_DECLARATION: {
auto *ident = node->AsTSTypeAliasDeclaration()->Id();
Binder()->TopScope()->Bindings().insert({ident->Name(), ident->Variable()});
break;
}
default: {
break;
}
}
}
void ETSParser::ParseTopLevelDeclaration(ArenaVector<ir::Statement *> &statements)
{
lexer::SourcePosition class_body_start_loc = Lexer()->GetToken().Start();
auto global_properties = ParseTopLevelStatements(statements);
auto *class_def = GetProgram()->GlobalClass();
if (class_def->IsGlobalInitialized()) {
class_def->AddProperties(std::move(global_properties));
Lexer()->NextToken();
return;
}
CreateCCtor(GetProgram()->GlobalClassScope()->StaticMethodScope(), global_properties, class_body_start_loc,
GetProgram()->Kind() != ScriptKind::STDLIB);
class_def->AddProperties(std::move(global_properties));
auto *class_decl = class_def->Parent()->AsClassDeclaration();
class_def->SetGlobalInitialized();
class_def->SetRange(class_def->Range());
statements.push_back(class_decl);
Lexer()->NextToken();
}
// NOLINTNEXTLINE(google-default-arguments)
void ETSParser::CreateCCtor(binder::LocalScope *class_scope, ArenaVector<ir::AstNode *> &properties,
const lexer::SourcePosition &loc, const bool in_global_class)
{
bool has_static_field = false;
for (const auto *prop : properties) {
if (prop->IsClassStaticBlock()) {
return;
}
if (!prop->IsClassProperty()) {
continue;
}
const auto *field = prop->AsClassProperty();
if (field->IsStatic()) {
has_static_field = true;
}
}
if (!has_static_field && !in_global_class) {
return;
}
auto class_ctx = binder::LexicalScope<binder::LocalScope>::Enter(Binder(), class_scope);
ArenaVector<ir::Expression *> params(Allocator()->Adapter());
auto *param_scope = Binder()->Allocator()->New<binder::FunctionParamScope>(Allocator(), Binder()->GetScope());
auto *scope = Binder()->Allocator()->New<binder::FunctionScope>(Allocator(), param_scope);
auto *id = AllocNode<ir::Identifier>(compiler::Signatures::CCTOR, Allocator());
ArenaVector<ir::Statement *> statements(Allocator()->Adapter());
auto *body = AllocNode<ir::BlockStatement>(scope, std::move(statements));
auto *func = AllocNode<ir::ScriptFunction>(scope, std::move(params), nullptr, body, nullptr,
ir::ScriptFunctionFlags::STATIC_BLOCK | ir::ScriptFunctionFlags::HIDDEN,
ir::ModifierFlags::STATIC, false);
scope->BindNode(func);
func->SetIdent(id);
param_scope->BindNode(func);
scope->BindParamScope(param_scope);
param_scope->BindFunctionScope(scope);
auto *func_expr = AllocNode<ir::FunctionExpression>(func);
auto *static_block = AllocNode<ir::ClassStaticBlock>(func_expr, Allocator());
static_block->AddModifier(ir::ModifierFlags::STATIC);
static_block->SetRange({loc, loc});
auto [_, var] = Binder()->NewVarDecl<binder::FunctionDecl>(loc, Allocator(), id->Name(), static_block);
(void)_;
var->AddFlag(binder::VariableFlags::METHOD);
id->SetVariable(var);
properties.push_back(static_block);
}
static bool IsClassModifier(lexer::TokenType type)
{
return type == lexer::TokenType::KEYW_STATIC || type == lexer::TokenType::KEYW_ABSTRACT ||
type == lexer::TokenType::KEYW_OPEN;
}
ir::ModifierFlags ETSParser::ParseClassModifiers()
{
ir::ModifierFlags flags = ir::ModifierFlags::NONE;
while (IsClassModifier(Lexer()->GetToken().KeywordType())) {
ir::ModifierFlags current_flag = ir::ModifierFlags::NONE;
lexer::TokenFlags token_flags = Lexer()->GetToken().Flags();
if ((token_flags & lexer::TokenFlags::HAS_ESCAPE) != 0) {
ThrowSyntaxError("Keyword must not contain escaped characters");
}
switch (Lexer()->GetToken().KeywordType()) {
case lexer::TokenType::KEYW_STATIC: {
current_flag = ir::ModifierFlags::STATIC;
break;
}
case lexer::TokenType::KEYW_OPEN: {
current_flag = ir::ModifierFlags::OPEN;
break;
}
case lexer::TokenType::KEYW_ABSTRACT: {
current_flag = ir::ModifierFlags::ABSTRACT;
break;
}
default: {
UNREACHABLE();
}
}
if ((flags & current_flag) != 0) {
ThrowSyntaxError("Duplicated modifier is not allowed");
}
Lexer()->NextToken();
flags |= current_flag;
}
return flags;
}
std::tuple<ir::Expression *, ir::TSTypeParameterInstantiation *> ETSParser::ParseClassImplementsElement()
{
TypeAnnotationParsingOptions options =
TypeAnnotationParsingOptions::THROW_ERROR | TypeAnnotationParsingOptions::DISALLOW_PRIMARY_TYPE |
TypeAnnotationParsingOptions::IGNORE_FUNCTION_TYPE | TypeAnnotationParsingOptions::ALLOW_WILDCARD;
return {ParseTypeReference(&options), nullptr};
}
ir::Expression *ETSParser::ParseSuperClassReference()
{
if (Lexer()->GetToken().Type() == lexer::TokenType::KEYW_EXTENDS) {
Lexer()->NextToken();
TypeAnnotationParsingOptions options =
TypeAnnotationParsingOptions::THROW_ERROR | TypeAnnotationParsingOptions::DISALLOW_PRIMARY_TYPE |
TypeAnnotationParsingOptions::IGNORE_FUNCTION_TYPE | TypeAnnotationParsingOptions::ALLOW_WILDCARD;
return ParseTypeReference(&options);
}
return nullptr;
}
ir::TypeNode *ETSParser::ParseInterfaceExtendsElement()
{
TypeAnnotationParsingOptions options =
TypeAnnotationParsingOptions::THROW_ERROR | TypeAnnotationParsingOptions::DISALLOW_PRIMARY_TYPE |
TypeAnnotationParsingOptions::IGNORE_FUNCTION_TYPE | TypeAnnotationParsingOptions::ALLOW_WILDCARD;
return ParseTypeReference(&options);
}
static bool IsClassMemberAccessModifier(lexer::TokenType type)
{
return type == lexer::TokenType::KEYW_PUBLIC || type == lexer::TokenType::KEYW_PRIVATE ||
type == lexer::TokenType::KEYW_PROTECTED || type == lexer::TokenType::KEYW_INTERNAL;
}
std::tuple<ir::ModifierFlags, bool> ETSParser::ParseClassMemberAccessModifiers()
{
if (IsClassMemberAccessModifier(Lexer()->GetToken().Type())) {
char32_t next_cp = Lexer()->Lookahead();
if (!(next_cp != lexer::LEX_CHAR_EQUALS && next_cp != lexer::LEX_CHAR_COLON &&
next_cp != lexer::LEX_CHAR_LEFT_PAREN)) {
return {ir::ModifierFlags::NONE, false};
}
lexer::TokenFlags token_flags = Lexer()->GetToken().Flags();
if ((token_flags & lexer::TokenFlags::HAS_ESCAPE) != 0) {
ThrowSyntaxError("Keyword must not contain escaped characters");
}
ir::ModifierFlags access_flag = ir::ModifierFlags::NONE;
switch (Lexer()->GetToken().KeywordType()) {
case lexer::TokenType::KEYW_PUBLIC: {
access_flag = ir::ModifierFlags::PUBLIC;
break;
}
case lexer::TokenType::KEYW_PRIVATE: {
access_flag = ir::ModifierFlags::PRIVATE;
break;
}
case lexer::TokenType::KEYW_PROTECTED: {
access_flag = ir::ModifierFlags::PROTECTED;
break;
}
case lexer::TokenType::KEYW_INTERNAL: {
Lexer()->NextToken(lexer::NextTokenFlags::KEYWORD_TO_IDENT);
if (Lexer()->GetToken().KeywordType() != lexer::TokenType::KEYW_PROTECTED) {
access_flag = ir::ModifierFlags::INTERNAL;
return {access_flag, true};
}
access_flag = ir::ModifierFlags::INTERNAL_PROTECTED;
break;
}
default: {
UNREACHABLE();
}
}
Lexer()->NextToken(lexer::NextTokenFlags::KEYWORD_TO_IDENT);
return {access_flag, true};
}
return {ir::ModifierFlags::PUBLIC, false};
}
static bool IsClassFieldModifier(lexer::TokenType type)
{
return type == lexer::TokenType::KEYW_STATIC || type == lexer::TokenType::KEYW_READONLY;
}
ir::ModifierFlags ETSParser::ParseClassFieldModifiers(bool seen_static)
{
ir::ModifierFlags flags = seen_static ? ir::ModifierFlags::STATIC : ir::ModifierFlags::NONE;
while (IsClassFieldModifier(Lexer()->GetToken().KeywordType())) {
char32_t next_cp = Lexer()->Lookahead();
if (!(next_cp != lexer::LEX_CHAR_EQUALS && next_cp != lexer::LEX_CHAR_COLON)) {
return flags;
}
ir::ModifierFlags current_flag = ir::ModifierFlags::NONE;
lexer::TokenFlags token_flags = Lexer()->GetToken().Flags();
if ((token_flags & lexer::TokenFlags::HAS_ESCAPE) != 0) {
ThrowSyntaxError("Keyword must not contain escaped characters");
}
switch (Lexer()->GetToken().KeywordType()) {
case lexer::TokenType::KEYW_STATIC: {
current_flag = ir::ModifierFlags::STATIC;
break;
}
case lexer::TokenType::KEYW_READONLY: {
// TODO(OCs): Use ir::ModifierFlags::READONLY once compiler is ready for it.
current_flag = ir::ModifierFlags::CONST;
break;
}
default: {
UNREACHABLE();
}
}
if ((flags & current_flag) != 0) {
ThrowSyntaxError("Duplicated modifier is not allowed");
}
Lexer()->NextToken(lexer::NextTokenFlags::KEYWORD_TO_IDENT);
flags |= current_flag;
}
return flags;
}
static bool IsClassMethodModifier(lexer::TokenType type)
{
switch (type) {
case lexer::TokenType::KEYW_STATIC:
case lexer::TokenType::KEYW_OPEN:
case lexer::TokenType::KEYW_NATIVE:
case lexer::TokenType::KEYW_ASYNC:
case lexer::TokenType::KEYW_OVERRIDE:
case lexer::TokenType::KEYW_ABSTRACT: {
return true;
}
default: {
break;
}
}
return false;
}
ir::ModifierFlags ETSParser::ParseClassMethodModifiers(bool seen_static)
{
ir::ModifierFlags flags = seen_static ? ir::ModifierFlags::STATIC : ir::ModifierFlags::NONE;
while (IsClassMethodModifier(Lexer()->GetToken().KeywordType())) {
char32_t next_cp = Lexer()->Lookahead();
if (!(next_cp != lexer::LEX_CHAR_LEFT_PAREN)) {
return flags;
}
ir::ModifierFlags current_flag = ir::ModifierFlags::NONE;
lexer::TokenFlags token_flags = Lexer()->GetToken().Flags();
if ((token_flags & lexer::TokenFlags::HAS_ESCAPE) != 0) {
ThrowSyntaxError("Keyword must not contain escaped characters");
}
switch (Lexer()->GetToken().KeywordType()) {
case lexer::TokenType::KEYW_STATIC: {
current_flag = ir::ModifierFlags::STATIC;
break;
}
case lexer::TokenType::KEYW_OPEN: {
current_flag = ir::ModifierFlags::OPEN;
break;
}
case lexer::TokenType::KEYW_NATIVE: {
current_flag = ir::ModifierFlags::NATIVE;
break;
}
case lexer::TokenType::KEYW_ASYNC: {
current_flag = ir::ModifierFlags::ASYNC;
break;
}
case lexer::TokenType::KEYW_OVERRIDE: {
current_flag = ir::ModifierFlags::OVERRIDE;
break;
}
case lexer::TokenType::KEYW_ABSTRACT: {
current_flag = ir::ModifierFlags::ABSTRACT;
break;
}
default: {
UNREACHABLE();
}
}
if ((flags & current_flag) != 0) {
ThrowSyntaxError("Duplicated modifier is not allowed");
}
Lexer()->NextToken(lexer::NextTokenFlags::KEYWORD_TO_IDENT);
flags |= current_flag;
// NOLINTNEXTLINE(readability-implicit-bool-conversion)
if ((flags & ir::ModifierFlags::ASYNC && flags & ir::ModifierFlags::NATIVE) != 0) {
ThrowSyntaxError("Native method can not be async");
}
}
return flags;
}
void ETSParser::ParseClassFieldDefiniton(ir::Identifier *field_name, ir::ModifierFlags modifiers,
ArenaVector<ir::AstNode *> *declarations)
{
ir::TypeNode *type_annotation = nullptr;
TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::THROW_ERROR;
if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COLON) {
Lexer()->NextToken(); // eat ':'
type_annotation = ParseTypeAnnotation(&options);
}
ir::Expression *initializer = nullptr;
if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_SUBSTITUTION) {
Lexer()->NextToken(); // eat '='
initializer = ParseInitializer();
} else if (type_annotation == nullptr) {
ThrowSyntaxError("Field type annotation expected");
}
auto *field = AllocNode<ir::ClassProperty>(field_name, initializer, type_annotation, modifiers, Allocator(), false);
if ((modifiers & ir::ModifierFlags::CONST) != 0) {
Binder()->AddDecl<binder::ConstDecl>(field_name->Start(), field_name->Name(), field);
} else {
Binder()->AddDecl<binder::LetDecl>(field_name->Start(), field_name->Name(), field);
}
declarations->push_back(field);
if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COMMA) {
Lexer()->NextToken();
ir::Identifier *next_name = ExpectIdentifier();
ParseClassFieldDefiniton(next_name, modifiers, declarations);
}
}
ir::MethodDefinition *ETSParser::ParseClassMethodDefinition(ir::Identifier *method_name, ir::ModifierFlags modifiers)
{
auto new_status = ParserStatus::NEED_RETURN_TYPE | ParserStatus::ALLOW_SUPER;
auto method_kind = ir::MethodDefinitionKind::METHOD;
auto script_function_flag = ir::ScriptFunctionFlags::METHOD;
if ((modifiers & ir::ModifierFlags::CONSTRUCTOR) != 0) {
new_status = ParserStatus::CONSTRUCTOR_FUNCTION | ParserStatus::ALLOW_SUPER | ParserStatus::ALLOW_SUPER_CALL;
method_kind = ir::MethodDefinitionKind::CONSTRUCTOR;
script_function_flag |= ir::ScriptFunctionFlags::CONSTRUCTOR;
}
if ((modifiers & ir::ModifierFlags::ASYNC) != 0) {
new_status |= ParserStatus::ASYNC_FUNCTION;
}
ir::ScriptFunction *func = ParseFunction(new_status);
func->SetIdent(method_name);
auto *func_expr = AllocNode<ir::FunctionExpression>(func);
func_expr->SetRange(func->Range());
func->AddModifier(modifiers);
auto *method = AllocNode<ir::MethodDefinition>(method_kind, method_name, func_expr, modifiers, Allocator(), false);
method->SetRange(func_expr->Range());
CreateClassFunctionDeclaration(method_name, method, func);
return method;
}
ir::ScriptFunction *ETSParser::ParseFunction(ParserStatus new_status)
{
FunctionContext function_context(this, new_status | ParserStatus::FUNCTION);
lexer::SourcePosition start_loc = Lexer()->GetToken().Start();
auto [typeParamDecl, params, returnTypeAnnotation, funcParamScope, throw_marker] =
ParseFunctionSignature(new_status);
auto param_ctx = binder::LexicalScope<binder::FunctionParamScope>::Enter(Binder(), funcParamScope, false);
auto function_ctx = binder::LexicalScope<binder::FunctionScope>(Binder());
auto *function_scope = function_ctx.GetScope();
function_scope->BindParamScope(funcParamScope);
funcParamScope->BindFunctionScope(function_scope);
ir::AstNode *body = nullptr;
lexer::SourcePosition end_loc = start_loc;
bool is_overload = false;
bool is_arrow = (new_status & ParserStatus::ARROW_FUNCTION) != 0;
if ((new_status & ParserStatus::ASYNC_FUNCTION) != 0) {
function_context.AddFlag(ir::ScriptFunctionFlags::ASYNC);
}
if (is_arrow) {
if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_ARROW) {
ThrowSyntaxError("'=>' expected");
}
function_context.AddFlag(ir::ScriptFunctionFlags::ARROW);
Lexer()->NextToken();
}
if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_BRACE) {
std::tie(std::ignore, body, end_loc, is_overload) =
ParseFunctionBody(params, new_status, GetContext().Status(), function_scope);
} else if (is_arrow) {
body = ParseExpression();
end_loc = body->AsExpression()->End();
function_context.AddFlag(ir::ScriptFunctionFlags::EXPRESSION);
}
function_context.AddFlag(throw_marker);
auto *func_node = AllocNode<ir::ScriptFunction>(function_scope, std::move(params), typeParamDecl, body,
returnTypeAnnotation, function_context.Flags(), false);
function_scope->BindNode(func_node);
funcParamScope->BindNode(func_node);
func_node->SetRange({start_loc, end_loc});
return func_node;
}
std::tuple<bool, ir::BlockStatement *, lexer::SourcePosition, bool> ETSParser::ParseFunctionBody(
[[maybe_unused]] const ArenaVector<ir::Expression *> &params, [[maybe_unused]] ParserStatus new_status,
[[maybe_unused]] ParserStatus context_status, binder::FunctionScope *func_scope)
{
ASSERT(Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_BRACE);
ir::BlockStatement *body = ParseBlockStatement(func_scope);
return {true, body, body->End(), false};
}
ir::TypeNode *ETSParser::ParseFunctionReturnType([[maybe_unused]] ParserStatus status)
{
if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COLON) {
if ((status & ParserStatus::CONSTRUCTOR_FUNCTION) != 0U) {
ThrowSyntaxError("Type annotation isn't allowed for constructor.");
}
Lexer()->NextToken(); // eat ':'
TypeAnnotationParsingOptions options =
TypeAnnotationParsingOptions::THROW_ERROR | TypeAnnotationParsingOptions::CAN_BE_TS_TYPE_PREDICATE;
return ParseTypeAnnotation(&options);
}
return nullptr;
}
ir::ScriptFunctionFlags ETSParser::ParseFunctionThrowMarker(bool is_rethrows_allowed)
{
ir::ScriptFunctionFlags throw_marker = ir::ScriptFunctionFlags::NONE;
if (Lexer()->GetToken().Type() == lexer::TokenType::LITERAL_IDENT) {
if (Lexer()->GetToken().KeywordType() == lexer::TokenType::KEYW_THROWS) {
Lexer()->NextToken(); // eat 'throws'
throw_marker = ir::ScriptFunctionFlags::THROWS;
} else if (Lexer()->GetToken().KeywordType() == lexer::TokenType::KEYW_RETHROWS) {
if (is_rethrows_allowed) {
Lexer()->NextToken(); // eat 'rethrows'
throw_marker = ir::ScriptFunctionFlags::RETHROWS;
} else {
ThrowSyntaxError("Only 'throws' can be used with function types");
}
}
}
return throw_marker;
}
void ETSParser::ValidateLabeledStatement(lexer::TokenType type)
{
if (type != lexer::TokenType::KEYW_DO && type != lexer::TokenType::KEYW_WHILE &&
type != lexer::TokenType::KEYW_FOR && type != lexer::TokenType::KEYW_SWITCH) {
ThrowSyntaxError("Label must be followed by a loop statement", Lexer()->GetToken().Start());
}
}
// NOLINTNEXTLINE(google-default-arguments)
ir::AstNode *ETSParser::ParseClassElement([[maybe_unused]] const ArenaVector<ir::AstNode *> &properties,
[[maybe_unused]] ir::ClassDefinitionModifiers modifiers,
[[maybe_unused]] ir::ModifierFlags flags)
{
auto start_loc = Lexer()->GetToken().Start();
auto saved_pos = Lexer()->Save(); // NOLINT(clang-analyzer-deadcode.DeadStores)
if (Lexer()->GetToken().KeywordType() == lexer::TokenType::KEYW_STATIC &&
Lexer()->Lookahead() == lexer::LEX_CHAR_LEFT_BRACE) {
return ParseClassStaticBlock();
}
auto [memberModifiers, stepToken] = ParseClassMemberAccessModifiers();
bool seen_static = false;
char32_t next_cp = Lexer()->Lookahead();
if (Lexer()->GetToken().KeywordType() == lexer::TokenType::KEYW_STATIC && next_cp != lexer::LEX_CHAR_EQUALS &&
next_cp != lexer::LEX_CHAR_COLON && next_cp != lexer::LEX_CHAR_LEFT_PAREN &&
next_cp != lexer::LEX_CHAR_LESS_THAN) {
Lexer()->NextToken();
memberModifiers |= ir::ModifierFlags::STATIC;
seen_static = true;
}
if (IsClassFieldModifier(Lexer()->GetToken().KeywordType())) {
memberModifiers |= ParseClassFieldModifiers(seen_static);
} else if (IsClassMethodModifier(Lexer()->GetToken().Type())) {
memberModifiers |= ParseClassMethodModifiers(seen_static);
}
switch (Lexer()->GetToken().Type()) {
case lexer::TokenType::KEYW_INTERFACE:
case lexer::TokenType::KEYW_CLASS:
case lexer::TokenType::KEYW_ENUM: {
ThrowSyntaxError("Local type declaration (class, interface and enum) support is not yet implemented.");
// remove saved_pos nolint
Lexer()->Rewind(saved_pos);
if (stepToken) {
Lexer()->NextToken();
}
Lexer()->GetToken().SetTokenType(Lexer()->GetToken().KeywordType());
ir::AstNode *type_decl = ParseTypeDeclaration(true);
memberModifiers &= (ir::ModifierFlags::PUBLIC | ir::ModifierFlags::PROTECTED | ir::ModifierFlags::PRIVATE |
ir::ModifierFlags::INTERNAL);
type_decl->AddModifier(memberModifiers);
if (type_decl->IsClassDeclaration() && !seen_static) {
type_decl->AsClassDeclaration()->Definition()->AsClassDefinition()->SetInnerModifier();
}
return type_decl;
}
case lexer::TokenType::KEYW_CONSTRUCTOR: {
auto *member_name = AllocNode<ir::Identifier>(Lexer()->GetToken().Ident(), Allocator());
memberModifiers |= ir::ModifierFlags::CONSTRUCTOR;
Lexer()->NextToken();
auto *class_method = ParseClassMethodDefinition(member_name, memberModifiers);
class_method->SetStart(start_loc);
return class_method;
}
default: {
break;
}
}
switch (Lexer()->GetToken().Type()) {
case lexer::TokenType::KEYW_PUBLIC:
case lexer::TokenType::KEYW_PRIVATE:
case lexer::TokenType::KEYW_PROTECTED: {
ThrowSyntaxError("Access modifier must precede field and method modifiers.");
break;
}
default:
break;
}
auto *member_name = ExpectIdentifier();
if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS ||
Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LESS_THAN) {
auto *class_method = ParseClassMethodDefinition(member_name, memberModifiers);
class_method->SetStart(start_loc);
return class_method;
}
ArenaVector<ir::AstNode *> field_declarations(Allocator()->Adapter());
auto *placeholder = AllocNode<ir::TSInterfaceBody>(std::move(field_declarations));
ParseClassFieldDefiniton(member_name, memberModifiers, placeholder->BodyPtr());
return placeholder;
}
ir::Statement *ETSParser::ParseTypeDeclaration(bool allow_static)
{
auto saved_pos = Lexer()->Save();
auto modifiers = ir::ClassDefinitionModifiers::ID_REQUIRED | ir::ClassDefinitionModifiers::CLASS_DECL;
auto token_type = Lexer()->GetToken().Type();
switch (token_type) {
case lexer::TokenType::KEYW_STATIC: {
if (!allow_static) {
ThrowUnexpectedToken(Lexer()->GetToken().Type());
}
Lexer()->NextToken();
if (Lexer()->GetToken().Type() == lexer::TokenType::KEYW_INTERFACE) {
return ParseInterfaceDeclaration(true);
}
Lexer()->Rewind(saved_pos);
[[fallthrough]];
}
case lexer::TokenType::KEYW_ABSTRACT:
case lexer::TokenType::KEYW_OPEN: {
auto flags = ParseClassModifiers();
if (Lexer()->GetToken().Type() != lexer::TokenType::KEYW_CLASS) {
ThrowExpectedToken(lexer::TokenType::KEYW_CLASS);
}
if (allow_static && (flags & ir::ModifierFlags::STATIC) == 0U) {
modifiers |= ir::ClassDefinitionModifiers::INNER;
}
return ParseClassDeclaration(modifiers, flags);
}
case lexer::TokenType::KEYW_ENUM: {
return ParseEnumDeclaration(false);
}
case lexer::TokenType::KEYW_INTERFACE: {
return ParseInterfaceDeclaration(false);
}
case lexer::TokenType::KEYW_CLASS: {
return ParseClassDeclaration(modifiers);
}
case lexer::TokenType::LITERAL_IDENT: {
if (Lexer()->GetToken().KeywordType() == lexer::TokenType::KEYW_TYPE) {
return ParseTypeAliasDeclaration();
}
[[fallthrough]];
}
case lexer::TokenType::LITERAL_NUMBER:
case lexer::TokenType::LITERAL_NULL:
case lexer::TokenType::LITERAL_STRING:
case lexer::TokenType::LITERAL_FALSE:
case lexer::TokenType::LITERAL_TRUE:
case lexer::TokenType::LITERAL_CHAR: {
std::string err_msg("Cannot used in global scope '");
std::string text = token_type == lexer::TokenType::LITERAL_CHAR
? util::Helpers::UTF16toUTF8(Lexer()->GetToken().Utf16())
: Lexer()->GetToken().Ident().Mutf8();
if ((Lexer()->GetToken().Flags() & lexer::TokenFlags::HAS_ESCAPE) == 0) {
err_msg.append(text);
} else {
err_msg.append(util::Helpers::CreateEscapedString(text));
}
err_msg.append("'");
ThrowSyntaxError(err_msg.c_str());
}
default: {
ThrowUnexpectedToken(Lexer()->GetToken().Type());
}
}
}
ir::TSTypeAliasDeclaration *ETSParser::ParseTypeAliasDeclaration()
{
ASSERT(Lexer()->GetToken().KeywordType() == lexer::TokenType::KEYW_TYPE);
if ((GetContext().Status() & parser::ParserStatus::FUNCTION) != 0U) {
ThrowSyntaxError("Type alias is allowed only as top-level declaration");
}
lexer::SourcePosition type_start = Lexer()->GetToken().Start();
Lexer()->NextToken(); // eat type keyword
if (Lexer()->GetToken().Type() != lexer::TokenType::LITERAL_IDENT) {
ThrowSyntaxError("Identifier expected");
}
if (Lexer()->GetToken().IsReservedTypeName()) {
std::string err_msg("Type alias name cannot be '");
err_msg.append(TokenToString(Lexer()->GetToken().KeywordType()));
err_msg.append("'");
ThrowSyntaxError(err_msg.c_str());
}
const util::StringView ident = Lexer()->GetToken().Ident();
auto *id = AllocNode<ir::Identifier>(ident, Allocator());
id->SetRange(Lexer()->GetToken().Loc());
auto *type_alias_decl = AllocNode<ir::TSTypeAliasDeclaration>(Allocator(), id);
Binder()->AddDecl<binder::TypeAliasDecl>(Lexer()->GetToken().Start(), ident, type_alias_decl);
Lexer()->NextToken(); // eat alias name
auto type_params_ctx = binder::LexicalScope<binder::LocalScope>(Binder());
if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LESS_THAN) {
auto options =
TypeAnnotationParsingOptions::THROW_ERROR | TypeAnnotationParsingOptions::ALLOW_DECLARATION_SITE_VARIANCE;
ir::TSTypeParameterDeclaration *params = ParseTypeParameterDeclaration(&options);
type_alias_decl->AddTypeParameters(params);
params->SetParent(type_alias_decl);
}
if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_SUBSTITUTION) {
ThrowSyntaxError("'=' expected");
}
Lexer()->NextToken(); // eat '='
TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::THROW_ERROR;
ir::TypeNode *type_annotation = ParseTypeAnnotation(&options);
type_alias_decl->SetTsTypeAnnotation(type_annotation);
type_alias_decl->SetRange({type_start, Lexer()->GetToken().End()});
type_annotation->SetParent(type_alias_decl);
return type_alias_decl;
}
ir::TSInterfaceDeclaration *ETSParser::ParseInterfaceBody(ir::Identifier *name, bool is_static)
{
GetContext().Status() |= ParserStatus::ALLOW_THIS_TYPE;
auto type_params_ctx = binder::LexicalScope<binder::LocalScope>(Binder());
ir::TSTypeParameterDeclaration *type_param_decl = nullptr;
if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LESS_THAN) {
auto options =
TypeAnnotationParsingOptions::THROW_ERROR | TypeAnnotationParsingOptions::ALLOW_DECLARATION_SITE_VARIANCE;
type_param_decl = ParseTypeParameterDeclaration(&options);
}
ArenaVector<ir::TSInterfaceHeritage *> extends(Allocator()->Adapter());
if (Lexer()->GetToken().Type() == lexer::TokenType::KEYW_EXTENDS) {
extends = ParseInterfaceExtendsClause();
}
auto local_scope = binder::LexicalScope<binder::ClassScope>(Binder());
lexer::SourcePosition body_start = Lexer()->GetToken().Start();
auto members = ParseTypeLiteralOrInterface();
for (auto &member : members) {
if (member->Type() == ir::AstNodeType::CLASS_DECLARATION ||
member->Type() == ir::AstNodeType::TS_ENUM_DECLARATION ||
member->Type() == ir::AstNodeType::TS_INTERFACE_DECLARATION) {
ThrowSyntaxError("Local type declaration (class, interface and enum) support is not yet implemented.");
}
}
auto *body = AllocNode<ir::TSInterfaceBody>(std::move(members));
body->SetRange({body_start, Lexer()->GetToken().End()});
auto *interface_decl = AllocNode<ir::TSInterfaceDeclaration>(Allocator(), local_scope.GetScope(), name,
type_param_decl, body, std::move(extends), is_static);
Lexer()->NextToken();
GetContext().Status() &= ~ParserStatus::ALLOW_THIS_TYPE;
return interface_decl;
}
ir::Statement *ETSParser::ParseInterfaceDeclaration(bool is_static)
{
if ((GetContext().Status() & parser::ParserStatus::FUNCTION) != 0U) {
ThrowSyntaxError("Local interface declaration support is not yet implemented.");
}
lexer::SourcePosition interface_start = Lexer()->GetToken().Start();
Lexer()->NextToken(); // eat interface keyword
auto *id = ExpectIdentifier();
util::StringView ident = FormInterfaceOrEnumDeclarationIdBinding(id);
auto *decl_node = ParseInterfaceBody(id, is_static);
auto *decl = Binder()->AddDecl<binder::InterfaceDecl>(Lexer()->GetToken().Start(), Allocator(), ident, decl_node);
decl->AsInterfaceDecl()->Add(decl_node);
decl_node->SetRange({interface_start, Lexer()->GetToken().End()});
return decl_node;
}
// NOLINTNEXTLINE(google-default-arguments)
ir::Statement *ETSParser::ParseEnumDeclaration(bool is_const, bool is_static)
{
ASSERT(Lexer()->GetToken().Type() == lexer::TokenType::KEYW_ENUM);
if ((GetContext().Status() & parser::ParserStatus::FUNCTION) != 0U) {
ThrowSyntaxError("Local enum declaration support is not yet implemented.");
}
lexer::SourcePosition enum_start = Lexer()->GetToken().Start();
Lexer()->NextToken(); // eat enum keyword
auto *key = ExpectIdentifier();
util::StringView ident = FormInterfaceOrEnumDeclarationIdBinding(key);
auto *decl_node = ParseEnumMembers(key, enum_start, is_const, is_static);
auto *decl = Binder()->AddDecl<binder::EnumLiteralDecl>(Lexer()->GetToken().Start(), ident, decl_node, is_const);
decl->BindScope(decl_node->Scope());
return decl_node;
}
ir::Expression *ETSParser::ParseLaunchExpression(ExpressionParseFlags flags)
{
lexer::SourcePosition start = Lexer()->GetToken().Start();
Lexer()->NextToken(); // eat launch
ir::Expression *expr = ParseLeftHandSideExpression(flags);
if (!expr->IsCallExpression()) {
ThrowSyntaxError("Only call expressions are allowed after 'launch'", expr->Start());
}
auto call = expr->AsCallExpression();
auto *launch_expression = AllocNode<ir::ETSLaunchExpression>(call);
launch_expression->SetRange({start, call->End()});
return launch_expression;
}
// NOLINTNEXTLINE(google-default-arguments)
ir::ClassDefinition *ETSParser::ParseClassDefinition(ir::ClassDefinitionModifiers modifiers, ir::ModifierFlags flags)
{
Lexer()->NextToken();
ir::Identifier *ident_node = ParseClassIdent(modifiers);
auto type_params_ctx = binder::LexicalScope<binder::LocalScope>(Binder());
ir::TSTypeParameterDeclaration *type_param_decl = nullptr;
if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LESS_THAN) {
auto options =
TypeAnnotationParsingOptions::THROW_ERROR | TypeAnnotationParsingOptions::ALLOW_DECLARATION_SITE_VARIANCE;
type_param_decl = ParseTypeParameterDeclaration(&options);
}
auto class_ctx = binder::LexicalScope<binder::ClassScope>(Binder());
// Parse SuperClass
auto [superClass, superTypeParams] = ParseSuperClass();
if (superClass != nullptr) {
modifiers |= ir::ClassDefinitionModifiers::HAS_SUPER;
GetContext().Status() |= ParserStatus::ALLOW_SUPER;
}
// Parse implements clause
ArenaVector<ir::TSClassImplements *> implements(Allocator()->Adapter());
if (Lexer()->GetToken().KeywordType() == lexer::TokenType::KEYW_IMPLEMENTS) {
Lexer()->NextToken();
implements = ParseClassImplementClause();
}
ExpectToken(lexer::TokenType::PUNCTUATOR_LEFT_BRACE, false);
// Parse ClassBody
auto [ctor, properties, bodyRange] = ParseClassBody(modifiers, flags);
CreateCCtor(class_ctx.GetScope()->StaticMethodScope(), properties, bodyRange.start);
auto *class_scope = class_ctx.GetScope();
auto *class_definition = AllocNode<ir::ClassDefinition>(class_scope, util::StringView(), ident_node,
type_param_decl, superTypeParams, std::move(implements),
ctor, superClass, std::move(properties), modifiers, flags);
class_definition->SetRange(bodyRange);
class_scope->BindNode(class_definition);
GetContext().Status() &= ~ParserStatus::ALLOW_SUPER;
return class_definition;
}
static bool IsInterfaceMethodModifier(lexer::TokenType type)
{
return type == lexer::TokenType::KEYW_STATIC || type == lexer::TokenType::KEYW_PRIVATE;
}
ir::ModifierFlags ETSParser::ParseInterfaceMethodModifiers()
{
ir::ModifierFlags flags = ir::ModifierFlags::NONE;
while (IsInterfaceMethodModifier(Lexer()->GetToken().Type())) {
ir::ModifierFlags current_flag = ir::ModifierFlags::NONE;
switch (Lexer()->GetToken().Type()) {
case lexer::TokenType::KEYW_STATIC: {
current_flag = ir::ModifierFlags::STATIC;
break;
}
case lexer::TokenType::KEYW_PRIVATE: {
current_flag = ir::ModifierFlags::PRIVATE;
break;
}
default: {
UNREACHABLE();
}
}
char32_t next_cp = Lexer()->Lookahead();
if (next_cp == lexer::LEX_CHAR_COLON || next_cp == lexer::LEX_CHAR_LEFT_PAREN ||
next_cp == lexer::LEX_CHAR_EQUALS) {
break;
}
if ((flags & current_flag) != 0) {
ThrowSyntaxError("Duplicated modifier is not allowed");
}
Lexer()->NextToken();
flags |= current_flag;
}
return flags;
}
ir::ClassProperty *ETSParser::ParseInterfaceField(const lexer::SourcePosition &start_loc)
{
ASSERT(Lexer()->GetToken().Type() == lexer::TokenType::LITERAL_IDENT);
auto *name = AllocNode<ir::Identifier>(Lexer()->GetToken().Ident(), Allocator());
name->SetRange(Lexer()->GetToken().Loc());
Lexer()->NextToken();
ir::TypeNode *type_annotation = nullptr;
if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COLON) {
Lexer()->NextToken(); // eat ':'
TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::THROW_ERROR;
type_annotation = ParseTypeAnnotation(&options);
}
if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_SUBSTITUTION) {
ThrowExpectedToken(lexer::TokenType::PUNCTUATOR_SUBSTITUTION);
}
Lexer()->NextToken(); // eat '='
auto *initializer = ParseInitializer();
ir::ModifierFlags field_modifiers = ir::ModifierFlags::PUBLIC | ir::ModifierFlags::STATIC;
auto *field = AllocNode<ir::ClassProperty>(name, initializer, type_annotation, field_modifiers, Allocator(), false);
field->SetEnd(Lexer()->GetToken().End());
auto *decl = Binder()->AddDecl<binder::ConstDecl>(start_loc, field->Id()->Name(), field);
decl->BindNode(field);
return field;
}
ir::MethodDefinition *ETSParser::ParseInterfaceMethod(ir::ModifierFlags flags)
{
ASSERT(Lexer()->GetToken().Type() == lexer::TokenType::LITERAL_IDENT);
auto *name = AllocNode<ir::Identifier>(Lexer()->GetToken().Ident(), Allocator());
name->SetRange(Lexer()->GetToken().Loc());
Lexer()->NextToken();
FunctionContext function_context(this, ParserStatus::FUNCTION);
lexer::SourcePosition start_loc = Lexer()->GetToken().Start();
auto [typeParamDecl, params, returnTypeAnnotation, funcParamScope, throw_marker] =
ParseFunctionSignature(ParserStatus::NEED_RETURN_TYPE);
auto param_ctx = binder::LexicalScope<binder::FunctionParamScope>::Enter(Binder(), funcParamScope, false);
auto function_ctx = binder::LexicalScope<binder::FunctionScope>(Binder());
auto *function_scope = function_ctx.GetScope();
function_scope->BindParamScope(funcParamScope);
funcParamScope->BindFunctionScope(function_scope);
ir::BlockStatement *body = nullptr;
if ((flags & (ir::ModifierFlags::PRIVATE | ir::ModifierFlags::STATIC)) == 0) {
if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_BRACE) {
ThrowUnexpectedToken(lexer::TokenType::PUNCTUATOR_LEFT_BRACE);
}
if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_SEMI_COLON) {
Lexer()->NextToken();
}
} else if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_BRACE) {
body = ParseBlockStatement(function_scope);
} else {
ThrowSyntaxError("Private or static interface methods must have body", start_loc);
}
function_context.AddFlag(throw_marker);
auto *func = AllocNode<ir::ScriptFunction>(function_scope, std::move(params), typeParamDecl, body,
returnTypeAnnotation, function_context.Flags(), flags, true);
if ((flags & ir::ModifierFlags::STATIC) == 0) {
func->AddModifier(ir::ModifierFlags::ABSTRACT);
}
function_scope->BindNode(func);
funcParamScope->BindNode(func);
func->SetRange({start_loc, body != nullptr ? body->End() : returnTypeAnnotation->End()});
auto *func_expr = AllocNode<ir::FunctionExpression>(func);
func_expr->SetRange(func->Range());
func->AddFlag(ir::ScriptFunctionFlags::METHOD);
func->SetIdent(name);
auto *method =
AllocNode<ir::MethodDefinition>(ir::MethodDefinitionKind::METHOD, name, func_expr, flags, Allocator(), false);
method->SetRange(func_expr->Range());
return method;
}
void ETSParser::CreateClassFunctionDeclaration(ir::Identifier *method_name, ir::MethodDefinition *method,
ir::ScriptFunction *func)
{
ASSERT(Binder()->GetScope()->IsClassScope());
binder::ClassScope *cls_scope = Binder()->GetScope()->AsClassScope();
if (cls_scope->FindLocal(method_name->Name(), binder::ResolveBindingOptions::VARIABLES |
binder::ResolveBindingOptions::DECLARATION) != nullptr) {
Binder()->ThrowRedeclaration(method_name->Start(), method_name->Name());
}
binder::LocalScope *target_scope {};
if (method->IsStatic() || method->IsConstructor()) {
target_scope = cls_scope->StaticMethodScope();
} else {
target_scope = cls_scope->InstanceMethodScope();
}
auto *found = target_scope->FindLocal(method_name->Name());
if (found == nullptr) {
auto class_ctx = binder::LexicalScope<binder::LocalScope>::Enter(Binder(), target_scope);
auto [_, var] =
Binder()->NewVarDecl<binder::FunctionDecl>(method_name->Start(), Allocator(), method_name->Name(), method);
(void)_;
var->SetScope(cls_scope);
var->AddFlag(binder::VariableFlags::METHOD);
method_name->SetVariable(var);
return;
}
auto *current_node = found->Declaration()->Node();
current_node->AsMethodDefinition()->AddOverload(method);
method->Function()->Id()->SetVariable(found);
method->SetParent(current_node);
func->AddFlag(ir::ScriptFunctionFlags::OVERLOAD);
}
ir::AstNode *ETSParser::ParseTypeLiteralOrInterfaceMember()
{
auto start_loc = Lexer()->GetToken().Start();
ir::ModifierFlags method_flags = ParseInterfaceMethodModifiers();
if (method_flags != ir::ModifierFlags::NONE) {
if ((method_flags & ir::ModifierFlags::PRIVATE) == 0) {
method_flags |= ir::ModifierFlags::PUBLIC;
}
auto *method = ParseInterfaceMethod(method_flags);
method->SetStart(start_loc);
CreateClassFunctionDeclaration(method->Id(), method, method->Function());
return method;
}
if (Lexer()->GetToken().Type() == lexer::TokenType::LITERAL_IDENT) {
char32_t next_cp = Lexer()->Lookahead();
if (next_cp == lexer::LEX_CHAR_LEFT_PAREN || next_cp == lexer::LEX_CHAR_LESS_THAN) {
auto *method = ParseInterfaceMethod(ir::ModifierFlags::PUBLIC);
method->SetStart(start_loc);
CreateClassFunctionDeclaration(method->Id(), method, method->Function());
return method;
}
auto *field = ParseInterfaceField(start_loc);
field->SetStart(start_loc);
return field;
}
return ParseTypeDeclaration(true);
}
std::tuple<ir::Expression *, ir::TSTypeParameterInstantiation *> ETSParser::ParseTypeReferencePart(
TypeAnnotationParsingOptions *options)
{
ExpressionParseFlags flags = ExpressionParseFlags::NO_OPTS;
if (((*options) & TypeAnnotationParsingOptions::POTENTIAL_CLASS_LITERAL) != 0) {
flags |= ExpressionParseFlags::POTENTIAL_CLASS_LITERAL;
}
auto *type_name = ParseQualifiedName(flags);
if (type_name == nullptr) {
return {nullptr, nullptr};
}
if (((*options) & TypeAnnotationParsingOptions::POTENTIAL_CLASS_LITERAL) != 0 &&
Lexer()->GetToken().Type() == lexer::TokenType::KEYW_CLASS) {
return {type_name, nullptr};
}
ir::TSTypeParameterInstantiation *type_param_inst = nullptr;
if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_SHIFT ||
Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LESS_THAN) {
if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_SHIFT) {
Lexer()->BackwardToken(lexer::TokenType::PUNCTUATOR_LESS_THAN, 1);
}
*options |= TypeAnnotationParsingOptions::ALLOW_WILDCARD;
type_param_inst = ParseTypeParameterInstantiation(options);
*options &= ~TypeAnnotationParsingOptions::ALLOW_WILDCARD;
}
return {type_name, type_param_inst};
}
ir::TypeNode *ETSParser::ParseTypeReference(TypeAnnotationParsingOptions *options)
{
auto start_pos = Lexer()->GetToken().Start();
ir::ETSTypeReferencePart *type_ref_part = nullptr;
while (true) {
auto part_pos = Lexer()->GetToken().Start();
auto [typeName, typeParams] = ParseTypeReferencePart(options);
if (typeName == nullptr) {
return nullptr;
}
type_ref_part = AllocNode<ir::ETSTypeReferencePart>(typeName, typeParams, type_ref_part);
type_ref_part->SetRange({part_pos, Lexer()->GetToken().End()});
if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_PERIOD) {
break;
}
Lexer()->NextToken();
if (((*options) & TypeAnnotationParsingOptions::POTENTIAL_CLASS_LITERAL) != 0 &&
Lexer()->GetToken().Type() == lexer::TokenType::KEYW_CLASS) {
break;
}
}
auto *type_reference = AllocNode<ir::ETSTypeReference>(type_ref_part);
type_reference->SetRange({start_pos, Lexer()->GetToken().End()});
return type_reference;
}
ir::TypeNode *ETSParser::ParseBaseTypeReference(TypeAnnotationParsingOptions *options)
{
ir::TypeNode *type_annotation = nullptr;
switch (Lexer()->GetToken().Type()) {
case lexer::TokenType::KEYW_BOOLEAN: {
type_annotation = ParsePrimitiveType(options, ir::PrimitiveType::BOOLEAN);
break;
}
case lexer::TokenType::KEYW_BYTE: {
type_annotation = ParsePrimitiveType(options, ir::PrimitiveType::BYTE);
break;
}
case lexer::TokenType::KEYW_CHAR: {
type_annotation = ParsePrimitiveType(options, ir::PrimitiveType::CHAR);
break;
}
case lexer::TokenType::KEYW_DOUBLE: {
type_annotation = ParsePrimitiveType(options, ir::PrimitiveType::DOUBLE);
break;
}
case lexer::TokenType::KEYW_FLOAT: {
type_annotation = ParsePrimitiveType(options, ir::PrimitiveType::FLOAT);
break;
}
case lexer::TokenType::KEYW_INT: {
type_annotation = ParsePrimitiveType(options, ir::PrimitiveType::INT);
break;
}
case lexer::TokenType::KEYW_LONG: {
type_annotation = ParsePrimitiveType(options, ir::PrimitiveType::LONG);
break;
}
case lexer::TokenType::KEYW_SHORT: {
type_annotation = ParsePrimitiveType(options, ir::PrimitiveType::SHORT);
break;
}
default: {
break;
}
}
return type_annotation;
}
ir::TypeNode *ETSParser::ParsePrimitiveType(TypeAnnotationParsingOptions *options, ir::PrimitiveType type)
{
if (((*options) & TypeAnnotationParsingOptions::DISALLOW_PRIMARY_TYPE) != 0) {
ThrowSyntaxError("Primitive type is not allowed here.");
}
auto *type_annotation = AllocNode<ir::ETSPrimitiveType>(type);
type_annotation->SetRange(Lexer()->GetToken().Loc());
Lexer()->NextToken();
return type_annotation;
}
ir::TSIntersectionType *ETSParser::ParseIntersectionType(ir::Expression *type)
{
auto start_loc = type->Start();
ArenaVector<ir::Expression *> types(Allocator()->Adapter());
types.push_back(type);
TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::THROW_ERROR;
while (true) {
if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_BITWISE_AND) {
break;
}
Lexer()->NextToken(); // eat '&'
types.push_back(ParseTypeReference(&options));
}
lexer::SourcePosition end_loc = types.back()->End();
auto *intersection_type = AllocNode<ir::TSIntersectionType>(std::move(types));
intersection_type->SetRange({start_loc, end_loc});
return intersection_type;
}
ir::TypeNode *ETSParser::ParseWildcardType(TypeAnnotationParsingOptions *options)
{
const auto variance_start_loc = Lexer()->GetToken().Start();
const auto variance_end_loc = Lexer()->GetToken().End();
const auto variance_modifier = ParseTypeVarianceModifier(options);
auto *type_reference = [this, &variance_modifier, options]() -> ir::ETSTypeReference * {
if (variance_modifier == ir::ModifierFlags::OUT &&
(Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_GREATER_THAN ||
Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COMMA)) {
// unbounded 'out'
return nullptr;
}
return ParseTypeReference(options)->AsETSTypeReference();
}();
auto *wildcard_type = AllocNode<ir::ETSWildcardType>(type_reference, variance_modifier);
wildcard_type->SetRange({variance_start_loc, type_reference == nullptr ? variance_end_loc : type_reference->End()});
return wildcard_type;
}
ir::TypeNode *ETSParser::ParseFunctionType()
{
auto start_loc = Lexer()->GetToken().Start();
auto type_params_ctx = binder::LexicalScope<binder::LocalScope>(Binder());
FunctionParameterContext func_param_context(&GetContext(), Binder());
auto *func_param_scope = func_param_context.LexicalScope().GetScope();
auto [params, params_end_loc] = ParseFunctionParams();
auto *const return_type_annotation = [this]() -> ir::TypeNode * {
if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_ARROW) {
return nullptr;
}
Lexer()->NextToken(); // eat '=>'
TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::THROW_ERROR;
return ParseTypeAnnotation(&options);
}();
ir::ScriptFunctionFlags throw_marker = ParseFunctionThrowMarker(false);
auto *func_type = AllocNode<ir::ETSFunctionType>(func_param_scope, std::move(params), nullptr,
return_type_annotation, throw_marker);
const auto end_loc = return_type_annotation != nullptr ? return_type_annotation->End() : params_end_loc;
func_type->SetRange({start_loc, end_loc});
func_param_scope->BindNode(func_type);
return func_type;
}
ir::TypeNode *ETSParser::ParseTypeAnnotation(TypeAnnotationParsingOptions *options)
{
ir::TypeNode *type_annotation = nullptr;
bool throw_error = ((*options) & TypeAnnotationParsingOptions::THROW_ERROR) != 0;
switch (Lexer()->GetToken().Type()) {
case lexer::TokenType::LITERAL_IDENT: {
if (const auto keyword = Lexer()->GetToken().KeywordType();
keyword == lexer::TokenType::KEYW_IN || keyword == lexer::TokenType::KEYW_OUT) {
type_annotation = ParseWildcardType(options);
} else {
type_annotation = ParseTypeReference(options);
}
if (((*options) & TypeAnnotationParsingOptions::POTENTIAL_CLASS_LITERAL) != 0 &&
Lexer()->GetToken().Type() == lexer::TokenType::KEYW_CLASS) {
return type_annotation;
}
break;
}
case lexer::TokenType::KEYW_VOID: {
type_annotation = ParsePrimitiveType(options, ir::PrimitiveType::VOID);
break;
}
case lexer::TokenType::KEYW_BOOLEAN: {
type_annotation = ParsePrimitiveType(options, ir::PrimitiveType::BOOLEAN);
break;
}
case lexer::TokenType::KEYW_BYTE: {
type_annotation = ParsePrimitiveType(options, ir::PrimitiveType::BYTE);
break;
}
case lexer::TokenType::KEYW_CHAR: {
type_annotation = ParsePrimitiveType(options, ir::PrimitiveType::CHAR);
break;
}
case lexer::TokenType::KEYW_DOUBLE: {
type_annotation = ParsePrimitiveType(options, ir::PrimitiveType::DOUBLE);
break;
}
case lexer::TokenType::KEYW_FLOAT: {
type_annotation = ParsePrimitiveType(options, ir::PrimitiveType::FLOAT);
break;
}
case lexer::TokenType::KEYW_INT: {
type_annotation = ParsePrimitiveType(options, ir::PrimitiveType::INT);
break;
}
case lexer::TokenType::KEYW_LONG: {
type_annotation = ParsePrimitiveType(options, ir::PrimitiveType::LONG);
break;
}
case lexer::TokenType::KEYW_SHORT: {
type_annotation = ParsePrimitiveType(options, ir::PrimitiveType::SHORT);
break;
}
case lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS: {
auto start_loc = Lexer()->GetToken().Start();
lexer::LexerPosition saved_pos = Lexer()->Save();
Lexer()->NextToken(); // eat '('
if (((*options) & TypeAnnotationParsingOptions::IGNORE_FUNCTION_TYPE) == 0 &&
(Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS ||
Lexer()->Lookahead() == lexer::LEX_CHAR_COLON)) {
type_annotation = ParseFunctionType();
type_annotation->SetStart(start_loc);
return type_annotation;
}
type_annotation = ParseTypeAnnotation(options);
type_annotation->SetStart(start_loc);
if (throw_error) {
ExpectToken(lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS, true);
if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_BITWISE_OR) {
ThrowSyntaxError(
"A parenthesized type must be followed by ' | null' after the parenthesis: ( T ) | null");
}
break;
}
if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS) {
Lexer()->NextToken(); // eat ')'
if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_BITWISE_OR) {
break;
}
}
Lexer()->Rewind(saved_pos);
type_annotation = nullptr;
break;
}
default: {
break;
}
}
if (type_annotation == nullptr) {
if (throw_error) {
ThrowSyntaxError("Invalid Type");
}
return nullptr;
}
const lexer::SourcePosition &start_pos = Lexer()->GetToken().Start();
if (((*options) & TypeAnnotationParsingOptions::ALLOW_INTERSECTION) != 0 &&
Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_BITWISE_AND) {
if (type_annotation->IsETSPrimitiveType()) {
ThrowSyntaxError("Invalid intersection type.");
}
return ParseIntersectionType(type_annotation);
}
while (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_SQUARE_BRACKET) {
Lexer()->NextToken(); // eat '['
if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_SQUARE_BRACKET) {
if (throw_error) {
ThrowExpectedToken(lexer::TokenType::PUNCTUATOR_RIGHT_SQUARE_BRACKET);
}
return nullptr;
}
Lexer()->NextToken(); // eat ']'
type_annotation = AllocNode<ir::TSArrayType>(type_annotation);
type_annotation->SetRange({start_pos, Lexer()->GetToken().End()});
}
while (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_BITWISE_OR) {
Lexer()->NextToken(); // eat '|'
if (Lexer()->GetToken().Type() != lexer::TokenType::LITERAL_NULL) {
if (throw_error) {
ThrowExpectedToken(lexer::TokenType::LITERAL_NULL);
}
return nullptr;
}
Lexer()->NextToken(); // eat 'null'
type_annotation->AddModifier(ir::ModifierFlags::NULLABLE);
}
return type_annotation;
}
void ETSParser::ThrowIfVarDeclaration(VariableParsingFlags flags)
{
if ((flags & VariableParsingFlags::VAR) != 0) {
ThrowUnexpectedToken(lexer::TokenType::KEYW_VAR);
}
}
void ETSParser::ValidateForInStatement()
{
ThrowUnexpectedToken(lexer::TokenType::KEYW_IN);
}
ir::DebuggerStatement *ETSParser::ParseDebuggerStatement()
{
ThrowUnexpectedToken(lexer::TokenType::KEYW_DEBUGGER);
}
ir::Statement *ETSParser::ParseFunctionStatement([[maybe_unused]] StatementParsingFlags flags)
{
ThrowUnexpectedToken(lexer::TokenType::KEYW_FUNCTION);
}
void ETSParser::ParsePackageDeclaration(ArenaVector<ir::Statement *> &statements)
{
auto start_loc = Lexer()->GetToken().Start();
if (Lexer()->GetToken().Type() != lexer::TokenType::KEYW_PACKAGE) {
if (!IsETSModule() && GetProgram()->IsEntryPoint()) {
return;
}
auto base_name = GetProgram()->SourceFile().Utf8();
base_name = base_name.substr(base_name.find_last_of(panda::os::file::File::GetPathDelim()) + 1);
const size_t idx = base_name.find_last_of('.');
if (idx != std::string::npos) {
base_name = base_name.substr(0, idx);
}
GetProgram()->SetPackageName(base_name);
return;
}
Lexer()->NextToken();
ir::Expression *name = ParseQualifiedName();
auto *package_declaration = AllocNode<ir::ETSPackageDeclaration>(name);
package_declaration->SetRange({start_loc, Lexer()->GetToken().End()});
ConsumeSemicolon(package_declaration);
statements.push_back(package_declaration);
if (name->IsIdentifier()) {
GetProgram()->SetPackageName(name->AsIdentifier()->Name());
} else {
GetProgram()->SetPackageName(name->AsTSQualifiedName()->ToString(Allocator()));
}
}
std::tuple<ir::ImportSource *, std::vector<std::string>> ETSParser::ParseFromClause(bool require_from)
{
if (Lexer()->GetToken().KeywordType() != lexer::TokenType::KEYW_FROM) {
if (require_from) {
ThrowSyntaxError("Unexpected token.");
}
} else {
Lexer()->NextToken(); // eat `from`
}
if (Lexer()->GetToken().Type() != lexer::TokenType::LITERAL_STRING) {
ThrowSyntaxError("Unexpected token.");
}
ASSERT(Lexer()->GetToken().Type() == lexer::TokenType::LITERAL_STRING);
std::vector<std::string> user_paths;
bool is_module = false;
auto import_path = Lexer()->GetToken().Ident();
if ((GetContext().Status() & ParserStatus::IN_DEFAULT_IMPORTS) == 0) {
std::tie(user_paths, is_module) = CollectUserSources(import_path.Mutf8());
}
if (is_module) {
auto pos = import_path.Mutf8().find_last_of(panda::os::file::File::GetPathDelim());
util::UString base_name(import_path.Mutf8().substr(0, pos), Allocator());
import_path = base_name.View();
}
auto *source = AllocNode<ir::StringLiteral>(import_path);
source->SetRange(Lexer()->GetToken().Loc());
Lexer()->NextToken();
auto *import_source = Allocator()->New<ir::ImportSource>(source);
return {import_source, user_paths};
}
std::vector<std::string> ETSParser::ParseImportDeclarations(ArenaVector<ir::Statement *> &statements)
{
std::vector<std::string> all_user_paths;
std::vector<std::string> user_paths;
ArenaVector<ir::ImportDeclaration *> imports(Allocator()->Adapter());
while (Lexer()->GetToken().Type() == lexer::TokenType::KEYW_IMPORT) {
auto start_loc = Lexer()->GetToken().Start();
Lexer()->NextToken(); // eat import
ArenaVector<ir::AstNode *> specifiers(Allocator()->Adapter());
ir::ImportSource *import_source = nullptr;
if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_MULTIPLY) {
ParseNameSpaceImport(&specifiers);
} else {
ParseNamedImportSpecifiers(&specifiers);
}
std::tie(import_source, user_paths) = ParseFromClause(true);
all_user_paths.insert(all_user_paths.end(), user_paths.begin(), user_paths.end());
lexer::SourcePosition end_loc = import_source->Source()->End();
auto *import_declaration = AllocNode<ir::ImportDeclaration>(import_source->Source(), std::move(specifiers));
import_declaration->SetRange({start_loc, end_loc});
ConsumeSemicolon(import_declaration);
statements.push_back(import_declaration);
imports.push_back(import_declaration);
}
if ((GetContext().Status() & ParserStatus::IN_DEFAULT_IMPORTS) != 0) {
static_cast<binder::ETSBinder *>(Binder())->SetDefaultImports(std::move(imports));
}
sort(all_user_paths.begin(), all_user_paths.end());
all_user_paths.erase(unique(all_user_paths.begin(), all_user_paths.end()), all_user_paths.end());
return all_user_paths;
}
void ETSParser::ParseNamedImportSpecifiers(ArenaVector<ir::AstNode *> *specifiers)
{
// TODO(user): handle qualifiedName in file bindings: qualifiedName '.' '*'
if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_LEFT_BRACE) {
ThrowSyntaxError("Unexpected token, expected '{'");
}
Lexer()->NextToken(); // eat '{'
auto file_name = GetProgram()->SourceFile().Mutf8();
while (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_BRACE) {
if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_MULTIPLY) {
ThrowSyntaxError("The '*' token is not allowed as a selective binding (between braces)");
}
if (Lexer()->GetToken().Type() != lexer::TokenType::LITERAL_IDENT) {
ThrowSyntaxError("Unexpected token");
}
lexer::Token imported_token = Lexer()->GetToken();
auto *imported = AllocNode<ir::Identifier>(imported_token.Ident(), Allocator());
ir::Identifier *local = nullptr;
imported->SetRange(Lexer()->GetToken().Loc());
Lexer()->NextToken(); // eat import name
if (CheckModuleAsModifier() && Lexer()->GetToken().Type() == lexer::TokenType::KEYW_AS) {
Lexer()->NextToken(); // eat `as` literal
local = ParseNamedImport(Lexer()->GetToken());
Lexer()->NextToken(); // eat local name
} else {
local = ParseNamedImport(imported_token);
}
auto *specifier = AllocNode<ir::ImportSpecifier>(imported, local);
specifier->SetRange({imported->Start(), local->End()});
util::Helpers::CheckImportedName(specifiers, specifier, file_name);
specifiers->push_back(specifier);
if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COMMA) {
Lexer()->NextToken(lexer::NextTokenFlags::KEYWORD_TO_IDENT); // eat comma
}
}
Lexer()->NextToken(); // eat '}'
if (Lexer()->GetToken().Type() != lexer::TokenType::KEYW_FROM) {
ThrowSyntaxError("Unexpected token, expected 'from'");
}
}
void ETSParser::ParseNameSpaceImport(ArenaVector<ir::AstNode *> *specifiers)
{
lexer::SourcePosition namespace_start = Lexer()->GetToken().Start();
Lexer()->NextToken(); // eat `*` character
if (!CheckModuleAsModifier()) {
ThrowSyntaxError("Unexpected token.");
}
auto *local = AllocNode<ir::Identifier>(util::StringView(""), Allocator());
if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COMMA ||
Lexer()->GetToken().KeywordType() == lexer::TokenType::KEYW_FROM) {
auto *specifier = AllocNode<ir::ImportNamespaceSpecifier>(local);
specifier->SetRange({namespace_start, Lexer()->GetToken().End()});
specifiers->push_back(specifier);
return;
}
Lexer()->NextToken(); // eat `as` literal
local = ParseNamedImport(Lexer()->GetToken());
auto *specifier = AllocNode<ir::ImportNamespaceSpecifier>(local);
specifier->SetRange({namespace_start, Lexer()->GetToken().End()});
specifiers->push_back(specifier);
Binder()->AddDecl<binder::ImportDecl>(local->Start(), local->Name(), local->Name(), specifier);
Lexer()->NextToken(); // eat local name
}
bool ETSParser::CheckModuleAsModifier()
{
if ((Lexer()->GetToken().Flags() & lexer::TokenFlags::HAS_ESCAPE) != 0U) {
ThrowSyntaxError("Escape sequences are not allowed in 'as' keyword");
}
return true;
}
ir::Expression *ETSParser::ParseFunctionParameter()
{
ir::AnnotatedExpression *function_parameter {};
ir::Identifier *param_ident {};
switch (Lexer()->GetToken().Type()) {
case lexer::TokenType::LITERAL_IDENT: {
function_parameter = AllocNode<ir::Identifier>(Lexer()->GetToken().Ident(), Allocator());
param_ident = function_parameter->AsIdentifier();
function_parameter->SetRange(Lexer()->GetToken().Loc());
Lexer()->NextToken();
break;
}
case lexer::TokenType::PUNCTUATOR_PERIOD_PERIOD_PERIOD: {
auto start_loc = Lexer()->GetToken().Start();
Lexer()->NextToken();
if (Lexer()->GetToken().Type() != lexer::TokenType::LITERAL_IDENT) {
ThrowSyntaxError("Unexpected token, expected an identifier.");
}
auto *rest_name = AllocNode<ir::Identifier>(Lexer()->GetToken().Ident(), Allocator());
param_ident = rest_name->AsIdentifier();
rest_name->SetRange(Lexer()->GetToken().Loc());
function_parameter = AllocNode<ir::SpreadElement>(ir::AstNodeType::REST_ELEMENT, Allocator(), rest_name);
function_parameter->SetRange({start_loc, Lexer()->GetToken().End()});
Lexer()->NextToken();
break;
}
default: {
ThrowSyntaxError("Unexpected token, expected an identifier.");
}
}
if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_COLON) {
ThrowSyntaxError("Unexpected token, expected ':'");
}
Lexer()->NextToken(); // eat ':'
TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::THROW_ERROR;
ir::TypeNode *type_annotation = ParseTypeAnnotation(&options);
type_annotation->SetParent(function_parameter);
function_parameter->SetTsTypeAnnotation(type_annotation);
function_parameter->SetEnd(type_annotation->End());
binder::Variable *var {};
std::tie(std::ignore, var) = Binder()->AddParamDecl(function_parameter);
param_ident->SetVariable(var);
var->SetScope(Binder()->GetScope());
return function_parameter;
}
void ETSParser::AddVariableDeclarationBindings(ir::Expression *init, lexer::SourcePosition start_loc,
VariableParsingFlags flags)
{
std::vector<ir::Identifier *> bindings = util::Helpers::CollectBindingNames(init);
for (auto *binding : bindings) {
binder::Decl *decl {};
binder::Variable *var {};
if ((flags & VariableParsingFlags::LET) != 0U) {
std::tie(decl, var) = Binder()->NewVarDecl<binder::LetDecl>(start_loc, binding->Name());
} else {
std::tie(decl, var) = Binder()->NewVarDecl<binder::ConstDecl>(start_loc, binding->Name());
}
binding->SetVariable(var);
var->SetScope(Binder()->GetScope());
var->AddFlag(binder::VariableFlags::LOCAL);
decl->BindNode(init);
}
}
ir::AnnotatedExpression *ETSParser::ParseVariableDeclaratorKey([[maybe_unused]] VariableParsingFlags flags)
{
ir::Identifier *init = ExpectIdentifier();
if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COLON) {
Lexer()->NextToken(); // eat ':'
TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::THROW_ERROR;
auto *type_annotation = ParseTypeAnnotation(&options);
init->SetTsTypeAnnotation(type_annotation);
type_annotation->SetParent(init);
} else if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_SUBSTITUTION) {
ThrowSyntaxError("Variable must be initializer or it's type must be declared");
}
return init;
}
ir::Expression *ETSParser::ParseInitializer()
{
if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_SQUARE_BRACKET) {
return ParseArrayLiteral();
}
return ParseExpression();
}
ir::ArrayExpression *ETSParser::ParseArrayLiteral()
{
ASSERT(Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_SQUARE_BRACKET);
lexer::SourcePosition start_loc = Lexer()->GetToken().Start();
ArenaVector<ir::Expression *> elements(Allocator()->Adapter());
Lexer()->NextToken();
while (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_SQUARE_BRACKET) {
elements.push_back(ParseInitializer());
if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COMMA) {
Lexer()->NextToken(); // eat comma
continue;
}
}
auto *array_literal = AllocNode<ir::ArrayExpression>(std::move(elements), Allocator());
array_literal->SetRange({start_loc, Lexer()->GetToken().End()});
Lexer()->NextToken();
return array_literal;
}
ir::VariableDeclarator *ETSParser::ParseVariableDeclaratorInitializer(ir::Expression *init, VariableParsingFlags flags,
const lexer::SourcePosition &start_loc)
{
if ((flags & VariableParsingFlags::DISALLOW_INIT) != 0) {
ThrowSyntaxError("for-await-of loop variable declaration may not have an initializer");
}
Lexer()->NextToken();
ir::Expression *initializer = ParseInitializer();
lexer::SourcePosition end_loc = initializer->End();
auto *declarator = AllocNode<ir::VariableDeclarator>(init, initializer);
declarator->SetRange({start_loc, end_loc});
return declarator;
}
ir::VariableDeclarator *ETSParser::ParseVariableDeclarator(ir::Expression *init, lexer::SourcePosition start_loc,
VariableParsingFlags flags)
{
if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_SUBSTITUTION) {
return ParseVariableDeclaratorInitializer(init, flags, start_loc);
}
if ((flags & VariableParsingFlags::CONST) != 0) {
ThrowSyntaxError("Missing initializer in const declaration");
}
if (init->AsIdentifier()->TypeAnnotation() == nullptr) {
ThrowSyntaxError("Variable must be initializer or it's type must be declared");
}
lexer::SourcePosition end_loc = init->End();
auto declarator = AllocNode<ir::VariableDeclarator>(init);
declarator->SetRange({start_loc, end_loc});
return declarator;
}
ir::Statement *ETSParser::ParseAssertStatement()
{
lexer::SourcePosition start_loc = Lexer()->GetToken().Start();
Lexer()->NextToken();
ir::Expression *test = ParseExpression();
lexer::SourcePosition end_loc = test->End();
ir::Expression *second = nullptr;
if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COLON) {
Lexer()->NextToken(); // eat ':'
second = ParseExpression();
end_loc = second->End();
}
auto *as_statement = AllocNode<ir::AssertStatement>(test, second);
as_statement->SetRange({start_loc, end_loc});
ConsumeSemicolon(as_statement);
return as_statement;
}
ir::Statement *ETSParser::ParsePanicStatement()
{
lexer::SourcePosition start_loc = Lexer()->GetToken().Start();
Lexer()->NextToken(); // eat panic
ir::Expression *expr = ParseExpression(ExpressionParseFlags::ACCEPT_COMMA);
lexer::SourcePosition end_loc = expr->End();
auto *panic_statement = AllocNode<ir::PanicStatement>(expr);
panic_statement->SetRange({start_loc, end_loc});
ConsumeSemicolon(panic_statement);
return panic_statement;
}
ir::Statement *ETSParser::ParseDeferStatement()
{
lexer::SourcePosition start_loc = Lexer()->GetToken().Start();
Lexer()->NextToken(); // eat defer
ir::Statement *stmt = ParseStatement();
lexer::SourcePosition end_loc = stmt->End();
auto *defer_statement = AllocNode<ir::DeferStatement>(stmt);
defer_statement->SetRange({start_loc, end_loc});
ConsumeSemicolon(defer_statement);
return defer_statement;
}
void ETSParser::ParseCatchParamTypeAnnotation([[maybe_unused]] ir::AnnotatedExpression *param)
{
if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COLON) {
Lexer()->NextToken(); // eat ':'
TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::THROW_ERROR;
param->SetTsTypeAnnotation(ParseTypeAnnotation(&options));
} else {
ThrowSyntaxError("Parameter type in catch and recover is mandatory");
}
if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_SUBSTITUTION) {
ThrowSyntaxError("Catch clause variable cannot have an initializer");
}
}
ir::Statement *ETSParser::ParseTryStatement()
{
lexer::SourcePosition start_loc = Lexer()->GetToken().Start();
Lexer()->NextToken(); // eat the 'try' keyword
if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_LEFT_BRACE) {
ThrowSyntaxError("Unexpected token, expected '{'");
}
ir::BlockStatement *body = ParseBlockStatement();
ArenaVector<ir::CatchClause *> catch_clauses(Allocator()->Adapter());
while (Lexer()->GetToken().KeywordType() == lexer::TokenType::KEYW_CATCH ||
Lexer()->GetToken().KeywordType() == lexer::TokenType::KEYW_RECOVER) {
ir::CatchClause *clause {};
if (Lexer()->GetToken().Type() == lexer::TokenType::KEYW_RECOVER) {
clause = ParseCatchClause(ir::CatchClauseType::RECOVER);
} else {
clause = ParseCatchClause(ir::CatchClauseType::CATCH);
}
catch_clauses.push_back(clause);
}
if (catch_clauses.empty()) {
ThrowSyntaxError("Missing catch or recover clause");
}
lexer::SourcePosition end_loc = catch_clauses.back()->End();
// There is no finally clause in ETS, hence the nullptr as the third argument.
auto *try_statement = AllocNode<ir::TryStatement>(body, std::move(catch_clauses), nullptr);
try_statement->SetRange({start_loc, end_loc});
ConsumeSemicolon(try_statement);
return try_statement;
}
ir::Statement *ETSParser::ParseImportDeclaration([[maybe_unused]] StatementParsingFlags flags)
{
ImportDeclarationContext import_ctx(Binder());
char32_t next_char = Lexer()->Lookahead();
if (next_char == lexer::LEX_CHAR_LEFT_PAREN || next_char == lexer::LEX_CHAR_DOT) {
return ParseExpressionStatement();
}
lexer::SourcePosition start_loc = Lexer()->GetToken().Start();
Lexer()->NextToken(); // eat import
ArenaVector<ir::AstNode *> specifiers(Allocator()->Adapter());
ir::ImportSource *import_source = nullptr;
std::vector<std::string> user_paths;
if (Lexer()->GetToken().Type() != lexer::TokenType::LITERAL_STRING) {
ir::AstNode *ast_node = ParseImportSpecifiers(&specifiers);
if (ast_node != nullptr) {
ASSERT(ast_node->IsTSImportEqualsDeclaration());
ast_node->SetRange({start_loc, Lexer()->GetToken().End()});
ConsumeSemicolon(ast_node->AsTSImportEqualsDeclaration());
return ast_node->AsTSImportEqualsDeclaration();
}
std::tie(import_source, user_paths) = ParseFromClause(true);
} else {
std::tie(import_source, user_paths) = ParseFromClause(false);
}
lexer::SourcePosition end_loc = import_source->Source()->End();
auto *import_declaration = AllocNode<ir::ImportDeclaration>(import_source->Source(), std::move(specifiers));
import_declaration->SetRange({start_loc, end_loc});
ConsumeSemicolon(import_declaration);
return import_declaration;
}
ir::Statement *ETSParser::ParseExportDeclaration([[maybe_unused]] StatementParsingFlags flags)
{
ThrowUnexpectedToken(lexer::TokenType::KEYW_EXPORT);
}
// NOLINTNEXTLINE(google-default-arguments)
ir::Expression *ETSParser::ParseUnaryOrPrefixUpdateExpression(ExpressionParseFlags flags)
{
switch (Lexer()->GetToken().Type()) {
case lexer::TokenType::PUNCTUATOR_PLUS_PLUS:
case lexer::TokenType::PUNCTUATOR_MINUS_MINUS:
case lexer::TokenType::PUNCTUATOR_PLUS:
case lexer::TokenType::PUNCTUATOR_MINUS:
case lexer::TokenType::PUNCTUATOR_TILDE:
case lexer::TokenType::PUNCTUATOR_EXCLAMATION_MARK: {
break;
}
case lexer::TokenType::KEYW_LAUNCH: {
return ParseLaunchExpression(flags);
}
default: {
return ParseLeftHandSideExpression(flags);
}
}
lexer::TokenType operator_type = Lexer()->GetToken().Type();
auto start = Lexer()->GetToken().Start();
Lexer()->NextToken();
ir::Expression *argument = nullptr;
switch (Lexer()->GetToken().Type()) {
case lexer::TokenType::PUNCTUATOR_PLUS:
case lexer::TokenType::PUNCTUATOR_MINUS:
case lexer::TokenType::PUNCTUATOR_TILDE:
case lexer::TokenType::PUNCTUATOR_EXCLAMATION_MARK:
case lexer::TokenType::PUNCTUATOR_PLUS_PLUS:
case lexer::TokenType::PUNCTUATOR_MINUS_MINUS: {
argument = ParseUnaryOrPrefixUpdateExpression();
break;
}
default: {
argument = ParseLeftHandSideExpression(flags);
break;
}
}
if (lexer::Token::IsUpdateToken(operator_type)) {
if (!argument->IsIdentifier() && !argument->IsMemberExpression()) {
ThrowSyntaxError("Invalid left-hand side in prefix operation");
}
}
lexer::SourcePosition end = argument->End();
ir::Expression *return_expr = nullptr;
if (lexer::Token::IsUpdateToken(operator_type)) {
return_expr = AllocNode<ir::UpdateExpression>(argument, operator_type, true);
} else {
return_expr = AllocNode<ir::UnaryExpression>(argument, operator_type);
}
return_expr->SetRange({start, end});
return return_expr;
}
// NOLINTNEXTLINE(google-default-arguments)
ir::Expression *ETSParser::ParsePrimaryExpression(ExpressionParseFlags flags)
{
switch (Lexer()->GetToken().Type()) {
case lexer::TokenType::LITERAL_TRUE:
case lexer::TokenType::LITERAL_FALSE: {
return ParseBooleanLiteral();
}
case lexer::TokenType::LITERAL_NULL: {
return ParseNullLiteral();
}
case lexer::TokenType::LITERAL_NUMBER: {
return ParseNumberLiteral();
}
case lexer::TokenType::LITERAL_STRING: {
return ParseStringLiteral();
}
case lexer::TokenType::LITERAL_CHAR: {
return ParseCharLiteral();
}
case lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS: {
return ParseCoverParenthesizedExpressionAndArrowParameterList();
}
case lexer::TokenType::KEYW_THIS: {
return ParseThisExpression();
}
case lexer::TokenType::KEYW_SUPER: {
return ParseSuperExpression();
}
case lexer::TokenType::KEYW_NEW: {
return ParseNewExpression();
}
case lexer::TokenType::KEYW_ASYNC: {
return ParseAsyncExpression();
}
case lexer::TokenType::PUNCTUATOR_LEFT_SQUARE_BRACKET: {
return ParseArrayExpression(CarryPatternFlags(flags));
}
case lexer::TokenType::PUNCTUATOR_LEFT_BRACE: {
return ParseObjectExpression(CarryPatternFlags(flags));
}
default: {
auto start_loc = Lexer()->GetToken().Start();
auto saved_pos = Lexer()->Save();
TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::POTENTIAL_CLASS_LITERAL |
TypeAnnotationParsingOptions::IGNORE_FUNCTION_TYPE;
ir::TypeNode *potential_type = ParseTypeAnnotation(&options);
if (potential_type != nullptr) {
if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_PERIOD) {
Lexer()->NextToken(); // eat '.'
}
if (Lexer()->GetToken().Type() == lexer::TokenType::KEYW_CLASS) {
Lexer()->NextToken(); // eat 'class'
auto *class_literal = AllocNode<ir::ETSClassLiteral>(potential_type);
class_literal->SetRange({start_loc, Lexer()->GetToken().End()});
return class_literal;
}
}
Lexer()->Rewind(saved_pos);
if (Lexer()->GetToken().Type() == lexer::TokenType::LITERAL_IDENT) {
return ParsePrimaryExpressionIdent(flags);
}
break;
}
}
ThrowSyntaxError({"Unexpected token '", lexer::TokenToString(Lexer()->GetToken().Type()), "'."});
return nullptr;
}
bool ETSParser::IsArrowFunctionExpressionStart()
{
const auto saved_pos = Lexer()->Save();
ASSERT(Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS);
Lexer()->NextToken();
if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_PERIOD_PERIOD_PERIOD ||
Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS) {
Lexer()->Rewind(saved_pos);
return true;
}
if (Lexer()->GetToken().Type() != lexer::TokenType::LITERAL_IDENT) {
Lexer()->Rewind(saved_pos);
return false;
}
Lexer()->NextToken();
if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_COLON) {
Lexer()->Rewind(saved_pos);
return false;
}
Lexer()->Rewind(saved_pos);
return true;
}
ir::ArrowFunctionExpression *ETSParser::ParseArrowFunctionExpression()
{
auto new_status = ParserStatus::NEED_RETURN_TYPE | ParserStatus::ARROW_FUNCTION;
auto *func = ParseFunction(new_status);
auto *arrow_func_node = AllocNode<ir::ArrowFunctionExpression>(Allocator(), func);
arrow_func_node->SetRange(func->Range());
return arrow_func_node;
}
ir::Expression *ETSParser::ParseCoverParenthesizedExpressionAndArrowParameterList()
{
ASSERT(Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS);
if (IsArrowFunctionExpressionStart()) {
return ParseArrowFunctionExpression();
}
lexer::SourcePosition start = Lexer()->GetToken().Start();
Lexer()->NextToken();
ir::Expression *expr = ParseExpression(ExpressionParseFlags::ACCEPT_COMMA);
if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS) {
ThrowSyntaxError("Unexpected token, expected ')'");
}
expr->SetGrouped();
expr->SetRange({start, Lexer()->GetToken().End()});
Lexer()->NextToken();
return expr;
}
bool ETSParser::ParsePotentialGenericFunctionCall(ir::Expression *primary_expr, ir::Expression **return_expression,
[[maybe_unused]] const lexer::SourcePosition &start_loc,
bool ignore_call_expression)
{
if (Lexer()->Lookahead() == lexer::LEX_CHAR_LESS_THAN ||
(!primary_expr->IsIdentifier() && !primary_expr->IsMemberExpression())) {
return true;
}
const auto saved_pos = Lexer()->Save();
if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_SHIFT) {
Lexer()->BackwardToken(lexer::TokenType::PUNCTUATOR_LESS_THAN, 1);
}
TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::DISALLOW_PRIMARY_TYPE |
TypeAnnotationParsingOptions::ALLOW_WILDCARD |
TypeAnnotationParsingOptions::IGNORE_FUNCTION_TYPE;
ir::TSTypeParameterInstantiation *type_params = ParseTypeParameterInstantiation(&options);
if (type_params == nullptr) {
Lexer()->Rewind(saved_pos);
return true;
}
if (Lexer()->GetToken().Type() == lexer::TokenType::EOS) {
ThrowSyntaxError("'(' expected");
}
if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS) {
if (!ignore_call_expression) {
*return_expression = ParseCallExpression(*return_expression, false, false);
(*return_expression)->AsCallExpression()->SetTypeParams(type_params);
return false;
}
return true;
}
Lexer()->Rewind(saved_pos);
return true;
}
ir::Expression *ETSParser::ParsePostPrimaryExpression(ir::Expression *primary_expr, lexer::SourcePosition start_loc,
bool ignore_call_expression,
[[maybe_unused]] bool *is_chain_expression)
{
ir::Expression *return_expression = primary_expr;
while (true) {
switch (Lexer()->GetToken().Type()) {
case lexer::TokenType::PUNCTUATOR_PERIOD: {
Lexer()->NextToken(); // eat period
return_expression = ParsePropertyAccess(return_expression);
continue;
}
case lexer::TokenType::PUNCTUATOR_LEFT_SQUARE_BRACKET: {
return_expression = ParseElementAccess(return_expression);
continue;
}
case lexer::TokenType::PUNCTUATOR_LEFT_SHIFT:
case lexer::TokenType::PUNCTUATOR_LESS_THAN: {
if (ParsePotentialGenericFunctionCall(primary_expr, &return_expression, start_loc,
ignore_call_expression)) {
break;
}
continue;
}
case lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS: {
if (ignore_call_expression) {
break;
}
return_expression = ParseCallExpression(return_expression, false, false);
continue;
}
default: {
break;
}
}
break;
}
return return_expression;
}
ir::Expression *ETSParser::ParsePotentialAsExpression(ir::Expression *primary_expr)
{
ASSERT(Lexer()->GetToken().Type() == lexer::TokenType::KEYW_AS);
TypeAnnotationParsingOptions options =
TypeAnnotationParsingOptions::THROW_ERROR | TypeAnnotationParsingOptions::ALLOW_INTERSECTION;
Lexer()->NextToken();
ir::TypeNode *type = ParseTypeAnnotation(&options);
auto *as_expression = AllocNode<ir::TSAsExpression>(primary_expr, type, false);
as_expression->SetRange(primary_expr->Range());
return as_expression;
}
ir::Expression *ETSParser::ParseNewExpression()
{
lexer::SourcePosition start = Lexer()->GetToken().Start();
Lexer()->NextToken(); // eat new
TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::THROW_ERROR;
ir::TypeNode *base_type_reference = ParseBaseTypeReference(&options);
ir::TypeNode *type_reference = base_type_reference;
if (type_reference == nullptr) {
options |= TypeAnnotationParsingOptions::DISALLOW_PRIMARY_TYPE |
TypeAnnotationParsingOptions::IGNORE_FUNCTION_TYPE | TypeAnnotationParsingOptions::ALLOW_WILDCARD;
type_reference = ParseTypeReference(&options);
} else if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_BRACE) {
ThrowSyntaxError("Invalid { after base types.");
}
if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_SQUARE_BRACKET) {
Lexer()->NextToken();
ir::Expression *dimension = ParseExpression();
auto end_loc = Lexer()->GetToken().End();
ExpectToken(lexer::TokenType::PUNCTUATOR_RIGHT_SQUARE_BRACKET);
if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_LEFT_SQUARE_BRACKET) {
auto *arr_instance = AllocNode<ir::ETSNewArrayInstanceExpression>(type_reference, dimension);
arr_instance->SetRange({start, end_loc});
return arr_instance;
}
ArenaVector<ir::Expression *> dimensions(Allocator()->Adapter());
dimensions.push_back(dimension);
do {
Lexer()->NextToken();
dimensions.push_back(ParseExpression());
end_loc = Lexer()->GetToken().End();
ExpectToken(lexer::TokenType::PUNCTUATOR_RIGHT_SQUARE_BRACKET);
} while (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_SQUARE_BRACKET);
auto *multi_array = AllocNode<ir::ETSNewMultiDimArrayInstanceExpression>(type_reference, std::move(dimensions));
multi_array->SetRange({start, end_loc});
return multi_array;
}
ArenaVector<ir::Expression *> arguments(Allocator()->Adapter());
lexer::SourcePosition end_loc = type_reference->End();
if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS) {
if (base_type_reference != nullptr) {
ThrowSyntaxError("Can not use 'new' on primitive types.", base_type_reference->Start());
}
Lexer()->NextToken();
while (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS) {
ir::Expression *argument = ParseExpression();
arguments.push_back(argument);
if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COMMA) {
Lexer()->NextToken();
continue;
}
}
end_loc = Lexer()->GetToken().End();
Lexer()->NextToken();
}
ir::ClassDefinition *class_definition {};
if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_BRACE) {
auto *parent_class_scope = Binder()->GetScope();
while (!parent_class_scope->IsClassScope()) {
ASSERT(parent_class_scope->Parent());
parent_class_scope = parent_class_scope->Parent();
}
auto class_ctx = binder::LexicalScope<binder::ClassScope>(Binder());
ArenaVector<ir::TSClassImplements *> implements(Allocator()->Adapter());
auto modifiers = ir::ClassDefinitionModifiers::ANONYMOUS | ir::ClassDefinitionModifiers::HAS_SUPER;
auto [ctor, properties, bodyRange] = ParseClassBody(modifiers);
auto *class_scope = class_ctx.GetScope();
util::UString anonymous_name(util::StringView("#"), Allocator());
anonymous_name.Append(std::to_string(parent_class_scope->AsClassScope()->GetAndIncrementAnonymousClassIdx()));
auto new_ident = AllocNode<ir::Identifier>(anonymous_name.View(), Allocator());
class_definition = AllocNode<ir::ClassDefinition>(class_scope, anonymous_name.View(), new_ident, nullptr,
nullptr, std::move(implements), ctor, type_reference,
std::move(properties), modifiers, ir::ModifierFlags::NONE);
class_definition->SetRange(bodyRange);
class_scope->BindNode(class_definition);
}
auto *new_expr_node =
AllocNode<ir::ETSNewClassInstanceExpression>(type_reference, std::move(arguments), class_definition);
new_expr_node->SetRange({start, Lexer()->GetToken().End()});
return new_expr_node;
}
ir::Expression *ETSParser::ParseAsyncExpression()
{
Lexer()->NextToken(); // eat 'async'
if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS ||
!IsArrowFunctionExpressionStart()) {
ThrowSyntaxError("Unexpected token. expected '('");
}
auto new_status = ParserStatus::NEED_RETURN_TYPE | ParserStatus::ARROW_FUNCTION | ParserStatus::ASYNC_FUNCTION;
auto *func = ParseFunction(new_status);
auto *arrow_func_node = AllocNode<ir::ArrowFunctionExpression>(Allocator(), func);
arrow_func_node->SetRange(func->Range());
return arrow_func_node;
}
ir::ModifierFlags ETSParser::ParseTypeVarianceModifier(TypeAnnotationParsingOptions *const options)
{
if ((*options & TypeAnnotationParsingOptions::ALLOW_WILDCARD) == 0 &&
(*options & TypeAnnotationParsingOptions::ALLOW_DECLARATION_SITE_VARIANCE) == 0) {
ThrowSyntaxError("Variance modifier is not allowed here.");
}
switch (Lexer()->GetToken().KeywordType()) {
case lexer::TokenType::KEYW_IN: {
Lexer()->NextToken();
return ir::ModifierFlags::IN;
}
case lexer::TokenType::KEYW_OUT: {
Lexer()->NextToken();
return ir::ModifierFlags::OUT;
}
default: {
return ir::ModifierFlags::NONE;
}
}
}
ir::TSTypeParameter *ETSParser::ParseTypeParameter([[maybe_unused]] TypeAnnotationParsingOptions *options)
{
lexer::SourcePosition start_loc = Lexer()->GetToken().Start();
const auto variance_modifier = [this, options] {
switch (Lexer()->GetToken().KeywordType()) {
case lexer::TokenType::KEYW_IN:
case lexer::TokenType::KEYW_OUT:
return ParseTypeVarianceModifier(options);
default:
return ir::ModifierFlags::NONE;
}
}();
auto *param_ident = ExpectIdentifier();
auto [decl, var] = Binder()->NewVarDecl<binder::TypeParameterDecl>(param_ident->Start(), param_ident->Name());
param_ident->SetVariable(var);
var->SetScope(Binder()->GetScope());
var->AddFlag(binder::VariableFlags::TYPE_PARAMETER);
ir::TypeNode *constraint = nullptr;
if (Lexer()->GetToken().Type() == lexer::TokenType::KEYW_EXTENDS) {
Lexer()->NextToken();
TypeAnnotationParsingOptions new_options =
TypeAnnotationParsingOptions::THROW_ERROR | TypeAnnotationParsingOptions::ALLOW_INTERSECTION |
TypeAnnotationParsingOptions::IGNORE_FUNCTION_TYPE | TypeAnnotationParsingOptions::DISALLOW_PRIMARY_TYPE;
constraint = ParseTypeAnnotation(&new_options);
}
auto *type_param = AllocNode<ir::TSTypeParameter>(param_ident, constraint, nullptr, variance_modifier);
decl->BindNode(type_param);
type_param->SetRange({start_loc, Lexer()->GetToken().End()});
return type_param;
}
ir::TSEnumDeclaration *ETSParser::ParseEnumMembers(ir::Identifier *const key, const lexer::SourcePosition &enum_start,
const bool is_const, const bool is_static)
{
if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_LEFT_BRACE) {
ThrowSyntaxError("'{' expected");
}
Lexer()->NextToken(lexer::NextTokenFlags::KEYWORD_TO_IDENT); // eat '{'
if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_RIGHT_BRACE) {
ThrowSyntaxError("An enum must have at least one enum constant");
}
ArenaVector<ir::AstNode *> members(Allocator()->Adapter());
const auto enum_ctx = binder::LexicalScope<binder::LocalScope>(Binder());
auto parse_member = [this, &members, ordinal_number = uint32_t {0}]() mutable {
auto *const ident = ExpectIdentifier();
auto [decl, var] = Binder()->NewVarDecl<binder::LetDecl>(ident->Start(), ident->Name());
var->SetScope(Binder()->GetScope());
var->AddFlag(binder::VariableFlags::STATIC);
ident->SetVariable(var);
auto *const ordinal = AllocNode<ir::NumberLiteral>(lexer::Number(ordinal_number++));
auto *const member = AllocNode<ir::TSEnumMember>(ident, ordinal);
member->SetRange(ident->Range());
decl->BindNode(member);
members.push_back(member);
};
parse_member();
while (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_BRACE) {
if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_COMMA) {
ThrowSyntaxError("Missing comma between enum constants");
}
Lexer()->NextToken(lexer::NextTokenFlags::KEYWORD_TO_IDENT); // eat ','
if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_RIGHT_BRACE) {
ThrowSyntaxError("Trailing comma is not allowed in enum constant list");
}
parse_member();
}
auto *const enum_declaration = AllocNode<ir::TSEnumDeclaration>(Allocator(), Binder()->GetScope()->AsLocalScope(),
key, std::move(members), is_const, is_static);
enum_declaration->SetRange({enum_start, Lexer()->GetToken().End()});
Lexer()->NextToken(); // eat '}'
return enum_declaration;
}
ir::ThisExpression *ETSParser::ParseThisExpression()
{
auto *this_expression = TypedParser::ParseThisExpression();
switch (Lexer()->GetToken().Type()) {
case lexer::TokenType::PUNCTUATOR_PERIOD:
case lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS:
case lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS:
case lexer::TokenType::PUNCTUATOR_SEMI_COLON:
case lexer::TokenType::PUNCTUATOR_COLON:
case lexer::TokenType::PUNCTUATOR_EQUAL:
case lexer::TokenType::PUNCTUATOR_NOT_EQUAL:
case lexer::TokenType::PUNCTUATOR_COMMA:
case lexer::TokenType::PUNCTUATOR_QUESTION_MARK:
case lexer::TokenType::PUNCTUATOR_LEFT_SQUARE_BRACKET: {
break;
}
default: {
ThrowUnexpectedToken(Lexer()->GetToken().Type());
break;
}
}
return this_expression;
}
ir::Identifier *ETSParser::ParseClassIdent([[maybe_unused]] ir::ClassDefinitionModifiers modifiers)
{
return ExpectIdentifier();
}
// NOLINTNEXTLINE(google-default-arguments)
ir::ClassDeclaration *ETSParser::ParseClassStatement([[maybe_unused]] StatementParsingFlags flags,
[[maybe_unused]] ir::ClassDefinitionModifiers modifiers,
[[maybe_unused]] ir::ModifierFlags mod_flags)
{
ThrowSyntaxError("Illegal start of expression", Lexer()->GetToken().Start());
}
bool ETSParser::CheckClassElement(ir::AstNode *property, [[maybe_unused]] ir::MethodDefinition *&ctor,
[[maybe_unused]] ArenaVector<ir::AstNode *> &properties)
{
if (property->IsClassStaticBlock()) {
if (std::any_of(properties.cbegin(), properties.cend(),
[](const auto *prop) { return prop->IsClassStaticBlock(); })) {
ThrowSyntaxError("Only one static block is allowed", property->Start());
}
ASSERT(Binder()->GetScope()->IsClassScope());
auto class_ctx = binder::LexicalScope<binder::LocalScope>::Enter(
Binder(), Binder()->GetScope()->AsClassScope()->StaticMethodScope());
auto *id = AllocNode<ir::Identifier>(compiler::Signatures::CCTOR, Allocator());
auto [_, var] =
Binder()->NewVarDecl<binder::FunctionDecl>(property->Start(), Allocator(), id->Name(), property);
(void)_;
var->AddFlag(binder::VariableFlags::METHOD);
id->SetVariable(var);
property->AsClassStaticBlock()->Function()->SetIdent(id);
}
if (property->IsTSInterfaceBody()) {
return CheckClassElementInterfaceBody(property, properties);
}
return property->IsMethodDefinition() && property->AsMethodDefinition()->Function()->IsOverload();
}
void ETSParser::CreateImplicitConstructor([[maybe_unused]] ir::MethodDefinition *&ctor,
ArenaVector<ir::AstNode *> &properties,
[[maybe_unused]] ir::ClassDefinitionModifiers modifiers,
const lexer::SourcePosition &start_loc)
{
if (std::any_of(properties.cbegin(), properties.cend(), [](ir::AstNode *prop) {
return prop->IsMethodDefinition() && prop->AsMethodDefinition()->IsConstructor();
})) {
return;
}
if ((modifiers & ir::ClassDefinitionModifiers::ANONYMOUS) != 0) {
return;
}
auto *method_def = BuildImplicitConstructor(ir::ClassDefinitionModifiers::SET_CTOR_ID, start_loc);
properties.push_back(method_def);
ASSERT(Binder()->GetScope()->IsClassScope());
auto class_ctx = binder::LexicalScope<binder::LocalScope>::Enter(
Binder(), Binder()->GetScope()->AsClassScope()->StaticMethodScope());
auto [_, var] = Binder()->NewVarDecl<binder::FunctionDecl>(method_def->Start(), Allocator(),
method_def->Id()->Name(), method_def);
(void)_;
var->AddFlag(binder::VariableFlags::METHOD);
method_def->Function()->Id()->SetVariable(var);
}
util::StringView ETSParser::FormInterfaceOrEnumDeclarationIdBinding(ir::Identifier *id)
{
return id->Name();
}
ir::Expression *ETSParser::ParsePotentialExpressionSequence(ir::Expression *expr, ExpressionParseFlags flags)
{
if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COMMA &&
(flags & ExpressionParseFlags::ACCEPT_COMMA) != 0 && (flags & ExpressionParseFlags::IN_FOR) != 0U) {
return ParseSequenceExpression(expr, (flags & ExpressionParseFlags::ACCEPT_REST) != 0);
}
return expr;
}
// NOLINTNEXTLINE(google-default-arguments)
ir::Expression *ETSParser::ParseExpression(ExpressionParseFlags flags)
{
if (Lexer()->GetToken().Type() == lexer::TokenType::KEYW_YIELD &&
(flags & ExpressionParseFlags::DISALLOW_YIELD) == 0U) {
ir::YieldExpression *yield_expr = ParseYieldExpression();
return ParsePotentialExpressionSequence(yield_expr, flags);
}
ir::Expression *unary_expression_node = ParseUnaryOrPrefixUpdateExpression(flags);
ir::Expression *assignment_expression = ParseAssignmentExpression(unary_expression_node, flags);
if (Lexer()->GetToken().NewLine()) {
return assignment_expression;
}
if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COMMA &&
(flags & ExpressionParseFlags::ACCEPT_COMMA) != 0U && (flags & ExpressionParseFlags::IN_FOR) != 0U) {
return ParseSequenceExpression(assignment_expression, (flags & ExpressionParseFlags::ACCEPT_REST) != 0U);
}
return assignment_expression;
}
ExternalSourceParser::ExternalSourceParser(ETSParser *parser, Program *new_program)
: parser_(parser),
saved_program_(parser_->GetProgram()),
saved_lexer_(parser_->Lexer()),
saved_top_scope_(parser_->Binder()->TopScope())
{
parser_->SetProgram(new_program);
parser_->GetContext().SetProgram(new_program);
}
ExternalSourceParser::~ExternalSourceParser()
{
parser_->SetLexer(saved_lexer_);
parser_->SetProgram(saved_program_);
parser_->GetContext().SetProgram(saved_program_);
parser_->Binder()->ResetTopScope(saved_top_scope_);
}
InnerSourceParser::InnerSourceParser(ETSParser *parser)
: parser_(parser),
saved_lexer_(parser_->Lexer()),
saved_source_code_(parser_->GetProgram()->SourceCode()),
saved_source_file_(parser_->GetProgram()->SourceFile()),
saved_source_file_path_(parser_->GetProgram()->SourceFilePath())
{
}
InnerSourceParser::~InnerSourceParser()
{
parser_->SetLexer(saved_lexer_);
parser_->GetProgram()->SetSource(saved_source_code_, saved_source_file_, saved_source_file_path_);
}
} // namespace panda::es2panda::parser
#undef USE_UNIX_SYSCALL
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/klooer/sig_arkcompiler_ets_frontend.git
git@gitee.com:klooer/sig_arkcompiler_ets_frontend.git
klooer
sig_arkcompiler_ets_frontend
sig_arkcompiler_ets_frontend
master

搜索帮助