VirtualBox

source: vbox/trunk/src/VBox/Storage/testcase/VDScript.cpp@ 44941

Last change on this file since 44941 was 44941, checked in by vboxsync, 12 years ago

Storage/testcase: More scripting language work

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 93.9 KB
Line 
1/** $Id: VDScript.cpp 44941 2013-03-06 22:13:17Z vboxsync $ */
2/** @file
3 *
4 * VBox HDD container test utility - scripting engine.
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.virtualbox.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
19/** @page pg_vd_script VDScript - Simple scripting language for VD I/O testing.
20 *
21 * This component implements a very simple scripting language to make testing the VD
22 * library more flexible and testcases faster to implement without the need to recompile
23 * everything after it changed.
24 * The language is a small subset of the C language. It doesn't support unions, structs,
25 * global variables, typedefed types or pointers (yet). It also adds a boolean and a string type.
26 * Strings are immutable and only to print messages from the script.
27 * There are also not the default types like int or unsigned because theire ranges are architecture
28 * dependent. Instead VDScript uses uint8_t, int8_t, ... as primitive types.
29 *
30 * Why inventing a completely new language?
31 *
32 * Well it is not a completely new language to start with, it is a subset of C and the
33 * language can be extended later on to reach the full C language later on.
34 * Second, there is no static typed scripting language I like which could be implemented
35 * and finally because I can ;)
36 * The code implementing the scripting engine is designed to be easily incorporated into other
37 * code. Could be used as a scripting language for the VBox debugger for example or in the scm
38 * tool to automatically rewrite C code using the AST VDSCript generates...
39 *
40 * The syntax of VDSCript is derived from the C syntax. The syntax of C in BNF was taken
41 * from: http://www.csci.csusb.edu/dick/samples/c.syntax.html
42 * and: http://slps.github.com/zoo/c/iso-9899-tc3.html
43 * and: http://www.open-std.org/jtc1/sc22/WG14/www/docs/n1256.pdf
44 */
45#define LOGGROUP LOGGROUP_DEFAULT
46#include <iprt/string.h>
47#include <iprt/list.h>
48#include <iprt/mem.h>
49#include <iprt/ctype.h>
50#include <iprt/stream.h>
51
52#include <VBox/log.h>
53
54#include "VDScriptAst.h"
55#include "VDScriptInternal.h"
56
57/**
58 * VD script token class.
59 */
60typedef enum VDTOKENCLASS
61{
62 /** Invalid. */
63 VDTOKENCLASS_INVALID = 0,
64 /** Identifier class. */
65 VDTOKENCLASS_IDENTIFIER,
66 /** Numerical constant. */
67 VDTOKENCLASS_NUMCONST,
68 /** String constant. */
69 VDTOKENCLASS_STRINGCONST,
70 /** Operators */
71 VDTOKENCLASS_OPERATORS,
72 /** Reserved keyword */
73 VDTOKENCLASS_KEYWORD,
74 /** Punctuator */
75 VDTOKENCLASS_PUNCTUATOR,
76 /** End of stream */
77 VDTOKENCLASS_EOS,
78 /** 32bit hack. */
79 VDTOKENCLASS_32BIT_HACK = 0x7fffffff
80} VDTOKENCLASS;
81/** Pointer to a token class. */
82typedef VDTOKENCLASS *PVDTOKENCLASS;
83
84/**
85 * Keyword types.
86 */
87typedef enum VDSCRIPTTOKENKEYWORD
88{
89 VDSCRIPTTOKENKEYWORD_INVALID = 0,
90 VDSCRIPTTOKENKEYWORD_CONTINUE,
91 VDSCRIPTTOKENKEYWORD_DEFAULT,
92 VDSCRIPTTOKENKEYWORD_RETURN,
93 VDSCRIPTTOKENKEYWORD_SWITCH,
94 VDSCRIPTTOKENKEYWORD_WHILE,
95 VDSCRIPTTOKENKEYWORD_BREAK,
96 VDSCRIPTTOKENKEYWORD_FALSE,
97 VDSCRIPTTOKENKEYWORD_TRUE,
98 VDSCRIPTTOKENKEYWORD_ELSE,
99 VDSCRIPTTOKENKEYWORD_CASE,
100 VDSCRIPTTOKENKEYWORD_FOR,
101 VDSCRIPTTOKENKEYWORD_IF,
102 VDSCRIPTTOKENKEYWORD_DO,
103 VDSCRIPTTOKENKEYWORD_32BIT_HACK = 0x7fffffff
104} VDSCRIPTTOKENKEYWORD;
105/** Pointer to a keyword type. */
106typedef VDSCRIPTTOKENKEYWORD *PVDSCRIPTTOKENKEYWORD;
107
108/**
109 * VD script token.
110 */
111typedef struct VDSCRIPTTOKEN
112{
113 /** Token class. */
114 VDTOKENCLASS enmClass;
115 /** Token position in the source buffer. */
116 VDSRCPOS Pos;
117 /** Data based on the token class. */
118 union
119 {
120 /** Identifier. */
121 struct
122 {
123 /** Pointer to the start of the identifier. */
124 const char *pszIde;
125 /** Number of characters for the identifier excluding the null terminator. */
126 size_t cchIde;
127 } Ide;
128 /** Numerical constant. */
129 struct
130 {
131 uint64_t u64;
132 } NumConst;
133 /** String constant */
134 struct
135 {
136 /** Pointer to the start of the string constant. */
137 const char *pszString;
138 /** Number of characters of the string, including the null terminator. */
139 size_t cchString;
140 } StringConst;
141 /** Operator */
142 struct
143 {
144 /** The operator string. */
145 char aszOp[4]; /** Maximum of 3 for >>= + null terminator. */
146 } Operator;
147 /** Keyword. */
148 struct
149 {
150 /** The keyword type. */
151 VDSCRIPTTOKENKEYWORD enmKeyword;
152 } Keyword;
153 /** Punctuator. */
154 struct
155 {
156 /** The punctuator in question. */
157 char chPunctuator;
158 } Punctuator;
159 } Class;
160} VDSCRIPTTOKEN;
161/** Pointer to a script token. */
162typedef VDSCRIPTTOKEN *PVDSCRIPTTOKEN;
163/** Pointer to a const script token. */
164typedef const VDSCRIPTTOKEN *PCVDSCRIPTTOKEN;
165
166/**
167 * Tokenizer state.
168 */
169typedef struct VDTOKENIZER
170{
171 /** Char buffer to read from. */
172 const char *pszInput;
173 /** Current position ininput buffer. */
174 VDSRCPOS Pos;
175 /** Token 1. */
176 VDSCRIPTTOKEN Token1;
177 /** Token 2. */
178 VDSCRIPTTOKEN Token2;
179 /** Pointer to the current active token. */
180 PVDSCRIPTTOKEN pTokenCurr;
181 /** The next token in the input stream (used for peeking). */
182 PVDSCRIPTTOKEN pTokenNext;
183} VDTOKENIZER;
184
185/**
186 * Operators entry.
187 */
188typedef struct VDSCRIPTOP
189{
190 /** Operator string. */
191 const char *pszOp;
192 /** Size of the operator in characters without zero terminator. */
193 size_t cchOp;
194} VDSCRIPTOP;
195/** Pointer to a script operator. */
196typedef VDSCRIPTOP *PVDSCRIPTOP;
197
198/**
199 * Known operators array, sort from higest character count to lowest.
200 */
201static VDSCRIPTOP g_aScriptOps[] =
202{
203 {">>=", 3},
204 {"<<=", 3},
205 {"+=", 2},
206 {"-=", 2},
207 {"/=", 2},
208 {"%=", 2},
209 {"&=", 2},
210 {"|=", 2},
211 {"^=", 2},
212 {"&&", 2},
213 {"||", 2},
214 {"<<", 2},
215 {">>", 2},
216 {"++", 2},
217 {"--", 2},
218 {"==", 2},
219 {"!=", 2},
220 {">=", 2},
221 {"<=", 2},
222 {"=", 1},
223 {"+", 1},
224 {"-", 1},
225 {"*", 1},
226 {"/", 1},
227 {"%", 1},
228 {"|", 1},
229 {"&", 1},
230 {"^", 1},
231 {"<", 1},
232 {">", 1},
233 {"!", 1},
234 {"~", 1}
235};
236
237/**
238 * Known punctuators.
239 */
240static VDSCRIPTOP g_aScriptPunctuators[] =
241{
242 {"(", 1},
243 {")", 1},
244 {"{", 1},
245 {"}", 1},
246 {",", 1},
247 {";", 1},
248};
249
250/**
251 * Keyword entry.
252 */
253typedef struct VDSCRIPTKEYWORD
254{
255 /** Keyword string. */
256 const char *pszKeyword;
257 /** Size of the string in characters without zero terminator. */
258 size_t cchKeyword;
259 /** Keyword type. */
260 VDSCRIPTTOKENKEYWORD enmKeyword;
261} VDSCRIPTKEYWORD;
262/** */
263typedef VDSCRIPTKEYWORD *PVDSCRIPTKEYWORD;
264
265/**
266 * Known keywords.
267 */
268static VDSCRIPTKEYWORD g_aKeywords[] =
269{
270 {"continue", 8, VDSCRIPTTOKENKEYWORD_CONTINUE},
271 {"default", 7, VDSCRIPTTOKENKEYWORD_DEFAULT},
272 {"return", 6, VDSCRIPTTOKENKEYWORD_RETURN},
273 {"switch", 6, VDSCRIPTTOKENKEYWORD_SWITCH},
274 {"while", 5, VDSCRIPTTOKENKEYWORD_WHILE},
275 {"break", 5, VDSCRIPTTOKENKEYWORD_BREAK},
276 {"false", 5, VDSCRIPTTOKENKEYWORD_FALSE},
277 {"true", 4, VDSCRIPTTOKENKEYWORD_TRUE},
278 {"else", 4, VDSCRIPTTOKENKEYWORD_ELSE},
279 {"case", 4, VDSCRIPTTOKENKEYWORD_CASE},
280 {"for", 3, VDSCRIPTTOKENKEYWORD_FOR},
281 {"if", 2, VDSCRIPTTOKENKEYWORD_IF},
282 {"do", 2, VDSCRIPTTOKENKEYWORD_DO}
283};
284
285static int vdScriptParseCompoundStatement(PVDSCRIPTCTXINT pThis, PVDSCRIPTASTSTMT *ppAstNodeCompound);
286static int vdScriptParseStatement(PVDSCRIPTCTXINT pThis, PVDSCRIPTASTSTMT *ppAstNodeStmt);
287static int vdScriptParseExpression(PVDSCRIPTCTXINT pThis, PVDSCRIPTASTEXPR *ppAstNodeExpr);
288static int vdScriptParseAssignmentExpression(PVDSCRIPTCTXINT pThis, PVDSCRIPTASTEXPR *ppAstNodeExpr);
289
290/**
291 * Returns whether the tokenizer reached the end of the stream.
292 *
293 * @returns true if the tokenizer reached the end of stream marker
294 * false otherwise.
295 * @param pTokenizer The tokenizer state.
296 */
297DECLINLINE(bool) vdScriptTokenizerIsEos(PVDTOKENIZER pTokenizer)
298{
299 return *pTokenizer->pszInput == '\0';
300}
301
302/**
303 * Skip one character in the input stream.
304 *
305 * @returns nothing.
306 * @param pTokenizer The tokenizer state.
307 */
308DECLINLINE(void) vdScriptTokenizerSkipCh(PVDTOKENIZER pTokenizer)
309{
310 pTokenizer->pszInput++;
311 pTokenizer->Pos.iChStart++;
312 pTokenizer->Pos.iChEnd++;
313}
314
315/**
316 * Returns the next char in the input buffer without advancing it.
317 *
318 * @returns Next character in the input buffer.
319 * @param pTokenizer The tokenizer state.
320 */
321DECLINLINE(char) vdScriptTokenizerPeekCh(PVDTOKENIZER pTokenizer)
322{
323 return vdScriptTokenizerIsEos(pTokenizer)
324 ? '\0'
325 : *(pTokenizer->pszInput + 1);
326}
327
328/**
329 * Returns the next character in the input buffer advancing the internal
330 * position.
331 *
332 * @returns Next character in the stream.
333 * @param pTokenizer The tokenizer state.
334 */
335DECLINLINE(char) vdScriptTokenizerGetCh(PVDTOKENIZER pTokenizer)
336{
337 char ch;
338
339 if (vdScriptTokenizerIsEos(pTokenizer))
340 ch = '\0';
341 else
342 ch = *pTokenizer->pszInput;
343
344 return ch;
345}
346
347/**
348 * Sets a new line for the tokenizer.
349 *
350 * @returns nothing.
351 * @param pTokenizer The tokenizer state.
352 */
353DECLINLINE(void) vdScriptTokenizerNewLine(PVDTOKENIZER pTokenizer, unsigned cSkip)
354{
355 pTokenizer->pszInput += cSkip;
356 pTokenizer->Pos.iLine++;
357 pTokenizer->Pos.iChStart = 1;
358 pTokenizer->Pos.iChEnd = 1;
359}
360
361/**
362 * Checks whether the current position in the input stream is a new line
363 * and skips it.
364 *
365 * @returns Flag whether there was a new line at the current position
366 * in the input buffer.
367 * @param pTokenizer The tokenizer state.
368 */
369DECLINLINE(bool) vdScriptTokenizerIsSkipNewLine(PVDTOKENIZER pTokenizer)
370{
371 bool fNewline = true;
372
373 if ( vdScriptTokenizerGetCh(pTokenizer) == '\r'
374 && vdScriptTokenizerPeekCh(pTokenizer) == '\n')
375 vdScriptTokenizerNewLine(pTokenizer, 2);
376 else if (vdScriptTokenizerGetCh(pTokenizer) == '\n')
377 vdScriptTokenizerNewLine(pTokenizer, 1);
378 else
379 fNewline = false;
380
381 return fNewline;
382}
383
384/**
385 * Skips a multi line comment.
386 *
387 * @returns nothing.
388 * @param pTokenizer The tokenizer state.
389 */
390DECLINLINE(void) vdScriptTokenizerSkipComment(PVDTOKENIZER pTokenizer)
391{
392 while ( !vdScriptTokenizerIsEos(pTokenizer)
393 && ( vdScriptTokenizerGetCh(pTokenizer) != '*'
394 || vdScriptTokenizerPeekCh(pTokenizer) != '/'))
395 {
396 if (!vdScriptTokenizerIsSkipNewLine(pTokenizer))
397 vdScriptTokenizerSkipCh(pTokenizer);
398 }
399
400 if (!vdScriptTokenizerIsEos(pTokenizer))
401 vdScriptTokenizerSkipCh(pTokenizer);
402 if (!vdScriptTokenizerIsEos(pTokenizer))
403 vdScriptTokenizerSkipCh(pTokenizer);
404}
405
406/**
407 * Skip all whitespace starting from the current input buffer position.
408 * Skips all present comments too.
409 *
410 * @returns nothing.
411 * @param pTokenizer The tokenizer state.
412 */
413DECLINLINE(void) vdScriptTokenizerSkipWhitespace(PVDTOKENIZER pTokenizer)
414{
415 while (!vdScriptTokenizerIsEos(pTokenizer))
416 {
417 while ( vdScriptTokenizerGetCh(pTokenizer) == ' '
418 || vdScriptTokenizerGetCh(pTokenizer) == '\t')
419 vdScriptTokenizerSkipCh(pTokenizer);
420
421 if ( !vdScriptTokenizerIsEos(pTokenizer)
422 && !vdScriptTokenizerIsSkipNewLine(pTokenizer))
423 {
424 if ( vdScriptTokenizerGetCh(pTokenizer) == '/'
425 && vdScriptTokenizerPeekCh(pTokenizer) == '*')
426 {
427 vdScriptTokenizerSkipCh(pTokenizer);
428 vdScriptTokenizerSkipCh(pTokenizer);
429 vdScriptTokenizerSkipComment(pTokenizer);
430 }
431 else
432 break; /* Skipped everything, next is some real content. */
433 }
434 }
435}
436
437/**
438 * Get an identifier token from the tokenizer.
439 *
440 * @returns nothing.
441 * @param pTokenizer The tokenizer state.
442 * @param pToken The uninitialized token.
443 */
444static void vdScriptTokenizerGetIdeOrKeyword(PVDTOKENIZER pTokenizer, PVDSCRIPTTOKEN pToken)
445{
446 char ch;
447 size_t cchIde = 0;
448 bool fIsKeyword = false;
449 const char *pszIde = pTokenizer->pszInput;
450
451 pToken->Pos = pTokenizer->Pos;
452
453 Assert(RT_C_IS_ALPHA(*pszIde) || *pszIde == '_' );
454
455 do
456 {
457 cchIde++;
458 vdScriptTokenizerSkipCh(pTokenizer);
459 ch = vdScriptTokenizerGetCh(pTokenizer);
460 }
461 while (RT_C_IS_ALNUM(ch) || ch == '_');
462
463 /* Check whether we got an identifier or an reserved keyword. */
464 for (unsigned i = 0; i < RT_ELEMENTS(g_aKeywords); i++)
465 {
466 if (!RTStrNCmp(g_aKeywords[i].pszKeyword, pszIde, g_aKeywords[i].cchKeyword))
467 {
468 fIsKeyword = true;
469 pToken->enmClass = VDTOKENCLASS_KEYWORD;
470 pToken->Class.Keyword.enmKeyword = g_aKeywords[i].enmKeyword;
471 break;
472 }
473 }
474
475 if (!fIsKeyword)
476 {
477 pToken->enmClass = VDTOKENCLASS_IDENTIFIER;
478 pToken->Class.Ide.pszIde = pszIde;
479 pToken->Class.Ide.cchIde = cchIde;
480 }
481 pToken->Pos.iChEnd += cchIde;
482}
483
484/**
485 * Get a numerical constant from the tokenizer.
486 *
487 * @returns nothing.
488 * @param pTokenizer The tokenizer state.
489 * @param pToken The uninitialized token.
490 */
491static void vdScriptTokenizerGetNumberConst(PVDTOKENIZER pTokenizer, PVDSCRIPTTOKEN pToken)
492{
493 unsigned uBase = 10;
494 char *pszNext = NULL;
495
496 Assert(RT_C_IS_DIGIT(vdScriptTokenizerGetCh(pTokenizer)));
497
498 /* Let RTStrToUInt64Ex() do all the work, looks C compliant :). */
499 pToken->enmClass = VDTOKENCLASS_NUMCONST;
500 int rc = RTStrToUInt64Ex(pTokenizer->pszInput, &pszNext, 0, &pToken->Class.NumConst.u64);
501 Assert(RT_SUCCESS(rc) || rc == VWRN_TRAILING_CHARS || rc == VWRN_TRAILING_SPACES);
502 /** @todo: Handle number to big, throw a warning */
503
504 unsigned cchNumber = pszNext - pTokenizer->pszInput;
505 for (unsigned i = 0; i < cchNumber; i++)
506 vdScriptTokenizerSkipCh(pTokenizer);
507
508 /* Check for a supported suffix, supported are K|M|G. */
509 if (vdScriptTokenizerGetCh(pTokenizer) == 'K')
510 {
511 pToken->Class.NumConst.u64 *= _1K;
512 vdScriptTokenizerSkipCh(pTokenizer);
513 }
514 else if (vdScriptTokenizerGetCh(pTokenizer) == 'M')
515 {
516 pToken->Class.NumConst.u64 *= _1M;
517 vdScriptTokenizerSkipCh(pTokenizer);
518 }
519 else if (vdScriptTokenizerGetCh(pTokenizer) == 'G')
520 {
521 pToken->Class.NumConst.u64 *= _1G;
522 vdScriptTokenizerSkipCh(pTokenizer);
523 }
524}
525
526/**
527 * Parses a string constant.
528 *
529 * @returns nothing.
530 * @param pTokenizer The tokenizer state.
531 * @param pToken The uninitialized token.
532 *
533 * @remarks: No escape sequences allowed at this time.
534 */
535static void vdScriptTokenizerGetStringConst(PVDTOKENIZER pTokenizer, PVDSCRIPTTOKEN pToken)
536{
537 size_t cchStr = 0;
538
539 Assert(vdScriptTokenizerGetCh(pTokenizer) == '\"');
540 vdScriptTokenizerSkipCh(pTokenizer); /* Skip " */
541
542 pToken->enmClass = VDTOKENCLASS_STRINGCONST;
543 pToken->Pos = pTokenizer->Pos;
544 pToken->Class.StringConst.pszString = pTokenizer->pszInput;
545
546 while (vdScriptTokenizerGetCh(pTokenizer) != '\"')
547 {
548 cchStr++;
549 vdScriptTokenizerSkipCh(pTokenizer);
550 }
551
552 vdScriptTokenizerSkipCh(pTokenizer); /* Skip closing " */
553
554 pToken->Class.StringConst.cchString = cchStr;
555 pToken->Pos.iChEnd += cchStr;
556}
557
558/**
559 * Get the end of stream token.
560 *
561 * @returns nothing.
562 * @param pTokenizer The tokenizer state.
563 * @param pToken The uninitialized token.
564 */
565static void vdScriptTokenizerGetEos(PVDTOKENIZER pTokenizer, PVDSCRIPTTOKEN pToken)
566{
567 Assert(vdScriptTokenizerGetCh(pTokenizer) == '\0');
568
569 pToken->enmClass = VDTOKENCLASS_EOS;
570 pToken->Pos = pTokenizer->Pos;
571}
572
573/**
574 * Get operator or punctuator token.
575 *
576 * @returns nothing.
577 * @param pTokenizer The tokenizer state.
578 * @param pToken The uninitialized token.
579 */
580static void vdScriptTokenizerGetOperatorOrPunctuator(PVDTOKENIZER pTokenizer, PVDSCRIPTTOKEN pToken)
581{
582 bool fOpFound = false;
583
584 pToken->enmClass = VDTOKENCLASS_INVALID;
585 pToken->Pos = pTokenizer->Pos;
586
587 /*
588 * Use table based approach here, not the fastest solution but enough for our purpose
589 * for now.
590 */
591 for (unsigned i = 0; i < RT_ELEMENTS(g_aScriptOps); i++)
592 {
593 if (!RTStrNCmp(g_aScriptOps[i].pszOp, pTokenizer->pszInput, g_aScriptOps[i].cchOp))
594 {
595 memset(pToken->Class.Operator.aszOp, 0, sizeof(pToken->Class.Operator.aszOp));
596
597 int rc = RTStrCopy(pToken->Class.Operator.aszOp, sizeof(pToken->Class.Operator.aszOp), g_aScriptOps[i].pszOp);
598 AssertRC(rc);
599
600 pToken->enmClass = VDTOKENCLASS_OPERATORS;
601 pToken->Pos.iChEnd += g_aScriptOps[i].cchOp;
602
603 /** @todo: Make this prettier. */
604 for (unsigned j = 0; j < g_aScriptOps[i].cchOp; j++)
605 vdScriptTokenizerSkipCh(pTokenizer);
606 fOpFound = true;
607 break;
608 }
609 }
610
611 if (!fOpFound)
612 {
613 for (unsigned i = 0; i < RT_ELEMENTS(g_aScriptPunctuators); i++)
614 {
615 if (!RTStrNCmp(g_aScriptPunctuators[i].pszOp, pTokenizer->pszInput, g_aScriptPunctuators[i].cchOp))
616 {
617 pToken->Pos.iChEnd += g_aScriptPunctuators[i].cchOp;
618 pToken->enmClass = VDTOKENCLASS_PUNCTUATOR;
619 pToken->Class.Punctuator.chPunctuator = *g_aScriptPunctuators[i].pszOp;
620
621 vdScriptTokenizerSkipCh(pTokenizer);
622 fOpFound = true;
623 break;
624 }
625 }
626 }
627}
628
629/**
630 * Read the next token from the tokenizer stream.
631 *
632 * @returns nothing.
633 * @param pTokenizer The tokenizer to read from.
634 * @param pToken Uninitialized token to fill the token data into.
635 */
636static void vdScriptTokenizerReadNextToken(PVDTOKENIZER pTokenizer, PVDSCRIPTTOKEN pToken)
637{
638 /* Skip all eventually existing whitespace, newlines and comments first. */
639 vdScriptTokenizerSkipWhitespace(pTokenizer);
640
641 char ch = vdScriptTokenizerGetCh(pTokenizer);
642 if (RT_C_IS_ALPHA(ch) || ch == '_')
643 vdScriptTokenizerGetIdeOrKeyword(pTokenizer, pToken);
644 else if (RT_C_IS_DIGIT(ch))
645 vdScriptTokenizerGetNumberConst(pTokenizer, pToken);
646 else if (ch == '\"')
647 vdScriptTokenizerGetStringConst(pTokenizer, pToken);
648 else if (ch == '\0')
649 vdScriptTokenizerGetEos(pTokenizer, pToken);
650 else
651 vdScriptTokenizerGetOperatorOrPunctuator(pTokenizer, pToken);
652}
653
654/**
655 * Create a new tokenizer.
656 *
657 * @returns Pointer to the new tokenizer state on success.
658 * NULL if out of memory.
659 * @param pszInput The input to create the tokenizer for.
660 */
661static PVDTOKENIZER vdScriptTokenizerCreate(const char *pszInput)
662{
663 PVDTOKENIZER pTokenizer = (PVDTOKENIZER)RTMemAllocZ(sizeof(VDTOKENIZER));
664 if (pTokenizer)
665 {
666 pTokenizer->pszInput = pszInput;
667 pTokenizer->Pos.iLine = 1;
668 pTokenizer->Pos.iChStart = 1;
669 pTokenizer->Pos.iChEnd = 1;
670 pTokenizer->pTokenCurr = &pTokenizer->Token1;
671 pTokenizer->pTokenNext = &pTokenizer->Token2;
672 /* Fill the tokenizer with two first tokens. */
673 vdScriptTokenizerReadNextToken(pTokenizer, pTokenizer->pTokenCurr);
674 vdScriptTokenizerReadNextToken(pTokenizer, pTokenizer->pTokenNext);
675 }
676
677 return pTokenizer;
678}
679
680/**
681 * Destroys a given tokenizer state.
682 *
683 * @returns nothing.
684 * @param pTokenizer The tokenizer to destroy.
685 */
686static void vdScriptTokenizerDestroy(PVDTOKENIZER pTokenizer)
687{
688 RTMemFree(pTokenizer);
689}
690
691/**
692 * Get the current token in the input stream.
693 *
694 * @returns Pointer to the next token in the stream.
695 * @param pTokenizer The tokenizer to destroy.
696 */
697DECLINLINE(PCVDSCRIPTTOKEN) vdScriptTokenizerGetToken(PVDTOKENIZER pTokenizer)
698{
699 return pTokenizer->pTokenCurr;
700}
701
702/**
703 * Get the class of the current token.
704 *
705 * @returns Class of the current token.
706 * @param pTokenizer The tokenizer state.
707 */
708DECLINLINE(VDTOKENCLASS) vdScriptTokenizerGetTokenClass(PVDTOKENIZER pTokenizer)
709{
710 return pTokenizer->pTokenCurr->enmClass;
711}
712
713/**
714 * Returns the token class of the next token in the stream.
715 *
716 * @returns Token class of the next token.
717 * @param pTokenizer The tokenizer state.
718 */
719DECLINLINE(VDTOKENCLASS) vdScriptTokenizerPeekNextClass(PVDTOKENIZER pTokenizer)
720{
721 return pTokenizer->pTokenNext->enmClass;
722}
723
724/**
725 * Consume the current token advancing to the next in the stream.
726 *
727 * @returns nothing.
728 * @param pTokenizer The tokenizer state.
729 */
730static void vdScriptTokenizerConsume(PVDTOKENIZER pTokenizer)
731{
732 PVDSCRIPTTOKEN pTokenTmp = pTokenizer->pTokenCurr;
733
734 /* Switch next token to current token and read in the next token. */
735 pTokenizer->pTokenCurr = pTokenizer->pTokenNext;
736 pTokenizer->pTokenNext = pTokenTmp;
737 vdScriptTokenizerReadNextToken(pTokenizer, pTokenizer->pTokenNext);
738}
739
740/**
741 * Check whether the next token in the input stream is a punctuator and matches the given
742 * character.
743 *
744 * @returns true if the token matched.
745 * false otherwise.
746 * @param pTokenizer The tokenizer state.
747 * @param chCheck The punctuator to check against.
748 */
749static bool vdScriptTokenizerIsPunctuatorEqual(PVDTOKENIZER pTokenizer, char chCheck)
750{
751 PCVDSCRIPTTOKEN pToken = vdScriptTokenizerGetToken(pTokenizer);
752
753 if ( pToken->enmClass == VDTOKENCLASS_PUNCTUATOR
754 && pToken->Class.Punctuator.chPunctuator == chCheck)
755 return true;
756
757 return false;
758}
759
760/**
761 * Check whether the next token in the input stream is a punctuator and matches the given
762 * character and skips it.
763 *
764 * @returns true if the token matched and was skipped.
765 * false otherwise.
766 * @param pTokenizer The tokenizer state.
767 * @param chCheck The punctuator to check against.
768 */
769static bool vdScriptTokenizerSkipIfIsPunctuatorEqual(PVDTOKENIZER pTokenizer, char chCheck)
770{
771 bool fEqual = vdScriptTokenizerIsPunctuatorEqual(pTokenizer, chCheck);
772 if (fEqual)
773 vdScriptTokenizerConsume(pTokenizer);
774
775 return fEqual;
776}
777
778/**
779 * Check whether the next token in the input stream is a keyword and matches the given
780 * keyword.
781 *
782 * @returns true if the token matched.
783 * false otherwise.
784 * @param pTokenizer The tokenizer state.
785 * @param enmKey The keyword to check against.
786 */
787static bool vdScriptTokenizerIsKeywordEqual(PVDTOKENIZER pTokenizer, VDSCRIPTTOKENKEYWORD enmKeyword)
788{
789 PCVDSCRIPTTOKEN pToken = vdScriptTokenizerGetToken(pTokenizer);
790
791 if ( pToken->enmClass == VDTOKENCLASS_KEYWORD
792 && pToken->Class.Keyword.enmKeyword == enmKeyword)
793 return true;
794
795 return false;
796}
797
798/**
799 * Check whether the next token in the input stream is a keyword and matches the given
800 * keyword and skips it.
801 *
802 * @returns true if the token matched and was skipped.
803 * false otherwise.
804 * @param pTokenizer The tokenizer state.
805 * @param enmKey The keyword to check against.
806 */
807static bool vdScriptTokenizerSkipIfIsKeywordEqual(PVDTOKENIZER pTokenizer, VDSCRIPTTOKENKEYWORD enmKeyword)
808{
809 bool fEqual = vdScriptTokenizerIsKeywordEqual(pTokenizer, enmKeyword);
810 if (fEqual)
811 vdScriptTokenizerConsume(pTokenizer);
812
813 return fEqual;
814}
815
816/**
817 * Check whether the next token in the input stream is a keyword and matches the given
818 * keyword.
819 *
820 * @returns true if the token matched.
821 * false otherwise.
822 * @param pTokenizer The tokenizer state.
823 * @param pszOp The operation to check against.
824 */
825static bool vdScriptTokenizerIsOperatorEqual(PVDTOKENIZER pTokenizer, const char *pszOp)
826{
827 PCVDSCRIPTTOKEN pToken = vdScriptTokenizerGetToken(pTokenizer);
828
829 if ( pToken->enmClass == VDTOKENCLASS_OPERATORS
830 && !RTStrCmp(pToken->Class.Operator.aszOp, pszOp))
831 return true;
832
833 return false;
834}
835
836/**
837 * Check whether the next token in the input stream is an operator and matches the given
838 * keyword and skips it.
839 *
840 * @returns true if the token matched and was skipped.
841 * false otherwise.
842 * @param pTokenizer The tokenizer state.
843 * @param pszOp The operation to check against.
844 */
845static bool vdScriptTokenizerSkipIfIsOperatorEqual(PVDTOKENIZER pTokenizer, const char *pszOp)
846{
847 bool fEqual = vdScriptTokenizerIsOperatorEqual(pTokenizer, pszOp);
848 if (fEqual)
849 vdScriptTokenizerConsume(pTokenizer);
850
851 return fEqual;
852}
853
854/**
855 * Record an error while parsing.
856 *
857 * @returns VBox status code passed.
858 */
859static int vdScriptParserError(PVDSCRIPTCTXINT pThis, int rc, RT_SRC_POS_DECL, const char *pszFmt, ...)
860{
861 NOREF(pThis);
862 NOREF(pszFmt);
863 RTPrintf(pszFmt);
864 return rc;
865}
866
867/**
868 * Puts the next identifier AST node on the stack.
869 *
870 * @returns VBox status code.
871 * @param pThis The script context.
872 * @param ppAstNodeIde Where to store the identifier AST node on success.
873 */
874static int vdScriptParseIde(PVDSCRIPTCTXINT pThis, PVDSCRIPTASTIDE *ppAstNodeIde)
875{
876 int rc = VINF_SUCCESS;
877 PCVDSCRIPTTOKEN pToken;
878
879 LogFlowFunc(("pThis=%p ppAstNodeIde=%p\n", pThis, ppAstNodeIde));
880
881 pToken = vdScriptTokenizerGetToken(pThis->pTokenizer);
882 if (pToken->enmClass != VDTOKENCLASS_IDENTIFIER)
883 rc = vdScriptParserError(pThis, VERR_INVALID_PARAMETER, RT_SRC_POS, "Parser: Expected identifer got...\n");
884 else
885 {
886 /* Create new AST node and push onto stack. */
887 PVDSCRIPTASTIDE pAstNodeIde = vdScriptAstNodeIdeAlloc(pToken->Class.Ide.cchIde);
888 if (pAstNodeIde)
889 {
890 rc = RTStrCopyEx(pAstNodeIde->aszIde, pToken->Class.Ide.cchIde + 1, pToken->Class.Ide.pszIde, pToken->Class.Ide.cchIde);
891 AssertRC(rc);
892 pAstNodeIde->cchIde = pToken->Class.Ide.cchIde;
893
894 *ppAstNodeIde = pAstNodeIde;
895 vdScriptTokenizerConsume(pThis->pTokenizer);
896 }
897 else
898 rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating identifier AST node\n");
899 }
900
901 LogFlowFunc(("returns %Rrc\n", rc));
902 return rc;
903}
904
905/**
906 * Parse a primary expression.
907 *
908 * @returns VBox status code.
909 * @param pThis The script context.
910 * @param ppAstNodeExpr Where to store the primary expression on success.
911 */
912static int vdScriptParsePrimaryExpression(PVDSCRIPTCTXINT pThis, PVDSCRIPTASTEXPR *ppAstNodeExpr)
913{
914 int rc = VINF_SUCCESS;
915
916 LogFlowFunc(("pThis=%p ppAstNodeExpr=%p\n"));
917
918 if (vdScriptTokenizerSkipIfIsPunctuatorEqual(pThis->pTokenizer, '('))
919 {
920 rc = vdScriptParseExpression(pThis, ppAstNodeExpr);
921 if (RT_SUCCESS(rc)
922 && !vdScriptTokenizerSkipIfIsPunctuatorEqual(pThis->pTokenizer, ')'))
923 rc = vdScriptParserError(pThis, VERR_INVALID_PARAMETER, RT_SRC_POS, "Parser: Expected \")\", got ...\n");
924 }
925 else
926 {
927 PVDSCRIPTASTEXPR pExpr = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
928 if (pExpr)
929 {
930 if (vdScriptTokenizerGetTokenClass(pThis->pTokenizer) == VDTOKENCLASS_IDENTIFIER)
931 {
932 PVDSCRIPTASTIDE pIde = NULL;
933 rc = vdScriptParseIde(pThis, &pIde);
934 if (RT_SUCCESS(rc))
935 {
936 pExpr->enmType = VDSCRIPTEXPRTYPE_PRIMARY_IDENTIFIER;
937 pExpr->pIde = pIde;
938 }
939 }
940 else if (vdScriptTokenizerGetTokenClass(pThis->pTokenizer) == VDTOKENCLASS_NUMCONST)
941 {
942 PCVDSCRIPTTOKEN pToken = vdScriptTokenizerGetToken(pThis->pTokenizer);
943 pExpr->enmType = VDSCRIPTEXPRTYPE_PRIMARY_NUMCONST;
944 pExpr->u64 = pToken->Class.NumConst.u64;
945 vdScriptTokenizerConsume(pThis->pTokenizer);
946 }
947 else if (vdScriptTokenizerGetTokenClass(pThis->pTokenizer) == VDTOKENCLASS_STRINGCONST)
948 {
949 PCVDSCRIPTTOKEN pToken = vdScriptTokenizerGetToken(pThis->pTokenizer);
950 pExpr->enmType = VDSCRIPTEXPRTYPE_PRIMARY_STRINGCONST;
951 pExpr->pszStr = RTStrDupN(pToken->Class.StringConst.pszString, pToken->Class.StringConst.cchString);
952 vdScriptTokenizerConsume(pThis->pTokenizer);
953
954 if (!pExpr->pszStr)
955 rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating string\n");
956 }
957 else if (vdScriptTokenizerGetTokenClass(pThis->pTokenizer) == VDTOKENCLASS_KEYWORD)
958 {
959 PCVDSCRIPTTOKEN pToken = vdScriptTokenizerGetToken(pThis->pTokenizer);
960 pExpr->enmType = VDSCRIPTEXPRTYPE_PRIMARY_BOOLEAN;
961
962 if (pToken->Class.Keyword.enmKeyword == VDSCRIPTTOKENKEYWORD_TRUE)
963 pExpr->f = true;
964 else if (pToken->Class.Keyword.enmKeyword == VDSCRIPTTOKENKEYWORD_FALSE)
965 pExpr->f = false;
966 else
967 rc = vdScriptParserError(pThis, VERR_INVALID_PARAMETER, RT_SRC_POS, "Parser: Unexpected keyword, expected true or false\n");
968 vdScriptTokenizerConsume(pThis->pTokenizer);
969 }
970 else
971 rc = vdScriptParserError(pThis, VERR_INVALID_PARAMETER, RT_SRC_POS, "Parser: Expected \"(\" | identifier | constant | string, got ...\n");
972
973 if (RT_FAILURE(rc))
974 vdScriptAstNodeFree(&pExpr->Core);
975 else
976 *ppAstNodeExpr = pExpr;
977 }
978 else
979 rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
980 }
981
982 LogFlowFunc(("returns rc=%Rrc\n", rc));
983 return rc;
984}
985
986/**
987 * Parse an argument list for a function call.
988 *
989 * @returns VBox status code.
990 * @param pThis The script context.
991 * @param pFnCall The function call AST node.
992 */
993static int vdScriptParseFnCallArgumentList(PVDSCRIPTCTXINT pThis, PVDSCRIPTASTEXPR pFnCall)
994{
995 int rc = VINF_SUCCESS;
996 PVDSCRIPTASTEXPR pExpr = NULL;
997
998 LogFlowFunc(("pThis=%p ppAstNodeExpr=%p\n"));
999
1000 rc = vdScriptParseAssignmentExpression(pThis, &pExpr);
1001 if (RT_SUCCESS(rc))
1002 {
1003 RTListAppend(&pFnCall->FnCall.ListArgs, &pExpr->Core.ListNode);
1004 while (vdScriptTokenizerSkipIfIsPunctuatorEqual(pThis->pTokenizer, ','))
1005 {
1006 rc = vdScriptParseAssignmentExpression(pThis, &pExpr);
1007 if (RT_SUCCESS(rc))
1008 RTListAppend(&pFnCall->FnCall.ListArgs, &pExpr->Core.ListNode);
1009 else
1010 break;
1011 }
1012 if ( RT_SUCCESS(rc)
1013 && !vdScriptTokenizerSkipIfIsPunctuatorEqual(pThis->pTokenizer, ')'))
1014 rc = vdScriptParserError(pThis, VERR_INVALID_PARAMETER, RT_SRC_POS, "Parser: Expected \")\", got ...\n");
1015 }
1016
1017 LogFlowFunc(("returns rc=%Rrc\n", rc));
1018 return rc;
1019}
1020
1021/**
1022 * Parse a postfix expression.
1023 *
1024 * @returns VBox status code.
1025 * @param pThis The script context.
1026 * @param ppAstNodeExpr Where to store the expression AST node on success.
1027 *
1028 * @note Syntax:
1029 * postfix-expression:
1030 * primary-expression
1031 * postfix-expression ( argument-expression )
1032 * postfix-expression ++
1033 * postfix-expression --
1034 */
1035static int vdScriptParsePostfixExpression(PVDSCRIPTCTXINT pThis, PVDSCRIPTASTEXPR *ppAstNodeExpr)
1036{
1037 int rc = VINF_SUCCESS;
1038 PVDSCRIPTASTEXPR pExpr = NULL;
1039
1040 LogFlowFunc(("pThis=%p ppAstNodeExpr=%p\n"));
1041
1042 rc = vdScriptParsePrimaryExpression(pThis, &pExpr);
1043 if (RT_SUCCESS(rc))
1044 {
1045 while (true)
1046 {
1047 PVDSCRIPTASTEXPR pExprNew = NULL;
1048
1049 if (vdScriptTokenizerSkipIfIsOperatorEqual(pThis->pTokenizer, "++"))
1050 {
1051 pExprNew = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
1052 if (pExprNew)
1053 {
1054 pExprNew->enmType = VDSCRIPTEXPRTYPE_POSTFIX_INCREMENT;
1055 pExprNew->pExpr = pExpr;
1056 pExpr = pExprNew;
1057 }
1058 else
1059 rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
1060 }
1061 else if (vdScriptTokenizerSkipIfIsOperatorEqual(pThis->pTokenizer, "--"))
1062 {
1063 pExprNew = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
1064 if (pExprNew)
1065 {
1066 pExprNew->enmType = VDSCRIPTEXPRTYPE_POSTFIX_DECREMENT;
1067 pExprNew->pExpr = pExpr;
1068 pExpr = pExprNew;
1069 }
1070 else
1071 rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
1072 }
1073 else if (vdScriptTokenizerSkipIfIsPunctuatorEqual(pThis->pTokenizer, '('))
1074 {
1075 pExprNew = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
1076 if (pExprNew)
1077 {
1078 pExprNew->enmType = VDSCRIPTEXPRTYPE_POSTFIX_FNCALL;
1079 RTListInit(&pExprNew->FnCall.ListArgs);
1080 if (!vdScriptTokenizerSkipIfIsPunctuatorEqual(pThis->pTokenizer, ')'))
1081 rc = vdScriptParseFnCallArgumentList(pThis, pExprNew);
1082 pExprNew->FnCall.pFnIde = pExpr;
1083 pExpr = pExprNew;
1084 }
1085 else
1086 rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
1087 }
1088 else
1089 break;
1090
1091 if (RT_FAILURE(rc))
1092 break;
1093 }
1094
1095 if (RT_SUCCESS(rc))
1096 *ppAstNodeExpr = pExpr;
1097 else
1098 vdScriptAstNodeFree(&pExpr->Core);
1099 }
1100
1101 LogFlowFunc(("returns rc=%Rrc\n", rc));
1102 return rc;
1103}
1104
1105/**
1106 * Parse an unary expression.
1107 *
1108 * @returns VBox status code.
1109 * @param pThis The script context.
1110 * @param ppAstNodeExpr Where to store the expression AST node on success.
1111 *
1112 * @note Syntax:
1113 * unary-expression:
1114 * postfix-expression
1115 * ++ unary-expression
1116 * -- unary-expression
1117 * + unary-expression
1118 * - unary-expression
1119 * ~ unary-expression
1120 * ! unary-expression
1121 */
1122static int vdScriptParseUnaryExpression(PVDSCRIPTCTXINT pThis, PVDSCRIPTASTEXPR *ppAstNodeExpr)
1123{
1124 int rc = VINF_SUCCESS;
1125 PVDSCRIPTASTEXPR pExpr = NULL;
1126 PVDSCRIPTASTEXPR pExprTop = NULL;
1127
1128 LogFlowFunc(("pThis=%p ppAstNodeExpr=%p\n"));
1129
1130 while (true)
1131 {
1132 bool fQuit = false;
1133 PVDSCRIPTASTEXPR pExprNew = NULL;
1134
1135 if (vdScriptTokenizerSkipIfIsOperatorEqual(pThis->pTokenizer, "++"))
1136 {
1137 pExprNew = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
1138 if (pExprNew)
1139 pExprNew->enmType = VDSCRIPTEXPRTYPE_UNARY_INCREMENT;
1140 else
1141 rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
1142 }
1143 else if (vdScriptTokenizerSkipIfIsOperatorEqual(pThis->pTokenizer, "--"))
1144 {
1145 pExprNew = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
1146 if (pExprNew)
1147 pExprNew->enmType = VDSCRIPTEXPRTYPE_UNARY_DECREMENT;
1148 else
1149 rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
1150 }
1151 else if (vdScriptTokenizerSkipIfIsOperatorEqual(pThis->pTokenizer, "+"))
1152 {
1153 pExprNew = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
1154 if (pExprNew)
1155 pExprNew->enmType = VDSCRIPTEXPRTYPE_UNARY_POSSIGN;
1156 else
1157 rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
1158 }
1159 else if (vdScriptTokenizerSkipIfIsOperatorEqual(pThis->pTokenizer, "-"))
1160 {
1161 pExprNew = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
1162 if (pExprNew)
1163 pExprNew->enmType = VDSCRIPTEXPRTYPE_UNARY_NEGSIGN;
1164 else
1165 rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
1166 }
1167 else if (vdScriptTokenizerSkipIfIsOperatorEqual(pThis->pTokenizer, "~"))
1168 {
1169 pExprNew = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
1170 if (pExprNew)
1171 pExprNew->enmType = VDSCRIPTEXPRTYPE_UNARY_INVERT;
1172 else
1173 rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
1174 }
1175 else if (vdScriptTokenizerSkipIfIsOperatorEqual(pThis->pTokenizer, "!"))
1176 {
1177 pExprNew = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
1178 if (pExprNew)
1179 pExprNew->enmType = VDSCRIPTEXPRTYPE_UNARY_NEGATE;
1180 else
1181 rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
1182 }
1183 else
1184 {
1185 /* Must be a postfix expression. */
1186 rc = vdScriptParsePostfixExpression(pThis, &pExprNew);
1187 fQuit = true;
1188 }
1189
1190 if (RT_SUCCESS(rc))
1191 {
1192 if (!pExprTop)
1193 {
1194 pExprTop = pExprNew;
1195 pExpr = pExprNew;
1196 }
1197 else
1198 {
1199 pExpr->pExpr = pExprNew;
1200 pExpr = pExprNew;
1201 }
1202 if (fQuit)
1203 break;
1204 }
1205 else
1206 break;
1207 }
1208
1209 if (RT_SUCCESS(rc))
1210 *ppAstNodeExpr = pExprTop;
1211 else if (pExprTop)
1212 vdScriptAstNodeFree(&pExprTop->Core);
1213
1214 LogFlowFunc(("returns rc=%Rrc\n", rc));
1215 return rc;
1216}
1217
1218/**
1219 * Parse a multiplicative expression.
1220 *
1221 * @returns VBox status code.
1222 * @param pThis The script context.
1223 * @param ppAstNodeExpr Where to store the expression AST node on success.
1224 *
1225 * @note Syntax:
1226 * multiplicative-expression:
1227 * unary-expression
1228 * multiplicative-expression * unary-expression
1229 * multiplicative-expression / unary-expression
1230 * multiplicative-expression % unary-expression
1231 */
1232static int vdScriptParseMultiplicativeExpression(PVDSCRIPTCTXINT pThis, PVDSCRIPTASTEXPR *ppAstNodeExpr)
1233{
1234 int rc = VINF_SUCCESS;
1235 PVDSCRIPTASTEXPR pExpr = NULL;
1236
1237 LogFlowFunc(("pThis=%p ppAstNodeExpr=%p\n"));
1238
1239 rc = vdScriptParseUnaryExpression(pThis, &pExpr);
1240 if (RT_SUCCESS(rc))
1241 {
1242 PVDSCRIPTASTEXPR pExprNew = NULL;
1243 while (RT_SUCCESS(rc))
1244 {
1245 if (vdScriptTokenizerSkipIfIsOperatorEqual(pThis->pTokenizer, "*"))
1246 {
1247 pExprNew = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
1248 if (pExprNew)
1249 pExprNew->enmType = VDSCRIPTEXPRTYPE_MULTIPLICATION;
1250 else
1251 rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
1252 }
1253 else if (vdScriptTokenizerSkipIfIsOperatorEqual(pThis->pTokenizer, "/"))
1254 {
1255 pExprNew = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
1256 if (pExprNew)
1257 pExprNew->enmType = VDSCRIPTEXPRTYPE_DIVISION;
1258 else
1259 rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
1260 }
1261 else if (vdScriptTokenizerSkipIfIsOperatorEqual(pThis->pTokenizer, "%"))
1262 {
1263 pExprNew = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
1264 if (pExprNew)
1265 pExprNew->enmType = VDSCRIPTEXPRTYPE_MODULUS;
1266 else
1267 rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
1268 }
1269 else
1270 break;
1271
1272 pExprNew->BinaryOp.pLeftExpr = pExpr;
1273 pExpr = pExprNew;
1274 rc = vdScriptParseUnaryExpression(pThis, &pExprNew);
1275 if (RT_SUCCESS(rc))
1276 pExpr->BinaryOp.pRightExpr = pExprNew;
1277 }
1278
1279 if (RT_SUCCESS(rc))
1280 *ppAstNodeExpr = pExpr;
1281 else
1282 vdScriptAstNodeFree(&pExpr->Core);
1283 }
1284
1285 LogFlowFunc(("returns rc=%Rrc\n", rc));
1286 return rc;
1287}
1288
1289/**
1290 * Parse a additive expression.
1291 *
1292 * @returns VBox status code.
1293 * @param pThis The script context.
1294 * @param ppAstNodeExpr Where to store the expression AST node on success.
1295 *
1296 * @note Syntax:
1297 * additive-expression:
1298 * multiplicative-expression
1299 * additive-expression + multiplicative-expression
1300 * additive-expression - multiplicative-expression
1301 */
1302static int vdScriptParseAdditiveExpression(PVDSCRIPTCTXINT pThis, PVDSCRIPTASTEXPR *ppAstNodeExpr)
1303{
1304 int rc = VINF_SUCCESS;
1305 PVDSCRIPTASTEXPR pExpr = NULL;
1306
1307 LogFlowFunc(("pThis=%p ppAstNodeExpr=%p\n"));
1308
1309 rc = vdScriptParseMultiplicativeExpression(pThis, &pExpr);
1310 if (RT_SUCCESS(rc))
1311 {
1312 PVDSCRIPTASTEXPR pExprNew = NULL;
1313 while (RT_SUCCESS(rc))
1314 {
1315 if (vdScriptTokenizerSkipIfIsOperatorEqual(pThis->pTokenizer, "+"))
1316 {
1317 pExprNew = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
1318 if (pExprNew)
1319 pExprNew->enmType = VDSCRIPTEXPRTYPE_ADDITION;
1320 else
1321 rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
1322 }
1323 else if (vdScriptTokenizerSkipIfIsOperatorEqual(pThis->pTokenizer, "-"))
1324 {
1325 pExprNew = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
1326 if (pExprNew)
1327 pExprNew->enmType = VDSCRIPTEXPRTYPE_SUBTRACTION;
1328 else
1329 rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
1330 }
1331 else
1332 break;
1333
1334 pExprNew->BinaryOp.pLeftExpr = pExpr;
1335 pExpr = pExprNew;
1336 rc = vdScriptParseMultiplicativeExpression(pThis, &pExprNew);
1337 if (RT_SUCCESS(rc))
1338 pExpr->BinaryOp.pRightExpr = pExprNew;
1339 }
1340
1341 if (RT_SUCCESS(rc))
1342 *ppAstNodeExpr = pExpr;
1343 else
1344 vdScriptAstNodeFree(&pExpr->Core);
1345 }
1346
1347 LogFlowFunc(("returns rc=%Rrc\n", rc));
1348 return rc;
1349}
1350
1351/**
1352 * Parse a shift expression.
1353 *
1354 * @returns VBox status code.
1355 * @param pThis The script context.
1356 * @param ppAstNodeExpr Where to store the expression AST node on success.
1357 *
1358 * @note Syntax:
1359 * shift-expression:
1360 * additive-expression
1361 * shift-expression << additive-expression
1362 * shift-expression >> additive-expression
1363 */
1364static int vdScriptParseShiftExpression(PVDSCRIPTCTXINT pThis, PVDSCRIPTASTEXPR *ppAstNodeExpr)
1365{
1366 int rc = VINF_SUCCESS;
1367 PVDSCRIPTASTEXPR pExpr = NULL;
1368
1369 LogFlowFunc(("pThis=%p ppAstNodeExpr=%p\n"));
1370
1371 rc = vdScriptParseAdditiveExpression(pThis, &pExpr);
1372 if (RT_SUCCESS(rc))
1373 {
1374 PVDSCRIPTASTEXPR pExprNew = NULL;
1375 while (RT_SUCCESS(rc))
1376 {
1377 if (vdScriptTokenizerSkipIfIsOperatorEqual(pThis->pTokenizer, "<<"))
1378 {
1379 pExprNew = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
1380 if (pExprNew)
1381 pExprNew->enmType = VDSCRIPTEXPRTYPE_LSL;
1382 else
1383 rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
1384 }
1385 else if (vdScriptTokenizerSkipIfIsOperatorEqual(pThis->pTokenizer, ">>"))
1386 {
1387 pExprNew = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
1388 if (pExprNew)
1389 pExprNew->enmType = VDSCRIPTEXPRTYPE_LSR;
1390 else
1391 rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
1392 }
1393 else
1394 break;
1395
1396 pExprNew->BinaryOp.pLeftExpr = pExpr;
1397 pExpr = pExprNew;
1398 rc = vdScriptParseAdditiveExpression(pThis, &pExprNew);
1399 if (RT_SUCCESS(rc))
1400 pExpr->BinaryOp.pRightExpr = pExprNew;
1401 }
1402
1403 if (RT_SUCCESS(rc))
1404 *ppAstNodeExpr = pExpr;
1405 else
1406 vdScriptAstNodeFree(&pExpr->Core);
1407 }
1408
1409 LogFlowFunc(("returns rc=%Rrc\n", rc));
1410 return rc;
1411}
1412
1413/**
1414 * Parse a relational expression.
1415 *
1416 * @returns VBox status code.
1417 * @param pThis The script context.
1418 * @param ppAstNodeExpr Where to store the expression AST node on success.
1419 *
1420 * @note Syntax:
1421 * relational-expression:
1422 * shift-expression
1423 * relational-expression < shift-expression
1424 * relational-expression > shift-expression
1425 * relational-expression >= shift-expression
1426 * relational-expression <= shift-expression
1427 */
1428static int vdScriptParseRelationalExpression(PVDSCRIPTCTXINT pThis, PVDSCRIPTASTEXPR *ppAstNodeExpr)
1429{
1430 int rc = VINF_SUCCESS;
1431 PVDSCRIPTASTEXPR pExpr = NULL;
1432
1433 LogFlowFunc(("pThis=%p ppAstNodeExpr=%p\n"));
1434
1435 rc = vdScriptParseShiftExpression(pThis, &pExpr);
1436 if (RT_SUCCESS(rc))
1437 {
1438 PVDSCRIPTASTEXPR pExprNew = NULL;
1439 while (RT_SUCCESS(rc))
1440 {
1441 if (vdScriptTokenizerSkipIfIsOperatorEqual(pThis->pTokenizer, "<"))
1442 {
1443 pExprNew = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
1444 if (pExprNew)
1445 pExprNew->enmType = VDSCRIPTEXPRTYPE_LOWER;
1446 else
1447 rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
1448 }
1449 else if (vdScriptTokenizerSkipIfIsOperatorEqual(pThis->pTokenizer, ">"))
1450 {
1451 pExprNew = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
1452 if (pExprNew)
1453 pExprNew->enmType = VDSCRIPTEXPRTYPE_HIGHER;
1454 else
1455 rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
1456 }
1457 else if (vdScriptTokenizerSkipIfIsOperatorEqual(pThis->pTokenizer, ">="))
1458 {
1459 pExprNew = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
1460 if (pExprNew)
1461 pExprNew->enmType = VDSCRIPTEXPRTYPE_HIGHEREQUAL;
1462 else
1463 rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
1464 }
1465 else if (vdScriptTokenizerSkipIfIsOperatorEqual(pThis->pTokenizer, "<="))
1466 {
1467 pExprNew = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
1468 if (pExprNew)
1469 pExprNew->enmType = VDSCRIPTEXPRTYPE_LOWEREQUAL;
1470 else
1471 rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
1472 }
1473 else
1474 break;
1475
1476 pExprNew->BinaryOp.pLeftExpr = pExpr;
1477 pExpr = pExprNew;
1478 rc = vdScriptParseShiftExpression(pThis, &pExprNew);
1479 if (RT_SUCCESS(rc))
1480 pExpr->BinaryOp.pRightExpr = pExprNew;
1481 }
1482
1483 if (RT_SUCCESS(rc))
1484 *ppAstNodeExpr = pExpr;
1485 else
1486 vdScriptAstNodeFree(&pExpr->Core);
1487 }
1488
1489 LogFlowFunc(("returns rc=%Rrc\n", rc));
1490 return rc;
1491}
1492
1493/**
1494 * Parse a equality expression.
1495 *
1496 * @returns VBox status code.
1497 * @param pThis The script context.
1498 * @param ppAstNodeExpr Where to store the expression AST node on success.
1499 *
1500 * @note Syntax:
1501 * equality-expression:
1502 * relational-expression
1503 * equality-expression == relational-expression
1504 * equality-expression != relational-expression
1505 */
1506static int vdScriptParseEqualityExpression(PVDSCRIPTCTXINT pThis, PVDSCRIPTASTEXPR *ppAstNodeExpr)
1507{
1508 int rc = VINF_SUCCESS;
1509 PVDSCRIPTASTEXPR pExpr = NULL;
1510
1511 LogFlowFunc(("pThis=%p ppAstNodeExpr=%p\n"));
1512
1513 rc = vdScriptParseRelationalExpression(pThis, &pExpr);
1514 if (RT_SUCCESS(rc))
1515 {
1516 PVDSCRIPTASTEXPR pExprNew = NULL;
1517 while (RT_SUCCESS(rc))
1518 {
1519 if (vdScriptTokenizerSkipIfIsOperatorEqual(pThis->pTokenizer, "=="))
1520 {
1521 pExprNew = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
1522 if (pExprNew)
1523 pExprNew->enmType = VDSCRIPTEXPRTYPE_EQUAL;
1524 else
1525 rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
1526 }
1527 else if (vdScriptTokenizerSkipIfIsOperatorEqual(pThis->pTokenizer, "!="))
1528 {
1529 pExprNew = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
1530 if (pExprNew)
1531 pExprNew->enmType = VDSCRIPTEXPRTYPE_NOTEQUAL;
1532 else
1533 rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
1534 }
1535 else
1536 break;
1537
1538 pExprNew->BinaryOp.pLeftExpr = pExpr;
1539 pExpr = pExprNew;
1540 rc = vdScriptParseRelationalExpression(pThis, &pExprNew);
1541 if (RT_SUCCESS(rc))
1542 pExpr->BinaryOp.pRightExpr = pExprNew;
1543 }
1544
1545 if (RT_SUCCESS(rc))
1546 *ppAstNodeExpr = pExpr;
1547 else
1548 vdScriptAstNodeFree(&pExpr->Core);
1549 }
1550
1551 LogFlowFunc(("returns rc=%Rrc\n", rc));
1552 return rc;
1553}
1554
1555/**
1556 * Parse a bitwise and expression.
1557 *
1558 * @returns VBox status code.
1559 * @param pThis The script context.
1560 * @param ppAstNodeExpr Where to store the expression AST node on success.
1561 *
1562 * @note Syntax:
1563 * and-expression:
1564 * equality-expression
1565 * and-expression & equality-expression
1566 */
1567static int vdScriptParseBitwiseAndExpression(PVDSCRIPTCTXINT pThis, PVDSCRIPTASTEXPR *ppAstNodeExpr)
1568{
1569 int rc = VINF_SUCCESS;
1570 PVDSCRIPTASTEXPR pExpr = NULL;
1571
1572 LogFlowFunc(("pThis=%p ppAstNodeExpr=%p\n"));
1573
1574 rc = vdScriptParseEqualityExpression(pThis, &pExpr);
1575 if (RT_SUCCESS(rc))
1576 {
1577 PVDSCRIPTASTEXPR pExprNew = NULL;
1578 while ( RT_SUCCESS(rc)
1579 && vdScriptTokenizerSkipIfIsOperatorEqual(pThis->pTokenizer, "&"))
1580 {
1581 pExprNew = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
1582 if (pExprNew)
1583 {
1584 pExprNew->enmType = VDSCRIPTEXPRTYPE_EQUAL;
1585 pExprNew->BinaryOp.pLeftExpr = pExpr;
1586 pExpr = pExprNew;
1587 rc = vdScriptParseEqualityExpression(pThis, &pExprNew);
1588 if (RT_SUCCESS(rc))
1589 pExpr->BinaryOp.pRightExpr = pExprNew;
1590 }
1591 else
1592 rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
1593 }
1594
1595 if (RT_SUCCESS(rc))
1596 *ppAstNodeExpr = pExpr;
1597 else
1598 vdScriptAstNodeFree(&pExpr->Core);
1599 }
1600
1601 LogFlowFunc(("returns rc=%Rrc\n", rc));
1602 return rc;
1603}
1604
1605/**
1606 * Parse a bitwise xor expression.
1607 *
1608 * @returns VBox status code.
1609 * @param pThis The script context.
1610 * @param ppAstNodeExpr Where to store the expression AST node on success.
1611 *
1612 * @note Syntax:
1613 * xor-expression:
1614 * and-expression
1615 * xor-expression ^ equality-expression
1616 */
1617static int vdScriptParseBitwiseXorExpression(PVDSCRIPTCTXINT pThis, PVDSCRIPTASTEXPR *ppAstNodeExpr)
1618{
1619 int rc = VINF_SUCCESS;
1620 PVDSCRIPTASTEXPR pExpr = NULL;
1621
1622 LogFlowFunc(("pThis=%p ppAstNodeExpr=%p\n"));
1623
1624 rc = vdScriptParseBitwiseAndExpression(pThis, &pExpr);
1625 if (RT_SUCCESS(rc))
1626 {
1627 PVDSCRIPTASTEXPR pExprNew = NULL;
1628 while ( RT_SUCCESS(rc)
1629 && vdScriptTokenizerSkipIfIsOperatorEqual(pThis->pTokenizer, "^"))
1630 {
1631 pExprNew = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
1632 if (pExprNew)
1633 {
1634 pExprNew->enmType = VDSCRIPTEXPRTYPE_BITWISE_XOR;
1635 pExprNew->BinaryOp.pLeftExpr = pExpr;
1636 pExpr = pExprNew;
1637 rc = vdScriptParseBitwiseAndExpression(pThis, &pExprNew);
1638 if (RT_SUCCESS(rc))
1639 pExpr->BinaryOp.pRightExpr = pExprNew;
1640 }
1641 else
1642 rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
1643 }
1644
1645 if (RT_SUCCESS(rc))
1646 *ppAstNodeExpr = pExpr;
1647 else
1648 vdScriptAstNodeFree(&pExpr->Core);
1649 }
1650
1651 LogFlowFunc(("returns rc=%Rrc\n", rc));
1652 return rc;
1653}
1654
1655/**
1656 * Parse a bitwise or expression.
1657 *
1658 * @returns VBox status code.
1659 * @param pThis The script context.
1660 * @param ppAstNodeExpr Where to store the expression AST node on success.
1661 *
1662 * @note Syntax:
1663 * or-expression:
1664 * xor-expression
1665 * or-expression | xor-expression
1666 */
1667static int vdScriptParseBitwiseOrExpression(PVDSCRIPTCTXINT pThis, PVDSCRIPTASTEXPR *ppAstNodeExpr)
1668{
1669 int rc = VINF_SUCCESS;
1670 PVDSCRIPTASTEXPR pExpr = NULL;
1671
1672 LogFlowFunc(("pThis=%p ppAstNodeExpr=%p\n"));
1673
1674 rc = vdScriptParseBitwiseXorExpression(pThis, &pExpr);
1675 if (RT_SUCCESS(rc))
1676 {
1677 PVDSCRIPTASTEXPR pExprNew = NULL;
1678 while ( RT_SUCCESS(rc)
1679 && vdScriptTokenizerSkipIfIsOperatorEqual(pThis->pTokenizer, "|"))
1680 {
1681 pExprNew = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
1682 if (pExprNew)
1683 {
1684 pExprNew->enmType = VDSCRIPTEXPRTYPE_BITWISE_OR;
1685 pExprNew->BinaryOp.pLeftExpr = pExpr;
1686 pExpr = pExprNew;
1687 rc = vdScriptParseBitwiseXorExpression(pThis, &pExprNew);
1688 if (RT_SUCCESS(rc))
1689 pExpr->BinaryOp.pRightExpr = pExprNew;
1690 }
1691 else
1692 rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
1693 }
1694
1695 if (RT_SUCCESS(rc))
1696 *ppAstNodeExpr = pExpr;
1697 else
1698 vdScriptAstNodeFree(&pExpr->Core);
1699 }
1700
1701 LogFlowFunc(("returns rc=%Rrc\n", rc));
1702 return rc;
1703}
1704
1705/**
1706 * Parse a logical and expression.
1707 *
1708 * @returns VBox status code.
1709 * @param pThis The script context.
1710 * @param ppAstNodeExpr Where to store the expression AST node on success.
1711 *
1712 * @note Syntax:
1713 * logical-and-expression:
1714 * or-expression
1715 * logical-and-expression | or-expression
1716 */
1717static int vdScriptParseLogicalAndExpression(PVDSCRIPTCTXINT pThis, PVDSCRIPTASTEXPR *ppAstNodeExpr)
1718{
1719 int rc = VINF_SUCCESS;
1720 PVDSCRIPTASTEXPR pExpr = NULL;
1721
1722 LogFlowFunc(("pThis=%p ppAstNodeExpr=%p\n"));
1723
1724 rc = vdScriptParseBitwiseOrExpression(pThis, &pExpr);
1725 if (RT_SUCCESS(rc))
1726 {
1727 PVDSCRIPTASTEXPR pExprNew = NULL;
1728 while ( RT_SUCCESS(rc)
1729 && vdScriptTokenizerSkipIfIsOperatorEqual(pThis->pTokenizer, "&&"))
1730 {
1731 pExprNew = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
1732 if (pExprNew)
1733 {
1734 pExprNew->enmType = VDSCRIPTEXPRTYPE_LOGICAL_AND;
1735 pExprNew->BinaryOp.pLeftExpr = pExpr;
1736 pExpr = pExprNew;
1737 rc = vdScriptParseBitwiseOrExpression(pThis, &pExprNew);
1738 if (RT_SUCCESS(rc))
1739 pExpr->BinaryOp.pRightExpr = pExprNew;
1740 }
1741 else
1742 rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
1743 }
1744
1745 if (RT_SUCCESS(rc))
1746 *ppAstNodeExpr = pExpr;
1747 else
1748 vdScriptAstNodeFree(&pExpr->Core);
1749 }
1750
1751 LogFlowFunc(("returns rc=%Rrc\n", rc));
1752 return rc;
1753}
1754
1755/**
1756 * Parse a logical or expression.
1757 *
1758 * @returns VBox status code.
1759 * @param pThis The script context.
1760 * @param ppAstNodeExpr Where to store the expression AST node on success.
1761 *
1762 * @note Syntax:
1763 * logical-or-expression:
1764 * logical-and-expression
1765 * logical-or-expression | logical-and-expression
1766 */
1767static int vdScriptParseLogicalOrExpression(PVDSCRIPTCTXINT pThis, PVDSCRIPTASTEXPR *ppAstNodeExpr)
1768{
1769 int rc = VINF_SUCCESS;
1770 PVDSCRIPTASTEXPR pExpr = NULL;
1771
1772 LogFlowFunc(("pThis=%p ppAstNodeExpr=%p\n"));
1773
1774 rc = vdScriptParseLogicalAndExpression(pThis, &pExpr);
1775 if (RT_SUCCESS(rc))
1776 {
1777 PVDSCRIPTASTEXPR pExprNew = NULL;
1778 while ( RT_SUCCESS(rc)
1779 && vdScriptTokenizerSkipIfIsOperatorEqual(pThis->pTokenizer, "||"))
1780 {
1781 pExprNew = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
1782 if (pExprNew)
1783 {
1784 pExprNew->enmType = VDSCRIPTEXPRTYPE_LOGICAL_OR;
1785 pExprNew->BinaryOp.pLeftExpr = pExpr;
1786 pExpr = pExprNew;
1787 rc = vdScriptParseLogicalAndExpression(pThis, &pExprNew);
1788 if (RT_SUCCESS(rc))
1789 pExpr->BinaryOp.pRightExpr = pExprNew;
1790 }
1791 else
1792 rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
1793 }
1794
1795 if (RT_SUCCESS(rc))
1796 *ppAstNodeExpr = pExpr;
1797 else
1798 vdScriptAstNodeFree(&pExpr->Core);
1799 }
1800
1801 LogFlowFunc(("returns rc=%Rrc\n", rc));
1802 return rc;
1803}
1804
1805/**
1806 * Parse a conditional expression.
1807 *
1808 * @returns VBox status code.
1809 * @param pThis The script context.
1810 * @param ppAstNodeExpr Where to store the expression AST node on success.
1811 *
1812 * @note: VDScript doesn't support logical-or-expression ? expression : conditional-expression
1813 * so a conditional expression is equal to a logical-or-expression.
1814 */
1815static int vdScriptParseCondExpression(PVDSCRIPTCTXINT pThis, PVDSCRIPTASTEXPR *ppAstNodeExpr)
1816{
1817 return vdScriptParseLogicalOrExpression(pThis, ppAstNodeExpr);
1818}
1819
1820/**
1821 * Parse an assignment expression.
1822 *
1823 * @returns VBox status code.
1824 * @param pThis The script context.
1825 * @param ppAstNodeExpr Where to store the expression AST node on success.
1826 *
1827 * @note Syntax:
1828 * assignment-expression:
1829 * conditional-expression
1830 * unary-expression assignment-operator assignment-expression
1831 */
1832static int vdScriptParseAssignmentExpression(PVDSCRIPTCTXINT pThis, PVDSCRIPTASTEXPR *ppAstNodeExpr)
1833{
1834 int rc = VINF_SUCCESS;
1835 PVDSCRIPTASTEXPR pExpr;
1836
1837 LogFlowFunc(("pThis=%p ppAstNodeExpr=%p\n"));
1838
1839 rc = vdScriptParseLogicalOrExpression(pThis, &pExpr);
1840 if (RT_SUCCESS(rc))
1841 {
1842 PVDSCRIPTASTEXPR pExprNew = NULL;
1843 while (RT_SUCCESS(rc))
1844 {
1845 if (vdScriptTokenizerSkipIfIsOperatorEqual(pThis->pTokenizer, "="))
1846 {
1847 pExprNew = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
1848 if (pExprNew)
1849 pExprNew->enmType = VDSCRIPTEXPRTYPE_ASSIGN;
1850 else
1851 rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
1852 }
1853 else if (vdScriptTokenizerSkipIfIsOperatorEqual(pThis->pTokenizer, "*="))
1854 {
1855 pExprNew = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
1856 if (pExprNew)
1857 pExprNew->enmType = VDSCRIPTEXPRTYPE_ASSIGN_MULT;
1858 else
1859 rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
1860 }
1861 else if (vdScriptTokenizerSkipIfIsOperatorEqual(pThis->pTokenizer, "/="))
1862 {
1863 pExprNew = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
1864 if (pExprNew)
1865 pExprNew->enmType = VDSCRIPTEXPRTYPE_ASSIGN_DIV;
1866 else
1867 rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
1868 }
1869 else if (vdScriptTokenizerSkipIfIsOperatorEqual(pThis->pTokenizer, "%="))
1870 {
1871 pExprNew = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
1872 if (pExprNew)
1873 pExprNew->enmType = VDSCRIPTEXPRTYPE_ASSIGN_MOD;
1874 else
1875 rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
1876 }
1877 else if (vdScriptTokenizerSkipIfIsOperatorEqual(pThis->pTokenizer, "+="))
1878 {
1879 pExprNew = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
1880 if (pExprNew)
1881 pExprNew->enmType = VDSCRIPTEXPRTYPE_ASSIGN_ADD;
1882 else
1883 rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
1884 }
1885 else if (vdScriptTokenizerSkipIfIsOperatorEqual(pThis->pTokenizer, "-="))
1886 {
1887 pExprNew = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
1888 if (pExprNew)
1889 pExprNew->enmType = VDSCRIPTEXPRTYPE_ASSIGN_SUB;
1890 else
1891 rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
1892 }
1893 else if (vdScriptTokenizerSkipIfIsOperatorEqual(pThis->pTokenizer, "<<="))
1894 {
1895 pExprNew = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
1896 if (pExprNew)
1897 pExprNew->enmType = VDSCRIPTEXPRTYPE_ASSIGN_LSL;
1898 else
1899 rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
1900 }
1901 else if (vdScriptTokenizerSkipIfIsOperatorEqual(pThis->pTokenizer, ">>="))
1902 {
1903 pExprNew = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
1904 if (pExprNew)
1905 pExprNew->enmType = VDSCRIPTEXPRTYPE_ASSIGN_LSR;
1906 else
1907 rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
1908 }
1909 else if (vdScriptTokenizerSkipIfIsOperatorEqual(pThis->pTokenizer, "&="))
1910 {
1911 pExprNew = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
1912 if (pExprNew)
1913 pExprNew->enmType = VDSCRIPTEXPRTYPE_ASSIGN_AND;
1914 else
1915 rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
1916 }
1917 else if (vdScriptTokenizerSkipIfIsOperatorEqual(pThis->pTokenizer, "^="))
1918 {
1919 pExprNew = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
1920 if (pExprNew)
1921 pExprNew->enmType = VDSCRIPTEXPRTYPE_ASSIGN_XOR;
1922 else
1923 rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
1924 }
1925 else if (vdScriptTokenizerSkipIfIsOperatorEqual(pThis->pTokenizer, "|="))
1926 {
1927 pExprNew = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
1928 if (pExprNew)
1929 pExprNew->enmType = VDSCRIPTEXPRTYPE_ASSIGN_OR;
1930 else
1931 rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
1932 }
1933 else
1934 break;
1935
1936 pExprNew->BinaryOp.pLeftExpr = pExpr;
1937 pExpr = pExprNew;
1938 rc = vdScriptParseLogicalOrExpression(pThis, &pExprNew);
1939 if (RT_SUCCESS(rc))
1940 pExpr->BinaryOp.pRightExpr = pExprNew;
1941 }
1942
1943 if (RT_SUCCESS(rc))
1944 *ppAstNodeExpr = pExpr;
1945 else
1946 vdScriptAstNodeFree(&pExpr->Core);
1947 }
1948
1949 LogFlowFunc(("returns rc=%Rrc\n", rc));
1950 return rc;
1951}
1952
1953/**
1954 * Parse an expression.
1955 *
1956 * @returns VBox status code.
1957 * @param pThis The script context.
1958 * @param ppAstNodeExpr Where to store the expression AST node on success.
1959 *
1960 * @note Syntax:
1961 * expression:
1962 * assignment-expression
1963 * expression , assignment-expression
1964 */
1965static int vdScriptParseExpression(PVDSCRIPTCTXINT pThis, PVDSCRIPTASTEXPR *ppAstNodeExpr)
1966{
1967 int rc = VINF_SUCCESS;
1968 PVDSCRIPTASTEXPR pAssignExpr = NULL;
1969
1970 LogFlowFunc(("pThis=%p ppAstNodeExpr=%p\n"));
1971
1972 rc = vdScriptParseAssignmentExpression(pThis, &pAssignExpr);
1973 if ( RT_SUCCESS(rc)
1974 && vdScriptTokenizerSkipIfIsPunctuatorEqual(pThis->pTokenizer, ','))
1975 {
1976 PVDSCRIPTASTEXPR pListAssignExpr = (PVDSCRIPTASTEXPR)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_EXPRESSION);
1977 if (pListAssignExpr)
1978 {
1979 pListAssignExpr->enmType = VDSCRIPTEXPRTYPE_ASSIGNMENT_LIST;
1980 RTListInit(&pListAssignExpr->ListExpr);
1981 RTListAppend(&pListAssignExpr->ListExpr, &pAssignExpr->Core.ListNode);
1982 do
1983 {
1984 rc = vdScriptParseAssignmentExpression(pThis, &pAssignExpr);
1985 if (RT_SUCCESS(rc))
1986 RTListAppend(&pListAssignExpr->ListExpr, &pAssignExpr->Core.ListNode);
1987 } while ( RT_SUCCESS(rc)
1988 && vdScriptTokenizerSkipIfIsPunctuatorEqual(pThis->pTokenizer, ','));
1989
1990 if (RT_FAILURE(rc))
1991 vdScriptAstNodeFree(&pListAssignExpr->Core);
1992 else
1993 *ppAstNodeExpr = pListAssignExpr;
1994 }
1995 else
1996 rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating expression AST node\n");
1997 }
1998 else if (RT_SUCCESS(rc))
1999 *ppAstNodeExpr = pAssignExpr;
2000
2001 LogFlowFunc(("returns rc=%Rrc\n", rc));
2002 return rc;
2003}
2004
2005/**
2006 * Parse an if statement.
2007 *
2008 * @returns VBox status code.
2009 * @param pThis The script context.
2010 * @param pAstNodeIf Uninitialized if AST node.
2011 *
2012 * @note The caller skipped the "if" token already.
2013 */
2014static int vdScriptParseIf(PVDSCRIPTCTXINT pThis, PVDSCRIPTASTIF pAstNodeIf)
2015{
2016 int rc = VINF_SUCCESS;
2017
2018 if (vdScriptTokenizerSkipIfIsPunctuatorEqual(pThis->pTokenizer, '('))
2019 {
2020 PVDSCRIPTASTEXPR pCondExpr = NULL;
2021 rc = vdScriptParseExpression(pThis, &pCondExpr);
2022 if (RT_SUCCESS(rc))
2023 {
2024 if (vdScriptTokenizerSkipIfIsPunctuatorEqual(pThis->pTokenizer, ')'))
2025 {
2026 PVDSCRIPTASTSTMT pStmt = NULL;
2027 PVDSCRIPTASTSTMT pElseStmt = NULL;
2028 rc = vdScriptParseStatement(pThis, &pStmt);
2029 if ( RT_SUCCESS(rc)
2030 && vdScriptTokenizerSkipIfIsKeywordEqual(pThis->pTokenizer, VDSCRIPTTOKENKEYWORD_ELSE))
2031 rc = vdScriptParseStatement(pThis, &pElseStmt);
2032
2033 if (RT_SUCCESS(rc))
2034 {
2035 pAstNodeIf->pCond = pCondExpr;
2036 pAstNodeIf->pTrueStmt = pStmt;
2037 pAstNodeIf->pElseStmt = pElseStmt;
2038 }
2039 else if (pStmt)
2040 vdScriptAstNodeFree(&pStmt->Core);
2041 }
2042 else
2043 rc = vdScriptParserError(pThis, VERR_INVALID_PARAMETER, RT_SRC_POS, "Parser: Expected \")\", got ...\n");
2044
2045 if (RT_FAILURE(rc))
2046 vdScriptAstNodeFree(&pCondExpr->Core);
2047 }
2048 }
2049 else
2050 rc = vdScriptParserError(pThis, VERR_INVALID_PARAMETER, RT_SRC_POS, "Parser: Expected \"(\", got ...\n");
2051
2052 return rc;
2053}
2054
2055/**
2056 * Parse a switch statement.
2057 *
2058 * @returns VBox status code.
2059 * @param pThis The script context.
2060 * @param pAstNodeSwitch Uninitialized switch AST node.
2061 *
2062 * @note The caller skipped the "switch" token already.
2063 */
2064static int vdScriptParseSwitch(PVDSCRIPTCTXINT pThis, PVDSCRIPTASTSWITCH pAstNodeSwitch)
2065{
2066 int rc = VINF_SUCCESS;
2067
2068 if (vdScriptTokenizerSkipIfIsPunctuatorEqual(pThis->pTokenizer, '('))
2069 {
2070 PVDSCRIPTASTEXPR pExpr = NULL;
2071
2072 rc = vdScriptParseExpression(pThis, &pExpr);
2073 if ( RT_SUCCESS(rc)
2074 && vdScriptTokenizerSkipIfIsPunctuatorEqual(pThis->pTokenizer, ')'))
2075 {
2076 PVDSCRIPTASTSTMT pStmt = NULL;
2077 rc = vdScriptParseStatement(pThis, &pStmt);
2078 if (RT_SUCCESS(rc))
2079 {
2080 pAstNodeSwitch->pCond = pExpr;
2081 pAstNodeSwitch->pStmt = pStmt;
2082 }
2083 else
2084 vdScriptAstNodeFree(&pExpr->Core);
2085 }
2086 else if (RT_SUCCESS(rc))
2087 {
2088 rc = vdScriptParserError(pThis, VERR_INVALID_PARAMETER, RT_SRC_POS, "Parser: Expected \")\", got ...\n");
2089 vdScriptAstNodeFree(&pExpr->Core);
2090 }
2091 }
2092 else
2093 rc = vdScriptParserError(pThis, VERR_INVALID_PARAMETER, RT_SRC_POS, "Parser: Expected \"(\", got ...\n");
2094
2095 return rc;
2096}
2097
2098/**
2099 * Parse a while or do ... while statement.
2100 *
2101 * @returns VBox status code.
2102 * @param pThis The script context.
2103 * @param pAstNodeWhile Uninitialized while AST node.
2104 *
2105 * @note The caller skipped the "while" or "do" token already.
2106 */
2107static int vdScriptParseWhile(PVDSCRIPTCTXINT pThis, PVDSCRIPTASTWHILE pAstNodeWhile, bool fDoWhile)
2108{
2109 int rc = VINF_SUCCESS;
2110
2111 pAstNodeWhile->fDoWhile = fDoWhile;
2112
2113 if (fDoWhile)
2114 {
2115 PVDSCRIPTASTSTMT pStmt = NULL;
2116 rc = vdScriptParseStatement(pThis, &pStmt);
2117 if ( RT_SUCCESS(rc)
2118 && vdScriptTokenizerSkipIfIsKeywordEqual(pThis->pTokenizer, VDSCRIPTTOKENKEYWORD_WHILE))
2119 {
2120 if (vdScriptTokenizerSkipIfIsPunctuatorEqual(pThis->pTokenizer, '('))
2121 {
2122 PVDSCRIPTASTEXPR pExpr = NULL;
2123
2124 rc = vdScriptParseExpression(pThis, &pExpr);
2125 if ( RT_SUCCESS(rc)
2126 && vdScriptTokenizerSkipIfIsPunctuatorEqual(pThis->pTokenizer, ')'))
2127 {
2128 pAstNodeWhile->pCond = pExpr;
2129 pAstNodeWhile->pStmt = pStmt;
2130 }
2131 else if (RT_SUCCESS(rc))
2132 {
2133 rc = vdScriptParserError(pThis, VERR_INVALID_PARAMETER, RT_SRC_POS, "Parser: Expected \")\", got ...\n");
2134 vdScriptAstNodeFree(&pExpr->Core);
2135 }
2136 }
2137 else
2138 rc = vdScriptParserError(pThis, VERR_INVALID_PARAMETER, RT_SRC_POS, "Parser: Expected \"(\", got ...\n");
2139 }
2140 else if (RT_SUCCESS(rc))
2141 rc = vdScriptParserError(pThis, VERR_INVALID_PARAMETER, RT_SRC_POS, "Parser: Expected \"while\", got ...\n");
2142
2143 if ( RT_FAILURE(rc)
2144 && pStmt)
2145 vdScriptAstNodeFree(&pStmt->Core);
2146 }
2147 else
2148 {
2149 if (vdScriptTokenizerSkipIfIsPunctuatorEqual(pThis->pTokenizer, '('))
2150 {
2151 PVDSCRIPTASTEXPR pExpr = NULL;
2152
2153 rc = vdScriptParseExpression(pThis, &pExpr);
2154 if ( RT_SUCCESS(rc)
2155 && vdScriptTokenizerSkipIfIsPunctuatorEqual(pThis->pTokenizer, ')'))
2156 {
2157 PVDSCRIPTASTSTMT pStmt = NULL;
2158 rc = vdScriptParseStatement(pThis, &pStmt);
2159 if (RT_SUCCESS(rc))
2160 {
2161 pAstNodeWhile->pCond = pExpr;
2162 pAstNodeWhile->pStmt = pStmt;
2163 }
2164 else
2165 vdScriptAstNodeFree(&pExpr->Core);
2166 }
2167 else if (RT_SUCCESS(rc))
2168 {
2169 rc = vdScriptParserError(pThis, VERR_INVALID_PARAMETER, RT_SRC_POS, "Parser: Expected \")\", got ...\n");
2170 vdScriptAstNodeFree(&pExpr->Core);
2171 }
2172 }
2173 else
2174 rc = vdScriptParserError(pThis, VERR_INVALID_PARAMETER, RT_SRC_POS, "Parser: Expected \"(\", got ...\n");
2175 }
2176
2177 return rc;
2178}
2179
2180/**
2181 * Parse a for statement.
2182 *
2183 * @returns VBox status code.
2184 * @param pThis The script context.
2185 * @param pAstNodeFor Uninitialized for AST node.
2186 *
2187 * @note The caller skipped the "for" token already.
2188 */
2189static int vdScriptParseFor(PVDSCRIPTCTXINT pThis, PVDSCRIPTASTFOR pAstNodeFor)
2190{
2191 int rc = VINF_SUCCESS;
2192
2193 if (vdScriptTokenizerSkipIfIsPunctuatorEqual(pThis->pTokenizer, '('))
2194 {
2195 PVDSCRIPTASTEXPR pExprStart = NULL;
2196 PVDSCRIPTASTEXPR pExprCond = NULL;
2197 PVDSCRIPTASTEXPR pExpr3 = NULL;
2198
2199 rc = vdScriptParseExpression(pThis, &pExprStart);
2200 if ( RT_SUCCESS(rc)
2201 && vdScriptTokenizerSkipIfIsPunctuatorEqual(pThis->pTokenizer, ';'))
2202 {
2203 rc = vdScriptParseExpression(pThis, &pExprCond);
2204 if ( RT_SUCCESS(rc)
2205 && vdScriptTokenizerSkipIfIsPunctuatorEqual(pThis->pTokenizer, ';'))
2206 {
2207 rc = vdScriptParseExpression(pThis, &pExpr3);
2208 if ( RT_SUCCESS(rc)
2209 && vdScriptTokenizerSkipIfIsPunctuatorEqual(pThis->pTokenizer, ')'))
2210 {
2211 PVDSCRIPTASTSTMT pStmt = NULL;
2212 rc = vdScriptParseStatement(pThis, &pStmt);
2213 if (RT_SUCCESS(rc))
2214 {
2215 pAstNodeFor->pExprStart = pExprStart;
2216 pAstNodeFor->pExprCond = pExprCond;
2217 pAstNodeFor->pExpr3 = pExpr3;
2218 pAstNodeFor->pStmt = pStmt;
2219 }
2220 }
2221 }
2222 else if (RT_SUCCESS(rc))
2223 rc = vdScriptParserError(pThis, VERR_INVALID_PARAMETER, RT_SRC_POS, "Parser: Expected \";\", got ...\n");
2224 }
2225 else if (RT_SUCCESS(rc))
2226 rc = vdScriptParserError(pThis, VERR_INVALID_PARAMETER, RT_SRC_POS, "Parser: Expected \";\", got ...\n");
2227
2228 if (RT_FAILURE(rc))
2229 {
2230 if (pExprStart)
2231 vdScriptAstNodeFree(&pExprStart->Core);
2232 if (pExprCond)
2233 vdScriptAstNodeFree(&pExprCond->Core);
2234 if (pExpr3)
2235 vdScriptAstNodeFree(&pExpr3->Core);
2236 }
2237 }
2238 else
2239 rc = vdScriptParserError(pThis, VERR_INVALID_PARAMETER, RT_SRC_POS, "Parser: Expected \"(\", got ...\n");
2240
2241 return rc;
2242}
2243
2244/**
2245 * Parse a declaration.
2246 *
2247 * @returns VBox status code.
2248 * @param pThis The script context.
2249 * @param ppAstNodeDecl Where to store the declaration AST node on success.
2250 */
2251static int vdScriptParseDeclaration(PVDSCRIPTCTXINT pThis, PVDSCRIPTASTDECL *ppAstNodeDecl)
2252{
2253 int rc = VERR_NOT_IMPLEMENTED;
2254 return rc;
2255}
2256
2257/**
2258 * Parse a statement.
2259 *
2260 * @returns VBox status code.
2261 * @param pThis The script context.
2262 * @param ppAstNodeStmt Where to store the statement AST node on success.
2263 */
2264static int vdScriptParseStatement(PVDSCRIPTCTXINT pThis, PVDSCRIPTASTSTMT *ppAstNodeStmt)
2265{
2266 int rc = VINF_SUCCESS;
2267
2268 /* Shortcut for a new compound statement. */
2269 if (vdScriptTokenizerIsPunctuatorEqual(pThis->pTokenizer, '{'))
2270 rc = vdScriptParseCompoundStatement(pThis, ppAstNodeStmt);
2271 else
2272 {
2273 PVDSCRIPTASTSTMT pAstNodeStmt = (PVDSCRIPTASTSTMT)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_STATEMENT);
2274
2275 if (pAstNodeStmt)
2276 {
2277
2278 if (vdScriptTokenizerSkipIfIsKeywordEqual(pThis->pTokenizer, VDSCRIPTTOKENKEYWORD_DEFAULT))
2279 {
2280 if (vdScriptTokenizerSkipIfIsPunctuatorEqual(pThis->pTokenizer, ':'))
2281 {
2282 PVDSCRIPTASTSTMT pAstNodeStmtDef = NULL;
2283 pAstNodeStmt->enmStmtType = VDSCRIPTSTMTTYPE_DEFAULT;
2284 rc = vdScriptParseStatement(pThis, &pAstNodeStmtDef);
2285 if (RT_SUCCESS(rc))
2286 pAstNodeStmt->pStmt = pAstNodeStmtDef;
2287 }
2288 else
2289 rc = vdScriptParserError(pThis, VERR_INVALID_PARAMETER, RT_SRC_POS, "Parser: Expected \":\", got ...\n");
2290 }
2291 else if (vdScriptTokenizerSkipIfIsKeywordEqual(pThis->pTokenizer, VDSCRIPTTOKENKEYWORD_CASE))
2292 {
2293 PVDSCRIPTASTEXPR pAstNodeExpr = NULL;
2294 rc = vdScriptParseCondExpression(pThis, &pAstNodeExpr);
2295 if (RT_SUCCESS(rc))
2296 {
2297 if (vdScriptTokenizerSkipIfIsPunctuatorEqual(pThis->pTokenizer, ':'))
2298 {
2299 PVDSCRIPTASTSTMT pAstNodeCaseStmt = NULL;
2300 rc = vdScriptParseStatement(pThis, &pAstNodeCaseStmt);
2301 if (RT_SUCCESS(rc))
2302 {
2303 pAstNodeStmt->enmStmtType = VDSCRIPTSTMTTYPE_CASE;
2304 pAstNodeStmt->Case.pExpr = pAstNodeExpr;
2305 pAstNodeStmt->Case.pStmt = pAstNodeCaseStmt;
2306 }
2307 }
2308 else
2309 rc = vdScriptParserError(pThis, VERR_INVALID_PARAMETER, RT_SRC_POS, "Parser: Expected \":\", got ...\n");
2310
2311 if (RT_FAILURE(rc))
2312 vdScriptAstNodeFree(&pAstNodeExpr->Core);
2313 }
2314 }
2315 else if (vdScriptTokenizerSkipIfIsKeywordEqual(pThis->pTokenizer, VDSCRIPTTOKENKEYWORD_IF))
2316 {
2317 pAstNodeStmt->enmStmtType = VDSCRIPTSTMTTYPE_IF;
2318 rc = vdScriptParseIf(pThis, &pAstNodeStmt->If);
2319 }
2320 else if (vdScriptTokenizerSkipIfIsKeywordEqual(pThis->pTokenizer, VDSCRIPTTOKENKEYWORD_SWITCH))
2321 {
2322 pAstNodeStmt->enmStmtType = VDSCRIPTSTMTTYPE_SWITCH;
2323 rc = vdScriptParseSwitch(pThis, &pAstNodeStmt->Switch);
2324 }
2325 else if (vdScriptTokenizerSkipIfIsKeywordEqual(pThis->pTokenizer, VDSCRIPTTOKENKEYWORD_WHILE))
2326 {
2327 pAstNodeStmt->enmStmtType = VDSCRIPTSTMTTYPE_WHILE;
2328 rc = vdScriptParseWhile(pThis, &pAstNodeStmt->While, false /* fDoWhile */);
2329 }
2330 else if (vdScriptTokenizerSkipIfIsKeywordEqual(pThis->pTokenizer, VDSCRIPTTOKENKEYWORD_DO))
2331 {
2332 pAstNodeStmt->enmStmtType = VDSCRIPTSTMTTYPE_WHILE;
2333 rc = vdScriptParseWhile(pThis, &pAstNodeStmt->While, true /* fDoWhile */);
2334 }
2335 else if (vdScriptTokenizerSkipIfIsKeywordEqual(pThis->pTokenizer, VDSCRIPTTOKENKEYWORD_FOR))
2336 {
2337 pAstNodeStmt->enmStmtType = VDSCRIPTSTMTTYPE_FOR;
2338 rc = vdScriptParseFor(pThis, &pAstNodeStmt->For);
2339 }
2340 else if (vdScriptTokenizerSkipIfIsKeywordEqual(pThis->pTokenizer, VDSCRIPTTOKENKEYWORD_CONTINUE))
2341 {
2342 pAstNodeStmt->enmStmtType = VDSCRIPTSTMTTYPE_CONTINUE;
2343 if (!vdScriptTokenizerSkipIfIsPunctuatorEqual(pThis->pTokenizer, ';'))
2344 rc = vdScriptParserError(pThis, VERR_INVALID_PARAMETER, RT_SRC_POS, "Parser: Expected \";\", got ...\n");
2345 }
2346 else if (vdScriptTokenizerSkipIfIsKeywordEqual(pThis->pTokenizer, VDSCRIPTTOKENKEYWORD_BREAK))
2347 {
2348 pAstNodeStmt->enmStmtType = VDSCRIPTSTMTTYPE_BREAK;
2349 if (!vdScriptTokenizerSkipIfIsPunctuatorEqual(pThis->pTokenizer, ';'))
2350 rc = vdScriptParserError(pThis, VERR_INVALID_PARAMETER, RT_SRC_POS, "Parser: Expected \";\", got ...\n");
2351 }
2352 else if (vdScriptTokenizerSkipIfIsKeywordEqual(pThis->pTokenizer, VDSCRIPTTOKENKEYWORD_RETURN))
2353 {
2354 pAstNodeStmt->enmStmtType = VDSCRIPTSTMTTYPE_RETURN;
2355 if (!vdScriptTokenizerSkipIfIsPunctuatorEqual(pThis->pTokenizer, ';'))
2356 {
2357 rc = vdScriptParseExpression(pThis, &pAstNodeStmt->pExpr);
2358 if ( RT_SUCCESS(rc)
2359 && !vdScriptTokenizerSkipIfIsPunctuatorEqual(pThis->pTokenizer, ';'))
2360 rc = vdScriptParserError(pThis, VERR_INVALID_PARAMETER, RT_SRC_POS, "Parser: Expected \";\", got ...\n");
2361 }
2362 else
2363 pAstNodeStmt->pExpr = NULL; /* No expression for return. */
2364 }
2365 else
2366 {
2367 /* Must be an expression. */
2368 pAstNodeStmt->enmStmtType = VDSCRIPTSTMTTYPE_EXPRESSION;
2369 rc = vdScriptParseExpression(pThis, &pAstNodeStmt->pExpr);
2370 if ( RT_SUCCESS(rc)
2371 && !vdScriptTokenizerSkipIfIsPunctuatorEqual(pThis->pTokenizer, ';'))
2372 rc = vdScriptParserError(pThis, VERR_INVALID_PARAMETER, RT_SRC_POS, "Parser: Expected \";\", got ...\n");
2373 }
2374
2375 if (RT_SUCCESS(rc))
2376 *ppAstNodeStmt = pAstNodeStmt;
2377 else
2378 vdScriptAstNodeFree(&pAstNodeStmt->Core);
2379 }
2380 else
2381 rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory creating statement node\n");
2382 }
2383
2384 return rc;
2385}
2386
2387/**
2388 * Parses a compound statement.
2389 *
2390 * @returns VBox status code.
2391 * @param pThis The script context.
2392 * @param ppAstNodeCompound Where to store the compound AST node on success.
2393 */
2394static int vdScriptParseCompoundStatement(PVDSCRIPTCTXINT pThis, PVDSCRIPTASTSTMT *ppAstNodeCompound)
2395{
2396 int rc = VINF_SUCCESS;
2397
2398 if (vdScriptTokenizerSkipIfIsPunctuatorEqual(pThis->pTokenizer, '{'))
2399 {
2400 PVDSCRIPTASTSTMT pAstNodeCompound = (PVDSCRIPTASTSTMT)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_STATEMENT);
2401 if (pAstNodeCompound)
2402 {
2403 pAstNodeCompound->enmStmtType = VDSCRIPTSTMTTYPE_COMPOUND;
2404 RTListInit(&pAstNodeCompound->Compound.ListDecls);
2405 RTListInit(&pAstNodeCompound->Compound.ListStmts);
2406 while (!vdScriptTokenizerSkipIfIsPunctuatorEqual(pThis->pTokenizer, '}'))
2407 {
2408 /*
2409 * Check whether we have a declaration or a statement.
2410 * For now we assume that 2 identifier tokens specify a declaration
2411 * (type + variable name). Having two consecutive identifers is not possible
2412 * for a statement.
2413 */
2414 if ( vdScriptTokenizerGetTokenClass(pThis->pTokenizer) == VDTOKENCLASS_IDENTIFIER
2415 && vdScriptTokenizerPeekNextClass(pThis->pTokenizer) == VDTOKENCLASS_IDENTIFIER)
2416 {
2417 PVDSCRIPTASTDECL pAstNodeDecl = NULL;
2418 rc = vdScriptParseDeclaration(pThis, &pAstNodeDecl);
2419 if (RT_SUCCESS(rc))
2420 RTListAppend(&pAstNodeCompound->Compound.ListDecls, &pAstNodeDecl->Core.ListNode);
2421 }
2422 else
2423 {
2424 PVDSCRIPTASTSTMT pAstNodeStmt = NULL;
2425 rc = vdScriptParseStatement(pThis, &pAstNodeStmt);
2426 if (RT_SUCCESS(rc))
2427 RTListAppend(&pAstNodeCompound->Compound.ListStmts, &pAstNodeStmt->Core.ListNode);
2428 }
2429
2430 if (RT_FAILURE(rc))
2431 break;
2432 }
2433
2434 if (RT_SUCCESS(rc))
2435 *ppAstNodeCompound = pAstNodeCompound;
2436 else
2437 vdScriptAstNodeFree(&pAstNodeCompound->Core);
2438 }
2439 else
2440 rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory creating compound statement node\n");
2441 }
2442 else
2443 rc = vdScriptParserError(pThis, VERR_INVALID_PARAMETER, RT_SRC_POS, "Parser: Expected \"{\" got...\n");
2444
2445
2446 return rc;
2447}
2448
2449/**
2450 * Parses a function definition from the given tokenizer.
2451 *
2452 * @returns VBox status code.
2453 * @param pThis The script context.
2454 */
2455static int vdScriptParseAddFnDef(PVDSCRIPTCTXINT pThis)
2456{
2457 int rc = VINF_SUCCESS;
2458 PVDSCRIPTASTIDE pRetType = NULL;
2459 PVDSCRIPTASTIDE pFnIde = NULL;
2460
2461 LogFlowFunc(("pThis=%p\n", pThis));
2462
2463 /* Put return type on the stack. */
2464 rc = vdScriptParseIde(pThis, &pRetType);
2465 if (RT_SUCCESS(rc))
2466 {
2467 /* Function name */
2468 rc = vdScriptParseIde(pThis, &pFnIde);
2469 if (RT_SUCCESS(rc))
2470 {
2471 if (vdScriptTokenizerSkipIfIsPunctuatorEqual(pThis->pTokenizer, '('))
2472 {
2473 PVDSCRIPTASTFN pAstNodeFn = (PVDSCRIPTASTFN)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_FUNCTION);
2474
2475 if (pAstNodeFn)
2476 {
2477 pAstNodeFn->pFnIde = pFnIde;
2478 pAstNodeFn->pRetType = pRetType;
2479 RTListInit(&pAstNodeFn->ListArgs);
2480
2481 pFnIde = NULL;
2482 pRetType = NULL;
2483
2484 /* Parse parameter list, create empty parameter list AST node and put it on the stack. */
2485 while (!vdScriptTokenizerSkipIfIsPunctuatorEqual(pThis->pTokenizer, ')'))
2486 {
2487 PVDSCRIPTASTIDE pArgType = NULL;
2488 PVDSCRIPTASTIDE pArgIde = NULL;
2489 /* Parse two identifiers, first one is the type, second the name. */
2490 rc = vdScriptParseIde(pThis, &pArgType);
2491 if (RT_SUCCESS(rc))
2492 rc = vdScriptParseIde(pThis, &pArgIde);
2493
2494 if (RT_SUCCESS(rc))
2495 {
2496 PVDSCRIPTASTFNARG pAstNodeFnArg = (PVDSCRIPTASTFNARG)vdScriptAstNodeAlloc(VDSCRIPTASTCLASS_FUNCTIONARG);
2497 if (pAstNodeFnArg)
2498 {
2499 pAstNodeFnArg->pArgIde = pArgIde;
2500 pAstNodeFnArg->pType = pArgType;
2501 RTListAppend(&pAstNodeFn->ListArgs, &pAstNodeFnArg->Core.ListNode);
2502 pAstNodeFn->cArgs++;
2503 }
2504 else
2505 rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating function argument AST node\n");
2506 }
2507
2508 if (RT_FAILURE(rc))
2509 {
2510 if (pArgType)
2511 vdScriptAstNodeFree(&pArgType->Core);
2512 if (pArgIde)
2513 vdScriptAstNodeFree(&pArgIde->Core);
2514 }
2515
2516 if ( !vdScriptTokenizerSkipIfIsPunctuatorEqual(pThis->pTokenizer, ',')
2517 && !vdScriptTokenizerIsPunctuatorEqual(pThis->pTokenizer, ')'))
2518 {
2519 rc = vdScriptParserError(pThis, VERR_INVALID_PARAMETER, RT_SRC_POS, "Parser: Expected \",\" or \")\" got...\n");
2520 break;
2521 }
2522 }
2523
2524 /* Parse the compound or statement block now. */
2525 if (RT_SUCCESS(rc))
2526 {
2527 PVDSCRIPTASTSTMT pAstCompound = NULL;
2528
2529 rc = vdScriptParseCompoundStatement(pThis, &pAstCompound);
2530 if (RT_SUCCESS(rc))
2531 {
2532 /*
2533 * Link compound statement block to function AST node and add it to the
2534 * list of functions.
2535 */
2536 pAstNodeFn->pCompoundStmts = pAstCompound;
2537 RTListAppend(&pThis->ListAst, &pAstNodeFn->Core.ListNode);
2538
2539 PVDSCRIPTFN pFn = (PVDSCRIPTFN)RTMemAllocZ(sizeof(VDSCRIPTFN));
2540 if (pFn)
2541 {
2542 pFn->Core.pszString = pAstNodeFn->pFnIde->aszIde;
2543 pFn->Core.cchString = strlen(pFn->Core.pszString);
2544 pFn->fExternal = false;
2545 pFn->Type.Internal.pAstFn = pAstNodeFn;
2546 /** @todo: Parameters. */
2547 RTStrSpaceInsert(&pThis->hStrSpaceFn, &pFn->Core);
2548 }
2549 else
2550 rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Out of memory allocating memory for function\n");
2551 }
2552 }
2553
2554 if (RT_FAILURE(rc))
2555 vdScriptAstNodeFree(&pAstNodeFn->Core);
2556 }
2557 else
2558 rc = vdScriptParserError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Parser: Out of memory allocating function AST node\n");
2559 }
2560 else
2561 rc = vdScriptParserError(pThis, VERR_INVALID_PARAMETER, RT_SRC_POS, "Parser: Expected \"(\" got...\n");
2562 }
2563 }
2564
2565 if (RT_FAILURE(rc))
2566 {
2567 if (pRetType)
2568 vdScriptAstNodeFree(&pRetType->Core);
2569 if (pFnIde)
2570 vdScriptAstNodeFree(&pFnIde->Core);
2571 }
2572
2573 LogFlowFunc(("returns rc=%Rrc\n", rc));
2574 return rc;
2575}
2576
2577/**
2578 * Parses the script from the given tokenizer.
2579 *
2580 * @returns VBox status code.
2581 * @param pThis The script context.
2582 */
2583static int vdScriptParseFromTokenizer(PVDSCRIPTCTXINT pThis)
2584{
2585 int rc = VINF_SUCCESS;
2586
2587 LogFlowFunc(("pThis=%p\n", pThis));
2588
2589 /* This is a very very simple LL(1) parser, don't expect much from it for now :). */
2590 while ( RT_SUCCESS(rc)
2591 && !vdScriptTokenizerIsEos(pThis->pTokenizer))
2592 rc = vdScriptParseAddFnDef(pThis);
2593
2594 LogFlowFunc(("returns rc=%Rrc\n", rc));
2595 return rc;
2596}
2597
2598DECLHIDDEN(int) VDScriptCtxCreate(PVDSCRIPTCTX phScriptCtx)
2599{
2600 int rc = VINF_SUCCESS;
2601
2602 LogFlowFunc(("phScriptCtx=%p\n", phScriptCtx));
2603
2604 AssertPtrReturn(phScriptCtx, VERR_INVALID_POINTER);
2605
2606 PVDSCRIPTCTXINT pThis = (PVDSCRIPTCTXINT)RTMemAllocZ(sizeof(VDSCRIPTCTXINT));
2607 if (pThis)
2608 {
2609 pThis->hStrSpaceFn = NULL;
2610 RTListInit(&pThis->ListAst);
2611 *phScriptCtx = pThis;
2612 }
2613 else
2614 rc = VINF_SUCCESS;
2615
2616 LogFlowFunc(("returns rc=%Rrc\n", rc));
2617 return rc;
2618}
2619
2620static int vdScriptCtxDestroyFnSpace(PRTSTRSPACECORE pStr, void *pvUser)
2621{
2622 NOREF(pvUser);
2623
2624 /*
2625 * Just free the whole structure, the AST for internal functions will be
2626 * destroyed later.
2627 */
2628 RTMemFree(pStr);
2629 return VINF_SUCCESS;
2630}
2631
2632DECLHIDDEN(void) VDScriptCtxDestroy(VDSCRIPTCTX hScriptCtx)
2633{
2634 PVDSCRIPTCTXINT pThis = hScriptCtx;
2635
2636 AssertPtrReturnVoid(pThis);
2637
2638 LogFlowFunc(("hScriptCtx=%p\n", pThis));
2639
2640 RTStrSpaceDestroy(&pThis->hStrSpaceFn, vdScriptCtxDestroyFnSpace, NULL);
2641
2642 /** @todo: Go through the list and destroy all ASTs. */
2643 RTMemFree(pThis);
2644}
2645
2646DECLHIDDEN(int) VDScriptCtxCallbacksRegister(VDSCRIPTCTX hScriptCtx, PCVDSCRIPTCALLBACK paCallbacks,
2647 unsigned cCallbacks, void *pvUser)
2648{
2649 int rc = VINF_SUCCESS;
2650 PVDSCRIPTCTXINT pThis = hScriptCtx;
2651
2652 LogFlowFunc(("hScriptCtx=%p paCallbacks=%p cCallbacks=%u pvUser=%p\n",
2653 pThis, paCallbacks, cCallbacks, pvUser));
2654
2655 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
2656 AssertPtrReturn(paCallbacks, VERR_INVALID_POINTER);
2657 AssertReturn(cCallbacks > 0, VERR_INVALID_PARAMETER);
2658
2659 /** @todo: Unregister already registered callbacks in case of an error. */
2660 do
2661 {
2662 PVDSCRIPTFN pFn = NULL;
2663
2664 if (RTStrSpaceGet(&pThis->hStrSpaceFn, paCallbacks->pszFnName))
2665 {
2666 rc = VERR_DUPLICATE;
2667 break;
2668 }
2669
2670 pFn = (PVDSCRIPTFN)RTMemAllocZ(RT_OFFSETOF(VDSCRIPTFN, aenmArgTypes[paCallbacks->cArgs]));
2671 if (!pFn)
2672 {
2673 rc = VERR_NO_MEMORY;
2674 break;
2675 }
2676
2677 /** @todo: Validate argument and returns types. */
2678 pFn->Core.pszString = paCallbacks->pszFnName;
2679 pFn->Core.cchString = strlen(pFn->Core.pszString);
2680 pFn->fExternal = true;
2681 pFn->Type.External.pfnCallback = paCallbacks->pfnCallback;
2682 pFn->Type.External.pvUser = pvUser;
2683 pFn->enmTypeRetn = paCallbacks->enmTypeReturn;
2684 pFn->cArgs = paCallbacks->cArgs;
2685
2686 for (unsigned i = 0; i < paCallbacks->cArgs; i++)
2687 pFn->aenmArgTypes[i] = paCallbacks->paArgs[i];
2688
2689 RTStrSpaceInsert(&pThis->hStrSpaceFn, &pFn->Core);
2690 cCallbacks--;
2691 paCallbacks++;
2692 }
2693 while (cCallbacks);
2694
2695 LogFlowFunc(("returns rc=%Rrc\n", rc));
2696 return rc;
2697}
2698
2699DECLHIDDEN(int) VDScriptCtxLoadScript(VDSCRIPTCTX hScriptCtx, const char *pszScript)
2700{
2701 int rc = VINF_SUCCESS;
2702 PVDSCRIPTCTXINT pThis = hScriptCtx;
2703
2704 LogFlowFunc(("hScriptCtx=%p pszScript=%p\n", pThis, pszScript));
2705
2706 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
2707 AssertPtrReturn(pszScript, VERR_INVALID_POINTER);
2708
2709 PVDTOKENIZER pTokenizer = vdScriptTokenizerCreate(pszScript);
2710 if (pTokenizer)
2711 {
2712 pThis->pTokenizer = pTokenizer;
2713 rc = vdScriptParseFromTokenizer(pThis);
2714 pThis->pTokenizer = NULL;
2715 RTMemFree(pTokenizer);
2716 }
2717
2718 LogFlowFunc(("returns rc=%Rrc\n", rc));
2719 return rc;
2720}
2721
2722DECLHIDDEN(int) VDScriptCtxCallFn(VDSCRIPTCTX hScriptCtx, const char *pszFnCall,
2723 PVDSCRIPTARG paArgs, unsigned cArgs)
2724{
2725 PVDSCRIPTCTXINT pThis = hScriptCtx;
2726 VDSCRIPTARG Ret;
2727 return vdScriptCtxInterprete(pThis, pszFnCall, paArgs, cArgs, &Ret);
2728}
Note: See TracBrowser for help on using the repository browser.

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