📄 vxi.cpp
字号:
bool VXI::PushExecutionContext(const VXIMap * sessionArgs){ log->LogDiagnostic(2, L"VXI::PushExecutionContext()"); if (stackDepth >= MAX_EXE_STACK_DEPTH) { log->LogError(211); return false; } ExecutionContext * ep = new ExecutionContext(rec, jsi, *log, exe); if (ep == NULL) throw VXIException::OutOfMemory(); exe = ep; ++stackDepth; // Init new context from channel exe->script.PushScope(SCOPE_Session); if (sessionArgs != NULL && VXIMapNumProperties(sessionArgs) != 0) { const vxistring SESSIONDOT = vxistring(SCOPE_Session) + L"."; const VXIchar * key; const VXIValue * value; VXIMapIterator * i = VXIMapGetFirstProperty(sessionArgs, &key, &value); exe->script.SetValue(SESSIONDOT + key, value); while (VXIMapGetNextProperty(i, &key, &value) == VXIvalue_RESULT_SUCCESS) exe->script.SetValue(SESSIONDOT + key, value); VXIMapIteratorDestroy(&i); } log->LogDiagnostic(2, L"VXI::PushExecutionContext - session variables " L"initialized"); return true;}void VXI::PopExecutionContext(){ if (exe == NULL) return; ExecutionContext * current = exe; exe = current->next; --stackDepth; delete current;}void VXI::AttemptDocumentLoad(const vxistring & uri, const VXIMapHolder & uriProperties, VXMLDocument & doc, VXIMapHolder & docProperties, bool isDefaults){ // (1) Create map to store document properties. if (docProperties.GetValue() == NULL) throw VXIException::OutOfMemory(); // (2) Fetch the document int result = parser->FetchDocument(uri.c_str(), uriProperties, inet, *log, doc, docProperties, isDefaults); // (3) Handle error conditions. switch (result) { case -1: // Out of memory throw VXIException::OutOfMemory(); case 0: // Success break; case 1: // Invalid parameter case 2: // Unable to open URI log->LogError(203, SimpleLogger::URI, uri.c_str()); throw VXIException::InterpreterEvent(EV_ERROR_BADFETCH); case 3: // Unable to read from URI log->LogError(204, SimpleLogger::URI, uri.c_str()); throw VXIException::InterpreterEvent(EV_ERROR_BADFETCH); case 4: // Unable to parse contents of URI log->LogError(205, SimpleLogger::URI, uri.c_str()); throw VXIException::InterpreterEvent(EV_ERROR_BADFETCH); default: log->LogError(206, SimpleLogger::URI, uri.c_str()); throw VXIException::Fatal(); } if (doc.GetRoot() == 0) { log->LogError(999, SimpleLogger::MESSAGE, L"able to fetch initial document but node empty"); throw VXIException::Fatal(); }}void VXI::ProcessRootScripts(VXMLElement& doc){ if (doc == 0) return; log->LogDiagnostic(2, L"VXI::ProcessRootScripts()"); // Do <var> <script> and <meta> <property> elements for (VXMLNodeIterator it(doc); it; ++it) { VXMLNode child = *it; if (child.GetType() != VXMLNode::Type_VXMLElement) continue; const VXMLElement & elem = reinterpret_cast<const VXMLElement &>(child); VXMLElementType nodeName = elem.GetName(); if (nodeName == NODE_VAR) var_element(elem); else if (nodeName == NODE_META) meta_element(elem); else if (nodeName == NODE_SCRIPT) script_element(elem); } log->LogDiagnostic(2, L"VXI::ProcessRootScripts - done");}//#############################################################################// Dialog Loop//#############################################################################// There are two cases in which this routine may be entered.// A. After a new document is loaded (lastItem == 0)// B. After a return from <subdialog>// and three ways in which the loop may be re-entered.// 1. Jump to new dialog.// 2. Jump to new form item in the existing dialog.// 3. Jump to new dialog after recognizing a document scope grammar.//// The ECMA script scopes are reset accordingly:// anonymous: A B 1 2 3// local: A 1 2 3// dialog: A 1 3void VXI::RunInnerLoop(){ log->LogDiagnostic(2, L"VXI::RunInnerLoop()"); if (exe->currentDialog == 0) { log->LogError(999, SimpleLogger::MESSAGE, L"no current active document"); return; } int loop_count = 0; VXMLElement item = exe->lastItem; exe->lastItem = VXMLElement(); bool newDialog = (item == 0); exe->playingPrompts = true; // For passing answers. RecognitionAnswer unprocessedAnswer; bool usedDTMF = false; bool formLevelGrammar = false; while (1) { try { // (1) Check loop count. Throw event if exceeded, caught in DocumentLoop if (++loop_count > 4 * MAX_LOOP_ITERATIONS) { log->LogError(210); throw VXIException::InterpreterEvent(EV_ERROR_LOOP_COUNT); } try { if (exe->script.CurrentScope(SCOPE_Anonymous)) exe->script.PopScope(); // (2) Initialize dialog (if necessary) if (newDialog) { newDialog = false; exe->playingPrompts = true; // (2.1) Reset ECMA script scope. if (exe->script.CurrentScope(SCOPE_Local)) exe->script.PopScope(); if (exe->script.CurrentScope(SCOPE_Dialog)) exe->script.PopScope(); exe->script.PushScope(SCOPE_Dialog); // (2.2) Do 'initialization phase' from FIA. VXIMapHolder params(sdParams); sdParams = NULL; FormInit(exe->currentDialog, params); // (2.3) Do 'select phase' from FIA if the item is not already known if (item == 0) { DoInnerJump(exe->currentDialog, L""); break; } } // (3) The loop cases. if (!unprocessedAnswer.keys.empty()) { // (3.1) Re-entering loop with an unprocessed recognition result. RecognitionAnswer temp = unprocessedAnswer; unprocessedAnswer.Clear(); ProcessRecognitionResult(exe->currentDialog, formLevelGrammar ? VXMLElement() : item, usedDTMF, temp); } else if (sdResult != NULL) { // (3.2) Re-entering loop after returning from a <subdialog>. VXIValue * temp = sdResult; sdResult = NULL; ProcessReturn(exe->currentDialog, item, temp); } else { // (3.3) Each time we enter collect phase, we get fresh local scope. // All filled and catched triggered form here will execute in this // scope. The final local scope is popped with we leave. if (exe->script.CurrentScope(SCOPE_Local)) exe->script.PopScope(); exe->script.PushScope(SCOPE_Local); // Do the 'collect phase & process phase' from the FIA. CollectPhase(exe->currentDialog, item); } } catch (const VXIException::InterpreterEvent & e) { // Handles document events. if (log->IsLogging(2)) { log->StartDiagnostic(2) << L"VXI::RunInnerLoop - got exception: " << e.GetValue(); log->EndDiagnostic(); } if (item != 0) DoEvent(item, e); else DoEvent(exe->currentDialog, e); } DoInnerJump(exe->currentDialog, L""); break; } catch (JumpDialog & e) { // Handle <goto> events exe->currentDialog = e.dialog; item = VXMLElement(); newDialog = true; } catch (const JumpItem & e) { // This handles local <goto>s. item = e.item; } catch (AnswerInformation & e) { if (exe->currentDialog != e.dialog) { exe->currentDialog = e.dialog; item = e.element; newDialog = true; } unprocessedAnswer = e.recAnswer; usedDTMF = e.usedDTMF; formLevelGrammar = (e.dialog == e.element); } } // while (1) log->LogDiagnostic(2, L"VXI::RunInnerLoop - done");}void VXI::ProcessReturn(const VXMLElement& form, const VXMLElement & item, VXIValue * & result){ log->LogDiagnostic(2, L"VXI::ProcessReturn()"); if (VXIValueGetType(result) == VALUE_STRING) { const VXIString * temp = reinterpret_cast<const VXIString *>(result); throw VXIException::InterpreterEvent(toString(temp)); } vxistring filled; item.GetAttribute(ATTRIBUTE__ITEMNAME, filled); exe->script.SetValue(filled, result); VXIValueDestroy(&result); EasyFilled(filled, form);}// Perform initialization associated with property tags and form level// variables. Reset the event and prompts counts.//void VXI::FormInit(const VXMLElement & form, VXIMapHolder & params){ log->LogDiagnostic(2, L"VXI::FormInit()"); // (1) Set the form properties. exe->properties.SetProperties(form, DIALOG_PROP, VXIMapHolder()); // (2) Clear the prompt & event counts when the form is entered. exe->promptcounts.Clear(); exe->eventcounts.Clear(); exe->formitems.clear(); // (3) Walk through the form nodes. Set up variables as necessary. for (VXMLNodeIterator it(form); it; ++it) { VXMLNode child = *it; if (child.GetType() != VXMLNode::Type_VXMLElement) continue; const VXMLElement & elem = reinterpret_cast<const VXMLElement &>(child); // (3.1) Handle <var> elements. VXMLElementType nodeName = elem.GetName(); if (nodeName == NODE_VAR) { // (3.1.1) We first follow the normal proceedure. var_element(elem); if (params.GetValue() != NULL) { // (3.1.2) Undefined variables get set to the value in the param list. // Each located parameter gets removed from the map. vxistring name; elem.GetAttribute(ATTRIBUTE_NAME, name); if (!name.empty() && !exe->script.IsVarDefined(name)) { const VXIValue * value = VXIMapGetProperty(params.GetValue(), name.c_str()); if (value != NULL) { exe->script.SetValue(name, value); VXIMapDeleteProperty(params.GetValue(), name.c_str()); } } } continue; } // (3.2) Ignore anything which is not a form item. if (!IsFormItemNode(elem)) continue; // (3.3) Initialize variables for each form item. vxistring name; vxistring expr; elem.GetAttribute(ATTRIBUTE__ITEMNAME, name); elem.GetAttribute(ATTRIBUTE_EXPR, expr); exe->script.MakeVar(name, expr); exe->formitems.push_back(name); } // (4) Did all incoming parameters get used? if (params.GetValue() != NULL && VXIMapNumProperties(params.GetValue()) != 0) throw VXIException::InterpreterEvent(EV_ERROR_SEMANTIC); log->LogDiagnostic(2, L"VXI::FormInit - Done");}// Returns true iff the element is a form item.//// This is the list from section 6.2 of the VXML 1.0 specification with one// addition - <menu>.//bool VXI::IsFormItemNode(const VXMLElement & doc){ VXMLElementType nodeName = doc.GetName(); if (nodeName == NODE_FIELD || nodeName == NODE_INITIAL || nodeName == NODE_RECORD || nodeName == NODE_TRANSFER || nodeName == NODE_OBJECT || nodeName == NODE_SUBDIALOG || nodeName == NODE_MENU || nodeName == NODE_BLOCK) return true; return false;}// Finds the named form item within the dialog. If the name is empty, the// first non-filled item is returned.//void VXI::DoInnerJump(const VXMLElement & elem, const vxistring & item){ if (elem == 0) return; if (log->IsLogging(2)) { log->StartDiagnostic(2) << L"VXI::DoInnerJump(" << item << L")"; log->EndDiagnostic(); } // find form. VXMLElement current = elem; while (1) { VXMLElementType nodeName = current.GetName(); if (nodeName == NODE_MENU) throw JumpItem(current); // Menu is a special case. if (nodeName == NODE_FORM) break; const VXMLElement & parent = current.GetParent(); if (parent == 0) { log->LogError(999, SimpleLogger::MESSAGE, L"could not locate form on local jump"); throw VXIException::Fatal(); } current = parent; }; // (2) If the next item is specified (such as from a previous <goto>, look // for an exact match. if (!item.empty()) { for (VXMLNodeIterator it(current); it; ++it) { VXMLNode child = *it; if (child.GetType() != VXMLNode::Type_VXMLElement) continue; const VXMLElement & elem = reinterpret_cast<const VXMLElement &>(child); if (!IsFormItemNode(elem)) continue; vxistring name; if (!elem.GetAttribute(ATTRIBUTE__ITEMNAME, name)) continue; if (item == name) throw JumpItem(elem); } } // (3) Otherwise, find the first non-filled item with a valid condition. else { for (VXMLNodeIterator it(current); it; ++it) { VXMLNode child = *it; if (child.GetType() != VXMLNode::Type_VXMLElement) continue; const VXMLElement & elem = reinterpret_cast<const VXMLElement &>(child); if (!IsFormItemNode(elem)) continue; // Must use itemname here, as could be implicit name vxistring itemname; if (!elem.GetAttribute(ATTRIBUTE__ITEMNAME, itemname)) { log->LogError(999, SimpleLogger::MESSAGE, L"unnamed item found on local jump"); throw VXIException::Fatal(); } if (exe->script.IsVarDefined(itemname)) continue; // OK if var is undefined, check condition vxistring cond; elem.GetAttribute(ATTRIBUTE_COND, cond); if (cond.empty() || exe->script.TestCondition(cond)) throw JumpItem(elem); } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -