📄 jsicontext.cpp
字号:
// Copy simple variables
runtime = rt;
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 + -