📄 jsicontext.cpp
字号:
maxBranches = mb; // Base logging class initialization SetLog (l, diagTagBase); Diag (SBJSI_LOG_CONTEXT, L"JsiContext::Create", L"start 0x%p", this); // Create the context VXIjsiResult rc = runtime->NewContext (contextSize, &context); if ( rc != VXIjsi_RESULT_SUCCESS ) return rc; // Lock the context for access #ifdef JS_THREADSAFE JS_BeginRequest (context); #else if ( AccessBegin( ) != true ) rc = VXIjsi_RESULT_SYSTEM_ERROR; #endif // Attach this as private data to the context for use in callbacks if ( rc == VXIjsi_RESULT_SUCCESS ) JS_SetContextPrivate (context, this); // Set the callback to enforce maxBranches if ( rc == VXIjsi_RESULT_SUCCESS ) JS_SetBranchCallback (context, JsiContext::BranchCallback); // Set the callback for reporting errors if ( rc == VXIjsi_RESULT_SUCCESS ) JS_SetErrorReporter (context, JsiContext::ErrorReporter); // Add JSOPTION_STRICT to enable strictness, which provides // additional warnings/errors. // // TBD make these flags run-time configurable? Would be helpful for // migrating older apps to VoiceXML 2.0 April 2002 (April 2002 // requires declaring variables prior to use, older VoiceXML does // not). #if defined(JSI_MUST_DECLARE_VARS) || defined(JSI_STRICT) if ( rc == VXIjsi_RESULT_SUCCESS ) JS_SetOptions (context, #if defined(JSI_MUST_DECLARE_VARS) || defined(JSI_STRICT) #if defined(SWI_JSOPTION_MUST_DECLARE_VARS) SWI_JSOPTION_MUST_DECLARE_VARS | JSOPTION_STRICT #else JSOPTION_STRICT #endif #else #ifdef JSI_MUST_DECLARE_VARS #ifdef SWI_JSOPTION_MUST_DECLARE_VARS SWI_JSOPTION_MUST_DECLARE_VARS #endif #endif #ifdef JSI_STRICT JSOPTION_STRICT #endif #endif ); #endif // Create and intialize the global scope we require in the context, // the scope chain node object locks it to protect it from the // garbage collector if ( rc == VXIjsi_RESULT_SUCCESS ) { JSObject *globalScope = JS_NewObject (context, &SCOPE_CLASS, NULL, NULL); if ( ! globalScope ) rc = VXIjsi_RESULT_OUT_OF_MEMORY; else { Diag (SBJSI_LOG_SCOPE, L"JsiContext::Create", L"global scope 0x%p, context 0x%p", globalScope, context); scopeChain = new JsiScopeChainNode (context, NULL, GLOBAL_SCOPE_NAME_W); if ( scopeChain ) { rc = scopeChain->Create (globalScope); if ( rc == VXIjsi_RESULT_SUCCESS ) { if ( JS_SetPrivate (context, globalScope, scopeChain) ) currentScope = scopeChain; else rc = VXIjsi_RESULT_FATAL_ERROR; } } else { rc = VXIjsi_RESULT_OUT_OF_MEMORY; } } } // Initialize the standard JavaScript classes, like Array, Math, String, etc. if (( rc == VXIjsi_RESULT_SUCCESS ) && ( ! JS_InitStandardClasses (context, currentScope->GetJsobj( )) )) rc = VXIjsi_RESULT_OUT_OF_MEMORY; // Set version only after there is a valid global scope object if (( rc == VXIjsi_RESULT_SUCCESS ) && ( version != JSVERSION_DEFAULT )) JS_SetVersion (context, version); // On failure, destroy the context here to avoid use of it if ( rc != VXIjsi_RESULT_SUCCESS ) { if ( context ) { #ifdef JS_THREADSAFE JS_EndRequest (context); #endif runtime->DestroyContext (&context); } } #ifdef JS_THREADSAFE else { contextRefs = JS_SuspendRequest (context); } #else if ( AccessEnd( ) != true ) rc = VXIjsi_RESULT_SYSTEM_ERROR; #endif Diag (SBJSI_LOG_CONTEXT, L"JsiContext::Create", L"end 0x%p, JS context 0x%p", this, context); return rc; } // Create a script variable relative to the current scope VXIjsiResult JsiContext::CreateVar (const VXIchar *name, const VXIchar *expr) { if (( name == NULL ) || ( name[0] == 0 )) return VXIjsi_RESULT_INVALID_ARGUMENT; // If this is a fully qualified name, just do a SetVar( ) as that // handles explicitly scoped variables and this doesn't. No // functional effect to doing so, the only difference is that // CreateVar( ) masks vars of the same name from prior scopes when // SetVar( ) just sets the old one, having an explicit scope makes // that irrelevant since then JS knows exactly what to do. if ( wcschr (name, L'.') ) return SetVar (name, expr); if ( AccessBegin( ) == false ) return VXIjsi_RESULT_SYSTEM_ERROR; // Evaluate the expression, need to eval before setting so we can // deal with things like "1; 2;" which can't be handled if we just // make a temporary script VXIjsiResult rc = VXIjsi_RESULT_SUCCESS; JsiProtectedJsval val (context); // Check if the current scope is writeable rc = CheckWriteable(context, currentScope->GetJsobj(), name); if ( rc == VXIjsi_RESULT_SUCCESS && ( expr != NULL ) && ( expr[0] != 0 )) rc = EvaluateScript (expr, &val); // Set the variable in the current scope directly, ensures we mask // any var of the same name from earlier scopes if ( rc == VXIjsi_RESULT_SUCCESS ) { if( IsValidVarName(context, currentScope->GetJsobj( ), name) ) { GET_JSCHAR_FROM_VXICHAR(tmpname, tmpnamelen, name); if (! JS_DefineUCProperty (context, currentScope->GetJsobj( ), tmpname, tmpnamelen, val.Get( ), NULL, NULL, JSPROP_ENUMERATE) ) rc = VXIjsi_RESULT_OUT_OF_MEMORY; } else rc = VXIjsi_RESULT_SYNTAX_ERROR; } // Must unroot before unlocking val.Clear( ); if ( AccessEnd( ) == false ) rc = VXIjsi_RESULT_SYSTEM_ERROR; return rc; } // Create a script variable relative to the current scope VXIjsiResult JsiContext::CreateVar (const VXIchar *name, const VXIValue *value) { if (( name == NULL ) || ( name[0] == 0 )) return VXIjsi_RESULT_INVALID_ARGUMENT; // If this is a fully qualified name, just do a SetVar( ) as that // handles explicitly scoped variables and this doesn't. No // functional effect to doing so, the only difference is that // CreateVar( ) masks vars of the same name from prior scopes when // SetVar( ) just sets the old one, having an explicit scope makes // that irrelevant since then JS knows exactly what to do. if ( wcschr (name, L'.') ) return SetVar (name, value); if ( AccessBegin( ) == false ) return VXIjsi_RESULT_SYSTEM_ERROR; // Convert the value to a JavaScript variable VXIjsiResult rc = VXIjsi_RESULT_SUCCESS; JsiProtectedJsval val (context); // Check if the current scope is writeable rc = CheckWriteable(context, currentScope->GetJsobj(), name); if ( rc == VXIjsi_RESULT_SUCCESS && value ) rc = VXIValueToJsval (context, value, &val); // Set the variable in the current scope directly, ensures we mask // any var of the same name from earlier scopes if ( rc == VXIjsi_RESULT_SUCCESS ) { // check if variable name is valid if( IsValidVarName(context, currentScope->GetJsobj( ), name) ) { GET_JSCHAR_FROM_VXICHAR(tmpname, tmpnamelen, name); if ( ! JS_DefineUCProperty (context, currentScope->GetJsobj( ), tmpname, tmpnamelen, val.Get( ), NULL, NULL, JSPROP_ENUMERATE) ) rc = VXIjsi_RESULT_OUT_OF_MEMORY; } else rc = VXIjsi_RESULT_SYNTAX_ERROR; } // Must unroot before unlocking val.Clear( ); if ( AccessEnd( ) == false ) rc = VXIjsi_RESULT_SYSTEM_ERROR; return rc; } // Set a script variable relative to the current scope VXIjsiResult JsiContext::SetVar (const VXIchar *name, const VXIchar *expr) { if (( name == NULL ) || ( name[0] == 0 ) || ( expr == NULL ) || ( expr[0] == 0 )) return VXIjsi_RESULT_INVALID_ARGUMENT; if ( AccessBegin( ) == false ) return VXIjsi_RESULT_SYSTEM_ERROR; JsiProtectedJsval val (context); VXIjsiResult rc = VXIjsi_RESULT_SUCCESS; #ifdef JSI_MUST_DECLARE_VARS // Must declare the variable before attempt rc = EvaluateScript(name, &val, false); #endif // Evaluate the expression, need to eval before setting so we can // deal with things like "1; 2;" which can't be handled if we just // make a temporary script if( rc == VXIjsi_RESULT_SUCCESS ) rc = EvaluateScript (expr, &val); // Check if the current scope is writeable if( rc == VXIjsi_RESULT_SUCCESS ) rc = CheckWriteable(context, currentScope->GetJsobj(), name); // What we'd like to do is lookup the variable, then set it to the // jsval we got above. (The lookup is complex because it could be // a partially or fully qualified name, with potential scope // chain/prototype chain lookups.) However, that isn't possible in // SpiderMonkey. So instead we set a temporary variable in the // global scope, then assign the specified object to that, then // destroy the temporary. if ( rc == VXIjsi_RESULT_SUCCESS ) { if ( JS_DefineProperty (context, currentScope->GetJsobj( ), GLOBAL_TEMP_VAR, val.Get( ), NULL, NULL, 0) ) { // Do the copy using a temporary script SBjsiString script (name); script += L"="; script += GLOBAL_TEMP_VAR_W; rc = EvaluateScript (script.c_str( ), NULL); // Destroy the temporary variable jsval ignored = JSVAL_VOID; if ( ! JS_DeleteProperty2 (context, currentScope->GetJsobj( ), GLOBAL_TEMP_VAR, &ignored) ) rc = VXIjsi_RESULT_FATAL_ERROR; } else { rc = VXIjsi_RESULT_OUT_OF_MEMORY; } } // Must unroot before unlocking val.Clear( ); if ( AccessEnd( ) == false ) rc = VXIjsi_RESULT_SYSTEM_ERROR; return rc; } // Set a script variable relative to the current scope VXIjsiResult JsiContext::SetVar (const VXIchar *name, const VXIValue *value) { if (( name == NULL ) || ( name[0] == 0 ) || ( value == NULL )) return VXIjsi_RESULT_INVALID_ARGUMENT; if ( AccessBegin( ) == false ) return VXIjsi_RESULT_SYSTEM_ERROR; // Convert the value to a JavaScript variable JsiProtectedJsval val (context); VXIjsiResult rc = VXIjsi_RESULT_SUCCESS; #ifdef JSI_MUST_DECLARE_VARS rc = EvaluateScript(name, &val, false); #endif if( rc == VXIjsi_RESULT_SUCCESS ) rc = VXIValueToJsval (context, value, &val); // Check if the current scope is writeable if( rc == VXIjsi_RESULT_SUCCESS ) rc = CheckWriteable(context, currentScope->GetJsobj(), name); // What we'd like to do is lookup the variable, then set it to the // jsval we got above. (The lookup is complex because it could be // a partially or fully qualified name, with potential scope // chain/prototype chain lookups.) However, that isn't possible in // SpiderMonkey. So instead we set a temporary variable in the // global scope, then assign the specified object to that, then // destroy the temporary. if ( rc == VXIjsi_RESULT_SUCCESS ) { if ( JS_DefineProperty (context, currentScope->GetJsobj( ), GLOBAL_TEMP_VAR, val.Get( ), NULL, NULL, 0) ) { // Do the copy using a temporary script SBjsiString script (name); script += L"="; script += GLOBAL_TEMP_VAR_W; rc = EvaluateScript (script.c_str( ), NULL); // Destroy the temporary variable jsval ignored = JSVAL_VOID; if ( ! JS_DeleteProperty2 (context, currentScope->GetJsobj( ), GLOBAL_TEMP_VAR, &ignored) ) rc = VXIjsi_RESULT_FATAL_ERROR; } else { rc = VXIjsi_RESULT_OUT_OF_MEMORY; } } // Must unroot before unlocking val.Clear( ); if ( AccessEnd( ) == false ) rc = VXIjsi_RESULT_SYSTEM_ERROR; return rc; } // Set the given scope namespace to read-only attribute VXIjsiResult JsiContext::SetReadOnly(const VXIchar *name) const { if (( name == NULL ) || ( name[0] == 0 )) return VXIjsi_RESULT_INVALID_ARGUMENT; if ( AccessBegin( ) == false ) return VXIjsi_RESULT_SYSTEM_ERROR; // setting the attribute of the given object's name // to read-only status. By evaluating the object's name we'll // get to the correct scope. JSBool foundp; JsiProtectedJsval val (context); VXIjsiResult rc = EvaluateScript (name, &val); // Check if this variable is an object if( rc == VXIjsi_RESULT_SUCCESS && JSVAL_IS_OBJECT (val.Get()) ) { // Check if it is an instance of SCOPE_CLASS object JSObject *robj = JSVAL_TO_OBJECT(val.Get()); if( JS_InstanceOf (context, robj, &SCOPE_CLASS, NULL) ) { // find the parent node of the current scope because JS_SetUCPropertyAttributes // only works from top-down JsiScopeChainNode * prdata = (JsiScopeChainNode *) JS_GetPrivate(context, robj); if( prdata && prdata->GetParent()) { // Set the property to read-only JSObject *pobj = prdata->GetParent()->GetJsobj(); GET_JSCHAR_FROM_VXICHAR(tmpname, tmpnamelen, name); if( JS_SetUCPropertyAttributes(context, pobj, tmpname, tmpnamelen, JSPROP_ENUMERATE | JSPROP_READONLY, &foundp) ) { if( !foundp ) { rc = VXIjsi_RESULT_FAILURE; } } else rc = VXIjsi_RESULT_FAILURE; } } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -