<commit_before>#include <fstream>
#include <memory>
    
#include "javascript.h"


namespace v8toolkit {

ContextHelper::ContextHelper(std::shared_ptr<IsolateHelper> isolate_helper, v8::Local<v8::Context> context) : 
    isolate_helper(isolate_helper), isolate(isolate_helper->get_isolate()), context(v8::Global<v8::Context>(isolate, context)) 
{}


v8::Local<v8::Context> ContextHelper::get_context(){
    return context.Get(isolate);
}


v8::Isolate * ContextHelper::get_isolate() 
{
    return this->isolate;
}


std::shared_ptr<IsolateHelper> ContextHelper::get_isolate_helper()
{
    return this->isolate_helper;
}


ContextHelper::~ContextHelper() {    
#ifdef V8TOOLKIT_JAVASCRIPT_DEBUG
    printf("Deleting ContextHelper\n");  
#endif
}


std::shared_ptr<ScriptHelper> ContextHelper::compile_from_file(const std::string filename)
{
    std::string contents;
    time_t modification_time = 0;
    if (!get_file_contents(filename, contents, modification_time)) {
        
        throw V8CompilationException(*this, std::string("Could not load file: ") + filename);
    }

    return compile(contents);
}


std::shared_ptr<ScriptHelper> ContextHelper::compile(const std::string javascript_source)
{
    return v8toolkit::scoped_run(isolate, context.Get(isolate), [&](){
    
        // printf("Compiling %s\n", javascript_source.c_str());
        // This catches any errors thrown during script compilation
        v8::TryCatch try_catch(isolate);
    
        v8::Local<v8::String> source =
            v8::String::NewFromUtf8(this->isolate, javascript_source.c_str());

        // Compile the source code.
        v8::MaybeLocal<v8::Script> compiled_script = v8::Script::Compile(context.Get(isolate), source);
        if (compiled_script.IsEmpty()) {
            throw V8CompilationException(isolate, v8::Global<v8::Value>(isolate, try_catch.Exception()));
        }
        return std::shared_ptr<ScriptHelper>(new ScriptHelper(shared_from_this(), compiled_script.ToLocalChecked()));
    });
}


v8::Global<v8::Value> ContextHelper::run(const v8::Global<v8::Script> & script)
{
    return v8toolkit::scoped_run(isolate, context.Get(isolate), [&](){
    
        // This catches any errors thrown during script compilation
        v8::TryCatch try_catch(isolate);
        // auto local_script = this->get_local(script);
        auto local_script = v8::Local<v8::Script>::New(isolate, script);
        auto maybe_result = local_script->Run(context.Get(isolate));
        if(maybe_result.IsEmpty()) {

            
            v8::Local<v8::Value> e = try_catch.Exception();
            // print_v8_value_details(e);
            
            
            if(e->IsExternal()) {
                auto anybase = (AnyBase *)v8::External::Cast(*e)->Value();
                auto anyptr_exception_ptr = dynamic_cast<Any<std::exception_ptr> *>(anybase);
                assert(anyptr_exception_ptr); // cannot handle other types at this time TODO: throw some other type of exception if this happens UnknownExceptionException or something
            
                std::rethrow_exception(anyptr_exception_ptr->get());
            } else {
                printf("v8 internal exception thrown: %s\n", *v8::String::Utf8Value(e));
                throw V8Exception(isolate, v8::Global<v8::Value>(isolate, e));
            }
        }
        v8::Local<v8::Value> result = maybe_result.ToLocalChecked();
    
        return v8::Global<v8::Value>(isolate, result);
    });
}


v8::Global<v8::Value> ContextHelper::run(const std::string code)
{
    return (*this)([this, code]{
        auto compiled_code = compile(code);
        return compiled_code->run();
    });
}



v8::Global<v8::Value> ContextHelper::run(const v8::Local<v8::Value> value)
{
    return (*this)([this, value]{
        return run(*v8::String::Utf8Value(value));
    });
}


std::future<std::pair<v8::Global<v8::Value>, std::shared_ptr<ScriptHelper>>> 
 ContextHelper::run_async(const std::string code, std::launch launch_policy)
{
    // copy code into the lambda so it isn't lost when this outer function completes
    //   right after creating the async
    return (*this)([this, code, launch_policy]{
        return this->compile(code)->run_async(launch_policy);
    });
}


void ContextHelper::run_detached(const std::string code)
{
    (*this)([this, code]{
        this->compile(code)->run_detached();
    });
}


std::thread ContextHelper::run_thread(const std::string code)
{
    return (*this)([this, code]{
        return this->compile(code)->run_thread();
    });
}


IsolateHelper::IsolateHelper(v8::Isolate * isolate) : isolate(isolate)
{   
    v8toolkit::scoped_run(isolate, [this](auto isolate){
        this->global_object_template.Reset(isolate, v8::ObjectTemplate::New(this->get_isolate()));
    });
}

IsolateHelper::operator v8::Isolate*()
{
    return this->isolate;
}

IsolateHelper & IsolateHelper::add_print()
{
    (*this)([this](){
        v8toolkit::add_print(isolate, get_object_template());
    });
    return *this;
}

void IsolateHelper::add_require(std::vector<std::string> paths)
{
    (*this)([this, paths]{
       v8toolkit::add_require(isolate, get_object_template(), paths);
    });
}

v8::Isolate * IsolateHelper::get_isolate() 
{
    return this->isolate;
}


std::shared_ptr<ContextHelper> IsolateHelper::create_context()
{
    return operator()([this](){
        auto ot = this->get_object_template();
        auto context = v8::Context::New(this->isolate, NULL, ot);
    
        // can't use make_unique since the constructor is private
        auto context_helper = new ContextHelper(shared_from_this(), context);
        return std::unique_ptr<ContextHelper>(context_helper);
    });
}

v8::Local<v8::ObjectTemplate> IsolateHelper::get_object_template()
{
    return global_object_template.Get(isolate);
}

IsolateHelper::~IsolateHelper()
{
#ifdef V8TOOLKIT_JAVASCRIPT_DEBUG
    printf("Deleting isolate helper %p for isolate %p\n", this, this->isolate);
#endif

    // must explicitly Reset this because the isolate will be
    //   explicitly disposed of before the Global is destroyed
    this->global_object_template.Reset();
    
    this->isolate->Dispose();
    printf("End of isolate helper destructor\n");
}

void IsolateHelper::add_assert()
{
    add_function("assert", [](const v8::FunctionCallbackInfo<v8::Value>& info) {
        auto isolate = info.GetIsolate();
        auto context = isolate->GetCurrentContext();
        printf("Asserting: '%s'\n", *v8::String::Utf8Value(info[0]));
        
        printf("AKA: %s\n",  *v8::String::Utf8Value(info[0]->ToString()));

        v8::TryCatch tc(isolate);
        auto script_maybe = v8::Script::Compile(context, info[0]->ToString());
        if(tc.HasCaught()) {
            printf("Caught compilation error\n");
            tc.ReThrow();
            return;
        }
        auto script = script_maybe.ToLocalChecked();
        auto result_maybe = script->Run(context);
        if(tc.HasCaught()) {
            printf("Caught runtime exception\n");
            tc.ReThrow();
            return;
        }
        auto result = result_maybe.ToLocalChecked();
        print_v8_value_details(result);
        
        bool default_value = false;
        bool assert_result = result->BooleanValue(context).FromMaybe(default_value);
        if (!assert_result) {
            throw V8AssertionException(isolate, std::string("Expression returned false: ") + *v8::String::Utf8Value(info[0]));
        }
        
        printf("Done in assert\n");
    });
    
    add_function("assert_contents", [this](const v8::FunctionCallbackInfo<v8::Value>& args){
        auto isolate = args.GetIsolate();
        if(args.Length() != 2 || !compare_contents(*this, args[0], args[1])) {
            printf("Throwing v8assertionexception\n");
            throw V8AssertionException(*this, std::string("Data structures do not contain the same contents: ")+ stringify_value(isolate, args[0]).c_str() + " " + stringify_value(isolate, args[1]));
        }
    });
}


void PlatformHelper::init(int argc, char ** argv) 
{
    assert(!initialized);
    process_v8_flags(argc, argv);
    
    // Initialize V8.
    v8::V8::InitializeICU();
    
    // startup data is in the current directory<commit_msg>removed call to print_v8_value_details that was spamming the screen while running tests<commit_after>#include <fstream>
#include <memory>
    
#include "javascript.h"


namespace v8toolkit {

ContextHelper::ContextHelper(std::shared_ptr<IsolateHelper> isolate_helper, v8::Local<v8::Context> context) : 
    isolate_helper(isolate_helper), isolate(isolate_helper->get_isolate()), context(v8::Global<v8::Context>(isolate, context)) 
{}


v8::Local<v8::Context> ContextHelper::get_context(){
    return context.Get(isolate);
}


v8::Isolate * ContextHelper::get_isolate() 
{
    return this->isolate;
}


std::shared_ptr<IsolateHelper> ContextHelper::get_isolate_helper()
{
    return this->isolate_helper;
}


ContextHelper::~ContextHelper() {    
#ifdef V8TOOLKIT_JAVASCRIPT_DEBUG
    printf("Deleting ContextHelper\n");  
#endif
}


std::shared_ptr<ScriptHelper> ContextHelper::compile_from_file(const std::string filename)
{
    std::string contents;
    time_t modification_time = 0;
    if (!get_file_contents(filename, contents, modification_time)) {
        
        throw V8CompilationException(*this, std::string("Could not load file: ") + filename);
    }

    return compile(contents);
}


std::shared_ptr<ScriptHelper> ContextHelper::compile(const std::string javascript_source)
{
    return v8toolkit::scoped_run(isolate, context.Get(isolate), [&](){
    
        // printf("Compiling %s\n", javascript_source.c_str());
        // This catches any errors thrown during script compilation
        v8::TryCatch try_catch(isolate);
    
        v8::Local<v8::String> source =
            v8::String::NewFromUtf8(this->isolate, javascript_source.c_str());

        // Compile the source code.
        v8::MaybeLocal<v8::Script> compiled_script = v8::Script::Compile(context.Get(isolate), source);
        if (compiled_script.IsEmpty()) {
            throw V8CompilationException(isolate, v8::Global<v8::Value>(isolate, try_catch.Exception()));
        }
        return std::shared_ptr<ScriptHelper>(new ScriptHelper(shared_from_this(), compiled_script.ToLocalChecked()));
    });
}


v8::Global<v8::Value> ContextHelper::run(const v8::Global<v8::Script> & script)
{
    return v8toolkit::scoped_run(isolate, context.Get(isolate), [&](){
    
        // This catches any errors thrown during script compilation
        v8::TryCatch try_catch(isolate);
        // auto local_script = this->get_local(script);
        auto local_script = v8::Local<v8::Script>::New(isolate, script);
        auto maybe_result = local_script->Run(context.Get(isolate));
        if(maybe_result.IsEmpty()) {

            
            v8::Local<v8::Value> e = try_catch.Exception();
            // print_v8_value_details(e);
            
            
            if(e->IsExternal()) {
                auto anybase = (AnyBase *)v8::External::Cast(*e)->Value();
                auto anyptr_exception_ptr = dynamic_cast<Any<std::exception_ptr> *>(anybase);
                assert(anyptr_exception_ptr); // cannot handle other types at this time TODO: throw some other type of exception if this happens UnknownExceptionException or something
            
                std::rethrow_exception(anyptr_exception_ptr->get());
            } else {
                printf("v8 internal exception thrown: %s\n", *v8::String::Utf8Value(e));
                throw V8Exception(isolate, v8::Global<v8::Value>(isolate, e));
            }
        }
        v8::Local<v8::Value> result = maybe_result.ToLocalChecked();
    
        return v8::Global<v8::Value>(isolate, result);
    });
}


v8::Global<v8::Value> ContextHelper::run(const std::string code)
{
    return (*this)([this, code]{
        auto compiled_code = compile(code);
        return compiled_code->run();
    });
}



v8::Global<v8::Value> ContextHelper::run(const v8::Local<v8::Value> value)
{
    return (*this)([this, value]{
        return run(*v8::String::Utf8Value(value));
    });
}


std::future<std::pair<v8::Global<v8::Value>, std::shared_ptr<ScriptHelper>>> 
 ContextHelper::run_async(const std::string code, std::launch launch_policy)
{
    // copy code into the lambda so it isn't lost when this outer function completes
    //   right after creating the async
    return (*this)([this, code, launch_policy]{
        return this->compile(code)->run_async(launch_policy);
    });
}


void ContextHelper::run_detached(const std::string code)
{
    (*this)([this, code]{
        this->compile(code)->run_detached();
    });
}


std::thread ContextHelper::run_thread(const std::string code)
{
    return (*this)([this, code]{
        return this->compile(code)->run_thread();
    });
}


IsolateHelper::IsolateHelper(v8::Isolate * isolate) : isolate(isolate)
{   
    v8toolkit::scoped_run(isolate, [this](auto isolate){
        this->global_object_template.Reset(isolate, v8::ObjectTemplate::New(this->get_isolate()));
    });
}

IsolateHelper::operator v8::Isolate*()
{
    return this->isolate;
}

IsolateHelper & IsolateHelper::add_print()
{
    (*this)([this](){
        v8toolkit::add_print(isolate, get_object_template());
    });
    return *this;
}

void IsolateHelper::add_require(std::vector<std::string> paths)
{
    (*this)([this, paths]{
       v8toolkit::add_require(isolate, get_object_template(), paths);
    });
}

v8::Isolate * IsolateHelper::get_isolate() 
{
    return this->isolate;
}


std::shared_ptr<ContextHelper> IsolateHelper::create_context()
{
    return operator()([this](){
        auto ot = this->get_object_template();
        auto context = v8::Context::New(this->isolate, NULL, ot);
    
        // can't use make_unique since the constructor is private
        auto context_helper = new ContextHelper(shared_from_this(), context);
        return std::unique_ptr<ContextHelper>(context_helper);
    });
}

v8::Local<v8::ObjectTemplate> IsolateHelper::get_object_template()
{
    return global_object_template.Get(isolate);
}

IsolateHelper::~IsolateHelper()
{
#ifdef V8TOOLKIT_JAVASCRIPT_DEBUG
    printf("Deleting isolate helper %p for isolate %p\n", this, this->isolate);
#endif

    // must explicitly Reset this because the isolate will be
    //   explicitly disposed of before the Global is destroyed
    this->global_object_template.Reset();
    
    this->isolate->Dispose();
    printf("End of isolate helper destructor\n");
}

void IsolateHelper::add_assert()
{
    add_function("assert", [](const v8::FunctionCallbackInfo<v8::Value>& info) {
        auto isolate = info.GetIsolate();
        auto context = isolate->GetCurrentContext();
        printf("Asserting: '%s'\n", *v8::String::Utf8Value(info[0]));
        
        printf("AKA: %s\n",  *v8::String::Utf8Value(info[0]->ToString()));

        v8::TryCatch tc(isolate);
        auto script_maybe = v8::Script::Compile(context, info[0]->ToString());
        if(tc.HasCaught()) {
            printf("Caught compilation error\n");
            tc.ReThrow();
            return;
        }
        auto script = script_maybe.ToLocalChecked();
        auto result_maybe = script->Run(context);
        if(tc.HasCaught()) {
            printf("Caught runtime exception\n");
            tc.ReThrow();
            return;
        }
        auto result = result_maybe.ToLocalChecked();
        // print_v8_value_details(result);
        
        bool default_value = false;
        bool assert_result = result->BooleanValue(context).FromMaybe(default_value);
        if (!assert_result) {
            throw V8AssertionException(isolate, std::string("Expression returned false: ") + *v8::String::Utf8Value(info[0]));
        }
        
        printf("Done in assert\n");
    });
    
    add_function("assert_contents", [this](const v8::FunctionCallbackInfo<v8::Value>& args){
        auto isolate = args.GetIsolate();
        if(args.Length() != 2 || !compare_contents(*this, args[0], args[1])) {
            printf("Throwing v8assertionexception\n");
            throw V8AssertionException(*this, std::string("Data structures do not contain the same contents: ")+ stringify_value(isolate, args[0]).c_str() + " " + stringify_value(isolate, args[1]));
        }
    });
}


void PlatformHelper::init(int argc, char ** argv) 
{
    assert(!initialized);
    process_v8_flags(argc, argv);
    
    // Initialize V8.
    v8::V8::InitializeICU();
    
    // startup data is in the current directory
{'fraction_non_alphanumeric': 0.14617379243803896, 'fraction_numerical': 0.01151781945365736, 'mean_word_length': 3.5077466702908398, 'pattern_counts': {'":': 0, '<': 73, '<?xml version=': 0, '>': 135, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5773173', 'n_tokens_mistral': 5186, 'n_tokens_neox': 5063, 'n_words': 922}