~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to plugin/js_eval/js_eval.cc

  • Committer: Henrik Ingo
  • Date: 2011-09-02 10:32:57 UTC
  • mto: This revision was merged to the branch mainline in revision 2439.
  • Revision ID: henrik.ingo@avoinelama.fi-20110902103257-1i044y2jkrdn9ot6
Honoring EcmaScript standard arguments are made available as arguments[]
(was argv[])

Named parameters become global variables, as in
js_eval( "myvalue+anothervalue", 1 as 'myvalue', 2 as 'anothervalue')

Integers and real/decimal values passed as appropriate JS counterparts.
This makes js '+' operator work correctly.

Added whitespace to if() and function calls, sorry for noise in the diff.

Show diffs side-by-side

added added

removed removed

Lines of Context:
137
137
 * @param res Pointer to the drizzled::String object that will contain the result
138
138
 * @return a drizzled::String containing the value returned by executed JavaScript code (value of last executed statement) 
139
139
 */
140
 
String *JsEvalFunction::val_str(String *str)
 
140
String *JsEvalFunction::val_str( String *str )
141
141
{
142
 
  assert(fixed == 1);
 
142
  assert( fixed == 1 );
143
143
  // If we return from any of the error conditions during method, then 
144
144
  // return value of the drizzle function is null.
145
145
  null_value= true; 
146
146
  
147
147
  String *source_str=NULL;
148
 
  source_str = args[0]->val_str(str); 
 
148
  source_str = args[0]->val_str( str ); 
149
149
  
150
150
  // TODO Some of this (ObjectTemplate bindings) should probably be 
151
151
  // moved to initialize, but then it must be allocated on the heap.
164
164
  v8::Handle<v8::ObjectTemplate> db = v8::ObjectTemplate::New();
165
165
  v8::Handle<v8::ObjectTemplate> js = v8::ObjectTemplate::New();
166
166
  // Bind the 'version' function 
167
 
  global->Set(v8::String::New("db"), db);
168
 
  db->Set(v8::String::New("js"), js);
169
 
  js->Set(v8::String::New("version"), v8::FunctionTemplate::New(V8Version));
170
 
  js->Set(v8::String::New("engine"), v8::FunctionTemplate::New(JsEngine));
 
167
  global->Set( v8::String::New("db"), db );
 
168
  db->Set( v8::String::New("js"), js );
 
169
  js->Set( v8::String::New("version"), v8::FunctionTemplate::New(V8Version) );
 
170
  js->Set( v8::String::New("engine"), v8::FunctionTemplate::New(JsEngine) );
171
171
  
172
172
  // Now bind the arguments into argv[]
173
173
  // v8::Array can only be created when context is already entered (otherwise v8 segfaults!)
174
 
  v8::Persistent<v8::Context> context = v8::Context::New(NULL, global);
175
 
  if (context.IsEmpty()) {
 
174
  v8::Persistent<v8::Context> context = v8::Context::New( NULL, global );
 
175
  if ( context.IsEmpty() ) {
176
176
    // TODO: how do I set warning/error in the drizzle result?
177
 
    printf("Error in js_eval() while creating JavaScript context in v8.\n");
 
177
    printf( "Error in js_eval() while creating JavaScript context in v8.\n" );
178
178
    return NULL;
179
179
  }
180
180
  context->Enter();
182
182
  v8::Handle<v8::Array> a = v8::Array::New(arg_count-1);
183
183
  for( uint64_t n = 1; n < arg_count; n++ )
184
184
  {
185
 
    a->Set(n-1, v8::String::New(args[n]->val_str(str)->c_str()));
 
185
    // Need to do this differently for ints, doubles and strings
 
186
    // TODO: There is also ROW_RESULT. Is that relevant here? What does it look like? I could pass rows as an array or object.
 
187
    if( args[n]->result_type() == INT_RESULT ){
 
188
      if( args[n]->is_unsigned() ) {
 
189
        a->Set( n-1, v8::Integer::NewFromUnsigned( (uint32_t) args[n]->val_uint() ) );
 
190
      } else {
 
191
        a->Set( n-1, v8::Integer::New((int32_t)args[n]->val_int() ) );
 
192
      }
 
193
    } else if ( args[n]->result_type() == REAL_RESULT || args[n]->result_type() == DECIMAL_RESULT ) {
 
194
      a->Set( n-1, v8::Number::New(args[n]->val_real() ) );
 
195
    // TODO: Here's a question: Should DECIMAL_RESULT be sent as double or string?
 
196
    // Kind of unusable either way, we'd need to bind some biginteger arithmetic library into the js environment to make them usable
 
197
    } else if ( true || args[n]->result_type() == STRING_RESULT ) {
 
198
      // Default to creating string values in JavaScript
 
199
      a->Set( n-1, v8::String::New(args[n]->val_str(str)->c_str() ) );
 
200
    }
 
201
    // If user has given a name to the arguments, pass these as global variables
 
202
    if( ! args[n]->is_autogenerated_name ) {
 
203
      if( args[n]->result_type() == INT_RESULT ){
 
204
        if( args[n]->is_unsigned() ) {
 
205
          context->Global()->Set( v8::String::New(args[n]->name ), v8::Integer::NewFromUnsigned( (uint32_t) args[n]->val_uint() ) );
 
206
        } else {
 
207
          context->Global()->Set( v8::String::New(args[n]->name ), v8::Integer::New((int32_t)args[n]->val_int() ) );
 
208
        }
 
209
      } else if ( args[n]->result_type() == REAL_RESULT || args[n]->result_type() == DECIMAL_RESULT ) {
 
210
        context->Global()->Set( v8::String::New(args[n]->name ), v8::Number::New(args[n]->val_real() ) );
 
211
      } else if ( true || args[n]->result_type() == STRING_RESULT ) {
 
212
        context->Global()->Set( v8::String::New(args[n]->name ), v8::String::New(args[n]->val_str(str)->c_str() ) );
 
213
      }
 
214
    }
186
215
  }
187
216
  //Need to fetch the global element back from context, global doesn't work anymore
188
 
  context->Global()->Set(v8::String::New("argv"), a);
 
217
  context->Global()->Set( v8::String::New("arguments"), a );
189
218
 
190
219
  
191
220
  
196
225
  // Convert from drizzled::String to char* string to v8::String.
197
226
  v8::Handle<v8::String> source = v8::String::New(source_str->c_str());
198
227
  v8::Handle<v8::Script> script = v8::Script::Compile(source);
199
 
  if (script.IsEmpty()) {
 
228
  if ( script.IsEmpty() ) {
200
229
    // TODO: how do I set warning/error in the drizzle result?
201
230
    // Print errors that happened during compilation.
202
231
    ReportException(&try_catch);
203
232
    return NULL;
204
233
  } else {
205
234
    result = script->Run();
206
 
    if (result.IsEmpty()) {
207
 
      assert(try_catch.HasCaught());
 
235
    if ( result.IsEmpty() ) {
 
236
      assert( try_catch.HasCaught() );
208
237
      // TODO: how do I set warning/error in the drizzle result?
209
238
      // Print errors that happened during execution.
210
 
      ReportException(&try_catch);
 
239
      ReportException( &try_catch );
211
240
      // Dispose of Persistent objects before returning. (Is it needed?)
212
241
      context->Exit();
213
242
      context.Dispose();
214
243
      return NULL;
215
244
    } else {
216
 
      assert(!try_catch.HasCaught());
217
 
      if (result->IsUndefined()) {
218
 
        printf("js_eval() got Undefined result back from v8.\n");
 
245
      assert( !try_catch.HasCaught() );
 
246
      if ( result->IsUndefined() ) {
 
247
        // Nothing wrong here, but we return Undefined as NULL.
219
248
        // Dispose of Persistent objects before returning. (Is it needed?)
220
249
        context->Exit();
221
250
        context.Dispose();
231
260
  // Convert the result to a drizzled::String and print it.
232
261
  // Allocate space to the drizzled::String 
233
262
  str->free(); //TODO: Check the source for alloc(), but apparently I don't need this line?
234
 
  str->alloc(rstring->Utf8Length());
 
263
  str->alloc( rstring->Utf8Length() );
235
264
  // Now copy string from v8 heap to drizzled heap
236
 
  rstring->WriteUtf8(str->ptr());
 
265
  rstring->WriteUtf8( str->ptr() );
237
266
  // drizzled::String doesn't actually set string length properly in alloc(), so set it now
238
 
  str->length(rstring->Utf8Length());
 
267
  str->length( rstring->Utf8Length() );
239
268
 
240
269
  context->Exit();
241
270
  context.Dispose();
250
279
 
251
280
plugin::Create_function<JsEvalFunction> *js_eval_function = NULL;
252
281
 
253
 
static int initialize(module::Context &context)
 
282
static int initialize( module::Context &context )
254
283
{
255
 
  js_eval_function = new plugin::Create_function<JsEvalFunction>("js_eval");
256
 
  context.add(js_eval_function);
 
284
  js_eval_function = new plugin::Create_function<JsEvalFunction>( "js_eval" );
 
285
  context.add( js_eval_function );
257
286
  // Initialize V8
258
287
  v8::V8::Initialize();
259
288
  return 0;
262
291
 
263
292
/* v8 related functions ********************************/
264
293
 
265
 
v8::Handle<v8::Value> V8Version(const v8::Arguments&) {
266
 
  return v8::String::New(v8::V8::GetVersion());
 
294
v8::Handle<v8::Value> V8Version( const v8::Arguments& ) {
 
295
  return v8::String::New( v8::V8::GetVersion() );
267
296
}
268
297
 
269
 
v8::Handle<v8::Value> JsEngine(const v8::Arguments&) {
270
 
  return v8::String::New(JS_ENGINE);
 
298
v8::Handle<v8::Value> JsEngine( const v8::Arguments& ) {
 
299
  return v8::String::New( JS_ENGINE );
271
300
}
272
301
 
273
302