forked from gonzus/JavaScript-V8-XS
-
Notifications
You must be signed in to change notification settings - Fork 0
/
pl_eval.cc
186 lines (162 loc) · 5.8 KB
/
pl_eval.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
#include <map>
#include "pl_stats.h"
#include "pl_console.h"
#include "pl_eventloop.h"
#include "pl_v8.h"
#include "ppport.h"
#define PL_GC_RUNS 2
using namespace v8;
static const char* ToCString(const String::Utf8Value& value)
{
return *value ? *value : "<string conversion failed>";
}
static void ReportException(pTHX_ V8Context* ctx, TryCatch* try_catch)
{
SV* buffer = newSVpvs("");
Isolate* isolate = ctx->isolate;
HandleScope handle_scope(isolate);
String::Utf8Value exception(isolate, try_catch->Exception());
const char* exception_string = ToCString(exception);
Local<Message> message = try_catch->Message();
if (message.IsEmpty()) {
/* V8 didn't provide extra info about error; just print exception. */
Perl_sv_catpvf(aTHX_ buffer, "%s\n", exception_string);
} else {
Local<Context> context(isolate->GetCurrentContext());
Local<Value> stack_trace_string;
bool has_stack_trace = (
try_catch->StackTrace(context).ToLocal(&stack_trace_string) &&
stack_trace_string->IsString() &&
Local<String>::Cast(stack_trace_string)->Length() > 0);
if (!has_stack_trace) {
/* Print (filename):(line number): */
String::Utf8Value filename(isolate, message->GetScriptOrigin().ResourceName());
const char* filename_string = ToCString(filename);
int linenum = message->GetLineNumber(context).FromJust();
Perl_sv_catpvf(aTHX_ buffer, "%s:%i: ", filename_string, linenum);
}
/* Print (message). */
Perl_sv_catpvf(aTHX_ buffer, "error: %s\n", exception_string);
#if 0
/* Print offending line of source code. */
String::Utf8Value sourceline(
isolate, message->GetSourceLine(context).ToLocalChecked());
const char* sourceline_string = ToCString(sourceline);
Perl_sv_catpvf(aTHX_ buffer, "%s\n", sourceline_string);
/* Print wavy underline (GetUnderline is deprecated). */
int start = message->GetStartColumn(context).FromJust();
for (int i = 0; i < start; i++) {
Perl_sv_catpvf(aTHX_ buffer, " ");
}
int end = message->GetEndColumn(context).FromJust();
for (int i = start; i < end; i++) {
Perl_sv_catpvf(aTHX_ buffer, "^");
}
Perl_sv_catpvf(aTHX_ buffer, "\n");
#endif
/* Print stacktrace if any */
if (has_stack_trace) {
String::Utf8Value stack_trace(isolate, stack_trace_string);
const char* stack_trace_string = ToCString(stack_trace);
Perl_sv_catpvf(aTHX_ buffer, "%s\n", stack_trace_string);
}
}
STRLEN blen = 0;
char* bstr = SvPV(buffer, blen);
pl_show_error(ctx, "%s", bstr);
}
SV* pl_eval(pTHX_ V8Context* ctx, const char* code, const char* file)
{
SV* ret = &PL_sv_undef; /* return undef by default */
HandleScope handle_scope(ctx->isolate);
Local<Context> context = Local<Context>::New(ctx->isolate, *ctx->persistent_context);
Context::Scope context_scope(context);
ScriptOrigin* origin = 0;
TryCatch try_catch(ctx->isolate);
bool ok = true;
do {
if (file) {
/* Create a string containing the file name. */
Local<String> name;
ok = String::NewFromUtf8(ctx->isolate, file, NewStringType::kNormal).ToLocal(&name);
if (!ok) {
break;
}
#if V8_MAJOR_VERSION > 8
origin = new ScriptOrigin(ctx->isolate, name);
#else
origin = new ScriptOrigin(name);
#endif
if (!origin) {
break;
}
}
/* Create a string containing the JavaScript source code. */
Local<String> source;
ok = String::NewFromUtf8(ctx->isolate, code, NewStringType::kNormal).ToLocal(&source);
if (!ok) {
break;
}
Perf perf;
/* Compile the source code. */
pl_stats_start(aTHX_ ctx, &perf);
Local<Script> script;
ok = Script::Compile(context, source, origin).ToLocal(&script);
pl_stats_stop(aTHX_ ctx, &perf, "compile");
if (!ok) {
break;
}
/* Run the script to get the result. */
pl_stats_start(aTHX_ ctx, &perf);
Local<Value> result;
ok = script->Run(context).ToLocal(&result);
pl_stats_stop(aTHX_ ctx, &perf, "run");
if (!ok) {
break;
}
/* Convert the result into Perl data */
Local<Object> object = Local<Object>::Cast(result);
ret = pl_v8_to_perl(aTHX_ ctx, object);
/* Launch eventloop; call only returns after eventloop terminates. */
eventloop_run(ctx);
} while (0);
if (!ok) {
if (try_catch.HasCaught()) {
ReportException(aTHX_ ctx, &try_catch);
#if 0
String::Utf8Value error(ctx->isolate, try_catch.Exception());
pl_show_error(ctx, *error);
#endif
}
}
delete origin;
return ret;
}
int pl_run_function(V8Context* ctx, Persistent<Function>& func)
{
dTHX;
HandleScope handle_scope(ctx->isolate);
Local<Context> context = Local<Context>::New(ctx->isolate, *ctx->persistent_context);
Context::Scope context_scope(context);
TryCatch try_catch(ctx->isolate);
Local<Value> result;
bool ok = true;
do {
Local<Value> global = context->Global();
Local<Function> v8_func = Local<Function>::New(ctx->isolate, func);
ok = v8_func->Call(context, global, 0, 0).ToLocal(&result);
if (!ok) {
break;
}
} while (0);
if (!ok) {
if (try_catch.HasCaught()) {
ReportException(aTHX_ ctx, &try_catch);
#if 0
String::Utf8Value error(ctx->isolate, try_catch.Exception());
pl_show_error(ctx, *error);
#endif
}
}
return ok;
}