VirtualBox

source: vbox/trunk/src/VBox/Storage/testcase/VDScriptInterp.cpp@ 44943

最後變更 在這個檔案從44943是 44941,由 vboxsync 提交於 12 年 前

Storage/testcase: More scripting language work

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 26.3 KB
 
1/** $Id: VDScriptInterp.cpp 44941 2013-03-06 22:13:17Z vboxsync $ */
2/** @file
3 *
4 * VBox HDD container test utility - scripting engine, interpreter.
5 */
6
7/*
8 * Copyright (C) 2013 Oracle Corporation
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.alldomusa.eu.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License (GPL) as published by the Free Software
14 * Foundation, in version 2 as it comes in the "COPYING" file of the
15 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
16 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
17 */
18#define LOGGROUP LOGGROUP_DEFAULT
19#include <iprt/list.h>
20#include <iprt/mem.h>
21#include <iprt/assert.h>
22#include <iprt/string.h>
23#include <iprt/stream.h>
24
25#include <VBox/log.h>
26
27#include "VDScriptAst.h"
28#include "VDScriptStack.h"
29#include "VDScriptInternal.h"
30
31/**
32 * Interpreter variable.
33 */
34typedef struct VDSCRIPTINTERPVAR
35{
36 /** String space core. */
37 RTSTRSPACECORE Core;
38 /** Value. */
39 VDSCRIPTARG Value;
40} VDSCRIPTINTERPVAR;
41/** Pointer to an interpreter variable. */
42typedef VDSCRIPTINTERPVAR *PVDSCRIPTINTERPVAR;
43
44/**
45 * Block scope.
46 */
47typedef struct VDSCRIPTINTERPSCOPE
48{
49 /** Pointer to the enclosing scope if available. */
50 struct VDSCRIPTINTERPSCOPE *pParent;
51 /** String space of declared variables in this scope. */
52 RTSTRSPACE hStrSpaceVar;
53} VDSCRIPTINTERPSCOPE;
54/** Pointer to a scope block. */
55typedef VDSCRIPTINTERPSCOPE *PVDSCRIPTINTERPSCOPE;
56
57/**
58 * Function call.
59 */
60typedef struct VDSCRIPTINTERPFNCALL
61{
62 /** Pointer to the caller of this function. */
63 struct VDSCRIPTINTERPFNCALL *pCaller;
64 /** Root scope of this function. */
65 VDSCRIPTINTERPSCOPE ScopeRoot;
66 /** Current scope in this function. */
67 PVDSCRIPTINTERPSCOPE pScopeCurr;
68} VDSCRIPTINTERPFNCALL;
69/** Pointer to a function call. */
70typedef VDSCRIPTINTERPFNCALL *PVDSCRIPTINTERPFNCALL;
71
72/**
73 * Interpreter context.
74 */
75typedef struct VDSCRIPTINTERPCTX
76{
77 /** Pointer to the script context. */
78 PVDSCRIPTCTXINT pScriptCtx;
79 /** Current function call entry. */
80 PVDSCRIPTINTERPFNCALL pFnCallCurr;
81 /** Stack of calculated values. */
82 VDSCRIPTSTACK StackValues;
83 /** Evaluation control stack. */
84 VDSCRIPTSTACK StackCtrl;
85} VDSCRIPTINTERPCTX;
86/** Pointer to an interpreter context. */
87typedef VDSCRIPTINTERPCTX *PVDSCRIPTINTERPCTX;
88
89/**
90 * Interpreter control type.
91 */
92typedef enum VDSCRIPTINTERPCTRLTYPE
93{
94 VDSCRIPTINTERPCTRLTYPE_INVALID = 0,
95 /** Function call to evaluate now, all values are computed
96 * and are stored on the value stack.
97 */
98 VDSCRIPTINTERPCTRLTYPE_FN_CALL,
99 /** Cleanup the function call, deleting the scope and restoring the previous one. */
100 VDSCRIPTINTERPCTRLTYPE_FN_CALL_CLEANUP,
101 /** If statement to evaluate now, the guard is on the stack. */
102 VDSCRIPTINTERPCTRLTYPE_IF,
103 /** While statement. */
104 VDSCRIPTINTERPCTRLTYPE_WHILE,
105 /** for statement. */
106 VDSCRIPTINTERPCTRLTYPE_FOR,
107 /** switch statement. */
108 VDSCRIPTINTERPCTRLTYPE_SWITCH,
109 /** Compound statement. */
110 VDSCRIPTINTERPCTRLTYPE_COMPOUND,
111 /** 32bit blowup. */
112 VDSCRIPTINTERPCTRLTYPE_32BIT_HACK = 0x7fffffff
113} VDSCRIPTINTERPCTRLTYPE;
114/** Pointer to a control type. */
115typedef VDSCRIPTINTERPCTRLTYPE *PVDSCRIPINTERPCTRLTYPE;
116
117/**
118 * Interpreter stack control entry.
119 */
120typedef struct VDSCRIPTINTERPCTRL
121{
122 /** Flag whether this entry points to an AST node to evaluate. */
123 bool fEvalAst;
124 /** Flag dependent data. */
125 union
126 {
127 /** Pointer to the AST node to interprete. */
128 PVDSCRIPTASTCORE pAstNode;
129 /** Interpreter control structure. */
130 struct
131 {
132 /** Type of control. */
133 VDSCRIPTINTERPCTRLTYPE enmCtrlType;
134 /** Function call data. */
135 struct
136 {
137 /** Function to call. */
138 PVDSCRIPTFN pFn;
139 } FnCall;
140 /** Compound statement. */
141 struct
142 {
143 /** The compound statement node. */
144 PVDSCRIPTASTSTMT pStmtCompound;
145 /** Current statement evaluated. */
146 PVDSCRIPTASTSTMT pStmtCurr;
147 } Compound;
148 } Ctrl;
149 };
150} VDSCRIPTINTERPCTRL;
151/** Pointer to an exec stack control entry. */
152typedef VDSCRIPTINTERPCTRL *PVDSCRIPTINTERPCTRL;
153
154/**
155 * Record an error while interpreting.
156 *
157 * @returns VBox status code passed.
158 * @param pThis The interpreter context.
159 * @param rc The status code to record.
160 * @param RT_SRC_POS Position in the source code.
161 * @param pszFmt Format string.
162 */
163static int vdScriptInterpreterError(PVDSCRIPTINTERPCTX pThis, int rc, RT_SRC_POS_DECL, const char *pszFmt, ...)
164{
165 RTPrintf(pszFmt);
166 return rc;
167}
168
169/**
170 * Pops the topmost value from the value stack.
171 *
172 * @returns nothing.
173 * @param pThis The interpreter context.
174 * @param pVal Where to store the value.
175 */
176DECLINLINE(void) vdScriptInterpreterPopValue(PVDSCRIPTINTERPCTX pThis, PVDSCRIPTARG pVal)
177{
178 PVDSCRIPTARG pValStack = (PVDSCRIPTARG)vdScriptStackGetUsed(&pThis->StackValues);
179 AssertPtrReturnVoid(pValStack);
180
181 *pVal = *pValStack;
182 vdScriptStackPop(&pThis->StackValues);
183}
184
185/**
186 * Pushes a given value onto the value stack.
187 */
188DECLINLINE(int) vdScriptInterpreterPushValue(PVDSCRIPTINTERPCTX pThis, PVDSCRIPTARG pVal)
189{
190 PVDSCRIPTARG pValStack = (PVDSCRIPTARG)vdScriptStackGetUnused(&pThis->StackValues);
191 if (!pValStack)
192 return vdScriptInterpreterError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Out of memory pushing a value on the value stack");
193
194 *pValStack = *pVal;
195 vdScriptStackPush(&pThis->StackValues);
196 return VINF_SUCCESS;
197}
198
199/**
200 * Pushes a control entry without additional data onto the stack.
201 *
202 * @returns VBox status code.
203 * @param pThis The interpreter context.
204 * @param enmCtrlType The control entry type.
205 */
206DECLINLINE(int) vdScriptInterpreterPushNonDataCtrlEntry(PVDSCRIPTINTERPCTX pThis,
207 VDSCRIPTINTERPCTRLTYPE enmCtrlType)
208{
209 PVDSCRIPTINTERPCTRL pCtrl = NULL;
210
211 pCtrl = (PVDSCRIPTINTERPCTRL)vdScriptStackGetUnused(&pThis->StackCtrl);
212 if (pCtrl)
213 {
214 pCtrl->fEvalAst = false;
215 pCtrl->Ctrl.enmCtrlType = enmCtrlType;
216 vdScriptStackPush(&pThis->StackCtrl);
217 return VINF_SUCCESS;
218 }
219
220 return vdScriptInterpreterError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Out of memory adding an entry on the control stack");
221}
222
223/**
224 * Pushes a compound statement control entry onto the stack.
225 *
226 * @returns VBox status code.
227 * @param pThis The interpreter context.
228 * @param pStmtFirst The first statement of the compound statement
229 */
230DECLINLINE(int) vdScriptInterpreterPushCompoundCtrlEntry(PVDSCRIPTINTERPCTX pThis, PVDSCRIPTASTSTMT pStmt)
231{
232 PVDSCRIPTINTERPCTRL pCtrl = NULL;
233
234 pCtrl = (PVDSCRIPTINTERPCTRL)vdScriptStackGetUnused(&pThis->StackCtrl);
235 if (pCtrl)
236 {
237 pCtrl->fEvalAst = false;
238 pCtrl->Ctrl.enmCtrlType = VDSCRIPTINTERPCTRLTYPE_COMPOUND;
239 pCtrl->Ctrl.Compound.pStmtCompound = pStmt;
240 pCtrl->Ctrl.Compound.pStmtCurr = RTListGetFirst(&pStmt->Compound.ListStmts, VDSCRIPTASTSTMT, Core.ListNode);
241 vdScriptStackPush(&pThis->StackCtrl);
242 return VINF_SUCCESS;
243 }
244
245 return vdScriptInterpreterError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Out of memory adding an entry on the control stack");
246}
247
248/**
249 * Pushes an AST node onto the control stack.
250 *
251 * @returns VBox status code.
252 * @param pThis The interpreter context.
253 * @param enmCtrlType The control entry type.
254 */
255DECLINLINE(int) vdScriptInterpreterPushAstEntry(PVDSCRIPTINTERPCTX pThis,
256 PVDSCRIPTASTCORE pAstNode)
257{
258 PVDSCRIPTINTERPCTRL pCtrl = NULL;
259
260 pCtrl = (PVDSCRIPTINTERPCTRL)vdScriptStackGetUnused(&pThis->StackCtrl);
261
262 if (pCtrl)
263 {
264 pCtrl->fEvalAst = true;
265 pCtrl->pAstNode = pAstNode;
266 vdScriptStackPush(&pThis->StackCtrl);
267 return VINF_SUCCESS;
268 }
269
270 return vdScriptInterpreterError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Out of memory adding an entry on the control stack");
271}
272
273/**
274 * Destroy variable string space callback.
275 */
276static DECLCALLBACK(int) vdScriptInterpreterVarSpaceDestroy(PRTSTRSPACECORE pStr, void *pvUser)
277{
278 RTMemFree(pStr);
279 return VINF_SUCCESS;
280}
281
282/**
283 * Setsup a new scope in the current function call.
284 *
285 * @returns VBox status code.
286 * @param pThis The interpreter context.
287 */
288static int vdScriptInterpreterScopeCreate(PVDSCRIPTINTERPCTX pThis)
289{
290 int rc = VINF_SUCCESS;
291 PVDSCRIPTINTERPSCOPE pScope = (PVDSCRIPTINTERPSCOPE)RTMemAllocZ(sizeof(VDSCRIPTINTERPSCOPE));
292 if (pScope)
293 {
294 pScope->pParent = pThis->pFnCallCurr->pScopeCurr;
295 pScope->hStrSpaceVar = NULL;
296 pThis->pFnCallCurr->pScopeCurr = pScope;
297 }
298 else
299 rc = vdScriptInterpreterError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Out of memory allocating new scope");
300
301 return rc;
302}
303
304/**
305 * Destroys the current scope.
306 *
307 * @returns nothing.
308 * @param pThis The interpreter context.
309 */
310static void vdScriptInterpreterScopeDestroyCurr(PVDSCRIPTINTERPCTX pThis)
311{
312 AssertMsgReturnVoid(pThis->pFnCallCurr->pScopeCurr != &pThis->pFnCallCurr->ScopeRoot,
313 ("Current scope is root scope of function call\n"));
314
315 PVDSCRIPTINTERPSCOPE pScope = pThis->pFnCallCurr->pScopeCurr;
316 pThis->pFnCallCurr->pScopeCurr = pScope->pParent;
317 RTStrSpaceDestroy(&pScope->hStrSpaceVar, vdScriptInterpreterVarSpaceDestroy, NULL);
318 RTMemFree(pScope);
319}
320
321/**
322 * Get the content of the given variable identifier from the current or parent scope.
323 */
324static PVDSCRIPTINTERPVAR vdScriptInterpreterGetVar(PVDSCRIPTINTERPCTX pThis, const char *pszVar)
325{
326 PVDSCRIPTINTERPSCOPE pScopeCurr = pThis->pFnCallCurr->pScopeCurr;
327 PVDSCRIPTINTERPVAR pVar = NULL;
328
329 while ( !pVar
330 && pScopeCurr)
331 {
332 pVar = (PVDSCRIPTINTERPVAR)RTStrSpaceGet(&pScopeCurr->hStrSpaceVar, pszVar);
333 if (pVar)
334 break;
335 pScopeCurr = pScopeCurr->pParent;
336 }
337
338
339 return pVar;
340}
341
342/**
343 * Evaluate an expression.
344 *
345 * @returns VBox status code.
346 * @param pThis The interpreter context.
347 * @param pExpr The expression to evaluate.
348 */
349static int vdScriptInterpreterEvaluateExpression(PVDSCRIPTINTERPCTX pThis, PVDSCRIPTASTEXPR pExpr)
350{
351 int rc = VINF_SUCCESS;
352
353 switch (pExpr->enmType)
354 {
355 case VDSCRIPTEXPRTYPE_PRIMARY_NUMCONST:
356 {
357 /* Push the numerical constant on the value stack. */
358 VDSCRIPTARG NumConst;
359 NumConst.enmType = VDSCRIPTTYPE_UINT64;
360 NumConst.u64 = pExpr->u64;
361 rc = vdScriptInterpreterPushValue(pThis, &NumConst);
362 break;
363 }
364 case VDSCRIPTEXPRTYPE_PRIMARY_STRINGCONST:
365 {
366 /* Push the string literal on the value stack. */
367 VDSCRIPTARG StringConst;
368 StringConst.enmType = VDSCRIPTTYPE_STRING;
369 StringConst.psz = pExpr->pszStr;
370 rc = vdScriptInterpreterPushValue(pThis, &StringConst);
371 break;
372 }
373 case VDSCRIPTEXPRTYPE_PRIMARY_BOOLEAN:
374 {
375 VDSCRIPTARG BoolConst;
376 BoolConst.enmType = VDSCRIPTTYPE_BOOL;
377 BoolConst.f = pExpr->f;
378 rc = vdScriptInterpreterPushValue(pThis, &BoolConst);
379 break;
380 }
381 case VDSCRIPTEXPRTYPE_PRIMARY_IDENTIFIER:
382 {
383 /* Look it up and push the value onto the value stack. */
384 PVDSCRIPTINTERPVAR pVar = vdScriptInterpreterGetVar(pThis, pExpr->pIde->aszIde);
385
386 AssertPtrReturn(pVar, VERR_IPE_UNINITIALIZED_STATUS);
387 rc = vdScriptInterpreterPushValue(pThis, &pVar->Value);
388 break;
389 }
390 case VDSCRIPTEXPRTYPE_POSTFIX_INCREMENT:
391 case VDSCRIPTEXPRTYPE_POSTFIX_DECREMENT:
392 AssertMsgFailed(("TODO\n"));
393 case VDSCRIPTEXPRTYPE_POSTFIX_FNCALL:
394 {
395 PVDSCRIPTFN pFn = (PVDSCRIPTFN)RTStrSpaceGet(&pThis->pScriptCtx->hStrSpaceFn, pExpr->FnCall.pFnIde->pIde->aszIde);
396 if (pFn)
397 {
398 /* Push a function call control entry on the stack. */
399 PVDSCRIPTINTERPCTRL pCtrlFn = (PVDSCRIPTINTERPCTRL)vdScriptStackGetUnused(&pThis->StackCtrl);
400 if (pCtrlFn)
401 {
402 pCtrlFn->fEvalAst = false;
403 pCtrlFn->Ctrl.enmCtrlType = VDSCRIPTINTERPCTRLTYPE_FN_CALL;
404 pCtrlFn->Ctrl.FnCall.pFn = pFn;
405 vdScriptStackPush(&pThis->StackCtrl);
406
407 /* Push parameter expressions on the stack. */
408 PVDSCRIPTASTEXPR pArg = RTListGetFirst(&pExpr->FnCall.ListArgs, VDSCRIPTASTEXPR, Core.ListNode);
409 while (pArg)
410 {
411 rc = vdScriptInterpreterPushAstEntry(pThis, &pArg->Core);
412 if (RT_FAILURE(rc))
413 break;
414 pArg = RTListGetNext(&pExpr->FnCall.ListArgs, pArg, VDSCRIPTASTEXPR, Core.ListNode);
415 }
416 }
417 }
418 else
419 AssertMsgFailed(("Invalid program given, unknown function: %s\n", pExpr->FnCall.pFnIde->pIde->aszIde));
420 break;
421 }
422 case VDSCRIPTEXPRTYPE_UNARY_INCREMENT:
423 case VDSCRIPTEXPRTYPE_UNARY_DECREMENT:
424 case VDSCRIPTEXPRTYPE_UNARY_POSSIGN:
425 case VDSCRIPTEXPRTYPE_UNARY_NEGSIGN:
426 case VDSCRIPTEXPRTYPE_UNARY_INVERT:
427 case VDSCRIPTEXPRTYPE_UNARY_NEGATE:
428 case VDSCRIPTEXPRTYPE_MULTIPLICATION:
429 case VDSCRIPTEXPRTYPE_DIVISION:
430 case VDSCRIPTEXPRTYPE_MODULUS:
431 case VDSCRIPTEXPRTYPE_ADDITION:
432 case VDSCRIPTEXPRTYPE_SUBTRACTION:
433 case VDSCRIPTEXPRTYPE_LSR:
434 case VDSCRIPTEXPRTYPE_LSL:
435 case VDSCRIPTEXPRTYPE_LOWER:
436 case VDSCRIPTEXPRTYPE_HIGHER:
437 case VDSCRIPTEXPRTYPE_LOWEREQUAL:
438 case VDSCRIPTEXPRTYPE_HIGHEREQUAL:
439 case VDSCRIPTEXPRTYPE_EQUAL:
440 case VDSCRIPTEXPRTYPE_NOTEQUAL:
441 case VDSCRIPTEXPRTYPE_BITWISE_AND:
442 case VDSCRIPTEXPRTYPE_BITWISE_XOR:
443 case VDSCRIPTEXPRTYPE_BITWISE_OR:
444 case VDSCRIPTEXPRTYPE_LOGICAL_AND:
445 case VDSCRIPTEXPRTYPE_LOGICAL_OR:
446 case VDSCRIPTEXPRTYPE_ASSIGN:
447 case VDSCRIPTEXPRTYPE_ASSIGN_MULT:
448 case VDSCRIPTEXPRTYPE_ASSIGN_DIV:
449 case VDSCRIPTEXPRTYPE_ASSIGN_MOD:
450 case VDSCRIPTEXPRTYPE_ASSIGN_ADD:
451 case VDSCRIPTEXPRTYPE_ASSIGN_SUB:
452 case VDSCRIPTEXPRTYPE_ASSIGN_LSL:
453 case VDSCRIPTEXPRTYPE_ASSIGN_LSR:
454 case VDSCRIPTEXPRTYPE_ASSIGN_AND:
455 case VDSCRIPTEXPRTYPE_ASSIGN_XOR:
456 case VDSCRIPTEXPRTYPE_ASSIGN_OR:
457 case VDSCRIPTEXPRTYPE_ASSIGNMENT_LIST:
458 AssertMsgFailed(("TODO\n"));
459 default:
460 AssertMsgFailed(("Invalid expression type: %d\n", pExpr->enmType));
461 }
462 return rc;
463}
464
465/**
466 * Evaluate a statement.
467 *
468 * @returns VBox status code.
469 * @param pThis The interpreter context.
470 * @param pStmt The statement to evaluate.
471 */
472static int vdScriptInterpreterEvaluateStatement(PVDSCRIPTINTERPCTX pThis, PVDSCRIPTASTSTMT pStmt)
473{
474 int rc = VINF_SUCCESS;
475
476 switch (pStmt->enmStmtType)
477 {
478 case VDSCRIPTSTMTTYPE_COMPOUND:
479 {
480 /* Setup new scope. */
481 rc = vdScriptInterpreterScopeCreate(pThis);
482 if (RT_SUCCESS(rc))
483 {
484 /** @todo: Declarations */
485 rc = vdScriptInterpreterPushCompoundCtrlEntry(pThis, pStmt);
486 }
487 break;
488 }
489 case VDSCRIPTSTMTTYPE_EXPRESSION:
490 {
491 rc = vdScriptInterpreterPushAstEntry(pThis, &pStmt->pExpr->Core);
492 break;
493 }
494 case VDSCRIPTSTMTTYPE_IF:
495 case VDSCRIPTSTMTTYPE_SWITCH:
496 case VDSCRIPTSTMTTYPE_WHILE:
497 case VDSCRIPTSTMTTYPE_FOR:
498 case VDSCRIPTSTMTTYPE_CONTINUE:
499 case VDSCRIPTSTMTTYPE_BREAK:
500 case VDSCRIPTSTMTTYPE_RETURN:
501 case VDSCRIPTSTMTTYPE_CASE:
502 case VDSCRIPTSTMTTYPE_DEFAULT:
503 default:
504 AssertMsgFailed(("Invalid statement type: %d\n", pStmt->enmStmtType));
505 }
506
507 return rc;
508}
509
510/**
511 * Evaluates the given AST node.
512 *
513 * @returns VBox statuse code.
514 * @param pThis The interpreter context.
515 * @param pAstNode The AST node to interpret.
516 */
517static int vdScriptInterpreterEvaluateAst(PVDSCRIPTINTERPCTX pThis, PVDSCRIPTASTCORE pAstNode)
518{
519 int rc = VERR_NOT_IMPLEMENTED;
520
521 switch (pAstNode->enmClass)
522 {
523 case VDSCRIPTASTCLASS_DECLARATION:
524 {
525 AssertMsgFailed(("TODO\n"));
526 break;
527 }
528 case VDSCRIPTASTCLASS_STATEMENT:
529 {
530 rc = vdScriptInterpreterEvaluateStatement(pThis, (PVDSCRIPTASTSTMT)pAstNode);
531 break;
532 }
533 case VDSCRIPTASTCLASS_EXPRESSION:
534 {
535 rc = vdScriptInterpreterEvaluateExpression(pThis, (PVDSCRIPTASTEXPR)pAstNode);
536 break;
537 }
538 /* These should never ever appear here. */
539 case VDSCRIPTASTCLASS_IDENTIFIER:
540 case VDSCRIPTASTCLASS_FUNCTION:
541 case VDSCRIPTASTCLASS_FUNCTIONARG:
542 case VDSCRIPTASTCLASS_INVALID:
543 default:
544 AssertMsgFailed(("Invalid AST node class: %d\n", pAstNode->enmClass));
545 }
546
547 return rc;
548}
549
550/**
551 * Evaluate a function call.
552 *
553 * @returns VBox status code.
554 * @param pThis The interpreter context.
555 * @param pFn The function execute.
556 */
557static int vdScriptInterpreterFnCall(PVDSCRIPTINTERPCTX pThis, PVDSCRIPTFN pFn)
558{
559 int rc = VINF_SUCCESS;
560
561 if (!pFn->fExternal)
562 {
563 PVDSCRIPTASTFN pAstFn = pFn->Type.Internal.pAstFn;
564
565 /* Add function call cleanup marker on the stack first. */
566 rc = vdScriptInterpreterPushNonDataCtrlEntry(pThis, VDSCRIPTINTERPCTRLTYPE_FN_CALL_CLEANUP);
567 if (RT_SUCCESS(rc))
568 {
569 /* Create function call frame and set it up. */
570 PVDSCRIPTINTERPFNCALL pFnCall = (PVDSCRIPTINTERPFNCALL)RTMemAllocZ(sizeof(VDSCRIPTINTERPFNCALL));
571 if (pFnCall)
572 {
573 pFnCall->pCaller = pThis->pFnCallCurr;
574 pFnCall->ScopeRoot.pParent = NULL;
575 pFnCall->ScopeRoot.hStrSpaceVar = NULL;
576 pFnCall->pScopeCurr = &pFnCall->ScopeRoot;
577
578 /* Add the variables, remember order. The first variable in the argument has the value at the top of the value stack. */
579 PVDSCRIPTASTFNARG pArg = RTListGetFirst(&pAstFn->ListArgs, VDSCRIPTASTFNARG, Core.ListNode);
580 for (unsigned i = 0; i < pAstFn->cArgs; i++)
581 {
582 PVDSCRIPTINTERPVAR pVar = (PVDSCRIPTINTERPVAR)RTMemAllocZ(sizeof(VDSCRIPTINTERPVAR));
583 if (pVar)
584 {
585 pVar->Core.pszString = pArg->pArgIde->aszIde;
586 pVar->Core.cchString = pArg->pArgIde->cchIde;
587 vdScriptInterpreterPopValue(pThis, &pVar->Value);
588 bool fInserted = RTStrSpaceInsert(&pFnCall->ScopeRoot.hStrSpaceVar, &pVar->Core);
589 Assert(fInserted);
590 }
591 else
592 {
593 rc = vdScriptInterpreterError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Out of memory creating a variable");
594 break;
595 }
596 pArg = RTListGetNext(&pAstFn->ListArgs, pArg, VDSCRIPTASTFNARG, Core.ListNode);
597 }
598
599 if (RT_SUCCESS(rc))
600 {
601 /*
602 * Push compount statement on the control stack and make the newly created
603 * call frame the current one.
604 */
605 rc = vdScriptInterpreterPushAstEntry(pThis, &pAstFn->pCompoundStmts->Core);
606 if (RT_SUCCESS(rc))
607 pThis->pFnCallCurr = pFnCall;
608 }
609
610 if (RT_FAILURE(rc))
611 {
612 RTStrSpaceDestroy(&pFnCall->ScopeRoot.hStrSpaceVar, vdScriptInterpreterVarSpaceDestroy, NULL);
613 RTMemFree(pFnCall);
614 }
615 }
616 else
617 rc = vdScriptInterpreterError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Out of memory creating a call frame");
618 }
619 }
620 else
621 {
622 /* External function call, build the argument list. */
623 if (pFn->cArgs)
624 {
625 PVDSCRIPTARG paArgs = (PVDSCRIPTARG)RTMemAllocZ(pFn->cArgs * sizeof(VDSCRIPTARG));
626 if (paArgs)
627 {
628 for (unsigned i = 0; i < pFn->cArgs; i++)
629 vdScriptInterpreterPopValue(pThis, &paArgs[i]);
630
631 rc = pFn->Type.External.pfnCallback(paArgs, pFn->Type.External.pvUser);
632 RTMemFree(paArgs);
633 }
634 else
635 rc = vdScriptInterpreterError(pThis, VERR_NO_MEMORY, RT_SRC_POS,
636 "Out of memory creating argument array for external function call");
637 }
638 else
639 rc = pFn->Type.External.pfnCallback(NULL, pFn->Type.External.pvUser);
640 }
641
642 return rc;
643}
644
645/**
646 * Evaluate interpreter control statement.
647 *
648 * @returns VBox status code.
649 * @param pThis The interpreter context.
650 * @param pCtrl The control entry to evaluate.
651 */
652static int vdScriptInterpreterEvaluateCtrlEntry(PVDSCRIPTINTERPCTX pThis, PVDSCRIPTINTERPCTRL pCtrl)
653{
654 int rc = VINF_SUCCESS;
655
656 Assert(!pCtrl->fEvalAst);
657 switch (pCtrl->Ctrl.enmCtrlType)
658 {
659 case VDSCRIPTINTERPCTRLTYPE_FN_CALL:
660 {
661 PVDSCRIPTFN pFn = pCtrl->Ctrl.FnCall.pFn;
662
663 vdScriptStackPop(&pThis->StackCtrl);
664 rc = vdScriptInterpreterFnCall(pThis, pFn);
665 break;
666 }
667 case VDSCRIPTINTERPCTRLTYPE_FN_CALL_CLEANUP:
668 {
669 vdScriptStackPop(&pThis->StackCtrl);
670
671 /* Delete function call entry. */
672 AssertPtr(pThis->pFnCallCurr);
673 PVDSCRIPTINTERPFNCALL pFnCallFree = pThis->pFnCallCurr;
674
675 pThis->pFnCallCurr = pFnCallFree->pCaller;
676 Assert(pFnCallFree->pScopeCurr == &pFnCallFree->ScopeRoot);
677 RTStrSpaceDestroy(&pFnCallFree->ScopeRoot.hStrSpaceVar, vdScriptInterpreterVarSpaceDestroy, NULL);
678 RTMemFree(pFnCallFree);
679 break;
680 }
681 case VDSCRIPTINTERPCTRLTYPE_COMPOUND:
682 {
683 if (!pCtrl->Ctrl.Compound.pStmtCurr)
684 {
685 /* Evaluated last statement, cleanup and remove the control statement from the stack. */
686 vdScriptInterpreterScopeDestroyCurr(pThis);
687 vdScriptStackPop(&pThis->StackCtrl);
688 }
689 else
690 {
691 /* Push the current statement onto the control stack and move on. */
692 rc = vdScriptInterpreterPushAstEntry(pThis, &pCtrl->Ctrl.Compound.pStmtCurr->Core);
693 if (RT_SUCCESS(rc))
694 {
695 pCtrl->Ctrl.Compound.pStmtCurr = RTListGetNext(&pCtrl->Ctrl.Compound.pStmtCompound->Compound.ListStmts,
696 pCtrl->Ctrl.Compound.pStmtCurr, VDSCRIPTASTSTMT, Core.ListNode);
697 }
698 }
699 break;
700 }
701 default:
702 AssertMsgFailed(("Invalid evaluation control type on the stack: %d\n",
703 pCtrl->Ctrl.enmCtrlType));
704 }
705
706 return rc;
707}
708
709/**
710 * The interpreter evaluation core loop.
711 *
712 * @returns VBox status code.
713 * @param pThis The interpreter context.
714 */
715static int vdScriptInterpreterEvaluate(PVDSCRIPTINTERPCTX pThis)
716{
717 int rc = VINF_SUCCESS;
718 PVDSCRIPTINTERPCTRL pCtrl = NULL;
719
720 pCtrl = (PVDSCRIPTINTERPCTRL)vdScriptStackGetUsed(&pThis->StackCtrl);
721 while (pCtrl)
722 {
723 if (pCtrl->fEvalAst)
724 {
725 PVDSCRIPTASTCORE pAstNode = pCtrl->pAstNode;
726 vdScriptStackPop(&pThis->StackCtrl);
727
728 rc = vdScriptInterpreterEvaluateAst(pThis, pAstNode);
729 }
730 else
731 rc = vdScriptInterpreterEvaluateCtrlEntry(pThis, pCtrl);
732
733 pCtrl = (PVDSCRIPTINTERPCTRL)vdScriptStackGetUsed(&pThis->StackCtrl);
734 }
735
736 return rc;
737}
738
739DECLHIDDEN(int) vdScriptCtxInterprete(PVDSCRIPTCTXINT pThis, const char *pszFn,
740 PVDSCRIPTARG paArgs, unsigned cArgs,
741 PVDSCRIPTARG pRet)
742{
743 int rc = VINF_SUCCESS;
744 VDSCRIPTINTERPCTX InterpCtx;
745 PVDSCRIPTFN pFn = NULL;
746
747 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
748 AssertPtrReturn(pszFn, VERR_INVALID_POINTER);
749 AssertReturn( (!cArgs && !paArgs)
750 || (cArgs && paArgs), VERR_INVALID_PARAMETER);
751
752 InterpCtx.pScriptCtx = pThis;
753 InterpCtx.pFnCallCurr = NULL;
754 vdScriptStackInit(&InterpCtx.StackValues, sizeof(VDSCRIPTARG));
755 vdScriptStackInit(&InterpCtx.StackCtrl, sizeof(VDSCRIPTINTERPCTRL));
756
757 pFn = (PVDSCRIPTFN)RTStrSpaceGet(&pThis->hStrSpaceFn, pszFn);
758 if (pFn)
759 {
760 if (cArgs == pFn->cArgs)
761 {
762 /* Push the arguments onto the stack. */
763 /** @todo: Check expected and given argument types. */
764 for (unsigned i = 0; i < cArgs; i++)
765 {
766 PVDSCRIPTARG pArg = (PVDSCRIPTARG)vdScriptStackGetUnused(&InterpCtx.StackValues);
767 *pArg = paArgs[i];
768 vdScriptStackPush(&InterpCtx.StackValues);
769 }
770
771 if (RT_SUCCESS(rc))
772 {
773 /* Setup function call frame and parameters. */
774 rc = vdScriptInterpreterFnCall(&InterpCtx, pFn);
775 if (RT_SUCCESS(rc))
776 {
777 /* Run the interpreter. */
778 rc = vdScriptInterpreterEvaluate(&InterpCtx);
779 vdScriptStackDestroy(&InterpCtx.StackValues);
780 vdScriptStackDestroy(&InterpCtx.StackCtrl);
781 }
782 }
783 }
784 else
785 rc = vdScriptInterpreterError(&InterpCtx, VERR_INVALID_PARAMETER, RT_SRC_POS, "Invalid number of parameters, expected %d got %d", pFn->cArgs, cArgs);
786 }
787 else
788 rc = vdScriptInterpreterError(&InterpCtx, VERR_NOT_FOUND, RT_SRC_POS, "Function with identifier \"%s\" not found", pszFn);
789
790
791 return rc;
792}
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette