diff --git a/ets2panda/BUILD.gn b/ets2panda/BUILD.gn index 26f273d6689e4bf2e085648adfe5133f6f638e8a..1f5d3760bee4d3b0f225681f6017a54159830082 100644 --- a/ets2panda/BUILD.gn +++ b/ets2panda/BUILD.gn @@ -158,6 +158,7 @@ libes2panda_sources = [ "compiler/lowering/ets/opAssignment.cpp", "compiler/lowering/ets/unionLowering.cpp", "compiler/lowering/phase.cpp", + "compiler/lowering/plugin_phase.cpp", "compiler/lowering/util.cpp", "es2panda.cpp", "ir/as/namedType.cpp", @@ -342,6 +343,7 @@ libes2panda_sources = [ "util/bitset.cpp", "util/declgenEts2Ts.cpp", "util/helpers.cpp", + "util/plugin.cpp", "util/ustring.cpp", "varbinder/ASBinder.cpp", "varbinder/ETSBinder.cpp", diff --git a/ets2panda/CMakeLists.txt b/ets2panda/CMakeLists.txt index 75f77a2394adfe82e21b0af131288fd05124d528..1af37b05b7ffab7b37ac9300e25ddbd5e1c34666 100644 --- a/ets2panda/CMakeLists.txt +++ b/ets2panda/CMakeLists.txt @@ -135,6 +135,7 @@ set(ES2PANDA_LIB_SRC compiler/function/generatorFunctionBuilder.cpp compiler/lowering/checkerPhase.cpp compiler/lowering/phase.cpp + compiler/lowering/plugin_phase.cpp compiler/lowering/util.cpp compiler/lowering/ets/generateDeclarations.cpp compiler/lowering/ets/opAssignment.cpp @@ -460,6 +461,7 @@ set(ES2PANDA_PUBLIC_SOURCES public/es2panda_lib.cpp util/generateBin.cpp util/options.cpp + util/plugin.cpp ) diff --git a/ets2panda/aot/main.cpp b/ets2panda/aot/main.cpp index cfe42af47936d3a7876724678d17f600fc9c23a7..cb4969c6ea059ec1b9a927ccca8752a3022238b2 100644 --- a/ets2panda/aot/main.cpp +++ b/ets2panda/aot/main.cpp @@ -22,9 +22,11 @@ #include "util/arktsconfig.h" #include "util/generateBin.h" #include "util/options.h" +#include "util/plugin.h" #include #include +#include namespace panda::es2panda::aot { using mem::MemConfig; @@ -106,6 +108,21 @@ static int CompileFromConfig(es2panda::Compiler &compiler, util::Options *option return overall_res; } +static std::optional> InitializePlugins(std::vector const &names) +{ + std::vector res; + for (auto &name : names) { + auto plugin = util::Plugin(util::StringView {name}); + if (!plugin.IsOk()) { + std::cerr << "Error: Failed to load plugin " << name << std::endl; + return {}; + } + plugin.Initialize(); + res.push_back(std::move(plugin)); + } + return {std::move(res)}; +} + static int Run(int argc, const char **argv) { auto options = std::make_unique(); @@ -118,7 +135,11 @@ static int Run(int argc, const char **argv) Logger::ComponentMask mask {}; mask.set(Logger::Component::ES2PANDA); Logger::InitializeStdLogging(Logger::LevelFromString(options->LogLevel()), mask); - es2panda::Compiler compiler(options->Extension(), options->ThreadCount()); + auto plugins_opt = InitializePlugins(options->CompilerOptions().plugins); + if (!plugins_opt.has_value()) { + return 1; + } + es2panda::Compiler compiler(options->Extension(), options->ThreadCount(), std::move(plugins_opt.value())); if (options->CompilerOptions().compilation_mode == CompilationMode::PROJECT) { return CompileFromConfig(compiler, options.get()); diff --git a/ets2panda/checker/checker.h b/ets2panda/checker/checker.h index 9927c78589745ccaa56b973dd6495904e8a761e0..7b865547a4a10cb6c4faf434e5c360ec28c172e5 100644 --- a/ets2panda/checker/checker.h +++ b/ets2panda/checker/checker.h @@ -70,7 +70,7 @@ using ArgRange = std::pair; class Checker { public: explicit Checker(); - ~Checker() = default; + virtual ~Checker() = default; NO_COPY_SEMANTIC(Checker); NO_MOVE_SEMANTIC(Checker); diff --git a/ets2panda/compiler/core/compilerImpl.cpp b/ets2panda/compiler/core/compilerImpl.cpp index 14bc8b7fbdbde505a5043aef2087f4e2f417a36d..7d7f797194b6b4cd717ebed5d37a46c78bf17721 100644 --- a/ets2panda/compiler/core/compilerImpl.cpp +++ b/ets2panda/compiler/core/compilerImpl.cpp @@ -15,6 +15,7 @@ #include "compilerImpl.h" +#include "es2panda.h" #include "compiler/core/compilerContext.h" #include "compiler/core/compileQueue.h" #include "compiler/core/compilerImpl.h" @@ -41,7 +42,7 @@ #include "checker/ETSchecker.h" #include "checker/ASchecker.h" #include "checker/JSchecker.h" -#include "es2panda.h" +#include "public/public.h" #include "util/declgenEts2Ts.h" #include @@ -89,13 +90,28 @@ static CompilerContext::CodeGenCb MakeCompileJob() }; } +static void SetupPublicContext(public_lib::Context *context, const SourceFile *source_file, ArenaAllocator *allocator, + CompileQueue *queue, std::vector const *plugins, + parser::ParserImpl *parser, CompilerContext *compiler_context) +{ + context->source_file = source_file; + context->allocator = allocator; + context->queue = queue; + context->plugins = plugins; + context->parser = parser; + context->checker = compiler_context->Checker(); + context->analyzer = context->checker->GetAnalyzer(); + context->compiler_context = compiler_context; + context->emitter = compiler_context->GetEmitter(); +} + using EmitCb = std::function; using PhaseListGetter = std::function()>; template static pandasm::Program *CreateCompiler(const CompilationUnit &unit, const PhaseListGetter &get_phases, - const EmitCb &emit_cb) + CompilerImpl *compiler_impl) { ArenaAllocator allocator(SpaceType::SPACE_TYPE_COMPILER, nullptr, true); auto program = parser::Program::NewProgram(&allocator); @@ -115,47 +131,49 @@ static pandasm::Program *CreateCompiler(const CompilationUnit &unit, const Phase auto emitter = Emitter(&context); context.SetEmitter(&emitter); + public_lib::Context public_context; + SetupPublicContext(&public_context, &unit.input, &allocator, compiler_impl->Queue(), &compiler_impl->Plugins(), + &parser, &context); + parser.ParseScript(unit.input, unit.options.compilation_mode == CompilationMode::GEN_STD_LIB); for (auto *phase : get_phases()) { - if (!phase->Apply(&context, &program)) { + if (!phase->Apply(&public_context, &program)) { return nullptr; } } emitter.GenAnnotation(); - return emit_cb(&context); + return compiler_impl->Emit(&context); } pandasm::Program *CompilerImpl::Compile(const CompilationUnit &unit) { - auto emit_cb = [this](CompilerContext *context) -> pandasm::Program * { return Emit(context); }; - switch (unit.ext) { case ScriptExtension::TS: { return CreateCompiler(unit, compiler::GetTrivialPhaseList, - emit_cb); + this); } case ScriptExtension::AS: { return CreateCompiler(unit, compiler::GetTrivialPhaseList, - emit_cb); + this); } case ScriptExtension::ETS: { return CreateCompiler(unit, compiler::GetETSPhaseList, - emit_cb); + this); } case ScriptExtension::JS: { return CreateCompiler(unit, compiler::GetTrivialPhaseList, - emit_cb); + this); } default: { UNREACHABLE(); diff --git a/ets2panda/compiler/core/compilerImpl.h b/ets2panda/compiler/core/compilerImpl.h index cee0090c005d3e6cede14ae5c38d18c58b436d61..9ed854e5394b837053315b4b2a1bb77fa81e52d8 100644 --- a/ets2panda/compiler/core/compilerImpl.h +++ b/ets2panda/compiler/core/compilerImpl.h @@ -49,20 +49,35 @@ public: class CompilerImpl { public: - explicit CompilerImpl(size_t thread_count) : queue_(thread_count) {} + explicit CompilerImpl(size_t thread_count, std::vector const *plugins) + : queue_(thread_count), plugins_(plugins) + { + } NO_COPY_SEMANTIC(CompilerImpl); NO_MOVE_SEMANTIC(CompilerImpl); ~CompilerImpl() = default; pandasm::Program *Compile(const CompilationUnit &unit); + std::vector const &Plugins() + { + return *plugins_; + } + static void DumpAsm(const panda::pandasm::Program *prog); -private: panda::pandasm::Program *Emit(CompilerContext *context); + + CompileQueue *Queue() + { + return &queue_; + } + +private: static void HandleContextLiterals(CompilerContext *context); CompileQueue queue_; + std::vector const *plugins_; }; } // namespace panda::es2panda::compiler diff --git a/ets2panda/compiler/lowering/checkerPhase.cpp b/ets2panda/compiler/lowering/checkerPhase.cpp index a6c865ca83bb8b1ae64008e1268c4d16c70e848c..9d9c74108751a71f1c2a22c1b528a50a259867ca 100644 --- a/ets2panda/compiler/lowering/checkerPhase.cpp +++ b/ets2panda/compiler/lowering/checkerPhase.cpp @@ -18,9 +18,9 @@ #include "compiler/core/compilerContext.h" namespace panda::es2panda::compiler { -bool CheckerPhase::Perform(CompilerContext *ctx, [[maybe_unused]] parser::Program *program) +bool CheckerPhase::Perform(public_lib::Context *ctx, [[maybe_unused]] parser::Program *program) { - return ctx->Checker()->StartChecker(ctx->VarBinder(), *ctx->Options()); + return ctx->checker->StartChecker(ctx->compiler_context->VarBinder(), *ctx->compiler_context->Options()); } } // namespace panda::es2panda::compiler diff --git a/ets2panda/compiler/lowering/checkerPhase.h b/ets2panda/compiler/lowering/checkerPhase.h index 86e0db579bd58b4821d836ed9c05005a55cc8748..ef42e7004bac3154dedd78a1dd44ece3f79e51a5 100644 --- a/ets2panda/compiler/lowering/checkerPhase.h +++ b/ets2panda/compiler/lowering/checkerPhase.h @@ -20,13 +20,12 @@ namespace panda::es2panda::compiler { class CheckerPhase : public Phase { - std::string const &Name() override + std::string_view Name() override { - static std::string const NAME = "checker"; - return NAME; + return "checker"; } - bool Perform(CompilerContext *ctx, parser::Program *program) override; + bool Perform(public_lib::Context *ctx, parser::Program *program) override; }; } // namespace panda::es2panda::compiler diff --git a/ets2panda/compiler/lowering/ets/generateDeclarations.cpp b/ets2panda/compiler/lowering/ets/generateDeclarations.cpp index 41393a607b8e170c7eab618830d4765d4e3e74cb..96472eae5015737399508c79f631274e485363d2 100644 --- a/ets2panda/compiler/lowering/ets/generateDeclarations.cpp +++ b/ets2panda/compiler/lowering/ets/generateDeclarations.cpp @@ -19,11 +19,12 @@ #include "util/declgenEts2Ts.h" namespace panda::es2panda::compiler { -bool GenerateTsDeclarationsPhase::Perform(CompilerContext *ctx, parser::Program *program) +bool GenerateTsDeclarationsPhase::Perform(public_lib::Context *ctx, parser::Program *program) { - auto *checker = ctx->Checker(); - return (ctx->Options()->ts_decl_out.empty() || - util::GenerateTsDeclarations(checker->AsETSChecker(), program, ctx->Options()->ts_decl_out)); + auto *checker = ctx->checker; + return ( + ctx->compiler_context->Options()->ts_decl_out.empty() || + util::GenerateTsDeclarations(checker->AsETSChecker(), program, ctx->compiler_context->Options()->ts_decl_out)); } } // namespace panda::es2panda::compiler diff --git a/ets2panda/compiler/lowering/ets/generateDeclarations.h b/ets2panda/compiler/lowering/ets/generateDeclarations.h index fb7fcea3fdf721a01dffa15195528d964a803449..15ab3c61ef11d7d8962e305089a076684093a707 100644 --- a/ets2panda/compiler/lowering/ets/generateDeclarations.h +++ b/ets2panda/compiler/lowering/ets/generateDeclarations.h @@ -22,12 +22,11 @@ namespace panda::es2panda::compiler { class GenerateTsDeclarationsPhase : public Phase { public: - std::string const &Name() override + std::string_view Name() override { - static std::string const NAME = "generate-ts-declarations"; - return NAME; + return "generate-ts-declarations"; } - bool Perform(CompilerContext *ctx, parser::Program *program) override; + bool Perform(public_lib::Context *ctx, parser::Program *program) override; }; } // namespace panda::es2panda::compiler diff --git a/ets2panda/compiler/lowering/ets/opAssignment.cpp b/ets2panda/compiler/lowering/ets/opAssignment.cpp index 03ecf30834638433b677dd8cf385f568d88f2c15..8a20d5885270d1bd8b73a8afb7fb8cbb6844f5f7 100644 --- a/ets2panda/compiler/lowering/ets/opAssignment.cpp +++ b/ets2panda/compiler/lowering/ets/opAssignment.cpp @@ -44,10 +44,9 @@ namespace panda::es2panda::compiler { -std::string const &OpAssignmentLowering::Name() +std::string_view OpAssignmentLowering::Name() { - static std::string const NAME = "op-assignment"; - return NAME; + return "op-assignment"; } struct Conversion { @@ -246,9 +245,9 @@ ir::Expression *HandleOpAssignment(checker::ETSChecker *checker, ir::AssignmentE return res; } -bool OpAssignmentLowering::Perform(CompilerContext *ctx, parser::Program *program) +bool OpAssignmentLowering::Perform(public_lib::Context *ctx, parser::Program *program) { - if (ctx->Options()->compilation_mode == CompilationMode::GEN_STD_LIB) { + if (ctx->compiler_context->Options()->compilation_mode == CompilationMode::GEN_STD_LIB) { for (auto &[_, ext_programs] : program->ExternalSources()) { (void)_; for (auto *ext_prog : ext_programs) { @@ -257,7 +256,7 @@ bool OpAssignmentLowering::Perform(CompilerContext *ctx, parser::Program *progra } } - checker::ETSChecker *checker = ctx->Checker()->AsETSChecker(); + checker::ETSChecker *checker = ctx->checker->AsETSChecker(); program->Ast()->TransformChildrenRecursively([checker](ir::AstNode *ast) -> ir::AstNode * { if (ast->IsAssignmentExpression() && @@ -271,9 +270,9 @@ bool OpAssignmentLowering::Perform(CompilerContext *ctx, parser::Program *progra return true; } -bool OpAssignmentLowering::Postcondition(CompilerContext *ctx, const parser::Program *program) +bool OpAssignmentLowering::Postcondition(public_lib::Context *ctx, const parser::Program *program) { - if (ctx->Options()->compilation_mode == CompilationMode::GEN_STD_LIB) { + if (ctx->compiler_context->Options()->compilation_mode == CompilationMode::GEN_STD_LIB) { for (auto &[_, ext_programs] : program->ExternalSources()) { (void)_; for (auto *ext_prog : ext_programs) { diff --git a/ets2panda/compiler/lowering/ets/opAssignment.h b/ets2panda/compiler/lowering/ets/opAssignment.h index b3c8dbd789b419afdf7683eabd8f93629b426661..407d558a2e32051fa9ed61591cee17172df188d2 100644 --- a/ets2panda/compiler/lowering/ets/opAssignment.h +++ b/ets2panda/compiler/lowering/ets/opAssignment.h @@ -22,9 +22,9 @@ namespace panda::es2panda::compiler { class OpAssignmentLowering : public Phase { public: - std::string const &Name() override; - bool Perform(CompilerContext *ctx, parser::Program *program) override; - bool Postcondition(CompilerContext *ctx, const parser::Program *program) override; + std::string_view Name() override; + bool Perform(public_lib::Context *ctx, parser::Program *program) override; + bool Postcondition(public_lib::Context *ctx, const parser::Program *program) override; }; } // namespace panda::es2panda::compiler diff --git a/ets2panda/compiler/lowering/ets/unionLowering.cpp b/ets2panda/compiler/lowering/ets/unionLowering.cpp index f036bdab81d8125c6a4a86a88fdf445edff8c45f..9d8c120fdf9d2cea812ee533bea5f00fc5bca622 100644 --- a/ets2panda/compiler/lowering/ets/unionLowering.cpp +++ b/ets2panda/compiler/lowering/ets/unionLowering.cpp @@ -37,10 +37,9 @@ namespace panda::es2panda::compiler { -std::string const &UnionLowering::Name() +std::string_view UnionLowering::Name() { - static std::string const NAME = "union-property-access"; - return NAME; + return "union-property-access"; } ir::ClassDefinition *GetUnionFieldClass(checker::ETSChecker *checker, varbinder::VarBinder *varbinder) @@ -155,7 +154,7 @@ ir::Expression *HandleBinaryExpressionWithUnion(checker::ETSChecker *checker, ir return expr; } -bool UnionLowering::Perform(CompilerContext *ctx, parser::Program *program) +bool UnionLowering::Perform(public_lib::Context *ctx, parser::Program *program) { for (auto &[_, ext_programs] : program->ExternalSources()) { (void)_; @@ -164,12 +163,12 @@ bool UnionLowering::Perform(CompilerContext *ctx, parser::Program *program) } } - checker::ETSChecker *checker = ctx->Checker()->AsETSChecker(); + checker::ETSChecker *checker = ctx->checker->AsETSChecker(); - program->Ast()->TransformChildrenRecursively([checker, ctx](ir::AstNode *ast) -> ir::AstNode * { + program->Ast()->TransformChildrenRecursively([checker](ir::AstNode *ast) -> ir::AstNode * { if (ast->IsMemberExpression() && ast->AsMemberExpression()->Object()->TsType() != nullptr && ast->AsMemberExpression()->Object()->TsType()->IsETSUnionType()) { - HandleUnionPropertyAccess(checker, ctx->VarBinder(), ast->AsMemberExpression()); + HandleUnionPropertyAccess(checker, checker->VarBinder(), ast->AsMemberExpression()); return ast; } @@ -184,14 +183,14 @@ bool UnionLowering::Perform(CompilerContext *ctx, parser::Program *program) return true; } -bool UnionLowering::Postcondition(CompilerContext *ctx, const parser::Program *program) +bool UnionLowering::Postcondition(public_lib::Context *ctx, const parser::Program *program) { bool current = !program->Ast()->IsAnyChild([](const ir::AstNode *ast) { return ast->IsMemberExpression() && ast->AsMemberExpression()->Object()->TsType() != nullptr && ast->AsMemberExpression()->Object()->TsType()->IsETSUnionType() && ast->AsMemberExpression()->PropVar() == nullptr; }); - if (!current || ctx->Options()->compilation_mode != CompilationMode::GEN_STD_LIB) { + if (!current || ctx->compiler_context->Options()->compilation_mode != CompilationMode::GEN_STD_LIB) { return current; } diff --git a/ets2panda/compiler/lowering/ets/unionLowering.h b/ets2panda/compiler/lowering/ets/unionLowering.h index c8a4b49a905835aa4776dd09d9d427178bf695a2..efc0bf6bff7470fb1a3f6a99719f4a0c2c5a9b15 100644 --- a/ets2panda/compiler/lowering/ets/unionLowering.h +++ b/ets2panda/compiler/lowering/ets/unionLowering.h @@ -22,9 +22,9 @@ namespace panda::es2panda::compiler { class UnionLowering : public Phase { public: - std::string const &Name() override; - bool Perform(CompilerContext *ctx, parser::Program *program) override; - bool Postcondition(CompilerContext *ctx, const parser::Program *program) override; + std::string_view Name() override; + bool Perform(public_lib::Context *ctx, parser::Program *program) override; + bool Postcondition(public_lib::Context *ctx, const parser::Program *program) override; }; } // namespace panda::es2panda::compiler diff --git a/ets2panda/compiler/lowering/phase.cpp b/ets2panda/compiler/lowering/phase.cpp index f3b2ff83a6ee0aba42f56ab2082eb0483dc834ac..19035aec00f28b0aa6daf67d5c65dfa20992a553 100644 --- a/ets2panda/compiler/lowering/phase.cpp +++ b/ets2panda/compiler/lowering/phase.cpp @@ -19,9 +19,11 @@ #include "compiler/core/compilerContext.h" #include "lexer/token/sourceLocation.h" #include "compiler/lowering/checkerPhase.h" +#include "compiler/lowering/plugin_phase.h" #include "compiler/lowering/ets/generateDeclarations.h" #include "compiler/lowering/ets/opAssignment.h" #include "compiler/lowering/ets/unionLowering.h" +#include "public/es2panda_lib.h" namespace panda::es2panda::compiler { @@ -37,25 +39,28 @@ std::vector GetTrivialPhaseList() static GenerateTsDeclarationsPhase GENERATE_TS_DECLARATIONS_PHASE; static OpAssignmentLowering OP_ASSIGNMENT_LOWERING; static UnionLowering UNION_LOWERING; +static PluginPhase PLUGINS_AFTER_PARSE {"plugins-after-parse", ES2PANDA_STATE_PARSED, &util::Plugin::AfterParse}; +static PluginPhase PLUGINS_AFTER_CHECK {"plugins-after-check", ES2PANDA_STATE_CHECKED, &util::Plugin::AfterCheck}; +static PluginPhase PLUGINS_AFTER_LOWERINGS {"plugins-after-lowering", ES2PANDA_STATE_LOWERED, + &util::Plugin::AfterLowerings}; std::vector GetETSPhaseList() { return std::vector { - &CHECKER_PHASE, - &GENERATE_TS_DECLARATIONS_PHASE, - &OP_ASSIGNMENT_LOWERING, - &UNION_LOWERING, + &PLUGINS_AFTER_PARSE, &CHECKER_PHASE, &PLUGINS_AFTER_CHECK, &GENERATE_TS_DECLARATIONS_PHASE, + &OP_ASSIGNMENT_LOWERING, &UNION_LOWERING, &PLUGINS_AFTER_LOWERINGS, }; } -bool Phase::Apply(CompilerContext *ctx, parser::Program *program) +bool Phase::Apply(public_lib::Context *ctx, parser::Program *program) { - const auto *options = ctx->Options(); - if (options->skip_phases.count(Name()) > 0) { + const auto *options = ctx->compiler_context->Options(); + const auto name = std::string {Name()}; + if (options->skip_phases.count(name) > 0) { return true; } - if (options->dump_before_phases.count(Name()) > 0) { + if (options->dump_before_phases.count(name) > 0) { std::cout << "Before phase " << Name() << ":" << std::endl; std::cout << program->Dump() << std::endl; } @@ -66,8 +71,8 @@ bool Phase::Apply(CompilerContext *ctx, parser::Program *program) // NOTE(tatiana): Add some error processing } if (!Precondition(ctx, program)) { - ctx->Checker()->ThrowTypeError({"Precondition check failed for ", util::StringView {Name()}}, - lexer::SourcePosition {}); + ctx->checker->ThrowTypeError({"Precondition check failed for ", util::StringView {Name()}}, + lexer::SourcePosition {}); } #endif @@ -75,7 +80,7 @@ bool Phase::Apply(CompilerContext *ctx, parser::Program *program) return false; } - if (options->dump_after_phases.count(Name()) > 0) { + if (options->dump_after_phases.count(name) > 0) { std::cout << "After phase " << Name() << ":" << std::endl; std::cout << program->Dump() << std::endl; } @@ -86,8 +91,8 @@ bool Phase::Apply(CompilerContext *ctx, parser::Program *program) // NOTE(tatiana): Add some error processing } if (!Postcondition(ctx, program)) { - ctx->Checker()->ThrowTypeError({"Postcondition check failed for ", util::StringView {Name()}}, - lexer::SourcePosition {}); + ctx->checker->ThrowTypeError({"Postcondition check failed for ", util::StringView {Name()}}, + lexer::SourcePosition {}); } #endif diff --git a/ets2panda/compiler/lowering/phase.h b/ets2panda/compiler/lowering/phase.h index 490c2fac13b5ac2ba47bf964e7ddff2a3fdb0259..d64ed04e4c321859203df0a6af00a26b81aa80f5 100644 --- a/ets2panda/compiler/lowering/phase.h +++ b/ets2panda/compiler/lowering/phase.h @@ -17,22 +17,25 @@ #define ES2PANDA_COMPILER_LOWERING_PHASE_H #include "parser/program/program.h" +#include "public/public.h" namespace panda::es2panda::compiler { class Phase { public: /* If Apply returns false, processing is stopped. */ - bool Apply(CompilerContext *ctx, parser::Program *program); + bool Apply(public_lib::Context *ctx, parser::Program *program); - virtual std::string const &Name() = 0; + virtual std::string_view Name() = 0; - virtual bool Precondition([[maybe_unused]] CompilerContext *ctx, [[maybe_unused]] const parser::Program *program) + virtual bool Precondition([[maybe_unused]] public_lib::Context *ctx, + [[maybe_unused]] const parser::Program *program) { return true; } - virtual bool Perform(CompilerContext *ctx, parser::Program *program) = 0; - virtual bool Postcondition([[maybe_unused]] CompilerContext *ctx, [[maybe_unused]] const parser::Program *program) + virtual bool Perform(public_lib::Context *ctx, parser::Program *program) = 0; + virtual bool Postcondition([[maybe_unused]] public_lib::Context *ctx, + [[maybe_unused]] const parser::Program *program) { return true; } diff --git a/ets2panda/compiler/lowering/plugin_phase.cpp b/ets2panda/compiler/lowering/plugin_phase.cpp new file mode 100644 index 0000000000000000000000000000000000000000..35fa31a61bdfb1b9b6ffc013d66e9349fa200e58 --- /dev/null +++ b/ets2panda/compiler/lowering/plugin_phase.cpp @@ -0,0 +1,38 @@ +/** + * Copyright (c) 2023 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 "plugin_phase.h" + +namespace panda::es2panda::compiler { + +bool PluginPhase::Perform(public_lib::Context *ctx, [[maybe_unused]] parser::Program *program) +{ + ctx->state = context_state_; + + if (ctx->plugins == nullptr) { + return true; + } + + for (auto &plugin : *(ctx->plugins)) { + (plugin.*method_call_)(reinterpret_cast(ctx)); + if (ctx->state == ES2PANDA_STATE_ERROR) { + ctx->checker->ThrowTypeError(ctx->error_message, ctx->error_pos); + } + } + + return true; +} + +} // namespace panda::es2panda::compiler diff --git a/ets2panda/compiler/lowering/plugin_phase.h b/ets2panda/compiler/lowering/plugin_phase.h new file mode 100644 index 0000000000000000000000000000000000000000..4cff33ec06cc614b88fc4b320843c51bb15c8145 --- /dev/null +++ b/ets2panda/compiler/lowering/plugin_phase.h @@ -0,0 +1,47 @@ +/** + * Copyright (c) 2023 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. + */ + +#ifndef ES2PANDA_COMPILER_PLUGIN_PHASE_H +#define ES2PANDA_COMPILER_PLUGIN_PHASE_H + +#include "compiler/lowering/phase.h" +#include "util/plugin.h" + +namespace panda::es2panda::compiler { + +class PluginPhase : public Phase { +public: + constexpr PluginPhase(char const *name, es2panda_ContextState context_state, + void (util::Plugin::*method_call)(es2panda_Context *) const) noexcept + : name_(name), context_state_(context_state), method_call_(method_call) + { + } + + std::string_view Name() override + { + return name_; + } + + bool Perform(public_lib::Context *ctx, parser::Program *program) override; + +private: + char const *name_; + es2panda_ContextState context_state_; + void (util::Plugin::*method_call_)(es2panda_Context *) const; +}; + +} // namespace panda::es2panda::compiler + +#endif diff --git a/ets2panda/compiler/lowering/util.cpp b/ets2panda/compiler/lowering/util.cpp index 247f182093c3aadccab01eb842fd1e022f4e33b9..ae42b4b5bf06e36b24b9b2fab6efddd82e3b08ba 100644 --- a/ets2panda/compiler/lowering/util.cpp +++ b/ets2panda/compiler/lowering/util.cpp @@ -23,6 +23,10 @@ namespace panda::es2panda::compiler { varbinder::Scope *NearestScope(const ir::AstNode *ast) { + if (ast == nullptr) { + return nullptr; + } + while (!ast->IsScopeBearer()) { ast = ast->Parent(); ASSERT(ast != nullptr); diff --git a/ets2panda/es2panda.cpp b/ets2panda/es2panda.cpp index 458f00dd7b422b8a611d8d79e4f9c0ca49bf797c..4b7051f93dc6bd8f239cf935b5fa949e163d9989 100644 --- a/ets2panda/es2panda.cpp +++ b/ets2panda/es2panda.cpp @@ -16,6 +16,7 @@ #include "es2panda.h" #include "compiler/core/compilerImpl.h" +#include "util/options.h" #include #include @@ -56,10 +57,12 @@ SourceFile::SourceFile(std::string_view fn, std::string_view s, std::string_view { } -Compiler::Compiler(ScriptExtension ext) : Compiler(ext, DEFAULT_THREAD_COUNT) {} +Compiler::Compiler(ScriptExtension ext) : Compiler(ext, DEFAULT_THREAD_COUNT, {}) {} -Compiler::Compiler(ScriptExtension ext, size_t thread_count) - : compiler_(new compiler::CompilerImpl(thread_count)), ext_(ext) +Compiler::Compiler(ScriptExtension ext, size_t thread_count) : Compiler(ext, thread_count, {}) {} + +Compiler::Compiler(ScriptExtension ext, size_t thread_count, std::vector &&plugins) + : plugins_(std::move(plugins)), compiler_(new compiler::CompilerImpl(thread_count, &plugins_)), ext_(ext) { } diff --git a/ets2panda/es2panda.h b/ets2panda/es2panda.h index 40774251e567cf0ba3ed97295b1960267869cddd..846ad613df7be9544ab4e18d99d33a52bc050ad2 100644 --- a/ets2panda/es2panda.h +++ b/ets2panda/es2panda.h @@ -18,6 +18,7 @@ #include "macros.h" #include "util/arktsconfig.h" +#include "util/plugin.h" #include "util/ustring.h" #include @@ -99,6 +100,7 @@ struct CompilerOptions { bool parse_only {}; std::string std_lib {}; std::string ts_decl_out {}; + std::vector plugins {}; std::unordered_set skip_phases {}; std::unordered_set dump_before_phases {}; std::unordered_set dump_after_phases {}; @@ -191,6 +193,7 @@ class Compiler { public: explicit Compiler(ScriptExtension ext); explicit Compiler(ScriptExtension ext, size_t thread_count); + explicit Compiler(ScriptExtension ext, size_t thread_count, std::vector &&plugins); ~Compiler(); NO_COPY_SEMANTIC(Compiler); NO_MOVE_SEMANTIC(Compiler); @@ -211,7 +214,13 @@ public: return error_; } + std::vector const &Plugins() + { + return plugins_; + } + private: + std::vector const plugins_; compiler::CompilerImpl *compiler_; Error error_; ScriptExtension ext_; diff --git a/ets2panda/ir/astNode.h b/ets2panda/ir/astNode.h index 950d346f6f7cd740eed5cb85242a15b16da29324..9e233d991be0d85f390ff33a80dd4f6091ffc255 100644 --- a/ets2panda/ir/astNode.h +++ b/ets2panda/ir/astNode.h @@ -263,6 +263,12 @@ public: variable_ = variable; } + // When no decorators are allowed, we cannot return a reference to an empty vector. + virtual const ArenaVector *DecoratorsPtr() const + { + return nullptr; + } + virtual void AddDecorators([[maybe_unused]] ArenaVector &&decorators) { UNREACHABLE(); diff --git a/ets2panda/ir/base/classDefinition.h b/ets2panda/ir/base/classDefinition.h index 7341aab83e5a2787b52579e2eb10a6256299f4bf..3e8f58cb09cc1ae307e3063ae0348784f90db17e 100644 --- a/ets2panda/ir/base/classDefinition.h +++ b/ets2panda/ir/base/classDefinition.h @@ -144,6 +144,11 @@ public: return super_class_; } + void SetSuper(Expression *super_class) + { + super_class_ = super_class; + } + bool IsGlobal() const { return (modifiers_ & ClassDefinitionModifiers::GLOBAL) != 0; @@ -208,6 +213,11 @@ public: return ctor_; } + void SetCtor(MethodDefinition *ctor) + { + ctor_ = ctor; + } + ArenaVector &Implements() { return implements_; @@ -228,6 +238,11 @@ public: return type_params_; } + void SetTypeParams(ir::TSTypeParameterDeclaration *type_params) + { + type_params_ = type_params; + } + const FunctionExpression *Ctor() const; bool HasPrivateMethod() const; bool HasComputedInstanceField() const; diff --git a/ets2panda/ir/base/classElement.h b/ets2panda/ir/base/classElement.h index ea99fb156653d56d229f50c4ff6972157bae7382..5557ff537b814141922027e76d8f93ce19fd4d2d 100644 --- a/ets2panda/ir/base/classElement.h +++ b/ets2panda/ir/base/classElement.h @@ -63,6 +63,11 @@ public: return decorators_; } + const ArenaVector *DecoratorsPtr() const override + { + return &Decorators(); + } + bool IsComputed() const { return is_computed_; @@ -73,6 +78,11 @@ public: decorators_ = std::move(decorators); } + bool CanHaveDecorator([[maybe_unused]] bool in_ts) const override + { + return true; + } + virtual PrivateFieldKind ToPrivateFieldKind(bool is_static) const = 0; protected: diff --git a/ets2panda/ir/base/methodDefinition.h b/ets2panda/ir/base/methodDefinition.h index 079bddf66cfa20019c67274a2b4b1579b4c0af61..dd08f87b0a99d6ec4ae5038dadf82fae4ad42626 100644 --- a/ets2panda/ir/base/methodDefinition.h +++ b/ets2panda/ir/base/methodDefinition.h @@ -50,6 +50,16 @@ public: return kind_ == MethodDefinitionKind::EXTENSION_METHOD; } + Expression const *Key() const + { + return key_; + } + + Expression const *Value() const + { + return value_; + } + const ArenaVector &Overloads() const { return overloads_; diff --git a/ets2panda/ir/base/spreadElement.h b/ets2panda/ir/base/spreadElement.h index 037cc59ca40d90174d64c54e4380f659c96ae2b5..7c56b7813f10f146b368586c5f9f2bc5fe1d3d06 100644 --- a/ets2panda/ir/base/spreadElement.h +++ b/ets2panda/ir/base/spreadElement.h @@ -58,12 +58,22 @@ public: return decorators_; } + const ArenaVector *DecoratorsPtr() const override + { + return &Decorators(); + } + void AddDecorators(ArenaVector &&decorators) override { decorators_ = std::move(decorators); } - void SetOptional(bool const optional) noexcept + bool CanHaveDecorator([[maybe_unused]] bool in_ts) const override + { + return true; + } + + void SetOptional(bool optional) noexcept { optional_ = optional; } diff --git a/ets2panda/ir/ets/etsFunctionType.h b/ets2panda/ir/ets/etsFunctionType.h index 62c59ffd9fb30b2a00ef9ef17bfc878c4961f611..d8323848934eb12c044460249b056ae6bdb1ca1a 100644 --- a/ets2panda/ir/ets/etsFunctionType.h +++ b/ets2panda/ir/ets/etsFunctionType.h @@ -80,6 +80,11 @@ public: functional_interface_ = functional_interface; } + ir::ScriptFunctionFlags Flags() + { + return func_flags_; + } + bool IsThrowing() const { return (func_flags_ & ir::ScriptFunctionFlags::THROWS) != 0; diff --git a/ets2panda/ir/ets/etsNewArrayInstanceExpression.h b/ets2panda/ir/ets/etsNewArrayInstanceExpression.h index 553bb75120377bf84d5ead2276bf5323fbf855b6..e95da6808c99c29fd8830ec7401f7490eac10a77 100644 --- a/ets2panda/ir/ets/etsNewArrayInstanceExpression.h +++ b/ets2panda/ir/ets/etsNewArrayInstanceExpression.h @@ -35,6 +35,26 @@ public: { } + ir::TypeNode *TypeReference() + { + return type_reference_; + } + + ir::TypeNode const *TypeReference() const + { + return type_reference_; + } + + ir::Expression *Dimension() + { + return dimension_; + } + + ir::Expression const *Dimension() const + { + return dimension_; + } + // NOLINTNEXTLINE(google-default-arguments) [[nodiscard]] Expression *Clone(ArenaAllocator *allocator, AstNode *parent = nullptr) override; diff --git a/ets2panda/ir/ets/etsNewMultiDimArrayInstanceExpression.h b/ets2panda/ir/ets/etsNewMultiDimArrayInstanceExpression.h index 1cf38efa643435cccf347872aed8957b3912a35d..733ade81ccc592f471184a5d0208b9b58b5ff103 100644 --- a/ets2panda/ir/ets/etsNewMultiDimArrayInstanceExpression.h +++ b/ets2panda/ir/ets/etsNewMultiDimArrayInstanceExpression.h @@ -34,6 +34,26 @@ public: { } + ir::TypeNode *TypeReference() + { + return type_reference_; + } + + ir::TypeNode const *TypeReference() const + { + return type_reference_; + } + + ArenaVector &Dimensions() + { + return dimensions_; + } + + ArenaVector const &Dimension() const + { + return dimensions_; + } + checker::Signature *Signature() { return signature_; diff --git a/ets2panda/ir/ets/etsStructDeclaration.h b/ets2panda/ir/ets/etsStructDeclaration.h index 90a448f581dfdf1ad83d074484be39a8ffb47acb..d400f3bc2f74b634716d57f7f6a5a5f5a0d4b6fe 100644 --- a/ets2panda/ir/ets/etsStructDeclaration.h +++ b/ets2panda/ir/ets/etsStructDeclaration.h @@ -41,6 +41,11 @@ public: return decorators_; } + const ArenaVector *DecoratorsPtr() const override + { + return &Decorators(); + } + void AddDecorators(ArenaVector &&decorators) override { decorators_ = std::move(decorators); diff --git a/ets2panda/ir/expressions/arrayExpression.h b/ets2panda/ir/expressions/arrayExpression.h index 5848b480b54f641968a51e5abaddad04fa2a09ed..2ea377ae67c66600a857c8b7081bc3de34d51e00 100644 --- a/ets2panda/ir/expressions/arrayExpression.h +++ b/ets2panda/ir/expressions/arrayExpression.h @@ -93,17 +93,26 @@ public: return decorators_; } + const ArenaVector *DecoratorsPtr() const override + { + return &Decorators(); + } + void AddDecorators([[maybe_unused]] ArenaVector &&decorators) override { decorators_ = std::move(decorators); } + bool CanHaveDecorator([[maybe_unused]] bool in_ts) const override + { + return true; + } + // NOLINTNEXTLINE(google-default-arguments) [[nodiscard]] Expression *Clone(ArenaAllocator *allocator, AstNode *parent = nullptr) override; [[nodiscard]] bool ConvertibleToArrayPattern(); [[nodiscard]] ValidationInfo ValidateExpression(); - void TransformChildren(const NodeTransformer &cb) override; void Iterate(const NodeTraverser &cb) const override; void Dump(ir::AstDumper *dumper) const override; diff --git a/ets2panda/ir/expressions/assignmentExpression.h b/ets2panda/ir/expressions/assignmentExpression.h index 5f14a1c1cff1321beae8fb22326bc89d9c25353a..81535ddd5a6017fb78a91851869efe0c290bbefb 100644 --- a/ets2panda/ir/expressions/assignmentExpression.h +++ b/ets2panda/ir/expressions/assignmentExpression.h @@ -80,7 +80,7 @@ public: return operator_; } - [[nodiscard]] lexer::TokenType SetOperatorType(lexer::TokenType token_type) noexcept + lexer::TokenType SetOperatorType(lexer::TokenType token_type) noexcept { return operator_ = token_type; } diff --git a/ets2panda/ir/expressions/identifier.h b/ets2panda/ir/expressions/identifier.h index a6ee3dd78ef7aaa4e9400a3bb702c9cd6a3ddc0b..4810b4ac223eb96706eea9115f31ca5fb5bc3f25 100644 --- a/ets2panda/ir/expressions/identifier.h +++ b/ets2panda/ir/expressions/identifier.h @@ -83,6 +83,11 @@ public: return decorators_; } + const ArenaVector *DecoratorsPtr() const override + { + return &Decorators(); + } + [[nodiscard]] bool IsOptional() const noexcept { return (flags_ & IdentifierFlags::OPTIONAL) != 0; @@ -188,6 +193,11 @@ public: // NOLINTNEXTLINE(google-default-arguments) [[nodiscard]] Expression *Clone(ArenaAllocator *allocator, AstNode *parent = nullptr) override; + bool CanHaveDecorator([[maybe_unused]] bool in_ts) const override + { + return true; + } + [[nodiscard]] ValidationInfo ValidateExpression(); void TransformChildren(const NodeTransformer &cb) override; diff --git a/ets2panda/ir/expressions/importExpression.h b/ets2panda/ir/expressions/importExpression.h index d275dd9a9a4e87384f2455bf2f8a0fa934ec7ca4..df534532e684e4d5ba2c411884d34461d4e3c0be 100644 --- a/ets2panda/ir/expressions/importExpression.h +++ b/ets2panda/ir/expressions/importExpression.h @@ -29,6 +29,11 @@ public: explicit ImportExpression(Expression *source) : Expression(AstNodeType::IMPORT_EXPRESSION), source_(source) {} + Expression *Source() + { + return source_; + } + // NOLINTNEXTLINE(google-default-arguments) [[nodiscard]] Expression *Clone(ArenaAllocator *allocator, AstNode *parent = nullptr) override; diff --git a/ets2panda/ir/expressions/objectExpression.h b/ets2panda/ir/expressions/objectExpression.h index b258313d0b93de38a1d3b55eab3cae03dfbc5123..f1e05b743f8746aad44a7924e1b6a8f1e9489f2a 100644 --- a/ets2panda/ir/expressions/objectExpression.h +++ b/ets2panda/ir/expressions/objectExpression.h @@ -77,17 +77,26 @@ public: return decorators_; } + const ArenaVector *DecoratorsPtr() const override + { + return &Decorators(); + } + void AddDecorators([[maybe_unused]] ArenaVector &&decorators) override { decorators_ = std::move(decorators); } + bool CanHaveDecorator([[maybe_unused]] bool in_ts) const override + { + return true; + } + // NOLINTNEXTLINE(google-default-arguments) [[nodiscard]] Expression *Clone(ArenaAllocator *allocator, AstNode *parent = nullptr) override; [[nodiscard]] ValidationInfo ValidateExpression(); [[nodiscard]] bool ConvertibleToObjectPattern(); - void SetDeclaration(); void SetOptional(bool optional); void TransformChildren(const NodeTransformer &cb) override; diff --git a/ets2panda/ir/statements/classDeclaration.h b/ets2panda/ir/statements/classDeclaration.h index c2e535c0740205f0be808f6d4e772d51b8f8e7b1..7e4b65d78fd0b94b64f827e8f2eea8b7ac882a18 100644 --- a/ets2panda/ir/statements/classDeclaration.h +++ b/ets2panda/ir/statements/classDeclaration.h @@ -41,6 +41,11 @@ public: return decorators_; } + const ArenaVector *DecoratorsPtr() const override + { + return &Decorators(); + } + void AddDecorators(ArenaVector &&decorators) override { decorators_ = std::move(decorators); diff --git a/ets2panda/ir/statements/variableDeclaration.h b/ets2panda/ir/statements/variableDeclaration.h index 601170366b6d7bc04feb7395bc72542d65953875..fac991570d54d21800e1fcdf469654a2c48fbd11 100644 --- a/ets2panda/ir/statements/variableDeclaration.h +++ b/ets2panda/ir/statements/variableDeclaration.h @@ -55,6 +55,11 @@ public: return decorators_; } + const ArenaVector *DecoratorsPtr() const override + { + return &Decorators(); + } + void AddDecorators([[maybe_unused]] ArenaVector &&decorators) override { decorators_ = std::move(decorators); diff --git a/ets2panda/ir/ts/tsEnumDeclaration.h b/ets2panda/ir/ts/tsEnumDeclaration.h index 72a6d0870e70927c208743b2179173baf897b3e6..32c1927fdd5f3bd2305e77e572ffdf4913276ec0 100644 --- a/ets2panda/ir/ts/tsEnumDeclaration.h +++ b/ets2panda/ir/ts/tsEnumDeclaration.h @@ -89,6 +89,11 @@ public: return decorators_; } + const ArenaVector *DecoratorsPtr() const override + { + return &Decorators(); + } + void AddDecorators([[maybe_unused]] ArenaVector &&decorators) override { decorators_ = std::move(decorators); diff --git a/ets2panda/ir/ts/tsInterfaceDeclaration.h b/ets2panda/ir/ts/tsInterfaceDeclaration.h index e209324087ebff6e72b4d94dd77acfee8c52eb2d..9ede275089e2f6b24cf5570e0da0f9de83682d62 100644 --- a/ets2panda/ir/ts/tsInterfaceDeclaration.h +++ b/ets2panda/ir/ts/tsInterfaceDeclaration.h @@ -120,6 +120,11 @@ public: return decorators_; } + const ArenaVector *DecoratorsPtr() const override + { + return &Decorators(); + } + void AddDecorators([[maybe_unused]] ArenaVector &&decorators) override { decorators_ = std::move(decorators); diff --git a/ets2panda/ir/ts/tsTypeAliasDeclaration.h b/ets2panda/ir/ts/tsTypeAliasDeclaration.h index 5dc000528a098a4fca951d7e7431644d01f39082..77061cb11274a031479d4f0c9e89fef551171035 100644 --- a/ets2panda/ir/ts/tsTypeAliasDeclaration.h +++ b/ets2panda/ir/ts/tsTypeAliasDeclaration.h @@ -72,6 +72,11 @@ public: return decorators_; } + const ArenaVector *DecoratorsPtr() const override + { + return &Decorators(); + } + void AddTypeParameters(ir::TSTypeParameterDeclaration *type_params) { type_params_ = type_params; diff --git a/ets2panda/ir/ts/tsTypeParameterDeclaration.h b/ets2panda/ir/ts/tsTypeParameterDeclaration.h index 6e203679adc7e041816cf6af1c97fc13b9de56f3..0d9b263ebab82dc22b4a58ea8853f394322fe39b 100644 --- a/ets2panda/ir/ts/tsTypeParameterDeclaration.h +++ b/ets2panda/ir/ts/tsTypeParameterDeclaration.h @@ -18,9 +18,9 @@ #include "varbinder/scope.h" #include "ir/expression.h" +#include "ir/ts/tsTypeParameter.h" namespace panda::es2panda::ir { -class TSTypeParameter; class TSTypeParameterDeclaration : public Expression { public: @@ -48,6 +48,14 @@ public: return params_; } + void AddParam(TSTypeParameter *param) + { + if (required_params_ == params_.size() && param->DefaultType() == nullptr) { + required_params_++; + } + params_.push_back(param); + } + size_t RequiredParams() const { return required_params_; diff --git a/ets2panda/parser/ETSparser.h b/ets2panda/parser/ETSparser.h index ba8e78e3598ff4a5968eafceb990cbf6237273d0..f816fdb8cea4f62b4cc5d6a903bb0625a3ddb0f1 100644 --- a/ets2panda/parser/ETSparser.h +++ b/ets2panda/parser/ETSparser.h @@ -37,7 +37,7 @@ public: NO_COPY_SEMANTIC(ETSParser); NO_MOVE_SEMANTIC(ETSParser); - ~ETSParser() = default; + ~ETSParser() final = default; ir::Expression *CreateExpression(ExpressionParseFlags flags, std::string_view source_code, std::string_view file_name = DEFAULT_SOURCE_FILE); diff --git a/ets2panda/parser/parserImpl.h b/ets2panda/parser/parserImpl.h index 21c674b2e6d56b19aeb6cc03885a5bde0e9b866a..700c1eedef6a3f8f3ff977e0ee6103c48a554ad3 100644 --- a/ets2panda/parser/parserImpl.h +++ b/ets2panda/parser/parserImpl.h @@ -175,7 +175,7 @@ public: explicit ParserImpl(Program *program, const CompilerOptions &options, ParserStatus status = ParserStatus::NO_OPTS); NO_COPY_SEMANTIC(ParserImpl); NO_MOVE_SEMANTIC(ParserImpl); - ~ParserImpl() = default; + virtual ~ParserImpl() = default; void ParseScript(const SourceFile &source_file, bool gen_std_lib); diff --git a/ets2panda/public/es2panda_lib.cpp b/ets2panda/public/es2panda_lib.cpp index 6b6c6e5cf449bf91a56ad8835176fa9a9796107e..ad6d9c04f19420c4947cb825a4f2d148c994ba5b 100644 --- a/ets2panda/public/es2panda_lib.cpp +++ b/ets2panda/public/es2panda_lib.cpp @@ -16,6 +16,10 @@ #include "es2panda_lib.h" #include +#include "varbinder/varbinder.h" +#include "varbinder/scope.h" +#include "varbinder/variable.h" +#include "public/public.h" #include "generated/signatures.h" #include "es2panda.h" #include "assembler/assembly-program.h" @@ -28,39 +32,221 @@ #include "compiler/core/ETSGen.h" #include "compiler/core/regSpiller.h" #include "compiler/lowering/phase.h" +#include "compiler/lowering/util.h" #include "ir/astNode.h" +#include "ir/expressions/arrowFunctionExpression.h" +#include "ir/ts/tsAsExpression.h" +#include "ir/expressions/assignmentExpression.h" +#include "ir/expressions/binaryExpression.h" +#include "ir/statements/blockStatement.h" +#include "ir/expressions/callExpression.h" +#include "ir/expressions/chainExpression.h" +#include "ir/statements/classDeclaration.h" +#include "ir/base/classDefinition.h" +#include "ir/base/classElement.h" +#include "ir/ts/tsClassImplements.h" +#include "ir/base/classProperty.h" +#include "ir/statements/expressionStatement.h" +#include "ir/statements/functionDeclaration.h" +#include "ir/expressions/functionExpression.h" +#include "ir/ets/etsFunctionType.h" #include "ir/expressions/identifier.h" +#include "ir/statements/ifStatement.h" +#include "ir/module/importDeclaration.h" +#include "ir/expressions/importExpression.h" +#include "ir/module/importSpecifier.h" +#include "ir/base/methodDefinition.h" +#include "ir/ets/etsNewClassInstanceExpression.h" +#include "ir/ets/etsNewArrayInstanceExpression.h" +#include "ir/ets/etsNewMultiDimArrayInstanceExpression.h" +#include "ir/expressions/thisExpression.h" +#include "ir/ts/tsTypeParameter.h" +#include "ir/ts/tsTypeParameterDeclaration.h" +#include "ir/ts/tsTypeParameterInstantiation.h" +#include "ir/statements/variableDeclaration.h" +#include "ir/statements/variableDeclarator.h" #include "parser/ETSparser.h" #include "parser/context/parserContext.h" #include "parser/program/program.h" #include "util/generateBin.h" +#include "util/language.h" #include "util/options.h" namespace panda::es2panda::public_lib { -struct ConfigImpl { - std::unique_ptr options; -}; -struct Context { - ConfigImpl *config = nullptr; - std::string source_file_name; - std::string input; - std::unique_ptr source_file; - std::unique_ptr allocator; - std::unique_ptr queue; - - std::unique_ptr parser_program; - std::unique_ptr parser; - std::unique_ptr checker; - std::unique_ptr analyzer; - std::unique_ptr compiler_context; - std::unique_ptr emitter; - std::unique_ptr program; - - es2panda_ContextState state = ES2PANDA_STATE_NEW; - std::string error_message; +struct TokenTypeToStr { + lexer::TokenType token; + char const *str; }; +static lexer::TokenType StrToToken(TokenTypeToStr const *table, char const *str) +{ + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) + for (auto *tp = table; tp->str != nullptr; tp++) { + if (strcmp(str, tp->str) == 0) { + return tp->token; + } + } + UNREACHABLE(); +} + +static char const *TokenToStr(TokenTypeToStr const *table, lexer::TokenType token) +{ + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) + for (auto *tp = table; tp->str != nullptr; tp++) { + if (tp->token == token) { + return tp->str; + } + } + UNREACHABLE(); +} + +static char const *StringViewToCString(ArenaAllocator *allocator, util::StringView const sv) +{ + // NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic, readability-simplify-subscript-expr) + std::string_view utf8 = sv.Utf8(); + if (utf8.data()[utf8.size()] == '\0') { + // Avoid superfluous allocation. + return utf8.data(); + } + char *res = reinterpret_cast(allocator->Alloc(utf8.size() + 1)); + memmove(res, utf8.cbegin(), utf8.size()); + res[utf8.size()] = '\0'; + return res; + // NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic, readability-simplify-subscript-expr) +} + +static char const *ArenaStrdup(ArenaAllocator *allocator, char const *src) +{ + size_t len = strlen(src); + char *res = reinterpret_cast(allocator->Alloc(len + 1)); + memmove(res, src, len); + + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) + res[len] = '\0'; + return res; +} + +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define FOR_ALL_MODIFIER_FLAGS(_) \ + _(STATIC) \ + _(ASYNC) \ + _(PUBLIC) \ + _(PROTECTED) \ + _(PRIVATE) \ + _(DECLARE) \ + _(READONLY) \ + _(OPTIONAL) \ + _(DEFINITE) \ + _(ABSTRACT) \ + _(CONST) \ + _(FINAL) \ + _(NATIVE) \ + _(OVERRIDE) \ + _(CONSTRUCTOR) \ + _(SYNCHRONIZED) \ + _(FUNCTIONAL) \ + _(IN) \ + _(OUT) \ + _(INTERNAL) \ + _(NULL_ASSIGNABLE) \ + _(UNDEFINED_ASSIGNABLE) \ + _(EXPORT) \ + _(SETTER) \ + _(DEFAULT_EXPORT) + +static ir::ModifierFlags E2pToIrModifierFlags(es2panda_ModifierFlags e2p_flags) +{ + ir::ModifierFlags ir_flags {ir::ModifierFlags::NONE}; + +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define DO_FLAG(FL) \ + if ((e2p_flags & ES2PANDA_MODIFIER_##FL) != 0) { \ + ir_flags |= ir::ModifierFlags::FL; \ + } + + FOR_ALL_MODIFIER_FLAGS(DO_FLAG) + +#undef DO_FLAG + + return ir_flags; +} + +static es2panda_ModifierFlags IrToE2pModifierFlags(ir::ModifierFlags ir_flags) +{ + es2panda_ModifierFlags e2p_flags {ES2PANDA_MODIFIER_NONE}; + +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define DO_FLAG(FL) \ + if ((ir_flags & ir::ModifierFlags::FL) != 0) { \ + e2p_flags = static_cast(e2p_flags | ES2PANDA_MODIFIER_##FL); \ + } + + FOR_ALL_MODIFIER_FLAGS(DO_FLAG) + +#undef DO_FLAG + + return e2p_flags; +} + +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define FOR_ALL_SCRIPT_FUNCTION_FLAGS(_) \ + _(GENERATOR) \ + _(ASYNC) \ + _(ARROW) \ + _(EXPRESSION) \ + _(OVERLOAD) \ + _(CONSTRUCTOR) \ + _(METHOD) \ + _(STATIC_BLOCK) \ + _(HIDDEN) \ + _(IMPLICIT_SUPER_CALL_NEEDED) \ + _(ENUM) \ + _(EXTERNAL) \ + _(PROXY) \ + _(THROWS) \ + _(RETHROWS) \ + _(GETTER) \ + _(SETTER) \ + _(DEFAULT_PARAM_PROXY) \ + _(ENTRY_POINT) \ + _(INSTANCE_EXTENSION_METHOD) \ + _(HAS_RETURN) + +static ir::ScriptFunctionFlags E2pToIrScriptFunctionFlags(es2panda_ScriptFunctionFlags e2p_flags) +{ + ir::ScriptFunctionFlags ir_flags {ir::ScriptFunctionFlags::NONE}; + +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define DO_FLAG(FL) \ + if ((e2p_flags & ES2PANDA_SCRIPT_FUNCTION_##FL) != 0) { \ + ir_flags |= ir::ScriptFunctionFlags::FL; \ + } + + FOR_ALL_SCRIPT_FUNCTION_FLAGS(DO_FLAG) + +#undef DO_FLAG + + return ir_flags; +} + +static es2panda_ScriptFunctionFlags IrToE2pScriptFunctionFlags(ir::ScriptFunctionFlags ir_flags) +{ + es2panda_ScriptFunctionFlags e2p_flags {ES2PANDA_SCRIPT_FUNCTION_NONE}; + +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define DO_FLAG(FL) \ + if ((ir_flags & ir::ScriptFunctionFlags::FL) != 0) { \ + e2p_flags = static_cast(e2p_flags | ES2PANDA_SCRIPT_FUNCTION_##FL); \ + } + + FOR_ALL_SCRIPT_FUNCTION_FLAGS(DO_FLAG) + +#undef DO_FLAG + + return e2p_flags; +} + extern "C" es2panda_Config *CreateConfig(int args, char const **argv) { constexpr auto COMPILER_SIZE = 256_MB; @@ -68,7 +254,7 @@ extern "C" es2panda_Config *CreateConfig(int args, char const **argv) mem::MemConfig::Initialize(0, 0, COMPILER_SIZE, 0, 0, 0); PoolManager::Initialize(PoolType::MMAP); - auto options = std::make_unique(); + auto *options = new util::Options(); if (!options->Parse(args, argv)) { // NOTE: gogabr. report option errors properly. std::cerr << options->ErrorMsg() << std::endl; @@ -79,7 +265,7 @@ extern "C" es2panda_Config *CreateConfig(int args, char const **argv) Logger::InitializeStdLogging(Logger::LevelFromString(options->LogLevel()), mask); auto *res = new ConfigImpl; - res->options = std::move(options); + res->options = options; return reinterpret_cast(res); } @@ -88,7 +274,10 @@ extern "C" void DestroyConfig(es2panda_Config *config) PoolManager::Finalize(); mem::MemConfig::Finalize(); - delete reinterpret_cast(config); + auto *cfg = reinterpret_cast(config); + + delete cfg->options; + delete cfg; } static void CompileJob(compiler::CompilerContext *context, varbinder::FunctionScope *scope, @@ -107,31 +296,32 @@ static es2panda_Context *CreateContext(es2panda_Config *config, std::string cons { auto *cfg = reinterpret_cast(config); auto *res = new Context; - res->config = cfg; res->input = source; res->source_file_name = file_name; try { - res->source_file = std::make_unique(res->source_file_name, res->input, cfg->options->ParseModule()); - res->allocator = std::make_unique(SpaceType::SPACE_TYPE_COMPILER, nullptr, true); - res->queue = std::make_unique(cfg->options->ThreadCount()); + res->source_file = new SourceFile(res->source_file_name, res->input, cfg->options->ParseModule()); + res->allocator = new ArenaAllocator(SpaceType::SPACE_TYPE_COMPILER, nullptr, true); + res->queue = new compiler::CompileQueue(cfg->options->ThreadCount()); - auto *varbinder = res->allocator->New(res->allocator.get()); - res->parser_program = std::make_unique(res->allocator.get(), varbinder); + auto *varbinder = res->allocator->New(res->allocator); + res->parser_program = new parser::Program(res->allocator, varbinder); res->parser_program->MarkEntry(); - res->parser = std::make_unique(res->parser_program.get(), cfg->options->CompilerOptions(), - parser::ParserStatus::NO_OPTS); - res->checker = std::make_unique(); - res->analyzer = std::make_unique(res->checker.get()); - res->checker->SetAnalyzer(res->analyzer.get()); - - varbinder->SetProgram(res->parser_program.get()); - - res->compiler_context = std::make_unique( - varbinder, res->checker.get(), cfg->options->CompilerOptions(), CompileJob); - varbinder->SetCompilerContext(res->compiler_context.get()); - res->emitter = std::make_unique(res->compiler_context.get()); - res->compiler_context->SetEmitter(res->emitter.get()); + res->parser = + new parser::ETSParser(res->parser_program, cfg->options->CompilerOptions(), parser::ParserStatus::NO_OPTS); + res->checker = new checker::ETSChecker(); + res->analyzer = new checker::ETSAnalyzer(res->checker); + res->checker->SetAnalyzer(res->analyzer); + + varbinder->SetProgram(res->parser_program); + + res->compiler_context = + new compiler::CompilerContext(varbinder, res->checker, cfg->options->CompilerOptions(), CompileJob); + varbinder->SetCompilerContext(res->compiler_context); + res->phases = compiler::GetETSPhaseList(); + res->current_phase = 0; + res->emitter = new compiler::ETSEmitter(res->compiler_context); + res->compiler_context->SetEmitter(res->emitter); res->program = nullptr; res->state = ES2PANDA_STATE_NEW; } catch (Error &e) { @@ -151,7 +341,7 @@ extern "C" es2panda_Context *CreateContextFromFile(es2panda_Config *config, char auto *res = new Context; res->error_message = "Failed to open file: "; res->error_message.append(source_file_name); - return reinterpret_cast(res); + return reinterpret_cast(res); } std::stringstream ss; ss << input_stream.rdbuf(); @@ -159,7 +349,7 @@ extern "C" es2panda_Context *CreateContextFromFile(es2panda_Config *config, char auto *res = new Context; res->error_message = "Failed to read file: "; res->error_message.append(source_file_name); - return reinterpret_cast(res); + return reinterpret_cast(res); } return CreateContext(config, ss.str(), source_file_name); } @@ -178,8 +368,9 @@ static Context *Parse(Context *ctx) return ctx; } try { - ctx->parser->ParseScript(*ctx->source_file, ctx->config->options->CompilerOptions().compilation_mode == - CompilationMode::GEN_STD_LIB); + ctx->parser->ParseScript(*ctx->source_file, + ctx->compiler_context->Options()->compilation_mode == CompilationMode::GEN_STD_LIB); + ctx->parser_program = ctx->compiler_context->VarBinder()->Program(); ctx->state = ES2PANDA_STATE_PARSED; } catch (Error &e) { std::stringstream ss; @@ -204,8 +395,13 @@ static Context *Check(Context *ctx) ASSERT(ctx->state == ES2PANDA_STATE_PARSED); try { - ctx->compiler_context->Checker()->StartChecker(ctx->compiler_context->VarBinder(), - ctx->config->options->CompilerOptions()); + do { + if (ctx->current_phase >= ctx->phases.size()) { + break; + } + + ctx->phases[ctx->current_phase]->Apply(ctx, ctx->parser_program); + } while (ctx->phases[ctx->current_phase++]->Name() != "checker"); ctx->state = ES2PANDA_STATE_CHECKED; } catch (Error &e) { std::stringstream ss; @@ -229,8 +425,8 @@ static Context *Lower(Context *ctx) ASSERT(ctx->state == ES2PANDA_STATE_CHECKED); try { - for (auto *phase : compiler::GetETSPhaseList()) { - phase->Apply(ctx->compiler_context.get(), ctx->compiler_context->VarBinder()->Program()); + while (ctx->current_phase < ctx->phases.size()) { + ctx->phases[ctx->current_phase++]->Apply(ctx, ctx->parser_program); } ctx->state = ES2PANDA_STATE_LOWERED; @@ -269,13 +465,12 @@ static Context *GenerateAsm(Context *ctx) emitter->LiteralBufferIndex() += ctx->compiler_context->ContextLiterals().size(); /* Main thread can also be used instead of idling */ - ctx->queue->Schedule(ctx->compiler_context.get()); + ctx->queue->Schedule(ctx->compiler_context); ctx->queue->Consume(); ctx->queue->Wait( [emitter](compiler::CompileJob *job) { emitter->AddProgramElement(job->GetProgramElement()); }); ASSERT(ctx->program == nullptr); - ctx->program = std::unique_ptr { - emitter->Finalize(ctx->compiler_context->DumpDebugInfo(), compiler::Signatures::ETS_GLOBAL)}; + ctx->program = emitter->Finalize(ctx->compiler_context->DumpDebugInfo(), compiler::Signatures::ETS_GLOBAL); ctx->state = ES2PANDA_STATE_ASM_GENERATED; } catch (Error &e) { @@ -301,7 +496,7 @@ Context *GenerateBin(Context *ctx) try { ASSERT(ctx->program != nullptr); - util::GenerateProgram(ctx->program.get(), ctx->config->options.get(), + util::GenerateProgram(ctx->program, ctx->config->options, [ctx](const std::string &str) { ctx->error_message = str; }); ctx->state = ES2PANDA_STATE_BIN_GENERATED; @@ -345,8 +540,18 @@ extern "C" es2panda_Context *ProceedToState(es2panda_Context *context, es2panda_ extern "C" void DestroyContext(es2panda_Context *context) { - auto *s = reinterpret_cast(context); - delete s; + auto *ctx = reinterpret_cast(context); + delete ctx->program; + delete ctx->emitter; + delete ctx->compiler_context; + delete ctx->analyzer; + delete ctx->checker; + delete ctx->parser; + delete ctx->parser_program; + delete ctx->queue; + delete ctx->allocator; + delete ctx->source_file; + delete ctx; } extern "C" es2panda_ContextState ContextState(es2panda_Context *context) @@ -361,13 +566,1942 @@ extern "C" char const *ContextErrorMessage(es2panda_Context *context) return s->error_message.c_str(); } -es2panda_Impl IMPL = {ES2PANDA_LIB_VERSION, +extern "C" es2panda_Program *ContextProgram(es2panda_Context *context) +{ + auto *ctx = reinterpret_cast(context); + return reinterpret_cast(ctx->compiler_context->VarBinder()->Program()); +} + +extern "C" es2panda_AstNode *ProgramAst(es2panda_Program *program) +{ + auto *pgm = reinterpret_cast(program); + return reinterpret_cast(pgm->Ast()); +} + +using ExternalSourceEntry = std::pair *>; + +extern "C" es2panda_ExternalSource **ProgramExternalSources(es2panda_Program *program, size_t *len_p) +{ + auto *pgm = reinterpret_cast(program); + auto *allocator = pgm->VarBinder()->Allocator(); + auto *vec = allocator->New>(allocator->Adapter()); + + for (auto &[e_name, e_programs] : pgm->ExternalSources()) { + vec->push_back(allocator->New(StringViewToCString(allocator, e_name), &e_programs)); + } + + *len_p = vec->size(); + return reinterpret_cast(vec->data()); +} + +extern "C" char const *ExternalSourceName(es2panda_ExternalSource *e_source) +{ + auto *entry = reinterpret_cast(e_source); + return entry->first; +} + +extern "C" es2panda_Program **ExternalSourcePrograms(es2panda_ExternalSource *e_source, size_t *len_p) +{ + auto *entry = reinterpret_cast(e_source); + *len_p = entry->second->size(); + return reinterpret_cast(entry->second->data()); +} + +extern "C" es2panda_Type *AstNodeType(es2panda_AstNode *ast) +{ + auto *node = reinterpret_cast(ast); + // Need to work with other TypeAstNodes + if (node->IsExpression()) { + return reinterpret_cast(node->AsExpression()->TsType()); + } + return nullptr; +} + +extern "C" es2panda_AstNode *const *AstNodeDecorators(es2panda_AstNode *ast, size_t *size_p) +{ + auto *node = reinterpret_cast(ast); + if (node->CanHaveDecorator(false)) { + auto *decorators = node->DecoratorsPtr(); + *size_p = decorators->size(); + return reinterpret_cast(decorators->data()); + } + *size_p = 0; + return nullptr; +} + +extern "C" es2panda_ModifierFlags AstNodeModifierFlags(es2panda_AstNode *ast) +{ + auto *node = reinterpret_cast(ast); + return IrToE2pModifierFlags(node->Modifiers()); +} + +extern "C" void AstNodeSetDecorators(es2panda_Context *context, es2panda_AstNode *ast, es2panda_AstNode **decorators, + size_t n_decorators) +{ + auto *ctx = reinterpret_cast(context); + auto *allocator = ctx->allocator; + auto *node = reinterpret_cast(ast); + + ArenaVector decorators_vector {allocator->Adapter()}; + for (size_t i = 0; i < n_decorators; i++) { + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) + decorators_vector.push_back(reinterpret_cast(decorators[i])->AsDecorator()); + } + node->AddDecorators(std::move(decorators_vector)); +} + +extern "C" void AstNodeSetType(es2panda_AstNode *ast, es2panda_Type *type) +{ + auto *node = reinterpret_cast(ast); + auto *tp = reinterpret_cast(type); + // Need to work with other TypedAstNodes + if (node->IsExpression()) { + node->AsExpression()->SetTsType(tp); + } else { + UNREACHABLE(); + } +} + +extern "C" void AstNodeForEach(es2panda_AstNode *ast, void (*func)(es2panda_AstNode *, void *), void *arg) +{ + auto *node = reinterpret_cast(ast); + func(ast, arg); + node->IterateRecursively([=](ir::AstNode *child) { func(reinterpret_cast(child), arg); }); +} + +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define IS(public_name, e2p_name) \ + extern "C" bool Is##public_name(es2panda_AstNode *ast) \ + { \ + auto *node = reinterpret_cast(ast); \ + return node->Is##e2p_name(); \ + } + +IS(ArrowFunctionExpression, ArrowFunctionExpression) +IS(AsExpression, TSAsExpression) +IS(AssignmentExpression, AssignmentExpression) +IS(BinaryExpression, BinaryExpression) +IS(BlockStatement, BlockStatement) +IS(CallExpression, CallExpression) +IS(ChainExpression, ChainExpression) +IS(ClassDeclaration, ClassDeclaration) +IS(ClassDefinition, ClassDefinition) +IS(ClassImplementsClause, TSClassImplements) +IS(ClassProperty, ClassProperty) +IS(ExpressionStatement, ExpressionStatement) +IS(FunctionDeclaration, FunctionDeclaration) +IS(FunctionExpression, FunctionExpression) +IS(FunctionTypeNode, TSFunctionType) +IS(Identifier, Identifier) +IS(IfStatement, IfStatement) +IS(ImportDeclaration, ImportDeclaration) +IS(ImportExpression, ImportExpression) +IS(ImportSpecifier, ImportSpecifier) +IS(MemberExpression, MemberExpression) +IS(MethodDefinition, MethodDefinition) +IS(NewClassInstanceExpression, ETSNewClassInstanceExpression) +IS(NewArrayInstanceExpression, ETSNewArrayInstanceExpression) +IS(NewMultiDimArrayInstanceExpression, ETSNewMultiDimArrayInstanceExpression) +IS(NonNullExpression, TSNonNullExpression) +IS(NumberLiteral, NumberLiteral) +IS(ObjectExpression, ObjectExpression) +IS(ParameterDeclaration, ETSParameterExpression) +IS(PrimitiveTypeNode, ETSPrimitiveType) +IS(ReturnStatement, ReturnStatement) +IS(ScriptFunction, ScriptFunction) +IS(StringLiteral, StringLiteral) +IS(ThisExpression, ThisExpression) +IS(TypeParameter, TSTypeParameter) +IS(TypeParameterDeclaration, TSTypeParameterDeclaration) +IS(TypeParameterInstantiation, TSTypeParameterInstantiation) +IS(TypeReferenceNode, ETSTypeReference) +IS(TypeReferencePart, ETSTypeReferencePart) +IS(UnionTypeNode, TSUnionType) +IS(VariableDeclaration, VariableDeclaration) +IS(VariableDeclarator, VariableDeclarator) + +#undef IS + +extern "C" es2panda_AstNode *CreateArrowFunctionExpression(es2panda_Context *context, es2panda_AstNode *script_function) +{ + auto *ctx = reinterpret_cast(context); + auto *func = reinterpret_cast(script_function)->AsScriptFunction(); + auto *allocator = ctx->allocator; + + return reinterpret_cast(allocator->New(allocator, func)); +} + +extern "C" es2panda_AstNode *ArrowFunctionExpressionScriptFunction(es2panda_AstNode *ast) +{ + auto *node = reinterpret_cast(ast)->AsArrowFunctionExpression(); + return reinterpret_cast(node->Function()); +} + +extern "C" es2panda_AstNode *CreateAsExpression(es2panda_Context *context, es2panda_AstNode *expr, + es2panda_AstNode *type_annotation, bool is_const) +{ + auto *ctx = reinterpret_cast(context); + auto *left_expr = reinterpret_cast(expr)->AsExpression(); + auto *tp = reinterpret_cast(type_annotation)->AsExpression()->AsTypeNode(); + auto *allocator = ctx->allocator; + + return reinterpret_cast(allocator->New(left_expr, tp, is_const)); +} + +extern "C" es2panda_AstNode *AsExpressionExpr(es2panda_AstNode *ast) +{ + auto *node = reinterpret_cast(ast)->AsTSAsExpression(); + return reinterpret_cast(node->Expr()); +} + +extern "C" es2panda_AstNode *AsExpressionTypeAnnotation(es2panda_AstNode *ast) +{ + auto *node = reinterpret_cast(ast)->AsTSAsExpression(); + return reinterpret_cast(node->Type()); +} + +extern "C" bool AsExpressionIsConst(es2panda_AstNode *ast) +{ + auto *node = reinterpret_cast(ast)->AsTSAsExpression(); + return node->IsConst(); +} + +extern "C" void AsExpressionSetExpr(es2panda_AstNode *ast, es2panda_AstNode *expr) +{ + auto *node = reinterpret_cast(ast)->AsTSAsExpression(); + auto *new_expr = reinterpret_cast(expr)->AsExpression(); + node->SetExpr(new_expr); +} + +extern "C" void AsExpressionSetTypeAnnotation(es2panda_AstNode *ast, es2panda_AstNode *type_annotation) +{ + auto *node = reinterpret_cast(ast)->AsTSAsExpression(); + auto *tp = reinterpret_cast(type_annotation)->AsExpression()->AsTypeNode(); + node->SetTsTypeAnnotation(tp); +} + +static constexpr std::array ASSIGNMENT_TOKEN_TYPES { + {{lexer::TokenType::PUNCTUATOR_SUBSTITUTION, "="}, + {lexer::TokenType::PUNCTUATOR_UNSIGNED_RIGHT_SHIFT_EQUAL, ">>>="}, + {lexer::TokenType::PUNCTUATOR_RIGHT_SHIFT_EQUAL, ">>="}, + {lexer::TokenType::PUNCTUATOR_LEFT_SHIFT_EQUAL, "<<="}, + {lexer::TokenType::PUNCTUATOR_PLUS_EQUAL, "+="}, + {lexer::TokenType::PUNCTUATOR_MINUS_EQUAL, "-="}, + {lexer::TokenType::PUNCTUATOR_MULTIPLY_EQUAL, "*="}, + {lexer::TokenType::PUNCTUATOR_DIVIDE_EQUAL, "/="}, + {lexer::TokenType::PUNCTUATOR_MOD_EQUAL, "%="}, + {lexer::TokenType::PUNCTUATOR_BITWISE_AND_EQUAL, "&="}, + {lexer::TokenType::PUNCTUATOR_BITWISE_OR_EQUAL, "|="}, + {lexer::TokenType::PUNCTUATOR_BITWISE_XOR_EQUAL, "^="}, + {lexer::TokenType::PUNCTUATOR_LOGICAL_AND_EQUAL, "&&="}, + {lexer::TokenType::PUNCTUATOR_LOGICAL_OR_EQUAL, "||="}, + {lexer::TokenType::PUNCTUATOR_LOGICAL_NULLISH_EQUAL, "\?\?="}, + {lexer::TokenType::PUNCTUATOR_EXPONENTIATION_EQUAL, "**="}, + {lexer::TokenType::EOS, nullptr}}}; + +extern "C" es2panda_AstNode *CreateAssignmentExpression(es2panda_Context *context, es2panda_AstNode *left, + es2panda_AstNode *right, char const *operator_type) +{ + auto *ctx = reinterpret_cast(context); + auto *allocator = ctx->allocator; + auto *left_node = reinterpret_cast(left)->AsExpression(); + auto *right_node = reinterpret_cast(right)->AsExpression(); + lexer::TokenType tok = StrToToken(ASSIGNMENT_TOKEN_TYPES.data(), operator_type); + return reinterpret_cast(allocator->New(left_node, right_node, tok)); +} + +extern "C" es2panda_AstNode *AssignmentExpressionLeft(es2panda_AstNode *ast) +{ + auto *node = reinterpret_cast(ast)->AsAssignmentExpression(); + return reinterpret_cast(node->Left()); +} + +extern "C" es2panda_AstNode *AssignmentExpressionRight(es2panda_AstNode *ast) +{ + auto *node = reinterpret_cast(ast)->AsAssignmentExpression(); + return reinterpret_cast(node->Right()); +} + +extern "C" char const *AssignmentExpressionOperatorType(es2panda_AstNode *ast) +{ + auto *node = reinterpret_cast(ast)->AsAssignmentExpression(); + return TokenToStr(ASSIGNMENT_TOKEN_TYPES.data(), node->OperatorType()); +} + +extern "C" void AssignmentExpressionSetOperatorType(es2panda_AstNode *ast, char const *operator_type) +{ + auto *node = reinterpret_cast(ast)->AsAssignmentExpression(); + auto tok = StrToToken(ASSIGNMENT_TOKEN_TYPES.data(), operator_type); + node->SetOperatorType(tok); +} + +static constexpr std::array BINARY_OP_TOKEN_TYPES { + {{lexer::TokenType::PUNCTUATOR_UNSIGNED_RIGHT_SHIFT, ">>>"}, + {lexer::TokenType::PUNCTUATOR_RIGHT_SHIFT, ">>"}, + {lexer::TokenType::PUNCTUATOR_LEFT_SHIFT, "<<"}, + {lexer::TokenType::PUNCTUATOR_PLUS, "+"}, + {lexer::TokenType::PUNCTUATOR_MINUS, "-"}, + {lexer::TokenType::PUNCTUATOR_MULTIPLY, "*"}, + {lexer::TokenType::PUNCTUATOR_DIVIDE, "/"}, + {lexer::TokenType::PUNCTUATOR_MOD, "%"}, + {lexer::TokenType::PUNCTUATOR_BITWISE_AND, "&"}, + {lexer::TokenType::PUNCTUATOR_BITWISE_OR, "|"}, + {lexer::TokenType::PUNCTUATOR_BITWISE_XOR, "^"}, + {lexer::TokenType::PUNCTUATOR_LOGICAL_AND, "&&"}, + {lexer::TokenType::PUNCTUATOR_LOGICAL_OR, "||"}, + {lexer::TokenType::PUNCTUATOR_NULLISH_COALESCING, "??"}, + {lexer::TokenType::PUNCTUATOR_EXPONENTIATION, "**"}, + {lexer::TokenType::PUNCTUATOR_EQUAL, "=="}, + {lexer::TokenType::PUNCTUATOR_NOT_EQUAL, "/="}, + {lexer::TokenType::PUNCTUATOR_STRICT_EQUAL, "==="}, + {lexer::TokenType::PUNCTUATOR_NOT_STRICT_EQUAL, "/=="}, + {lexer::TokenType::PUNCTUATOR_LESS_THAN, "<"}, + {lexer::TokenType::PUNCTUATOR_LESS_THAN_EQUAL, "<="}, + {lexer::TokenType::PUNCTUATOR_GREATER_THAN, ">"}, + {lexer::TokenType::PUNCTUATOR_GREATER_THAN_EQUAL, ">="}, + {lexer::TokenType::KEYW_IN, "in"}, + {lexer::TokenType::KEYW_INSTANCEOF, "instanceof"}, + {lexer::TokenType::EOS, nullptr}}}; + +extern "C" es2panda_AstNode *CreateBinaryExpression(es2panda_Context *context, es2panda_AstNode *left, + es2panda_AstNode *right, char const *operator_type) +{ + auto *ctx = reinterpret_cast(context); + auto *allocator = ctx->allocator; + auto *left_expr = reinterpret_cast(left)->AsExpression(); + auto *right_expr = reinterpret_cast(right)->AsExpression(); + auto tok = StrToToken(BINARY_OP_TOKEN_TYPES.data(), operator_type); + + return reinterpret_cast(allocator->New(left_expr, right_expr, tok)); +} + +extern "C" es2panda_AstNode *BinaryExpressionLeft(es2panda_AstNode *ast) +{ + auto *node = reinterpret_cast(ast)->AsBinaryExpression(); + return reinterpret_cast(node->Left()); +} + +extern "C" es2panda_AstNode *BinaryExpressionRight(es2panda_AstNode *ast) +{ + auto *node = reinterpret_cast(ast)->AsBinaryExpression(); + return reinterpret_cast(node->Right()); +} + +extern "C" char const *BinaryExpressionOperator(es2panda_AstNode *ast) +{ + auto *node = reinterpret_cast(ast)->AsBinaryExpression(); + return TokenToStr(BINARY_OP_TOKEN_TYPES.data(), node->OperatorType()); +} + +extern "C" void BinaryExpressionSetOperator(es2panda_AstNode *ast, char const *operator_type) +{ + auto *node = reinterpret_cast(ast)->AsBinaryExpression(); + auto op = StrToToken(BINARY_OP_TOKEN_TYPES.data(), operator_type); + node->SetOperator(op); +} + +extern "C" es2panda_AstNode *CreateBlockStatement(es2panda_Context *context, es2panda_AstNode *in_scope_of) +{ + auto *ctx = reinterpret_cast(context); + auto *allocator = ctx->allocator; + auto *parent = reinterpret_cast(in_scope_of); + auto *parent_scope = compiler::NearestScope(parent); + + auto *scope = allocator->New(allocator, parent_scope); + ArenaVector stmts {allocator->Adapter()}; + return reinterpret_cast(allocator->New(allocator, scope, std::move(stmts))); +} + +extern "C" es2panda_AstNode **BlockStatementStatements(es2panda_AstNode *ast, size_t *size_p) +{ + auto *node = reinterpret_cast(ast)->AsBlockStatement(); + *size_p = node->Statements().size(); + return reinterpret_cast(node->Statements().data()); +} + +extern "C" void BlockStatementAddStatement(es2panda_AstNode *ast, es2panda_AstNode *statement) +{ + auto *node = reinterpret_cast(ast)->AsBlockStatement(); + auto *stmt = reinterpret_cast(statement)->AsBlockStatement(); + node->Statements().push_back(stmt); +} + +extern "C" es2panda_AstNode *CreateCallExpression(es2panda_Context *context, es2panda_AstNode *callee, + es2panda_AstNode *type_arguments, es2panda_AstNode **arguments, + size_t n_arguments, bool is_optional) +{ + auto *ctx = reinterpret_cast(context); + auto *allocator = ctx->allocator; + auto *callee_node = reinterpret_cast(callee)->AsExpression(); + + ir::TSTypeParameterInstantiation *type_args = nullptr; + if (type_arguments != nullptr) { + type_args = reinterpret_cast(type_arguments)->AsTSTypeParameterInstantiation(); + } + + ArenaVector args {allocator->Adapter()}; + for (size_t i = 0; i < n_arguments; i++) { + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) + args.push_back(reinterpret_cast(arguments[i])->AsExpression()); + } + return reinterpret_cast( + allocator->New(callee_node, std::move(args), type_args, is_optional)); +} + +extern "C" es2panda_AstNode const *CallExpressionCallee(es2panda_AstNode *ast) +{ + auto *node = reinterpret_cast(ast)->AsCallExpression(); + return reinterpret_cast(node->Callee()); +} + +extern "C" es2panda_AstNode const *CallExpressionTypeArguments(es2panda_AstNode *ast) +{ + auto *node = reinterpret_cast(ast)->AsCallExpression(); + return reinterpret_cast(node->TypeParams()); +} + +extern "C" es2panda_AstNode **CallExpressionArguments(es2panda_AstNode *ast, size_t *size_p) +{ + auto *node = reinterpret_cast(ast)->AsCallExpression(); + *size_p = node->Arguments().size(); + return reinterpret_cast(node->Arguments().data()); +} + +extern "C" bool CallExpressionIsOptional(es2panda_AstNode *ast) +{ + auto *node = reinterpret_cast(ast)->AsCallExpression(); + return node->IsOptional(); +} + +extern "C" void CallExpressionSetTypeArguments(es2panda_AstNode *ast, es2panda_AstNode *type_arguments) +{ + auto *node = reinterpret_cast(ast)->AsCallExpression(); + auto *type_args = reinterpret_cast(type_arguments)->AsTSTypeParameterInstantiation(); + node->SetTypeParams(type_args); +} + +extern "C" es2panda_AstNode *CreateChainExpression(es2panda_Context *context, es2panda_AstNode *child) +{ + auto *ctx = reinterpret_cast(context); + auto *allocator = ctx->allocator; + auto *child_expr = reinterpret_cast(child)->AsExpression(); + + return reinterpret_cast(allocator->New(child_expr)); +} + +extern "C" es2panda_AstNode const *ChainExpressionChild(es2panda_AstNode *ast) +{ + auto *node = reinterpret_cast(ast)->AsChainExpression(); + return reinterpret_cast(node->GetExpression()); +} + +extern "C" es2panda_AstNode *CreateClassDeclaration(es2panda_Context *context, es2panda_AstNode *definition) +{ + auto *ctx = reinterpret_cast(context); + auto *allocator = ctx->allocator; + auto *dfn = reinterpret_cast(definition)->AsClassDefinition(); + + return reinterpret_cast(allocator->New(dfn, allocator)); +} + +extern "C" es2panda_AstNode *ClassDeclarationDefinition(es2panda_AstNode *ast) +{ + auto *node = reinterpret_cast(ast)->AsClassDeclaration(); + return reinterpret_cast(node->Definition()); +} + +extern "C" es2panda_AstNode *CreateClassDefinition(es2panda_Context *context, es2panda_AstNode *in_scope_of, + es2panda_AstNode *identifier, es2panda_ModifierFlags flags) +{ + auto *ctx = reinterpret_cast(context); + auto *allocator = ctx->allocator; + auto *parent = reinterpret_cast(in_scope_of); + auto *parent_scope = compiler::NearestScope(parent); + auto *id = reinterpret_cast(identifier)->AsIdentifier(); + + auto *scope = allocator->New(allocator, parent_scope); + return reinterpret_cast( + allocator->New(allocator, scope, id, ir::ClassDefinitionModifiers::NONE, + E2pToIrModifierFlags(flags), Language::FromString("ets").value())); +} + +extern "C" es2panda_AstNode *ClassDefinitionIdentifier(es2panda_AstNode *ast) +{ + auto *node = reinterpret_cast(ast)->AsClassDefinition(); + return reinterpret_cast(node->Ident()); +} + +extern "C" es2panda_AstNode *ClassDefinitionTypeParameters(es2panda_AstNode *ast) +{ + auto *node = reinterpret_cast(ast)->AsClassDefinition(); + return reinterpret_cast(node->TypeParams()); +} + +extern "C" es2panda_AstNode *ClassDefinitionSuperClass(es2panda_AstNode *ast) +{ + auto *node = reinterpret_cast(ast)->AsClassDefinition(); + return reinterpret_cast(node->Super()); +} + +extern "C" es2panda_AstNode **ClassDefinitionImplements(es2panda_AstNode *ast, size_t *size_p) +{ + auto *node = reinterpret_cast(ast)->AsClassDefinition(); + auto &impl_vec = node->Implements(); + *size_p = impl_vec.size(); + return reinterpret_cast(impl_vec.data()); +} + +extern "C" es2panda_AstNode *ClassDefinitionConstructor(es2panda_AstNode *ast) +{ + auto *node = reinterpret_cast(ast)->AsClassDefinition(); + return reinterpret_cast(node->Ctor()); +} + +extern "C" es2panda_AstNode **ClassDefinitionBody(es2panda_AstNode *ast, size_t *size_p) +{ + auto *node = reinterpret_cast(ast)->AsClassDefinition(); + auto &body_vec = node->Body(); + *size_p = body_vec.size(); + return reinterpret_cast(body_vec.data()); +} + +extern "C" void ClassDefinitionSetIdentifier(es2panda_AstNode *ast, es2panda_AstNode *identifier) +{ + auto *node = reinterpret_cast(ast)->AsClassDefinition(); + auto *id = reinterpret_cast(identifier)->AsIdentifier(); + node->SetIdent(id); +} + +extern "C" void ClassDefinitionSetTypeParameters(es2panda_AstNode *ast, es2panda_AstNode *type_params) +{ + auto *node = reinterpret_cast(ast)->AsClassDefinition(); + auto *tpd = reinterpret_cast(type_params)->AsTSTypeParameterDeclaration(); + node->SetTypeParams(tpd); +} - CreateConfig, DestroyConfig, +extern "C" void ClassDefinitionSetSuperClass(es2panda_AstNode *ast, es2panda_AstNode *super_class) +{ + auto *node = reinterpret_cast(ast)->AsClassDefinition(); + auto *super = reinterpret_cast(super_class)->AsExpression(); + node->SetSuper(super); +} - CreateContextFromFile, CreateContextFromString, ProceedToState, DestroyContext, +extern "C" void ClassDefinitionSetImplements(es2panda_AstNode *ast, es2panda_AstNode **implements, size_t n_implements) +{ + auto *node = reinterpret_cast(ast)->AsClassDefinition(); + auto &impl_vec = node->Implements(); + impl_vec.resize(0); + for (size_t i = 0; i < n_implements; i++) { + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) + impl_vec.push_back(reinterpret_cast(implements[i])->AsTSClassImplements()); + } +} - ContextState, ContextErrorMessage}; +extern "C" void ClassDefinitionAddImplements(es2panda_AstNode *ast, es2panda_AstNode *implements) +{ + auto *node = reinterpret_cast(ast)->AsClassDefinition(); + auto &impl_vec = node->Implements(); + impl_vec.push_back(reinterpret_cast(implements)->AsTSClassImplements()); +} + +extern "C" void ClassDefinitionSetConstructor(es2panda_AstNode *ast, es2panda_AstNode *constructor) +{ + auto *node = reinterpret_cast(ast)->AsClassDefinition(); + auto *ctor = reinterpret_cast(constructor)->AsMethodDefinition(); + node->SetCtor(ctor); +} + +extern "C" void ClassDefinitionSetBody(es2panda_AstNode *ast, es2panda_AstNode **body, size_t n_elems) +{ + auto *node = reinterpret_cast(ast)->AsClassDefinition(); + auto &body_vec = node->Body(); + body_vec.resize(0); + for (size_t i = 0; i < n_elems; i++) { + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) + body_vec.push_back(reinterpret_cast(body[i])); + } +} + +extern "C" void ClassDefinitionAddToBody(es2panda_AstNode *ast, es2panda_AstNode *body_elem) +{ + auto *node = reinterpret_cast(ast)->AsClassDefinition(); + auto *elem = reinterpret_cast(body_elem); + auto &body_vec = node->Body(); + body_vec.push_back(reinterpret_cast(elem)); +} + +extern "C" es2panda_AstNode *ClassElementKey(es2panda_AstNode *ast) +{ + auto *node = reinterpret_cast(ast)->AsClassElement(); + return reinterpret_cast(node->Key()); +} + +extern "C" es2panda_AstNode *ClassElementValue(es2panda_AstNode *ast) +{ + auto *node = reinterpret_cast(ast)->AsClassElement(); + return reinterpret_cast(node->Value()); +} + +extern "C" es2panda_AstNode *CreateClassImplementsClause(es2panda_Context *context, es2panda_AstNode *expression, + es2panda_AstNode *type_arguments) +{ + auto *ctx = reinterpret_cast(context); + auto *allocator = ctx->allocator; + auto *expr = reinterpret_cast(expression)->AsExpression(); + auto *targs = type_arguments == nullptr + ? nullptr + : reinterpret_cast(type_arguments)->AsTSTypeParameterInstantiation(); + + return reinterpret_cast(allocator->New(expr, targs)); +} + +extern "C" es2panda_AstNode *ClassImplementsClauseExpression(es2panda_AstNode *ast) +{ + auto *node = reinterpret_cast(ast)->AsTSClassImplements(); + return reinterpret_cast(node->Expr()); +} + +extern "C" es2panda_AstNode const *ClassImplementsClauseTypeArguments(es2panda_AstNode *ast) +{ + auto *node = reinterpret_cast(ast)->AsTSClassImplements(); + return reinterpret_cast(node->TypeParameters()); +} + +extern "C" es2panda_AstNode *CreateClassProperty(es2panda_Context *context, es2panda_AstNode *key, + es2panda_AstNode *value, es2panda_AstNode *type_annotation, + es2panda_ModifierFlags modifier_flags, bool is_computed) +{ + auto *ctx = reinterpret_cast(context); + auto *allocator = ctx->allocator; + auto *ekey = reinterpret_cast(key)->AsExpression(); + auto *evalue = value == nullptr ? nullptr : reinterpret_cast(value)->AsExpression(); + auto *tp_ann = type_annotation == nullptr + ? nullptr + : reinterpret_cast(type_annotation)->AsExpression()->AsTypeNode(); + auto modifiers = E2pToIrModifierFlags(modifier_flags); + + return reinterpret_cast( + allocator->New(ekey, evalue, tp_ann, modifiers, allocator, is_computed)); +} + +extern "C" es2panda_AstNode *ClassPropertyTypeAnnotation(es2panda_AstNode *ast) +{ + auto *node = reinterpret_cast(ast)->AsClassProperty(); + return reinterpret_cast(node->TypeAnnotation()); +} + +extern "C" es2panda_AstNode *CreateExpressionStatement(es2panda_Context *context, es2panda_AstNode *expression) +{ + auto *ctx = reinterpret_cast(context); + auto *allocator = ctx->allocator; + auto *expr = reinterpret_cast(expression)->AsExpression(); + + return reinterpret_cast(allocator->New(expr)); +} + +extern "C" es2panda_AstNode *ExpressionStatementExpression(es2panda_AstNode *ast) +{ + auto *node = reinterpret_cast(ast)->AsExpressionStatement(); + return reinterpret_cast(node->GetExpression()); +} + +extern "C" es2panda_AstNode *CreateFunctionDeclaration(es2panda_Context *context, es2panda_AstNode *function) +{ + auto *ctx = reinterpret_cast(context); + auto *allocator = ctx->allocator; + auto *func = reinterpret_cast(function)->AsScriptFunction(); + + return reinterpret_cast(allocator->New(allocator, func)); +} + +extern "C" es2panda_AstNode *FunctionDeclarationFunction(es2panda_AstNode *ast) +{ + auto *node = reinterpret_cast(ast)->AsFunctionDeclaration(); + return reinterpret_cast(node->Function()); +} + +extern "C" es2panda_AstNode *CreateFunctionExpression(es2panda_Context *context, es2panda_AstNode *function) +{ + auto *ctx = reinterpret_cast(context); + auto *allocator = ctx->allocator; + auto *func = reinterpret_cast(function)->AsScriptFunction(); + + return reinterpret_cast(allocator->New(func)); +} + +extern "C" es2panda_AstNode *FunctionExpressionFunction(es2panda_AstNode *ast) +{ + auto *node = reinterpret_cast(ast)->AsFunctionExpression(); + return reinterpret_cast(node->Function()); +} + +extern "C" es2panda_AstNode *CreateFunctionTypeNode(es2panda_Context *context, es2panda_AstNode *in_scope_of, + es2panda_AstNode *type_params, es2panda_AstNode **params, + size_t n_params, es2panda_AstNode *return_type, + es2panda_ScriptFunctionFlags func_flags) +{ + auto *ctx = reinterpret_cast(context); + auto *allocator = ctx->allocator; + auto *parent = reinterpret_cast(in_scope_of); + auto *parent_scope = compiler::NearestScope(parent); + auto *tpar = + type_params == nullptr ? nullptr : reinterpret_cast(type_params)->AsTSTypeParameterDeclaration(); + auto *tret = + return_type == nullptr ? nullptr : reinterpret_cast(return_type)->AsExpression()->AsTypeNode(); + auto flags = E2pToIrScriptFunctionFlags(func_flags); + + auto *scope = allocator->New(allocator, parent_scope); + + ArenaVector par {allocator->Adapter()}; + for (size_t i = 0; i < n_params; i++) { + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) + par.push_back(reinterpret_cast(params[i])->AsExpression()); + } + + return reinterpret_cast( + allocator->New(scope, std::move(par), tpar, tret, flags)); +} + +extern "C" es2panda_AstNode const *FunctionTypeNodeTypeParams(es2panda_AstNode *ast) +{ + auto *node = reinterpret_cast(ast)->AsETSFunctionType(); + return reinterpret_cast(node->TypeParams()); +} + +extern "C" es2panda_AstNode *const *FunctionTypeNodeParams(es2panda_AstNode *ast, size_t *size_p) +{ + auto *node = reinterpret_cast(ast)->AsETSFunctionType(); + auto ¶ms = node->Params(); + *size_p = params.size(); + return reinterpret_cast(params.data()); +} + +extern "C" es2panda_AstNode *FunctionTypeNodeReturnType(es2panda_AstNode *ast) +{ + auto *node = reinterpret_cast(ast)->AsETSFunctionType(); + return reinterpret_cast(node->ReturnType()); +} + +extern "C" es2panda_ScriptFunctionFlags FunctionTypeNodeFlags(es2panda_AstNode *ast) +{ + auto *node = reinterpret_cast(ast)->AsETSFunctionType(); + return IrToE2pScriptFunctionFlags(node->Flags()); +} + +extern "C" es2panda_AstNode *CreateIdentifier(es2panda_Context *context, char const *name, + es2panda_AstNode *type_annotations) +{ + auto *ctx = reinterpret_cast(context); + auto *allocator = ctx->allocator; + auto *name_copy = ArenaStrdup(ctx->allocator, name); + auto *tp_ann = type_annotations == nullptr + ? nullptr + : reinterpret_cast(type_annotations)->AsExpression()->AsTypeNode(); + + auto *res = allocator->New(util::StringView {name_copy}, tp_ann, allocator); + + return reinterpret_cast(res); +} + +extern "C" char const *IdentifierName(es2panda_Context *context, es2panda_AstNode *identifier) +{ + auto *ctx = reinterpret_cast(context); + auto *id = reinterpret_cast(identifier); + ASSERT(id->IsIdentifier()); + + return StringViewToCString(ctx->allocator, id->AsIdentifier()->Name()); +} + +extern "C" es2panda_AstNode *IdentifierTypeAnnotation(es2panda_AstNode *identifier) +{ + auto *id = reinterpret_cast(identifier)->AsIdentifier(); + return reinterpret_cast(id->TypeAnnotation()); +} + +extern "C" es2panda_Variable *IdentifierVariable(es2panda_AstNode *identifier) +{ + auto *id = reinterpret_cast(identifier)->AsIdentifier(); + + return reinterpret_cast(id->Variable()); +} + +extern "C" void IdentifierSetVariable(es2panda_AstNode *identifier, es2panda_Variable *variable) +{ + auto *id = reinterpret_cast(identifier)->AsIdentifier(); + auto *var = reinterpret_cast(variable); + + id->SetVariable(var); +} + +extern "C" es2panda_AstNode *CreateIfStatement(es2panda_Context *context, es2panda_AstNode *test, + es2panda_AstNode *consequent, es2panda_AstNode *alternate) +{ + auto *ctx = reinterpret_cast(context); + auto *allocator = ctx->allocator; + auto *t = reinterpret_cast(test)->AsExpression(); + auto *conseq = reinterpret_cast(consequent)->AsStatement(); + auto *alt = reinterpret_cast(alternate)->AsStatement(); + + return reinterpret_cast(allocator->New(t, conseq, alt)); +} + +extern "C" es2panda_AstNode const *IfStatementTest(es2panda_AstNode *identifier) +{ + auto *if_stat = reinterpret_cast(identifier)->AsIfStatement(); + + return reinterpret_cast(if_stat->Test()); +} + +extern "C" es2panda_AstNode const *IfStatementConsequent(es2panda_AstNode *identifier) +{ + auto *if_stat = reinterpret_cast(identifier)->AsIfStatement(); + + return reinterpret_cast(if_stat->Consequent()); +} + +extern "C" es2panda_AstNode const *IfStatementAlternate(es2panda_AstNode *identifier) +{ + auto *if_stat = reinterpret_cast(identifier)->AsIfStatement(); + + return reinterpret_cast(if_stat->Alternate()); +} + +extern "C" es2panda_AstNode *CreateImportDeclaration(es2panda_Context *context, es2panda_AstNode *source, + es2panda_AstNode **specifiers, size_t n_specifiers) +{ + auto *ctx = reinterpret_cast(context); + auto *allocator = ctx->allocator; + auto *src = reinterpret_cast(source)->AsStringLiteral(); + + ArenaVector specs {allocator->Adapter()}; + for (size_t i = 0; i < n_specifiers; i++) { + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) + specs.push_back(reinterpret_cast(specifiers[i])); + } + + return reinterpret_cast(allocator->New(src, std::move(specs))); +} + +extern "C" es2panda_AstNode const *ImportDeclarationSource(es2panda_AstNode *ast) +{ + auto *decl = reinterpret_cast(ast)->AsImportDeclaration(); + + return reinterpret_cast(decl->Source()); +} + +extern "C" es2panda_AstNode *const *ImportDeclarationSpecifiers(es2panda_AstNode *ast, size_t *size_p) +{ + auto *decl = reinterpret_cast(ast)->AsImportDeclaration(); + auto &specs = decl->Specifiers(); + + *size_p = specs.size(); + + return reinterpret_cast(specs.data()); +} + +extern "C" es2panda_AstNode *CreateImportExpression(es2panda_Context *context, es2panda_AstNode *source) +{ + auto *ctx = reinterpret_cast(context); + auto *allocator = ctx->allocator; + auto *src = reinterpret_cast(source)->AsExpression(); + + return reinterpret_cast(allocator->New(src)); +} + +extern "C" es2panda_AstNode *ImportExpressionSource(es2panda_AstNode *ast) +{ + auto *node = reinterpret_cast(ast)->AsImportExpression(); + return reinterpret_cast(node->Source()); +} + +extern "C" es2panda_AstNode *CreateImportSpecifier(es2panda_Context *context, es2panda_AstNode *imported, + es2panda_AstNode *local) +{ + auto *ctx = reinterpret_cast(context); + auto *allocator = ctx->allocator; + auto *ir_imported = reinterpret_cast(imported)->AsIdentifier(); + auto *ir_local = reinterpret_cast(local)->AsIdentifier(); + + return reinterpret_cast(allocator->New(ir_imported, ir_local)); +} + +extern "C" es2panda_AstNode *ImportSpecifierImported(es2panda_AstNode *ast) +{ + auto *node = reinterpret_cast(ast)->AsImportSpecifier(); + return reinterpret_cast(node->Imported()); +} + +extern "C" es2panda_AstNode *ImportSpecifierLocal(es2panda_AstNode *ast) +{ + auto *node = reinterpret_cast(ast)->AsImportSpecifier(); + return reinterpret_cast(node->Local()); +} + +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define FOR_ALL_MEMBER_EXPRESSION_KINDS(_) \ + _(ELEMENT_ACCESS) \ + _(PROPERTY_ACCESS) \ + _(GETTER) \ + _(SETTER) + +static ir::MemberExpressionKind E2pToIrMemberExpressionKind(es2panda_MemberExpressionKind e2p_kind) +{ + ir::MemberExpressionKind ir_kind = ir::MemberExpressionKind::NONE; + +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define DO_KIND(K) \ + if ((e2p_kind & ES2PANDA_MEMBER_EXPRESSION_KIND_##K) != 0) { \ + ir_kind |= ir::MemberExpressionKind::K; \ + } + + FOR_ALL_MEMBER_EXPRESSION_KINDS(DO_KIND) + +#undef DO_KIND + + return ir_kind; +} + +static es2panda_MemberExpressionKind IrToE2pMemberExpressionKind(ir::MemberExpressionKind ir_kind) +{ + es2panda_MemberExpressionKind e2p_kind = ES2PANDA_MEMBER_EXPRESSION_KIND_NONE; + +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define DO_KIND(K) \ + if ((ir_kind & ir::MemberExpressionKind::K) != 0) { \ + e2p_kind = static_cast(e2p_kind | ES2PANDA_MEMBER_EXPRESSION_KIND_##K); \ + } + + FOR_ALL_MEMBER_EXPRESSION_KINDS(DO_KIND) + +#undef DO_KIND + + return e2p_kind; +} + +extern "C" es2panda_AstNode *CreateMemberExpression(es2panda_Context *context, es2panda_AstNode *object, + es2panda_AstNode *property, es2panda_MemberExpressionKind kind, + bool is_computed, bool is_optional) +{ + auto *ctx = reinterpret_cast(context); + auto *allocator = ctx->allocator; + auto ir_object = reinterpret_cast(object)->AsExpression(); + auto ir_property = reinterpret_cast(property)->AsExpression(); + auto ir_kind = E2pToIrMemberExpressionKind(kind); + + return reinterpret_cast( + allocator->New(ir_object, ir_property, ir_kind, is_computed, is_optional)); +} + +extern "C" es2panda_AstNode *MemberExpressionObject(es2panda_AstNode *ast) +{ + auto *node = reinterpret_cast(ast)->AsMemberExpression(); + return reinterpret_cast(node->Object()); +} + +extern "C" es2panda_AstNode *MemberExpressionProperty(es2panda_AstNode *ast) +{ + auto *node = reinterpret_cast(ast)->AsMemberExpression(); + return reinterpret_cast(node->Property()); +} + +extern "C" es2panda_MemberExpressionKind MemberExpressionKind(es2panda_AstNode *ast) +{ + auto *node = reinterpret_cast(ast)->AsMemberExpression(); + return IrToE2pMemberExpressionKind(node->Kind()); +} + +extern "C" bool MemberExpressionIsComputed(es2panda_AstNode *ast) +{ + auto *node = reinterpret_cast(ast)->AsMemberExpression(); + return node->IsComputed(); +} + +extern "C" bool MemberExpressionIsOptional(es2panda_AstNode *ast) +{ + auto *node = reinterpret_cast(ast)->AsMemberExpression(); + return node->IsOptional(); +} + +struct MethodDefinitionKindToStrStruct { + ir::MethodDefinitionKind kind; + char const *str; +}; + +static constexpr std::array METHOD_DEFINITION_KIND_TO_STR {{ + {ir::MethodDefinitionKind::CONSTRUCTOR, "constructor"}, + {ir::MethodDefinitionKind::METHOD, "method"}, + {ir::MethodDefinitionKind::EXTENSION_METHOD, "extension method"}, + {ir::MethodDefinitionKind::GET, "get"}, + {ir::MethodDefinitionKind::SET, "set"}, +}}; + +static ir::MethodDefinitionKind StrToMethodDefinitionKind(char const *str) +{ + for (auto &elem : METHOD_DEFINITION_KIND_TO_STR) { + if (strcmp(elem.str, str) == 0) { + return elem.kind; + } + } + return ir::MethodDefinitionKind::NONE; +} + +static char const *MethodDefinitionKindToStr(ir::MethodDefinitionKind kind) +{ + for (auto &elem : METHOD_DEFINITION_KIND_TO_STR) { + if (elem.kind == kind) { + return elem.str; + } + } + return "unknown"; +} + +extern "C" es2panda_AstNode *CreateMethodDefinition(es2panda_Context *context, char const *kind, es2panda_AstNode *key, + es2panda_AstNode *value, es2panda_ModifierFlags modifiers, + bool is_computed) +{ + auto *ctx = reinterpret_cast(context); + auto *allocator = ctx->allocator; + auto ir_kind = StrToMethodDefinitionKind(kind); + auto *ir_key = reinterpret_cast(key)->AsExpression(); + auto *ir_value = reinterpret_cast(value)->AsExpression(); + auto ir_flags = E2pToIrModifierFlags(modifiers); + + return reinterpret_cast( + allocator->New(ir_kind, ir_key, ir_value, ir_flags, allocator, is_computed)); +} + +extern "C" char const *MethodDefinitionKind(es2panda_AstNode *ast) +{ + auto *node = reinterpret_cast(ast)->AsMethodDefinition(); + return MethodDefinitionKindToStr(node->Kind()); +} + +extern "C" es2panda_AstNode const *MethodDefinitionKey(es2panda_AstNode *ast) +{ + auto *node = reinterpret_cast(ast)->AsMethodDefinition(); + return reinterpret_cast(node->Key()); +} + +extern "C" es2panda_AstNode const *MethodDefinitionValue(es2panda_AstNode *ast) +{ + auto *node = reinterpret_cast(ast)->AsMethodDefinition(); + return reinterpret_cast(node->Value()); +} + +extern "C" es2panda_ModifierFlags MethodDefinitionModifiers(es2panda_AstNode *ast) +{ + auto *node = reinterpret_cast(ast)->AsMethodDefinition(); + return IrToE2pModifierFlags(node->Modifiers()); +} + +extern "C" bool MethodDefinitionIsComputed(es2panda_AstNode *ast) +{ + auto *node = reinterpret_cast(ast)->AsMethodDefinition(); + return node->IsComputed(); +} + +extern "C" es2panda_AstNode *const *MethodDefinitionOverloads(es2panda_AstNode *ast, size_t *size_p) +{ + auto *node = reinterpret_cast(ast)->AsMethodDefinition(); + auto const &overloads = node->Overloads(); + *size_p = overloads.size(); + return reinterpret_cast(overloads.data()); +} + +extern "C" void MethodDefinitionSetOverloads(es2panda_AstNode *ast, es2panda_AstNode **overloads, size_t n_overloads) +{ + auto *node = reinterpret_cast(ast)->AsMethodDefinition(); + ArenaVector ir_overloads {node->Overloads().get_allocator()}; + ir_overloads.reserve(n_overloads); + for (size_t i = 0; i < n_overloads; i++) { + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) + ir_overloads.push_back(reinterpret_cast(overloads[i])->AsMethodDefinition()); + } + node->SetOverloads(std::move(ir_overloads)); +} + +extern "C" void MethodDefinitionAddOverload(es2panda_AstNode *ast, es2panda_AstNode *overload) +{ + auto *node = reinterpret_cast(ast)->AsMethodDefinition(); + auto *ir_overload = reinterpret_cast(overload)->AsMethodDefinition(); + node->AddOverload(ir_overload); +} + +extern "C" es2panda_AstNode *CreateNewClassInstanceExpression(es2panda_Context *context, + es2panda_AstNode *type_reference, + es2panda_AstNode **arguments, size_t n_arguments, + es2panda_AstNode *class_definition) +{ + auto *ctx = reinterpret_cast(context); + auto *allocator = ctx->allocator; + auto *ir_typeref = reinterpret_cast(type_reference)->AsExpression(); + + ArenaVector args {allocator->Adapter()}; + for (size_t i = 0; i < n_arguments; i++) { + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) + args.push_back(reinterpret_cast(arguments[i])->AsExpression()); + } + + auto *ir_classdef = + class_definition == nullptr ? nullptr : reinterpret_cast(class_definition)->AsClassDefinition(); + + return reinterpret_cast( + allocator->New(ir_typeref, std::move(args), ir_classdef)); +} + +extern "C" es2panda_AstNode *NewClassInstanceExpressionTypeReference(es2panda_AstNode *ast) +{ + auto *node = reinterpret_cast(ast)->AsETSNewClassInstanceExpression(); + return reinterpret_cast(node->GetTypeRef()); +} + +extern "C" es2panda_AstNode *const *NewClassInstanceExpressionArguments(es2panda_AstNode *ast, size_t *size_p) +{ + auto *node = reinterpret_cast(ast)->AsETSNewClassInstanceExpression(); + auto const &args = node->GetArguments(); + + *size_p = args.size(); + return reinterpret_cast(args.data()); +} + +extern "C" es2panda_AstNode *NewClassInstanceExpressionClassDefinition(es2panda_AstNode *ast) +{ + auto *node = reinterpret_cast(ast)->AsETSNewClassInstanceExpression(); + return reinterpret_cast(node->ClassDefinition()); +} + +extern "C" es2panda_AstNode *CreateNewArrayInstanceExpression(es2panda_Context *context, + es2panda_AstNode *type_reference, + es2panda_AstNode *dimension) +{ + auto *ctx = reinterpret_cast(context); + auto *allocator = ctx->allocator; + auto *ir_typeref = reinterpret_cast(type_reference)->AsExpression()->AsTypeNode(); + auto *ir_dim = reinterpret_cast(dimension)->AsExpression(); + + return reinterpret_cast(allocator->New(ir_typeref, ir_dim)); +} + +extern "C" es2panda_AstNode *NewArrayInstanceExpressionTypeReference(es2panda_AstNode *ast) +{ + auto *node = reinterpret_cast(ast)->AsETSNewArrayInstanceExpression(); + return reinterpret_cast(node->TypeReference()); +} + +extern "C" es2panda_AstNode *NewArrayInstanceExpressionDimension(es2panda_AstNode *ast) +{ + auto *node = reinterpret_cast(ast)->AsETSNewArrayInstanceExpression(); + return reinterpret_cast(node->Dimension()); +} + +extern "C" es2panda_AstNode *CreateNewMultiDimArrayInstanceExpression(es2panda_Context *context, + es2panda_AstNode *type_reference, + es2panda_AstNode **dimensions, + size_t n_dimensions) +{ + auto *ctx = reinterpret_cast(context); + auto *allocator = ctx->allocator; + auto *ir_typeref = reinterpret_cast(type_reference)->AsExpression()->AsTypeNode(); + + ArenaVector ir_dims {allocator->Adapter()}; + for (size_t i = 0; i < n_dimensions; i++) { + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) + ir_dims.push_back(reinterpret_cast(dimensions[i])->AsExpression()); + } + + return reinterpret_cast( + allocator->New(ir_typeref, std::move(ir_dims))); +} + +extern "C" es2panda_AstNode *NewMultiDimArrayInstanceExpressionTypeReference(es2panda_AstNode *ast) +{ + auto *node = reinterpret_cast(ast)->AsETSNewMultiDimArrayInstanceExpression(); + return reinterpret_cast(node->TypeReference()); +} + +extern "C" es2panda_AstNode *const *NewMultiDimArrayInstanceExpressionDimensions(es2panda_AstNode *ast, size_t *size_p) +{ + auto *node = reinterpret_cast(ast)->AsETSNewMultiDimArrayInstanceExpression(); + auto const &dims = node->Dimensions(); + + *size_p = dims.size(); + return reinterpret_cast(dims.data()); +} + +extern "C" es2panda_AstNode *CreateParameterDeclaration(es2panda_Context *context, + es2panda_AstNode *identifier_or_spread, + es2panda_AstNode *initializer) +{ + auto *ctx = reinterpret_cast(context); + auto *allocator = ctx->allocator; + + auto *ir_ident_or_spread_raw = reinterpret_cast(identifier_or_spread)->AsExpression(); + ir::AnnotatedExpression *ir_ident_or_spread; + if (ir_ident_or_spread_raw->IsIdentifier()) { + ir_ident_or_spread = ir_ident_or_spread_raw->AsIdentifier(); + } else if (ir_ident_or_spread_raw->IsSpreadElement()) { + ir_ident_or_spread = ir_ident_or_spread_raw->AsSpreadElement(); + } else { + UNREACHABLE(); + } + + auto *ir_initializer = + initializer == nullptr ? nullptr : reinterpret_cast(initializer)->AsExpression(); + + return reinterpret_cast( + allocator->New(ir_ident_or_spread, ir_initializer)); +} + +extern "C" es2panda_AstNode *ParameterDeclarationIdentifierOrSpread(es2panda_AstNode *ast) +{ + auto *node = reinterpret_cast(ast)->AsETSParameterExpression(); + + ir::AstNode *res; + if (node->IsRestParameter()) { + res = node->RestParameter(); + } else { + res = node->Ident(); + } + return reinterpret_cast(res); +} + +extern "C" es2panda_AstNode *ParameterDeclarationInitializer(es2panda_AstNode *ast) +{ + auto *node = reinterpret_cast(ast)->AsETSParameterExpression(); + return reinterpret_cast(node->Initializer()); +} + +struct PrimitiveTypeToStrStruct { + ir::PrimitiveType type; + char const *str; +}; + +static constexpr std::array PRIMITIVE_TYPE_TO_STR {{ + {ir::PrimitiveType::BYTE, "byte"}, + {ir::PrimitiveType::INT, "int"}, + {ir::PrimitiveType::LONG, "long"}, + {ir::PrimitiveType::SHORT, "short"}, + {ir::PrimitiveType::FLOAT, "float"}, + {ir::PrimitiveType::DOUBLE, "double"}, + {ir::PrimitiveType::BOOLEAN, "boolean"}, + {ir::PrimitiveType::CHAR, "char"}, + {ir::PrimitiveType::VOID, "void"}, +}}; + +static ir::PrimitiveType StrToPrimitiveType(char const *str) +{ + for (auto &elem : PRIMITIVE_TYPE_TO_STR) { + if (strcmp(elem.str, str) == 0) { + return elem.type; + } + } + return ir::PrimitiveType::VOID; +} + +static char const *PrimitiveTypeToStr(ir::PrimitiveType type) +{ + for (auto &elem : PRIMITIVE_TYPE_TO_STR) { + if (elem.type == type) { + return elem.str; + } + } + return "unknown"; +} + +extern "C" es2panda_AstNode *CreatePrimitiveTypeNode(es2panda_Context *context, char const *type) +{ + auto *ctx = reinterpret_cast(context); + auto *allocator = ctx->allocator; + auto tp = StrToPrimitiveType(type); + + return reinterpret_cast(allocator->New(tp)); +} + +extern "C" char const *PrimitiveTypeNodeType(es2panda_AstNode *ast) +{ + auto *node = reinterpret_cast(ast)->AsETSPrimitiveType(); + return PrimitiveTypeToStr(node->GetPrimitiveType()); +} + +extern "C" es2panda_AstNode *CreateReturnStatement(es2panda_Context *context, es2panda_AstNode *argument) +{ + auto *ctx = reinterpret_cast(context); + auto *allocator = ctx->allocator; + auto *ir_arg = argument == nullptr ? nullptr : reinterpret_cast(argument)->AsExpression(); + + return reinterpret_cast(allocator->New(ir_arg)); +} + +extern "C" es2panda_AstNode *ReturnStatementArgument(es2panda_AstNode *ast) +{ + auto *node = reinterpret_cast(ast)->AsReturnStatement(); + return reinterpret_cast(node->Argument()); +} + +extern "C" es2panda_Type *ReturnStatementReturnType(es2panda_AstNode *ast) +{ + auto *node = reinterpret_cast(ast)->AsReturnStatement(); + return reinterpret_cast(node->ReturnType()); +} + +extern "C" es2panda_AstNode *CreateScriptFunction(es2panda_Context *context, es2panda_AstNode *type_params, + es2panda_AstNode **params, size_t n_params, + es2panda_AstNode *return_type_annotation, + es2panda_ScriptFunctionFlags function_flags, + es2panda_ModifierFlags modifier_flags, bool is_declare, + es2panda_AstNode *in_scope_of) +{ + auto *ctx = reinterpret_cast(context); + auto *allocator = ctx->allocator; + auto *ir_type_params = + type_params == nullptr ? nullptr : reinterpret_cast(type_params)->AsTSTypeParameterDeclaration(); + + // NOTE(gogabr): without explicit reference to scope, scopes within params will be broken + ArenaVector ir_params {allocator->Adapter()}; + for (size_t i = 0; i < n_params; i++) { + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) + ir_params.push_back(reinterpret_cast(params[i])->AsExpression()); + } + + auto ir_return_type_annotation = + return_type_annotation == nullptr + ? nullptr + : reinterpret_cast(return_type_annotation)->AsExpression()->AsTypeNode(); + auto ir_function_flags = E2pToIrScriptFunctionFlags(function_flags); + auto ir_modifier_flags = E2pToIrModifierFlags(modifier_flags); + + auto *outer_scope = ir_type_params == nullptr ? compiler::NearestScope(reinterpret_cast(in_scope_of)) + : ir_type_params->Scope(); + auto *parameter_scope = allocator->New(allocator, outer_scope); + auto *body_scope = allocator->New(allocator, parameter_scope); + parameter_scope->BindFunctionScope(body_scope); + body_scope->BindParamScope(parameter_scope); + + return reinterpret_cast(allocator->New( + body_scope, std::move(ir_params), ir_type_params, nullptr, ir_return_type_annotation, ir_function_flags, + ir_modifier_flags, is_declare, Language::FromString("ets").value())); +} + +extern "C" es2panda_AstNode *ScriptFunctionTypeParams(es2panda_AstNode *ast) +{ + auto *node = reinterpret_cast(ast)->AsScriptFunction(); + return reinterpret_cast(node->TypeParams()); +} + +extern "C" es2panda_AstNode *const *ScriptFunctionParams(es2panda_AstNode *ast, size_t *size_p) +{ + auto *node = reinterpret_cast(ast)->AsScriptFunction(); + auto ¶ms = node->Params(); + + *size_p = params.size(); + return reinterpret_cast(params.data()); +} + +extern "C" es2panda_AstNode *ScriptFunctionReturnTypeAnnotation(es2panda_AstNode *ast) +{ + auto *node = reinterpret_cast(ast)->AsScriptFunction(); + return reinterpret_cast(node->ReturnTypeAnnotation()); +} + +extern "C" es2panda_ScriptFunctionFlags ScriptFunctionScriptFunctionFlags(es2panda_AstNode *ast) +{ + auto *node = reinterpret_cast(ast)->AsScriptFunction(); + return IrToE2pScriptFunctionFlags(node->Flags()); +} + +extern "C" bool ScriptFunctionIsDeclare(es2panda_AstNode *ast) +{ + auto *node = reinterpret_cast(ast)->AsScriptFunction(); + return node->Declare(); +} + +extern "C" es2panda_AstNode *ScriptFunctionIdentifier(es2panda_AstNode *ast) +{ + auto *node = reinterpret_cast(ast)->AsScriptFunction(); + return reinterpret_cast(node->Id()); +} + +extern "C" es2panda_AstNode *ScriptFunctionBody(es2panda_AstNode *ast) +{ + auto *node = reinterpret_cast(ast)->AsScriptFunction(); + return reinterpret_cast(node->Body()); +} + +extern "C" void ScriptFunctionSetIdentifier(es2panda_AstNode *ast, es2panda_AstNode *identifier) +{ + auto *node = reinterpret_cast(ast)->AsScriptFunction(); + auto *id = reinterpret_cast(identifier)->AsIdentifier(); + + node->SetIdent(id); +} + +extern "C" void ScriptFunctionSetBody(es2panda_AstNode *ast, es2panda_AstNode *body) +{ + auto *node = reinterpret_cast(ast)->AsScriptFunction(); + auto *ir_body = reinterpret_cast(body); + + node->SetBody(ir_body); +} + +extern "C" void ScriptFunctionSetParams(es2panda_AstNode *ast, es2panda_AstNode **params, size_t n_params) +{ + auto *node = reinterpret_cast(ast)->AsScriptFunction(); + auto &ir_params = node->Params(); + + ir_params.clear(); + for (size_t i = 0; i < n_params; i++) { + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) + ir_params.push_back(reinterpret_cast(params[i])->AsExpression()); + } +} + +extern "C" void ScripFunctionAddParam(es2panda_AstNode *ast, es2panda_AstNode *param) +{ + auto *node = reinterpret_cast(ast)->AsScriptFunction(); + auto *ir_param = reinterpret_cast(param)->AsExpression(); + + node->Params().push_back(ir_param); +} + +extern "C" es2panda_AstNode *CreateStringLiteral(es2panda_Context *context, char const *string) +{ + auto *ctx = reinterpret_cast(context); + auto *allocator = ctx->allocator; + auto *str = ArenaStrdup(allocator, string); + + return reinterpret_cast(allocator->New(str)); +} + +extern "C" char const *StringLiteralString(es2panda_Context *context, es2panda_AstNode *ast) +{ + auto *ctx = reinterpret_cast(context); + auto *allocator = ctx->allocator; + auto *node = reinterpret_cast(ast)->AsStringLiteral(); + return StringViewToCString(allocator, node->Str()); +} + +extern "C" es2panda_AstNode *CreateThisExpression(es2panda_Context *context) +{ + auto *ctx = reinterpret_cast(context); + auto *allocator = ctx->allocator; + + return reinterpret_cast(allocator->New()); +} + +extern "C" es2panda_AstNode *CreateTypeParameter(es2panda_Context *context, es2panda_AstNode *name, + es2panda_AstNode *constraint, es2panda_AstNode *default_type) +{ + auto *ctx = reinterpret_cast(context); + auto *allocator = ctx->allocator; + auto *nm = reinterpret_cast(name)->AsIdentifier(); + auto *constr = + constraint == nullptr ? nullptr : reinterpret_cast(constraint)->AsExpression()->AsTypeNode(); + auto *dflt = + default_type == nullptr ? nullptr : reinterpret_cast(default_type)->AsExpression()->AsTypeNode(); + + return reinterpret_cast(allocator->New(nm, constr, dflt)); +} + +extern "C" es2panda_AstNode const *TypeParameterName(es2panda_AstNode *ast) +{ + auto *tp = reinterpret_cast(ast)->AsTSTypeParameter(); + return reinterpret_cast(tp->Name()); +} + +extern "C" es2panda_AstNode const *TypeParameterConstraint(es2panda_AstNode *ast) +{ + auto *tp = reinterpret_cast(ast)->AsTSTypeParameter(); + return reinterpret_cast(tp->Constraint()); +} + +extern "C" es2panda_AstNode const *TypeParameterDefaultType(es2panda_AstNode *ast) +{ + auto *tp = reinterpret_cast(ast)->AsTSTypeParameter(); + return reinterpret_cast(tp->DefaultType()); +} + +extern "C" es2panda_AstNode *CreateTypeParameterDeclaration(es2panda_Context *context, es2panda_AstNode *in_scope_of) +{ + auto *ctx = reinterpret_cast(context); + auto *allocator = ctx->allocator; + auto *parent = reinterpret_cast(in_scope_of); + auto *parent_scope = compiler::NearestScope(parent); + + auto *scope = allocator->New(allocator, parent_scope); + ArenaVector params {allocator->Adapter()}; + return reinterpret_cast( + allocator->New(scope, std::move(params), 0)); +} + +extern "C" void TypeParameterDeclarationAddTypeParameter(es2panda_AstNode *ast, es2panda_AstNode *type_parameter) +{ + auto *tpd = reinterpret_cast(ast)->AsTSTypeParameterDeclaration(); + auto *param = reinterpret_cast(type_parameter)->AsTSTypeParameter(); + + tpd->AddParam(param); +} + +extern "C" es2panda_AstNode *const *TypeParameterDeclarationTypeParameters(es2panda_AstNode *ast, size_t *size_p) +{ + auto *tpd = reinterpret_cast(ast)->AsTSTypeParameterDeclaration(); + auto const ¶ms = tpd->Params(); + *size_p = params.size(); + return reinterpret_cast(params.data()); +} + +extern "C" es2panda_AstNode *CreateTypeParameterInstantiation(es2panda_Context *context, + es2panda_AstNode **type_parameters, size_t n_params) +{ + auto *ctx = reinterpret_cast(context); + auto *allocator = ctx->allocator; + + ArenaVector params {allocator->Adapter()}; + for (size_t i = 0; i < n_params; i++) { + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) + params.push_back(reinterpret_cast(type_parameters[i])->AsExpression()->AsTypeNode()); + } + return reinterpret_cast(allocator->New(std::move(params))); +} + +extern "C" es2panda_AstNode *const *TypeParameterInstantiationTypeParameters(es2panda_AstNode *ast, size_t *size_p) +{ + auto *tpi = reinterpret_cast(ast)->AsTSTypeParameterInstantiation(); + auto const ¶ms = tpi->Params(); + *size_p = params.size(); + return reinterpret_cast(params.data()); +} + +extern "C" es2panda_AstNode *CreateTypeReferenceNode(es2panda_Context *context, es2panda_AstNode *part) +{ + auto *ctx = reinterpret_cast(context); + auto *allocator = ctx->allocator; + auto *ir_part = reinterpret_cast(part)->AsETSTypeReferencePart(); + + return reinterpret_cast(allocator->New(ir_part)); +} + +extern "C" es2panda_AstNode *TypeReferenceNodePart(es2panda_AstNode *ast) +{ + auto *node = reinterpret_cast(ast)->AsETSTypeReference(); + return reinterpret_cast(node->Part()); +} + +extern "C" es2panda_AstNode *CreateTypeReferencePart(es2panda_Context *context, es2panda_AstNode *name, + es2panda_AstNode *type_arguments, es2panda_AstNode *previous) +{ + auto *ctx = reinterpret_cast(context); + auto *allocator = ctx->allocator; + auto *ir_name = reinterpret_cast(name)->AsExpression(); + auto *ir_type_args = type_arguments == nullptr + ? nullptr + : reinterpret_cast(type_arguments)->AsTSTypeParameterInstantiation(); + auto *ir_prev = previous == nullptr ? nullptr : reinterpret_cast(previous)->AsETSTypeReferencePart(); + + return reinterpret_cast( + allocator->New(ir_name, ir_type_args, ir_prev)); +} + +extern "C" es2panda_AstNode *TypeReferencePartName(es2panda_AstNode *ast) +{ + auto *node = reinterpret_cast(ast)->AsETSTypeReferencePart(); + return reinterpret_cast(node->Name()); +} + +extern "C" es2panda_AstNode *TypeReferencePartTypeArguments(es2panda_AstNode *ast) +{ + auto *node = reinterpret_cast(ast)->AsETSTypeReferencePart(); + return reinterpret_cast(node->TypeParams()); +} + +extern "C" es2panda_AstNode *TypeReferencePartPrevious(es2panda_AstNode *ast) +{ + auto *node = reinterpret_cast(ast)->AsETSTypeReferencePart(); + return reinterpret_cast(node->Previous()); +} + +extern "C" es2panda_AstNode *CreateUnionTypeNode(es2panda_Context *context, es2panda_AstNode **types, size_t n_types) +{ + auto *ctx = reinterpret_cast(context); + auto *allocator = ctx->allocator; + + ArenaVector ir_types {allocator->Adapter()}; + for (size_t i = 0; i < n_types; i++) { + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) + ir_types.push_back(reinterpret_cast(types[i])->AsExpression()->AsTypeNode()); + } + + return reinterpret_cast(allocator->New(std::move(ir_types))); +} + +extern "C" es2panda_AstNode *const *UnionTypeNodeTypes(es2panda_AstNode *ast, size_t *size_p) +{ + auto *node = reinterpret_cast(ast)->AsTSUnionType(); + auto &ir_types = node->Types(); + + *size_p = ir_types.size(); + return reinterpret_cast(ir_types.data()); +} + +struct VariableDeclarationKindToStrStruct { + ir::VariableDeclaration::VariableDeclarationKind kind; + char const *str; +}; + +static constexpr std::array VARIABLE_DECLARATION_KIND_TO_STR {{ + {ir::VariableDeclaration::VariableDeclarationKind::CONST, "const"}, + {ir::VariableDeclaration::VariableDeclarationKind::LET, "let"}, + {ir::VariableDeclaration::VariableDeclarationKind::VAR, "var"}, +}}; + +static ir::VariableDeclaration::VariableDeclarationKind StrToVariableDeclarationKind(char const *str) +{ + for (auto &elem : VARIABLE_DECLARATION_KIND_TO_STR) { + if (strcmp(elem.str, str) == 0) { + return elem.kind; + } + } + + // NOTE(gogabr): handle errors + UNREACHABLE(); +} + +static char const *VariableDeclarationKindToStr(ir::VariableDeclaration::VariableDeclarationKind kind) +{ + for (auto &elem : VARIABLE_DECLARATION_KIND_TO_STR) { + if (elem.kind == kind) { + return elem.str; + } + } + return "unknown"; +} + +extern "C" es2panda_AstNode *CreateVariableDeclaration(es2panda_Context *context, char const *kind, + es2panda_AstNode **declarators, size_t n_declarators, + bool is_declare) +{ + auto *ctx = reinterpret_cast(context); + auto *allocator = ctx->allocator; + auto ir_kind = StrToVariableDeclarationKind(kind); + + ArenaVector ir_declarators {allocator->Adapter()}; + for (size_t i = 0; i < n_declarators; i++) { + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) + ir_declarators.push_back(reinterpret_cast(declarators[i])->AsVariableDeclarator()); + } + + return reinterpret_cast( + allocator->New(ir_kind, allocator, std::move(ir_declarators), is_declare)); +} + +extern "C" char const *VariableDeclarationKind(es2panda_AstNode *ast) +{ + auto *node = reinterpret_cast(ast)->AsVariableDeclaration(); + return VariableDeclarationKindToStr(node->Kind()); +} + +extern "C" es2panda_AstNode *const *VariableDeclarationDeclarators(es2panda_AstNode *ast, size_t *size_p) +{ + auto *node = reinterpret_cast(ast)->AsVariableDeclaration(); + auto const &declarators = node->Declarators(); + *size_p = declarators.size(); + return reinterpret_cast(declarators.data()); +} + +extern "C" bool VariableDeclarationIsDeclare(es2panda_AstNode *ast) +{ + auto *node = reinterpret_cast(ast)->AsVariableDeclaration(); + return node->Declare(); +} + +extern "C" es2panda_AstNode *CreateVariableDeclarator(es2panda_Context *context, es2panda_AstNode *identifier, + es2panda_AstNode *initializer) +{ + auto *ctx = reinterpret_cast(context); + auto *allocator = ctx->allocator; + auto *ident = reinterpret_cast(identifier)->AsExpression(); + auto *init = initializer == nullptr ? nullptr : reinterpret_cast(initializer)->AsExpression(); + + return reinterpret_cast(allocator->New(ident, init)); +} + +extern "C" es2panda_AstNode *VariableDeclaratorIdentifier(es2panda_AstNode *ast) +{ + auto *node = reinterpret_cast(ast)->AsVariableDeclarator(); + return reinterpret_cast(node->Id()); +} + +extern "C" es2panda_AstNode *VariableDeclaratorInitializer(es2panda_AstNode *ast) +{ + auto *node = reinterpret_cast(ast)->AsVariableDeclarator(); + return reinterpret_cast(node->Init()); +} + +es2panda_Impl IMPL = { + ES2PANDA_LIB_VERSION, + + CreateConfig, + DestroyConfig, + + CreateContextFromFile, + CreateContextFromString, + ProceedToState, + DestroyContext, + + ContextState, + ContextErrorMessage, + + ContextProgram, + ProgramAst, + ProgramExternalSources, + ExternalSourceName, + ExternalSourcePrograms, + + AstNodeType, + AstNodeSetType, + + AstNodeDecorators, + AstNodeSetDecorators, + + AstNodeModifierFlags, + + AstNodeForEach, + + IsArrowFunctionExpression, + CreateArrowFunctionExpression, + ArrowFunctionExpressionScriptFunction, + + IsAsExpression, + CreateAsExpression, + AsExpressionExpr, + AsExpressionTypeAnnotation, + AsExpressionIsConst, + AsExpressionSetExpr, + AsExpressionSetTypeAnnotation, + + IsAssignmentExpression, + CreateAssignmentExpression, + AssignmentExpressionLeft, + AssignmentExpressionRight, + AssignmentExpressionOperatorType, + AssignmentExpressionSetOperatorType, + + IsBinaryExpression, + CreateBinaryExpression, + BinaryExpressionLeft, + BinaryExpressionRight, + BinaryExpressionOperator, + BinaryExpressionSetOperator, + + IsBlockStatement, + CreateBlockStatement, + BlockStatementStatements, + BlockStatementAddStatement, + + IsCallExpression, + CreateCallExpression, + CallExpressionCallee, + CallExpressionTypeArguments, + CallExpressionArguments, + CallExpressionIsOptional, + CallExpressionSetTypeArguments, + + IsChainExpression, + CreateChainExpression, + ChainExpressionChild, + + IsClassDeclaration, + CreateClassDeclaration, + ClassDeclarationDefinition, + + IsClassDefinition, + CreateClassDefinition, + ClassDefinitionIdentifier, + ClassDefinitionTypeParameters, + ClassDefinitionSuperClass, + ClassDefinitionImplements, + ClassDefinitionConstructor, + ClassDefinitionBody, + ClassDefinitionSetIdentifier, + ClassDefinitionSetTypeParameters, + ClassDefinitionSetSuperClass, + ClassDefinitionSetImplements, + ClassDefinitionAddImplements, + ClassDefinitionSetConstructor, + ClassDefinitionSetBody, + ClassDefinitionAddToBody, + + ClassElementKey, + ClassElementValue, + + IsClassImplementsClause, + CreateClassImplementsClause, + ClassImplementsClauseExpression, + ClassImplementsClauseTypeArguments, + + IsClassProperty, + CreateClassProperty, + ClassPropertyTypeAnnotation, + + IsExpressionStatement, + CreateExpressionStatement, + ExpressionStatementExpression, + + IsFunctionDeclaration, + CreateFunctionDeclaration, + FunctionDeclarationFunction, + + IsFunctionExpression, + CreateFunctionExpression, + FunctionExpressionFunction, + + IsFunctionTypeNode, + CreateFunctionTypeNode, + FunctionTypeNodeTypeParams, + FunctionTypeNodeParams, + FunctionTypeNodeReturnType, + FunctionTypeNodeFlags, + + IsIdentifier, + CreateIdentifier, + IdentifierName, + IdentifierTypeAnnotation, + IdentifierVariable, + IdentifierSetVariable, + + IsIfStatement, + CreateIfStatement, + IfStatementTest, + IfStatementConsequent, + IfStatementAlternate, + + IsImportDeclaration, + CreateImportDeclaration, + ImportDeclarationSource, + ImportDeclarationSpecifiers, + + IsImportExpression, + CreateImportExpression, + ImportExpressionSource, + + IsImportSpecifier, + CreateImportSpecifier, + ImportSpecifierImported, + ImportSpecifierLocal, + + IsMemberExpression, + CreateMemberExpression, + MemberExpressionObject, + MemberExpressionProperty, + MemberExpressionKind, + MemberExpressionIsComputed, + MemberExpressionIsOptional, + + IsMethodDefinition, + CreateMethodDefinition, + MethodDefinitionKind, + MethodDefinitionKey, + MethodDefinitionValue, + MethodDefinitionModifiers, + MethodDefinitionIsComputed, + MethodDefinitionOverloads, + MethodDefinitionSetOverloads, + MethodDefinitionAddOverload, + + IsNewClassInstanceExpression, + CreateNewClassInstanceExpression, + NewClassInstanceExpressionTypeReference, + NewClassInstanceExpressionArguments, + NewClassInstanceExpressionClassDefinition, + + IsNewArrayInstanceExpression, + CreateNewArrayInstanceExpression, + NewArrayInstanceExpressionTypeReference, + NewArrayInstanceExpressionDimension, + + IsNewMultiDimArrayInstanceExpression, + CreateNewMultiDimArrayInstanceExpression, + NewMultiDimArrayInstanceExpressionTypeReference, + NewMultiDimArrayInstanceExpressionDimensions, + + IsNonNullExpression, + IsNumberLiteral, + IsObjectExpression, + + IsParameterDeclaration, + CreateParameterDeclaration, + ParameterDeclarationIdentifierOrSpread, + ParameterDeclarationInitializer, + + IsPrimitiveTypeNode, + CreatePrimitiveTypeNode, + PrimitiveTypeNodeType, + + IsReturnStatement, + CreateReturnStatement, + ReturnStatementArgument, + ReturnStatementReturnType, + + IsScriptFunction, + CreateScriptFunction, + ScriptFunctionTypeParams, + ScriptFunctionParams, + ScriptFunctionReturnTypeAnnotation, + ScriptFunctionScriptFunctionFlags, + ScriptFunctionIsDeclare, + ScriptFunctionIdentifier, + ScriptFunctionBody, + ScriptFunctionSetIdentifier, + ScriptFunctionSetBody, + ScriptFunctionSetParams, + ScripFunctionAddParam, + + IsStringLiteral, + CreateStringLiteral, + StringLiteralString, + + IsThisExpression, + CreateThisExpression, + + IsTypeParameter, + CreateTypeParameter, + TypeParameterName, + TypeParameterConstraint, + TypeParameterDefaultType, + + IsTypeParameterDeclaration, + CreateTypeParameterDeclaration, + TypeParameterDeclarationAddTypeParameter, + TypeParameterDeclarationTypeParameters, + + IsTypeParameterInstantiation, + CreateTypeParameterInstantiation, + TypeParameterInstantiationTypeParameters, + + IsTypeReferenceNode, + CreateTypeReferenceNode, + TypeReferenceNodePart, + + IsTypeReferencePart, + CreateTypeReferencePart, + TypeReferencePartName, + TypeReferencePartTypeArguments, + TypeReferencePartPrevious, + + IsUnionTypeNode, + CreateUnionTypeNode, + UnionTypeNodeTypes, + + IsVariableDeclaration, + CreateVariableDeclaration, + VariableDeclarationKind, + VariableDeclarationDeclarators, + VariableDeclarationIsDeclare, + + IsVariableDeclarator, + CreateVariableDeclarator, + VariableDeclaratorIdentifier, + VariableDeclaratorInitializer, +}; } // namespace panda::es2panda::public_lib diff --git a/ets2panda/public/es2panda_lib.h b/ets2panda/public/es2panda_lib.h index d20aee7772e0c1f5f4cc3047186ae80618a76845..f61653f4653bc0a058a0ccf11a7d02cfa6b48aca 100644 --- a/ets2panda/public/es2panda_lib.h +++ b/ets2panda/public/es2panda_lib.h @@ -16,17 +16,27 @@ #ifndef ES2PANDA_LIB #define ES2PANDA_LIB +// Switch off the linter for C header +// NOLINTBEGIN + +#include +#include + #ifdef __cplusplus extern "C" { #endif -// Switch off the linter for C header -// NOLINTBEGIN +#define ES2PANDA_LIB_VERSION 1 -#define ES2PANDA_LIB_VERSION 0 +typedef struct es2panda_Config es2panda_Config; +typedef struct es2panda_Context es2panda_Context; -typedef void es2panda_Config; -typedef void es2panda_Context; +typedef struct es2panda_Program es2panda_Program; +typedef struct es2panda_ExternalSource es2panda_ExternalSource; +typedef struct es2panda_AstNode es2panda_AstNode; +typedef struct es2panda_Type es2panda_Type; +typedef struct es2panda_Variable es2panda_Variable; +typedef struct es2panda_Scope es2panda_Scope; enum es2panda_ContextState { ES2PANDA_STATE_NEW, @@ -40,6 +50,74 @@ enum es2panda_ContextState { }; typedef enum es2panda_ContextState es2panda_ContextState; +// NB: has to be synchronized with astNode.h +enum es2panda_ModifierFlags { + ES2PANDA_MODIFIER_NONE = 0U, + ES2PANDA_MODIFIER_STATIC = 1U << 0U, + ES2PANDA_MODIFIER_ASYNC = 1U << 1U, + ES2PANDA_MODIFIER_PUBLIC = 1U << 2U, + ES2PANDA_MODIFIER_PROTECTED = 1U << 3U, + ES2PANDA_MODIFIER_PRIVATE = 1U << 4U, + ES2PANDA_MODIFIER_DECLARE = 1U << 5U, + ES2PANDA_MODIFIER_READONLY = 1U << 6U, + ES2PANDA_MODIFIER_OPTIONAL = 1U << 7U, + ES2PANDA_MODIFIER_DEFINITE = 1U << 8U, + ES2PANDA_MODIFIER_ABSTRACT = 1U << 9U, + ES2PANDA_MODIFIER_CONST = 1U << 10U, + ES2PANDA_MODIFIER_FINAL = 1U << 11U, + ES2PANDA_MODIFIER_NATIVE = 1U << 12U, + ES2PANDA_MODIFIER_OVERRIDE = 1U << 13U, + ES2PANDA_MODIFIER_CONSTRUCTOR = 1U << 14U, + ES2PANDA_MODIFIER_SYNCHRONIZED = 1U << 15U, + ES2PANDA_MODIFIER_FUNCTIONAL = 1U << 16U, + ES2PANDA_MODIFIER_IN = 1U << 17U, + ES2PANDA_MODIFIER_OUT = 1U << 18U, + ES2PANDA_MODIFIER_INTERNAL = 1U << 19U, + ES2PANDA_MODIFIER_NULL_ASSIGNABLE = 1U << 20U, + ES2PANDA_MODIFIER_UNDEFINED_ASSIGNABLE = 1U << 21U, + ES2PANDA_MODIFIER_EXPORT = 1U << 22U, + ES2PANDA_MODIFIER_SETTER = 1U << 23U, + ES2PANDA_MODIFIER_DEFAULT_EXPORT = 1U << 24U, +}; +typedef enum es2panda_ModifierFlags es2panda_ModifierFlags; + +// Has to be synchronized with astNode.h +enum es2panda_ScriptFunctionFlags { + ES2PANDA_SCRIPT_FUNCTION_NONE = 0, + ES2PANDA_SCRIPT_FUNCTION_GENERATOR = 1U << 0U, + ES2PANDA_SCRIPT_FUNCTION_ASYNC = 1U << 1U, + ES2PANDA_SCRIPT_FUNCTION_ARROW = 1U << 2U, + ES2PANDA_SCRIPT_FUNCTION_EXPRESSION = 1U << 3U, + ES2PANDA_SCRIPT_FUNCTION_OVERLOAD = 1U << 4U, + ES2PANDA_SCRIPT_FUNCTION_CONSTRUCTOR = 1U << 5U, + ES2PANDA_SCRIPT_FUNCTION_METHOD = 1U << 6U, + ES2PANDA_SCRIPT_FUNCTION_STATIC_BLOCK = 1U << 7U, + ES2PANDA_SCRIPT_FUNCTION_HIDDEN = 1U << 8U, + ES2PANDA_SCRIPT_FUNCTION_IMPLICIT_SUPER_CALL_NEEDED = 1U << 9U, + ES2PANDA_SCRIPT_FUNCTION_ENUM = 1U << 10U, + ES2PANDA_SCRIPT_FUNCTION_EXTERNAL = 1U << 11U, + ES2PANDA_SCRIPT_FUNCTION_PROXY = 1U << 12U, + ES2PANDA_SCRIPT_FUNCTION_THROWS = 1U << 13U, + ES2PANDA_SCRIPT_FUNCTION_RETHROWS = 1U << 14U, + ES2PANDA_SCRIPT_FUNCTION_GETTER = 1U << 15U, + ES2PANDA_SCRIPT_FUNCTION_SETTER = 1U << 16U, + ES2PANDA_SCRIPT_FUNCTION_DEFAULT_PARAM_PROXY = 1U << 17U, + ES2PANDA_SCRIPT_FUNCTION_ENTRY_POINT = 1U << 18U, + ES2PANDA_SCRIPT_FUNCTION_INSTANCE_EXTENSION_METHOD = 1U << 19U, + ES2PANDA_SCRIPT_FUNCTION_HAS_RETURN = 1U << 20U +}; +typedef enum es2panda_ScriptFunctionFlags es2panda_ScriptFunctionFlags; + +// Needs to be synchronized with memberExpression.h +enum es2panda_MemberExpressionKind { + ES2PANDA_MEMBER_EXPRESSION_KIND_NONE = 0, + ES2PANDA_MEMBER_EXPRESSION_KIND_ELEMENT_ACCESS = 1U << 0U, + ES2PANDA_MEMBER_EXPRESSION_KIND_PROPERTY_ACCESS = 1U << 1U, + ES2PANDA_MEMBER_EXPRESSION_KIND_GETTER = 1U << 2U, + ES2PANDA_MEMBER_EXPRESSION_KIND_SETTER = 1U << 3U +}; +typedef enum es2panda_MemberExpressionKind es2panda_MemberExpressionKind; + struct es2panda_Impl { int version; @@ -53,6 +131,296 @@ struct es2panda_Impl { es2panda_ContextState (*ContextState)(es2panda_Context *context); char const *(*ContextErrorMessage)(es2panda_Context *context); + + es2panda_Program *(*ContextProgram)(es2panda_Context *context); + es2panda_AstNode *(*ProgramAst)(es2panda_Program *program); + es2panda_ExternalSource **(*ProgramExternalSources)(es2panda_Program *program, size_t *len_p); + char const *(*ExternalSourceName)(es2panda_ExternalSource *e_source); + es2panda_Program **(*ExternalSourcePrograms)(es2panda_ExternalSource *e_source, size_t *len_p); + + es2panda_Type *(*AstNodeType)(es2panda_AstNode *ast); + void (*AstNodeSetType)(es2panda_AstNode *ast, es2panda_Type *type); + + es2panda_AstNode *const *(*AstNodeDecorators)(es2panda_AstNode *ast, size_t *size_p); + void (*AstNodeSetDecorators)(es2panda_Context *context, es2panda_AstNode *ast, es2panda_AstNode **decorators, + size_t n_decorators); + + es2panda_ModifierFlags (*AstNodeModifierFlags)(es2panda_AstNode *ast); + + void (*AstNodeForEach)(es2panda_AstNode *ast, void (*func)(es2panda_AstNode *, void *), void *arg); + + bool (*IsArrowFunctionExpression)(es2panda_AstNode *ast); + es2panda_AstNode *(*CreateArrowFunctionExpression)(es2panda_Context *context, es2panda_AstNode *script_function); + es2panda_AstNode *(*ArrowFunctionExpressionScriptFunction)(es2panda_AstNode *ast); + + bool (*IsAsExpression)(es2panda_AstNode *ast); + es2panda_AstNode *(*CreateAsExpression)(es2panda_Context *context, es2panda_AstNode *expr, + es2panda_AstNode *type_annotation, bool is_const); + es2panda_AstNode *(*AsExpressionExpr)(es2panda_AstNode *ast); + es2panda_AstNode *(*AsExpressionTypeAnnotation)(es2panda_AstNode *ast); + bool (*AsExpressionIsConst)(es2panda_AstNode *ast); + void (*AsExpressionSetExpr)(es2panda_AstNode *ast, es2panda_AstNode *expr); + void (*AsExpressionSetTypeAnnotation)(es2panda_AstNode *ast, es2panda_AstNode *type_annotation); + + bool (*IsAssignmentExpression)(es2panda_AstNode *ast); + es2panda_AstNode *(*CreateAssignmentExpression)(es2panda_Context *context, es2panda_AstNode *left, + es2panda_AstNode *right, char const *operator_type); + es2panda_AstNode *(*AssignmentExpressionLeft)(es2panda_AstNode *ast); + es2panda_AstNode *(*AssignmentExpressionRight)(es2panda_AstNode *ast); + char const *(*AssignmentExpressionOperatorType)(es2panda_AstNode *ast); + void (*AssignmentExpressionSetOperatorType)(es2panda_AstNode *ast, char const *operator_type); + + bool (*IsBinaryExpression)(es2panda_AstNode *ast); + es2panda_AstNode *(*CreatebinaryExpression)(es2panda_Context *context, es2panda_AstNode *left, + es2panda_AstNode *right, char const *operator_type); + es2panda_AstNode *(*BinaryExpressionLeft)(es2panda_AstNode *ast); + es2panda_AstNode *(*BinaryExpressionRight)(es2panda_AstNode *ast); + char const *(*BinaryExpressionOperator)(es2panda_AstNode *ast); + void (*BinaryExpressionSetOperator)(es2panda_AstNode *ast, char const *operator_type); + + bool (*IsBlockStatement)(es2panda_AstNode *ast); + es2panda_AstNode *(*CreateBlockStatement)(es2panda_Context *context, es2panda_AstNode *in_scope_of); + es2panda_AstNode **(*BlockStatementStatements)(es2panda_AstNode *ast, size_t *size_p); + void (*BlockStatementAddStatement)(es2panda_AstNode *ast, es2panda_AstNode *statement); + + bool (*IsCallExpression)(es2panda_AstNode *ast); + es2panda_AstNode *(*CreateCallExpression)(es2panda_Context *context, es2panda_AstNode *callee, + es2panda_AstNode *type_arguments, es2panda_AstNode **arguments, + size_t n_arguments, bool optional); + es2panda_AstNode const *(*CallExpressionCallee)(es2panda_AstNode *ast); + es2panda_AstNode const *(*CallExpressionTypeArguments)(es2panda_AstNode *ast); + es2panda_AstNode **(*CallExpressionArguments)(es2panda_AstNode *ast, size_t *size_p); + bool (*CallExpressionIsOptional)(es2panda_AstNode *ast); + void (*CallExpressionSetTypeArguments)(es2panda_AstNode *ast, es2panda_AstNode *type_arguments); + + bool (*IsChainExpression)(es2panda_AstNode *ast); + es2panda_AstNode *(*CreateChainExpression)(es2panda_Context *context, es2panda_AstNode *child); + es2panda_AstNode const *(*ChainExpressionChild)(es2panda_AstNode *ast); + + bool (*IsClassDeclaration)(es2panda_AstNode *ast); + es2panda_AstNode *(*CreateClassDeclaration)(es2panda_Context *context, es2panda_AstNode *definition); + es2panda_AstNode *(*ClassDeclarationDefinition)(es2panda_AstNode *ast); + + bool (*IsClassDefinition)(es2panda_AstNode *ast); + es2panda_AstNode *(*CreateClassDefinition)(es2panda_Context *context, es2panda_AstNode *in_scope_of, + es2panda_AstNode *identifier, es2panda_ModifierFlags flags); + es2panda_AstNode *(*ClassDefinitionIdentifier)(es2panda_AstNode *ast); + es2panda_AstNode *(*ClassDefinitionTypeParameters)(es2panda_AstNode *ast); + es2panda_AstNode *(*ClassDefinitionSuperClass)(es2panda_AstNode *ast); + es2panda_AstNode **(*ClassDefinitionImplements)(es2panda_AstNode *ast, size_t *size_p); + es2panda_AstNode *(*ClassDefinitionConstructor)(es2panda_AstNode *ast); + es2panda_AstNode **(*ClassDefinitionBody)(es2panda_AstNode *ast, size_t *size_p); + void (*ClassDefinitionSetIdentifier)(es2panda_AstNode *ast, es2panda_AstNode *identifier); + void (*ClassDefinitionSetTypeParameters)(es2panda_AstNode *ast, es2panda_AstNode *type_params); + void (*ClassDefinitionSetSuperClass)(es2panda_AstNode *ast, es2panda_AstNode *super_class); + void (*ClassDefinitionSetImplements)(es2panda_AstNode *ast, es2panda_AstNode **implements, size_t n_implements); + void (*ClassDefinitionAddImplements)(es2panda_AstNode *ast, es2panda_AstNode *implements); + void (*ClassDefinitionSetConstructor)(es2panda_AstNode *ast, es2panda_AstNode *constructor); + void (*ClassDefinitonSetBody)(es2panda_AstNode *ast, es2panda_AstNode **body, size_t n_elems); + void (*ClassDefinitonAddToBody)(es2panda_AstNode *ast, es2panda_AstNode *statement); + + es2panda_AstNode *(*ClassElementKey)(es2panda_AstNode *ast); + es2panda_AstNode *(*ClassElementValue)(es2panda_AstNode *ast); + + bool (*IsClassImplementsClause)(es2panda_AstNode *ast); + es2panda_AstNode *(*CreateClassImplementsClause)(es2panda_Context *context, es2panda_AstNode *expression, + es2panda_AstNode *type_arguments); + es2panda_AstNode *(*ClassImplementsClauseExpression)(es2panda_AstNode *ast); + es2panda_AstNode const *(*ClassImplementsClauseTypeArguments)(es2panda_AstNode *ast); + + bool (*IsClassProperty)(es2panda_AstNode *ast); + es2panda_AstNode *(*CreateClassProperty)(es2panda_Context *context, es2panda_AstNode *key, es2panda_AstNode *value, + es2panda_AstNode *type_annotation, es2panda_ModifierFlags modifier_flags, + bool is_computed); + es2panda_AstNode *(*ClassPropertyTypeAnnotation)(es2panda_AstNode *ast); + + bool (*IsExpressionStatement)(es2panda_AstNode *ast); + es2panda_AstNode *(*CreateExpressionStatement)(es2panda_Context *context, es2panda_AstNode *expression); + es2panda_AstNode *(*ExpressionStatementExpression)(es2panda_AstNode *ast); + + bool (*IsFunctionDeclaration)(es2panda_AstNode *ast); + es2panda_AstNode *(*CreateFunctionDeclaration)(es2panda_Context *context, es2panda_AstNode *function); + es2panda_AstNode *(*FunctionDeclarationFunction)(es2panda_AstNode *ast); + + bool (*IsFunctionExpression)(es2panda_AstNode *ast); + es2panda_AstNode *(*CreateFunctionExpression)(es2panda_Context *context, es2panda_AstNode *function); + es2panda_AstNode *(*FunctionExpressionFunction)(es2panda_AstNode *ast); + + bool (*IsFunctionTypeNode)(es2panda_AstNode *ast); + es2panda_AstNode *(*CreateFunctionTypeNode)(es2panda_Context *context, es2panda_AstNode *in_scope_of, + es2panda_AstNode *type_params, es2panda_AstNode **params, + size_t n_params, es2panda_AstNode *return_type, + es2panda_ScriptFunctionFlags func_flags); + es2panda_AstNode const *(*FunctionTypeNodeTypeParams)(es2panda_AstNode *ast); + es2panda_AstNode *const *(*FunctionTypeNodeParams)(es2panda_AstNode *ast, size_t *size_p); + es2panda_AstNode *(*FunctionTypeNodeReturnType)(es2panda_AstNode *ast); + es2panda_ScriptFunctionFlags (*FunctionTypeNodeFlags)(es2panda_AstNode *ast); + + bool (*IsIdentifier)(es2panda_AstNode *ast); + es2panda_AstNode *(*CreateIdentifier)(es2panda_Context *context, char const *name, + es2panda_AstNode *type_annotation); + char const *(*IdentifierName)(es2panda_Context *context, es2panda_AstNode *identifier); + es2panda_AstNode *(*IdentifierTypeAnnotation)(es2panda_AstNode *identifier); + es2panda_Variable *(*IdentifierVariable)(es2panda_AstNode *identifier); + void (*IdentifierSetVariable)(es2panda_AstNode *identifier, es2panda_Variable *variable); + + bool (*IsIfStatement)(es2panda_AstNode *ast); + es2panda_AstNode *(*CreateIfStatement)(es2panda_Context *context, es2panda_AstNode *test, + es2panda_AstNode *consequent, es2panda_AstNode *alternate); + es2panda_AstNode const *(*IfStatementTest)(es2panda_AstNode *ast); + es2panda_AstNode const *(*IfStatementConsequent)(es2panda_AstNode *ast); + es2panda_AstNode const *(*IfStatementAlternate)(es2panda_AstNode *ast); + + bool (*IsImportDeclaration)(es2panda_AstNode *ast); + es2panda_AstNode *(*CreateImportDeclaration)(es2panda_Context *context, es2panda_AstNode *source, + es2panda_AstNode **specifiers, size_t n_specifiers); + es2panda_AstNode const *(*ImportDeclarationSource)(es2panda_AstNode *ast); + es2panda_AstNode *const *(*ImportDeclarationSpecifiers)(es2panda_AstNode *ast, size_t *size_p); + + bool (*IsImportExpression)(es2panda_AstNode *ast); + es2panda_AstNode *(*CreateImportExpression)(es2panda_Context *context, es2panda_AstNode *source); + es2panda_AstNode *(*ImportExpressionSource)(es2panda_AstNode *ast); + + bool (*IsImportSpecifier)(es2panda_AstNode *ast); + es2panda_AstNode *(*CreateImportSpecifier)(es2panda_Context *context, es2panda_AstNode *imported, + es2panda_AstNode *local); + es2panda_AstNode *(*ImportSpecifierImported)(es2panda_AstNode *ast); + es2panda_AstNode *(*ImportSpecifierLocal)(es2panda_AstNode *ast); + + bool (*IsMemberExpression)(es2panda_AstNode *ast); + es2panda_AstNode *(*CreateMemberExpression)(es2panda_Context *context, es2panda_AstNode *object, + es2panda_AstNode *property, es2panda_MemberExpressionKind kind, + bool is_computed, bool is_optional); + es2panda_AstNode *(*MemberExpressionObject)(es2panda_AstNode *ast); + es2panda_AstNode *(*MemberExpressionProperty)(es2panda_AstNode *ast); + es2panda_MemberExpressionKind (*MemberExpressionKind)(es2panda_AstNode *ast); + bool (*MemberExpressionIsComputed)(es2panda_AstNode *ast); + bool (*MemberExpressionIsOptional)(es2panda_AstNode *ast); + + bool (*IsMethodDefinition)(es2panda_AstNode *ast); + es2panda_AstNode *(*CreateMethodDefinition)(es2panda_Context *context, char const *kind, es2panda_AstNode *key, + es2panda_AstNode *value, es2panda_ModifierFlags modifiers, + bool is_computed); + char const *(*MethodDefinitionKind)(es2panda_AstNode *ast); + es2panda_AstNode const *(*MethodDefinitionKey)(es2panda_AstNode *ast); + es2panda_AstNode const *(*MethodDefinitionValue)(es2panda_AstNode *ast); + es2panda_ModifierFlags (*MethodDefinitionModifiers)(es2panda_AstNode *ast); + bool (*MethodDefinitionIsComputed)(es2panda_AstNode *ast); + es2panda_AstNode *const *(*MethodDefinitionOverloads)(es2panda_AstNode *ast, size_t *size_p); + void (*MethodDefinitionSetOverloads)(es2panda_AstNode *ast, es2panda_AstNode **overloads, size_t n_overloads); + void (*MethodDefinitionAddOverload)(es2panda_AstNode *ast, es2panda_AstNode *overload); + + bool (*IsNewClassInstanceExpression)(es2panda_AstNode *ast); + es2panda_AstNode *(*CreateNewClassInstanceExpression)(es2panda_Context *context, es2panda_AstNode *type_reference, + es2panda_AstNode **arguments, size_t n_arguments, + es2panda_AstNode *class_definition); + es2panda_AstNode *(*NewClassInstanceExpressionTypeReference)(es2panda_AstNode *ast); + es2panda_AstNode *const *(*NewClassInstanceExpressionArguments)(es2panda_AstNode *ast, size_t *size_p); + es2panda_AstNode *(*NewClassInstanceExpressionClassDefinition)(es2panda_AstNode *ast); + + bool (*IsNewArrayInstanceExpression)(es2panda_AstNode *ast); + es2panda_AstNode *(*CreateNewArrayInstanceExpression)(es2panda_Context *context, es2panda_AstNode *type_reference, + es2panda_AstNode *dimension); + es2panda_AstNode *(*NewArrayInstanceExpressionTypeReference)(es2panda_AstNode *ast); + es2panda_AstNode *(*NewArrayInstanceExpressionDimension)(es2panda_AstNode *ast); + + bool (*IsNewMultiDimArrayInstanceExpression)(es2panda_AstNode *ast); + es2panda_AstNode *(*CreateNewMultiDimArrayInstanceExpression)(es2panda_Context *context, + es2panda_AstNode *type_reference, + es2panda_AstNode **dimensions, size_t n_dimensions); + es2panda_AstNode *(*NewMultiDimArrayInstanceExpressionTypeReference)(es2panda_AstNode *ast); + es2panda_AstNode *const *(*NewMultiDimArrayInstanceExpressionDimensions)(es2panda_AstNode *ast, size_t *size_p); + + bool (*IsNonNullExpression)(es2panda_AstNode *ast); + bool (*IsNumberLiteral)(es2panda_AstNode *ast); + bool (*IsObjectExpression)(es2panda_AstNode *ast); + + bool (*IsParameterDeclaration)(es2panda_AstNode *ast); + es2panda_AstNode *(*CreateParameterDeclaration)(es2panda_Context *context, es2panda_AstNode *identifier_or_spread, + es2panda_AstNode *initializer); + es2panda_AstNode *(*ParameterDeclarationIdentifierOrSpread)(es2panda_AstNode *ast); + es2panda_AstNode *(*ParameterDeclarationInitializer)(es2panda_AstNode *ast); + + bool (*IsPrimitiveTypeNode)(es2panda_AstNode *ast); + es2panda_AstNode *(*CreatePrimitiveTypeNode)(es2panda_Context *context, char const *type); + char const *(*PrimitiveTypeNodeType)(es2panda_AstNode *ast); + + bool (*IsReturnStatement)(es2panda_AstNode *ast); + es2panda_AstNode *(*CreatereturnStatement)(es2panda_Context *context, es2panda_AstNode *argument); + es2panda_AstNode *(*ReturnStatementArgument)(es2panda_AstNode *ast); + es2panda_Type *(*ReturnStatementReturnType)(es2panda_AstNode *ast); + + bool (*IsScriptFunction)(es2panda_AstNode *ast); + es2panda_AstNode *(*CreateScriptFunction)(es2panda_Context *context, es2panda_AstNode *type_params, + es2panda_AstNode **params, size_t n_params, + es2panda_AstNode *return_type_annotation, + es2panda_ScriptFunctionFlags function_flags, + es2panda_ModifierFlags modifier_flags, bool is_declare, + es2panda_AstNode *in_scope_of); + es2panda_AstNode *(*ScriptFunctionTypeParams)(es2panda_AstNode *ast); + es2panda_AstNode *const *(*ScriptFunctionParams)(es2panda_AstNode *ast, size_t *size_p); + es2panda_AstNode *(*ScriptFunctionReturnTypeAnnotation)(es2panda_AstNode *ast); + es2panda_ScriptFunctionFlags (*ScriptFunctionScriptFunctionFlags)(es2panda_AstNode *ast); + bool (*ScriptFunctionIsDeclare)(es2panda_AstNode *ast); + es2panda_AstNode *(*ScriptFunctionIdentifier)(es2panda_AstNode *ast); + es2panda_AstNode *(*ScriptFunctionBody)(es2panda_AstNode *ast); + void (*ScriptFunctionSetIdentifier)(es2panda_AstNode *ast, es2panda_AstNode *ident); + void (*ScriptFunctionSetBody)(es2panda_AstNode *ast, es2panda_AstNode *body); + void (*ScriptFunctionSetParams)(es2panda_AstNode *ast, es2panda_AstNode **params, size_t n_params); + void (*ScripFunctionAddParam)(es2panda_AstNode *ast, es2panda_AstNode *param); + + bool (*IsStringLiteral)(es2panda_AstNode *ast); + es2panda_AstNode *(*CreateStringLiteral)(es2panda_Context *context, char const *string); + char const *(*StringLiteralString)(es2panda_Context *context, es2panda_AstNode *ast); + + bool (*IsThisExpression)(es2panda_AstNode *ast); + es2panda_AstNode *(*CreateThisExpression)(es2panda_Context *context); + + bool (*IsTypeParameter)(es2panda_AstNode *ast); + es2panda_AstNode *(*CreateTypeParameter)(es2panda_Context *context, es2panda_AstNode *name, + es2panda_AstNode *constraint, es2panda_AstNode *defaultType); + es2panda_AstNode const *(*TypeParameterName)(es2panda_AstNode *ast); + es2panda_AstNode const *(*TypeParameterConstraint)(es2panda_AstNode *ast); + es2panda_AstNode const *(*TypeParameterDefaultType)(es2panda_AstNode *ast); + + bool (*IsTypeParameterDeclaration)(es2panda_AstNode *ast); + es2panda_AstNode *(*CreateTypeParameterDeclaration)(es2panda_Context *context, es2panda_AstNode *in_scope_of); + void (*TypeParameterDeclarationAddTypeParameter)(es2panda_AstNode *ast, es2panda_AstNode *type_parameter); + es2panda_AstNode *const *(*TypeParameterDeclarationTypeParameters)(es2panda_AstNode *ast, size_t *size_p); + + bool (*IsTypeParameterInstantiation)(es2panda_AstNode *ast); + es2panda_AstNode *(*CreateTypeParameterInstantiation)(es2panda_Context *context, es2panda_AstNode **params, + size_t n_params); + es2panda_AstNode *const *(*TypeParameterInstantiationTypeParameters)(es2panda_AstNode *ast, size_t *size_p); + + bool (*IsTypeReferenceNode)(es2panda_AstNode *ast); + es2panda_AstNode *(*CreateTypeReferenceNode)(es2panda_Context *context, es2panda_AstNode *part); + es2panda_AstNode *(*TypeRefrenceNodePart)(es2panda_AstNode *ast); + + bool (*IsTypeReferencePart)(es2panda_AstNode *ast); + es2panda_AstNode *(*CreateTypeReferencePart)(es2panda_Context *context, es2panda_AstNode *name, + es2panda_AstNode *type_arguments, es2panda_AstNode *previous); + es2panda_AstNode *(*TypeReferencePartName)(es2panda_AstNode *ast); + es2panda_AstNode *(*TypeReferencePartTypeArguments)(es2panda_AstNode *ast); + es2panda_AstNode *(*TypeReferencePartPrevious)(es2panda_AstNode *ast); + + bool (*IsUnionTypeNode)(es2panda_AstNode *ast); + es2panda_AstNode *(*CreateUnionTypeNode)(es2panda_Context *context, es2panda_AstNode **types, size_t n_types); + es2panda_AstNode *const *(*UnionTypeNodeTypes)(es2panda_AstNode *ast, size_t *size_p); + + bool (*IsVariableDeclaration)(es2panda_AstNode *ast); + es2panda_AstNode *(*CreateVariableDeclaration)(es2panda_Context *context, char const *kind, + es2panda_AstNode **declarators, size_t n_declarators, + bool is_declare); + char const *(*VariableDeclarationKind)(es2panda_AstNode *ast); + es2panda_AstNode *const *(*VariableDeclarationDeclarators)(es2panda_AstNode *ast, size_t *size_p); + bool (*VariableDeclarationIsDeclare)(es2panda_AstNode *ast); + + bool (*IsVariableDeclarator)(es2panda_AstNode *ast); + es2panda_AstNode *(*CreateVariableDeclarator)(es2panda_Context *context, es2panda_AstNode *identifier, + es2panda_AstNode *initializer); + es2panda_AstNode *(*VariableDeclaratorIdentifier)(es2panda_AstNode *ast); + es2panda_AstNode *(*VariableDeclaratorInitializer)(es2panda_AstNode *ast); }; struct es2panda_Impl const *es2panda_GetImpl(int version); diff --git a/ets2panda/public/public.h b/ets2panda/public/public.h new file mode 100644 index 0000000000000000000000000000000000000000..81c04023c1b7ecf95082a8da2a8897c944d7aee0 --- /dev/null +++ b/ets2panda/public/public.h @@ -0,0 +1,65 @@ +/** + * Copyright (c) 2021-2022 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. + */ + +#ifndef ES2PANDA_PUBLIC_PUBLIC_H +#define ES2PANDA_PUBLIC_PUBLIC_H + +#include "public/es2panda_lib.h" + +#include "assembler/assembly-program.h" +#include "libpandabase/mem/arena_allocator.h" + +#include "es2panda.h" +#include "compiler/core/compileQueue.h" +#include "parser/ETSparser.h" +#include "checker/checker.h" +#include "compiler/core/emitter.h" +#include "util/options.h" + +namespace panda::es2panda::compiler { +class Phase; +} // namespace panda::es2panda::compiler + +namespace panda::es2panda::public_lib { +struct ConfigImpl { + util::Options *options; +}; + +struct Context { + ConfigImpl *config = nullptr; + std::string source_file_name; + std::string input; + SourceFile const *source_file = nullptr; + ArenaAllocator *allocator = nullptr; + compiler::CompileQueue *queue = nullptr; + std::vector const *plugins = nullptr; + std::vector phases; + size_t current_phase = 0; + + parser::Program *parser_program = nullptr; + parser::ParserImpl *parser = nullptr; + checker::Checker *checker = nullptr; + checker::SemanticAnalyzer *analyzer = nullptr; + compiler::CompilerContext *compiler_context = nullptr; + compiler::Emitter *emitter = nullptr; + pandasm::Program *program = nullptr; + + es2panda_ContextState state = ES2PANDA_STATE_NEW; + std::string error_message; + lexer::SourcePosition error_pos; +}; +} // namespace panda::es2panda::public_lib + +#endif diff --git a/ets2panda/test/CMakeLists.txt b/ets2panda/test/CMakeLists.txt index ff14df7c4ae66ff22c3618052179032ef05d69e4..5d1ca5e8a0edb6b288f4a18fd97e13e303e29459 100644 --- a/ets2panda/test/CMakeLists.txt +++ b/ets2panda/test/CMakeLists.txt @@ -76,7 +76,7 @@ if(PANDA_WITH_ETS) endforeach() panda_add_gtest( - NAME es2panda_public_tests + NAME es2panda_public_test SOURCES public/es2panda_public_test.cpp LIBRARIES @@ -85,7 +85,21 @@ if(PANDA_WITH_ETS) ${CMAKE_CURRENT_SOURCE_DIR}/.. SANITIZERS ${PANDA_SANITIZERS_LIST} + ) + + panda_add_library(e2p_test_plugin SHARED public/e2p_test_plugin.c) + panda_target_include_directories(e2p_test_plugin PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/..") + panda_target_link_libraries(e2p_test_plugin es2panda-public) + + add_custom_target(es2panda-plugin-test + COMMENT "Test es2panda plugin functionality" + COMMAND ${CMAKE_COMMAND} -E env LD_LIBRARY_PATH=${CMAKE_LIBRARY_OUTPUT_DIRECTORY} $ --plugins=e2p_test_plugin + "${CMAKE_CURRENT_SOURCE_DIR}/public/t.ets" > "${CMAKE_CURRENT_BINARY_DIR}/plugin_test.out" + COMMAND ${CMAKE_COMMAND} -E compare_files + "${CMAKE_CURRENT_BINARY_DIR}/plugin_test.out" "${CMAKE_CURRENT_SOURCE_DIR}/public/plugin_test.expected.txt" ) + add_dependencies(es2panda-plugin-test es2panda e2p_test_plugin) + add_dependencies(es2panda_tests es2panda-plugin-test) add_dependencies(es2panda_tests es2panda-regression-tests) if(TARGET ets_tests) diff --git a/ets2panda/test/public/e2p_test_plugin.c b/ets2panda/test/public/e2p_test_plugin.c new file mode 100644 index 0000000000000000000000000000000000000000..2de3ca54a7544505776c8c793151fc32847cd4b5 --- /dev/null +++ b/ets2panda/test/public/e2p_test_plugin.c @@ -0,0 +1,57 @@ +/** + * Copyright (c) 2023 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. + */ + +// No linting for pure C file +// NOLINTBEGIN + +#include +#include + +#include "public/es2panda_lib.h" + +static struct es2panda_Impl const *impl = NULL; + +void e2p_test_plugin_Initialize() +{ + puts("Hi there!"); + impl = es2panda_GetImpl(ES2PANDA_LIB_VERSION); +} + +static void PrintIfIdentifier(es2panda_AstNode *node, void *arg) +{ + es2panda_Context *ctx = arg; + if (impl->IsIdentifier(node)) { + puts(impl->IdentifierName(ctx, node)); + } +} + +void e2p_test_plugin_AfterParse(es2panda_Context *ctx) +{ + puts("After parse"); + es2panda_AstNode *ast = impl->ProgramAst(impl->ContextProgram(ctx)); + impl->AstNodeForEach(ast, PrintIfIdentifier, ctx); +} + +void e2p_test_plugin_AfterCheck(es2panda_Context *ctx) +{ + puts("After check"); +} + +void e2p_test_plugin_AfterLowerings(es2panda_Context *ctx) +{ + puts("After lowerings"); +} + +// NOLINTEND diff --git a/ets2panda/test/public/es2panda_public_test.cpp b/ets2panda/test/public/es2panda_public_test.cpp index 03846b4edb2ad52bc77c706bb89004f1a4cb8c28..723fd07de0e1eab8243f6312eb72f5d8d1972c97 100644 --- a/ets2panda/test/public/es2panda_public_test.cpp +++ b/ets2panda/test/public/es2panda_public_test.cpp @@ -53,10 +53,51 @@ TEST_F(Es2PandaLibTest, NoError) TEST_F(Es2PandaLibTest, TypeError) { es2panda_Context *ctx = - impl_->CreateContextFromString(cfg_, "function main() { let x: int = \"\" }", "no-error.ets"); - impl_->ProceedToState(ctx, ES2PANDA_STATE_ASM_GENERATED); // don't produce any object files + impl_->CreateContextFromString(cfg_, "function main() { let x: int = \"\" }", "type-error.ets"); + impl_->ProceedToState(ctx, ES2PANDA_STATE_ASM_GENERATED); ASSERT_EQ(impl_->ContextState(ctx), ES2PANDA_STATE_ERROR); ASSERT_EQ(std::string(impl_->ContextErrorMessage(ctx)), - "TypeError: Initializers type is not assignable to the target type[no-error.ets:1,32]"); + "TypeError: Initializers type is not assignable to the target type[type-error.ets:1,32]"); + impl_->DestroyContext(ctx); +} + +TEST_F(Es2PandaLibTest, ListIdentifiers) +{ + char const *text = R"XXX( +class C { + n: string = "oh" +} + +function main() { + let c = new C + console.log(c.n + 1) // type error, but not syntax error +} +)XXX"; + es2panda_Context *ctx = impl_->CreateContextFromString(cfg_, text, "list-ids.ets"); + ctx = impl_->ProceedToState(ctx, ES2PANDA_STATE_PARSED); + ASSERT_EQ(impl_->ContextState(ctx), ES2PANDA_STATE_PARSED); + + struct Arg { + es2panda_Impl const *impl = nullptr; + es2panda_Context *ctx = nullptr; + std::vector ids; + } arg; + arg.impl = impl_; + arg.ctx = ctx; + + auto func = [](es2panda_AstNode *ast, void *argp) { + auto *a = reinterpret_cast(argp); + if (a->impl->IsIdentifier(ast)) { + a->ids.emplace_back(a->impl->IdentifierName(a->ctx, ast)); + } + }; + + impl_->AstNodeForEach(impl_->ProgramAst(impl_->ContextProgram(ctx)), func, &arg); + + std::vector expected {"C", "n", "string", "constructor", "constructor", "ETSGLOBAL", + "_$init$_", "_$init$_", "main", "main", "c", "C", + "console", "log", "c", "n", ""}; + ASSERT_EQ(arg.ids, expected); + impl_->DestroyContext(ctx); } diff --git a/ets2panda/test/public/plugin_test.expected.txt b/ets2panda/test/public/plugin_test.expected.txt new file mode 100644 index 0000000000000000000000000000000000000000..f578824e8435dd77777c35b1233f0e02b4ea338d --- /dev/null +++ b/ets2panda/test/public/plugin_test.expected.txt @@ -0,0 +1,16 @@ +Hi there! +After parse +ETSGLOBAL +_$init$_ +_$init$_ +main +main +m +n +console +log +m +n + +After check +After lowerings diff --git a/ets2panda/test/public/t.ets b/ets2panda/test/public/t.ets new file mode 100644 index 0000000000000000000000000000000000000000..56969fa7e1bbcadaafa51e626c343bb58a055f7f --- /dev/null +++ b/ets2panda/test/public/t.ets @@ -0,0 +1,20 @@ +/** + * Copyright (c) 2023 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. + */ + +function main() { + let m: int = 1 + let n: int = 2 + console.log(m + n) +} diff --git a/ets2panda/util/options.cpp b/ets2panda/util/options.cpp index f5d6b87d989a9251c759e0300d71a9ce9f92c19a..91c3d897ac6068c32312087bda5c684046efea5f 100644 --- a/ets2panda/util/options.cpp +++ b/ets2panda/util/options.cpp @@ -36,21 +36,31 @@ Options::~Options() delete argparser_; } -static std::unordered_set StringToStringSet(const std::string &str) +static std::vector SplitToStringVector(std::string const &str) { - std::unordered_set res; + std::vector res; std::string_view curr_str {str}; auto ix = curr_str.find(','); while (ix != std::string::npos) { if (ix != 0) { - res.insert(std::string(curr_str.substr(0, ix))); + res.emplace_back(curr_str.substr(0, ix)); } curr_str = curr_str.substr(ix + 1); ix = curr_str.find(','); } if (!curr_str.empty()) { - res.insert(std::string(curr_str)); + res.emplace_back(curr_str); + } + return res; +} + +static std::unordered_set SplitToStringSet(std::string const &str) +{ + std::vector vec = SplitToStringVector(str); + std::unordered_set res; + for (auto &elem : vec) { + res.emplace(elem); } return res; } @@ -85,6 +95,7 @@ bool Options::Parse(int argc, const char **argv) panda::PandArg log_level("log-level", "error", "Log-level"); panda::PandArg std_lib("stdlib", "", "Path to standard library"); panda::PandArg gen_std_lib("gen-stdlib", false, "Gen standard library"); + panda::PandArg plugins("plugins", "", "Plugins"); panda::PandArg skip_phases("skip-phases", "", "Phases to skip"); panda::PandArg dump_before_phases("dump-before-phases", "", "Generate program dump before running phases in the list"); @@ -115,6 +126,7 @@ bool Options::Parse(int argc, const char **argv) argparser_->Add(&log_level); argparser_->Add(&std_lib); argparser_->Add(&gen_std_lib); + argparser_->Add(&plugins); argparser_->Add(&skip_phases); argparser_->Add(&dump_before_phases); argparser_->Add(&dump_after_phases); @@ -297,9 +309,10 @@ bool Options::Parse(int argc, const char **argv) compiler_options_.std_lib = std_lib.GetValue(); compiler_options_.compilation_mode = compilation_mode; compiler_options_.is_ets_module = op_ets_module.GetValue(); - compiler_options_.skip_phases = StringToStringSet(skip_phases.GetValue()); - compiler_options_.dump_before_phases = StringToStringSet(dump_before_phases.GetValue()); - compiler_options_.dump_after_phases = StringToStringSet(dump_after_phases.GetValue()); + compiler_options_.plugins = SplitToStringVector(plugins.GetValue()); + compiler_options_.skip_phases = SplitToStringSet(skip_phases.GetValue()); + compiler_options_.dump_before_phases = SplitToStringSet(dump_before_phases.GetValue()); + compiler_options_.dump_after_phases = SplitToStringSet(dump_after_phases.GetValue()); return true; } diff --git a/ets2panda/util/plugin.cpp b/ets2panda/util/plugin.cpp new file mode 100644 index 0000000000000000000000000000000000000000..74c1e273fdf397e8568e098809249f668265318d --- /dev/null +++ b/ets2panda/util/plugin.cpp @@ -0,0 +1,55 @@ +/** + * Copyright (c) 2021-2022 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 "plugin.h" +#include "os/library_loader.h" + +namespace panda::es2panda::util { + +std::string Plugin::FullNameForProcedure(std::string const &short_name) +{ + return std::string(name_.Utf8()) + "_" + short_name; +} + +Plugin::Plugin(util::StringView const &name) : name_ {name}, err_ {0}, h_ {nullptr} +{ + std::string so_name = + os::library_loader::DYNAMIC_LIBRARY_PREFIX + std::string(name) + os::library_loader::DYNAMIC_LIBRARY_SUFFIX; + if (auto load_res = os::library_loader::Load(so_name); load_res.HasValue()) { + h_ = std::move(load_res.Value()); + } else { + err_ = load_res.Error(); + ok_ = false; + } + + if (auto init_res = os::library_loader::ResolveSymbol(h_, FullNameForProcedure("Initialize")); + init_res.HasValue()) { + initialize_ = reinterpret_cast(init_res.Value()); + } + + if (auto ap_res = os::library_loader::ResolveSymbol(h_, FullNameForProcedure("AfterParse")); ap_res.HasValue()) { + after_parse_ = reinterpret_cast(ap_res.Value()); + } + + if (auto ac_res = os::library_loader::ResolveSymbol(h_, FullNameForProcedure("AfterCheck")); ac_res.HasValue()) { + after_check_ = reinterpret_cast(ac_res.Value()); + } + + if (auto al_res = os::library_loader::ResolveSymbol(h_, FullNameForProcedure("AfterLowerings")); + al_res.HasValue()) { + after_lowerings_ = reinterpret_cast(al_res.Value()); + } +} + +} // namespace panda::es2panda::util diff --git a/ets2panda/util/plugin.h b/ets2panda/util/plugin.h new file mode 100644 index 0000000000000000000000000000000000000000..74fd3c88563c537aa91323be61beff536075fc04 --- /dev/null +++ b/ets2panda/util/plugin.h @@ -0,0 +1,87 @@ +/** + * Copyright (c) 2021-2022 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. + */ +#ifndef ES2PANDA_UTIL_PLUGINS_H +#define ES2PANDA_UTIL_PLUGINS_H + +#include "macros.h" +#include "os/library_loader.h" +#include "public/es2panda_lib.h" +#include "util/ustring.h" + +namespace panda::es2panda::util { + +class Plugin { +public: + explicit Plugin(util::StringView const &name); + ~Plugin() = default; + + NO_COPY_SEMANTIC(Plugin); + DEFAULT_MOVE_SEMANTIC(Plugin); + + bool IsOk() + { + return ok_; + } + + os::Error Error() + { + return err_; + } + + void Initialize() const + { + if (initialize_ != nullptr) { + initialize_(); + } + } + + void AfterParse(es2panda_Context *context) const + { + if (after_parse_ != nullptr) { + after_parse_(context); + } + } + + void AfterCheck(es2panda_Context *context) const + { + if (after_check_ != nullptr) { + after_check_(context); + } + } + + void AfterLowerings(es2panda_Context *context) const + { + if (after_lowerings_ != nullptr) { + after_lowerings_(context); + } + } + +private: + std::string FullNameForProcedure(std::string const &short_name); + + util::StringView name_; + bool ok_ {true}; + os::Error err_; + os::library_loader::LibraryHandle h_; + + void (*initialize_)() = nullptr; + void (*after_parse_)(es2panda_Context *) = nullptr; + void (*after_check_)(es2panda_Context *) = nullptr; + void (*after_lowerings_)(es2panda_Context *) = nullptr; +}; + +} // namespace panda::es2panda::util + +#endif