source: trunk/FACT++/src/InterpreterV8.cc@ 14103

Last change on this file since 14103 was 14103, checked in by tbretz, 12 years ago
Added qos to service-object.
File size: 14.9 KB
Line 
1#include "InterpreterV8.h"
2
3#include <boost/tokenizer.hpp>
4
5InterpreterV8 *InterpreterV8::This = 0;
6
7#ifdef HAVE_V8
8
9#include <v8.h>
10#include <fstream>
11#include <sstream>
12#include <iomanip>
13
14using namespace std;
15using namespace v8;
16
17bool InterpreterV8::ReportException(TryCatch* try_catch)
18{
19 const HandleScope handle_scope;
20
21 const String::Utf8Value exception(try_catch->Exception());
22
23 if (*exception && string(*exception)=="exit")
24 return true;
25
26 const Handle<Message> message = try_catch->Message();
27
28 // Print (filename):(line number): (message).
29 const String::Utf8Value filename(message->GetScriptResourceName());
30
31 ostringstream out;
32
33 if (*filename)
34 out << *filename;
35 if (!message.IsEmpty())
36 out << ": l." << message->GetLineNumber();
37 if (*exception)
38 out << ": " << *exception;
39
40 JsException(out.str());
41
42 if (message.IsEmpty())
43 return false;
44
45 // Print line of source code.
46 const String::Utf8Value sourceline(message->GetSourceLine());
47 if (*sourceline)
48 JsException(*sourceline);
49
50 // Print wavy underline (GetUnderline is deprecated).
51 const int start = message->GetStartColumn();
52 const int end = message->GetEndColumn();
53
54 out.str("");
55 if (start>0)
56 out << setfill(' ') << setw(start) << ' ';
57 out << setfill('^') << setw(end-start) << '^';
58
59 JsException(out.str());
60
61 String::Utf8Value stack_trace(try_catch->StackTrace());
62 if (stack_trace.length()<=0)
63 return false;
64
65 //if (*stack_trace)
66 // JsException(string("\n")+*stack_trace);
67
68 return false;
69}
70
71// Executes a string within the current v8 context.
72bool InterpreterV8::ExecuteStringNT(const Handle<String> &code, const Handle<Value> &file)
73{
74 if (code.IsEmpty())
75 return true;
76
77 const HandleScope handle_scope;
78
79 const Handle<Script> script = Script::Compile(code, file);
80 if (script.IsEmpty())
81 return false;
82
83 const Handle<Value> result = script->Run();
84 if (result.IsEmpty())
85 return false;
86
87 // If all went well and the result wasn't undefined then print
88 // the returned value.
89 if (!result->IsUndefined())
90 JsResult(*String::Utf8Value(result));
91
92 return true;
93}
94
95bool InterpreterV8::ExecuteCode(const Handle<String> &code, const Handle<Value> &file)
96{
97 TryCatch exception;
98
99 const bool rc = ExecuteStringNT(code, file);
100
101 if (!exception.CanContinue())
102 return false;
103
104 if (exception.HasCaught())
105 return ReportException(&exception);
106
107 return rc;
108}
109
110bool InterpreterV8::ExecuteCode(const string &code, const string &file)
111{
112 return ExecuteCode(String::New(code.c_str(), code.size()),
113 String::New(file.c_str()));
114}
115
116bool InterpreterV8::ExecuteFile(const string &name)
117{
118 ifstream fin(name.c_str());
119 if (!fin)
120 {
121 JsException("Error - Could not open file '"+name+"'");
122 return false;
123 }
124
125 string buffer;
126 if (!getline(fin, buffer, '\0'))
127 return true;
128
129 if (fin.fail())
130 {
131 JsException("Error - reading file.");
132 return false;
133 }
134
135 return ExecuteCode(buffer, name);
136}
137
138Handle<Value> InterpreterV8::FuncWait(const Arguments& args)
139{
140 if (args.Length()!=2 && args.Length()!=3)
141 return ThrowException(String::New("Number of arguments must be 2 or 3."));
142
143 if (!args[0]->IsString())
144 return ThrowException(String::New("Argument 1 not a string."));
145
146 if (!args[1]->IsInt32())
147 return ThrowException(String::New("Argument 2 not an int32."));
148
149 if (args.Length()==3 && !args[2]->IsUint32())
150 return ThrowException(String::New("Argument 3 not an uint32."));
151
152 const string server = *String::Utf8Value(args[0]);
153 const int32_t state = args[1]->Int32Value();
154 const uint32_t millisec = args.Length()==3 ? args[2]->Int32Value() : 0;
155
156 const int rc = JsWait(server, state, millisec);
157
158 if (rc==0 || rc==1)
159 return Boolean::New(rc);
160
161 return ThrowException(String::New(("Waitig for state "+to_string(state)+" of server '"+server+"' failed.").c_str()));
162}
163
164Handle<Value> InterpreterV8::FuncSend(const Arguments& args)
165{
166 if (args.Length()==0)
167 return ThrowException(String::New("Number of arguments must be at least 1."));
168
169 if (!args[0]->IsString())
170 return ThrowException(String::New("Argument 1 must be a string."));
171
172 const HandleScope handle_scope;
173
174 const String::Utf8Value str(args[0]);
175
176 string command = *str;
177
178 for (int i=1; i<args.Length(); i++)
179 {
180 const String::Utf8Value arg(args[i]);
181 command += " \""+string(*arg)+"\"";
182 }
183
184 return Boolean::New(JsSend(command));
185}
186
187Handle<Value> InterpreterV8::FuncSleep(const Arguments& args)
188{
189 if (args.Length()!=1)
190 return ThrowException(String::New("Number of arguments must be exactly 1."));
191
192 if (!args[0]->IsUint32())
193 return ThrowException(String::New("Argument 1 must be an uint32."));
194
195 JsSleep(args[0]->Int32Value());
196
197 return Undefined();
198}
199
200Handle<Value> InterpreterV8::FuncState(const Arguments& args)
201{
202 if (args.Length()!=1)
203 return ThrowException(String::New("Number of arguments must be exactly 1."));
204
205 if (!args[0]->IsString())
206 return ThrowException(String::New("Argument 1 must be a string."));
207
208 // Return state.name/state.index
209
210 HandleScope handle_scope;
211
212 const String::Utf8Value str(args[0]);
213
214 const pair<int32_t, string> rc = JsState(*str);
215
216 Handle<ObjectTemplate> obj = ObjectTemplate::New();
217
218
219 obj->Set(String::New("index"), rc.first<=-256?Undefined():Integer::New(rc.first), ReadOnly);
220 obj->Set(String::New("name"), rc.first<=-256?Undefined():String::New(rc.second.c_str()), ReadOnly);
221 //obj->Set(String::New("toString"), String::New(("[Object state "+string(*str)+"]").c_str()), ReadOnly);
222
223 return handle_scope.Close(obj->NewInstance());
224}
225
226Handle<Value> InterpreterV8::FuncExit(const Arguments &)
227{
228 v8::V8::TerminateExecution(fThreadId);
229 return ThrowException(String::New("exit"));
230/*
231 if (args.Length()!=1)
232 return ThrowException(String::New("Number of arguments must be exactly 1."));
233
234 if (!args[0]->IsUint32())
235 return ThrowException(String::New("Argument 1 must be an uint32."));
236
237 const HandleScope handle_scope;
238
239 JsSleep(args[0]->Int32Value());
240*/
241 return Undefined();
242}
243
244// The callback that is invoked by v8 whenever the JavaScript 'print'
245// function is called. Prints its arguments on stdout separated by
246// spaces and ending with a newline.
247Handle<Value> InterpreterV8::FuncPrint(const Arguments& args)
248{
249 for (int i=0; i<args.Length(); i++)
250 {
251 const HandleScope handle_scope;
252
253 const String::Utf8Value str(args[i]);
254 if (*str)
255 JsPrint(*str);
256 }
257 return Undefined();
258}
259
260// The callback that is invoked by v8 whenever the JavaScript 'load'
261// function is called. Loads, compiles and executes its argument
262// JavaScript file.
263Handle<Value> InterpreterV8::FuncInclude(const Arguments& args)
264{
265 for (int i = 0; i<args.Length(); i++)
266 {
267 const HandleScope handle_scope;
268
269 const String::Utf8Value file(args[i]);
270 if (*file == NULL)
271 return ThrowException(String::New(("Error loading file '"+string(*file)+"'").c_str()));
272
273 if (!ExecuteFile(*file))
274 return ThrowException(String::New(("Execution of '"+string(*file)+"' failed").c_str()));
275 }
276 return Undefined();
277}
278
279Handle<Value> InterpreterV8::FuncVersion(const Arguments&)
280{
281 return String::New(V8::GetVersion());
282}
283
284Handle<Value> Convert(char type, const char* &ptr)
285{
286 switch (type)
287 {
288 case 'F': { Handle<Value> v=Number::New(*reinterpret_cast<const float*>(ptr)); ptr+=4; return v; }
289 case 'D': { Handle<Value> v=Number::New(*reinterpret_cast<const double*>(ptr)); ptr+=8; return v; }
290 case 'I': {
291 case 'L': Handle<Value> v=Integer::New(*reinterpret_cast<const uint32_t*>(ptr)); ptr += 4; return v; }
292 case 'X': { Handle<Value> v=Integer::New(*reinterpret_cast<const uint64_t*>(ptr)); ptr += 8; return v; }
293 case 'S': { Handle<Value> v=Integer::New(*reinterpret_cast<const uint16_t*>(ptr)); ptr += 2; return v; }
294 case 'C': { Handle<Value> v=Integer::New((uint16_t)*reinterpret_cast<const uint8_t*>(ptr)); ptr += 1; return v; }
295 case ':': { Handle<Value> v=String::New(ptr); return v; }
296 }
297 return Undefined();
298}
299
300
301Handle<Value> InterpreterV8::FuncClose(const Arguments &args)
302{
303 HandleScope handle_scope;
304
305 const String::Utf8Value str(args.Holder()->Get(String::New("name")));
306 return Boolean::New(JsUnsubscribe(*str));
307}
308
309Handle<Value> InterpreterV8::FuncGetData(const Arguments &args)
310{
311 HandleScope handle_scope;
312
313 const String::Utf8Value str(args.Holder()->Get(String::New("name")));
314
315 const pair<uint64_t, EventImp *> p = JsGetEvent(*str);
316
317 const EventImp *evt = p.second;
318 if (!evt)
319 return Undefined();
320
321 //if (counter==cnt)
322 // return info.Holder();//Holder()->Get(String::New("data"));
323 //cout << counter << " " << cnt << endl;
324
325 //const void *ppp = Local<External>::Cast(info.This()->GetInternalField(0))->Value();
326 //info.This()->SetInternalField(0, External::New((void*)evt));
327 //cout << info.This().
328
329 const vector<Description> vec = JsDescription(*str);
330
331 Handle<Array> ret = Array::New();
332 ret->Set(String::New("format"), String::New(evt->GetFormat().c_str()), ReadOnly);
333 ret->Set(String::New("named"), Boolean::New(vec.size()>0), ReadOnly);
334 ret->Set(String::New("counter"), Integer::New(p.first), ReadOnly);
335 ret->Set(String::New("time"), Date::New(evt->GetJavaDate()), ReadOnly);
336 ret->Set(String::New("qos"), Interger::New(evt->GetQoS()), ReadOnly);
337
338 typedef boost::char_separator<char> separator;
339 const boost::tokenizer<separator> tokenizer(evt->GetFormat(), separator(";:"));
340
341 const vector<string> tok(tokenizer.begin(), tokenizer.end());
342
343 Handle<Array> obj = tok.size()==1 ? ret : Array::New();
344
345 const char *ptr = evt->GetText();
346 try
347 {
348 size_t pos = 1;
349 for (auto it=tok.begin(); it!=tok.end(); it++, pos++)
350 {
351 char type = (*it)[0];
352 it++;
353
354 if (it==tok.end() && type=='C')
355 type = ':';
356
357 if (it==tok.end() && type!=':')
358 return ThrowException(String::New(("Format string invalid '"+evt->GetFormat()+"'").c_str()));
359
360 string name = pos<vec.size() ? vec[pos].name : "";
361 if (tok.size()==1)
362 name = "data";
363
364 const uint32_t cnt = it==tok.end() ? 1 : stoi(it->c_str());
365
366 if (cnt==1)
367 {
368 const Handle<Value> v = Convert(type, ptr);
369 if (tok.size()>1)
370 obj->Set(pos-1, v);
371 if (!name.empty())
372 obj->Set(String::New(name.c_str()), v);
373 }
374 else
375 {
376 Handle<Array> a = Array::New(cnt);
377 for (uint32_t i=0; i<cnt; i++)
378 a->Set(i, Convert(type, ptr));
379 if (tok.size()>1)
380 obj->Set(pos-1, a);
381 if (!name.empty())
382 obj->Set(String::New(name.c_str()), a);
383 }
384
385 if (it==tok.end())
386 break;
387 }
388
389 if (tok.size()>1)
390 ret->Set(String::New("data"), obj, ReadOnly);
391
392 return handle_scope.Close(ret);
393 }
394 catch (...)
395 {
396 return ThrowException(String::New(("Format string conversion '"+evt->GetFormat()+"' failed.").c_str()));
397 }
398}
399
400/*
401void Cleanup( Persistent<Value> object, void *parameter )
402{
403 cout << "======================> RemoveMyObj()" << endl;
404}*/
405
406Handle<Value> InterpreterV8::FuncOpen(const Arguments &args)
407{
408 if (args.Length()!=1)
409 return ThrowException(String::New("Number of arguments must be exactly 1."));
410
411 if (!args[0]->IsString())
412 return ThrowException(String::New("Argument 1 must be a string."));
413
414 //if (!args.IsConstructCall())
415 // return ThrowException(String::New("Must be used as constructor."));
416
417 HandleScope handle_scope;
418
419 const String::Utf8Value str(args[0]);
420
421 JsSubscribe(*str);
422
423 //args.This()->SetInternalField(0, External::New((void*)test));
424 //obj->SetInternalFieldCount(1);
425
426 Handle<ObjectTemplate> obj = ObjectTemplate::New();
427 obj->Set(String::New("get"), FunctionTemplate::New(WrapGetData), ReadOnly);
428 obj->Set(String::New("close"), FunctionTemplate::New(WrapClose), ReadOnly);
429 obj->Set(String::New("name"), String::New(*str), ReadOnly);
430 //obj->Set(String::New("toString"), String::New(("[object Dim "+string(*str)+"]").c_str()), ReadOnly);
431
432 return obj->NewInstance();
433
434 // Persistent<Object> p = Persistent<Object>::New(obj->NewInstance());
435 // obj.MakeWeak((void*)1, Cleanup);
436 // return obj;
437}
438
439bool InterpreterV8::JsRun(const string &filename, const map<string, string> &map)
440{
441 v8::Locker locker;
442 fThreadId = V8::GetCurrentThreadId();
443
444 JsLoad(filename);
445
446 HandleScope handle_scope;
447
448 // Create a template for the global object.
449 Handle<ObjectTemplate> dim = ObjectTemplate::New();
450 dim->Set(String::New("print"), FunctionTemplate::New(WrapPrint), ReadOnly);
451 dim->Set(String::New("wait"), FunctionTemplate::New(WrapWait), ReadOnly);
452 dim->Set(String::New("send"), FunctionTemplate::New(WrapSend), ReadOnly);
453 dim->Set(String::New("state"), FunctionTemplate::New(WrapState), ReadOnly);
454 dim->Set(String::New("sleep"), FunctionTemplate::New(WrapSleep), ReadOnly);
455 dim->Set(String::New("open"), FunctionTemplate::New(WrapOpen), ReadOnly);
456
457 Handle<ObjectTemplate> global = ObjectTemplate::New();
458 global->Set(String::New("dim"), dim, ReadOnly);
459 global->Set(String::New("include"), FunctionTemplate::New(WrapInclude), ReadOnly);
460 global->Set(String::New("exit"), FunctionTemplate::New(WrapExit), ReadOnly);
461 global->Set(String::New("version"), FunctionTemplate::New(InterpreterV8::FuncVersion), ReadOnly);
462
463 // Persistent
464 Handle<Context> context = Context::New(NULL, global);
465 if (context.IsEmpty())
466 {
467 //printf("Error creating context\n");
468 return false;
469 }
470
471 v8::Context::Scope scope(context);
472
473 Local<Array> args = Array::New(map.size());
474 for (auto it=map.begin(); it!=map.end(); it++)
475 args->Set(String::New(it->first.c_str()), String::New(it->second.c_str()));
476 context->Global()->Set(String::New("$"), args, ReadOnly);
477 context->Global()->Set(String::New("arg"), args, ReadOnly);
478
479 JsStart(filename);
480
481 //context->Enter();
482 v8::Locker::StartPreemption(10);
483 const bool rc = ExecuteFile(filename);
484 v8::Locker::StopPreemption();
485 //context->Exit();
486
487 //context.Dispose();
488
489 cout << "JsEnd" << endl;
490 JsEnd(filename);
491
492 return rc;
493}
494
495void InterpreterV8::JsStop()
496{
497 v8::Locker locker;
498 //cout << "Terminate " << fThreadId << endl;
499 if (This->fThreadId>=0)
500 v8::V8::TerminateExecution(This->fThreadId);
501 //cout << "Terminate " << fThreadId << endl;
502 v8::Unlocker unlocker;
503}
504
505#endif
506
Note: See TracBrowser for help on using the repository browser.