/* $Id: VDScriptAst.cpp $ */ /** @file * VBox HDD container test utility - scripting engine AST node related functions. */ /* * Copyright (C) 2013-2020 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; * you can redistribute it and/or modify it under the terms of the GNU * General Public License (GPL) as published by the Free Software * Foundation, in version 2 as it comes in the "COPYING" file of the * VirtualBox OSE distribution. VirtualBox OSE is distributed in the * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. */ #define LOGGROUP LOGGROUP_DEFAULT #include #include #include #include #include #include "VDScriptAst.h" /** * Put all child nodes of the given expression AST node onto the given to free list. * * @returns nothing. * @param pList The free list to append everything to. * @param pAstNode The expression node to free. */ static void vdScriptAstNodeExpressionPutOnFreeList(PRTLISTANCHOR pList, PVDSCRIPTASTCORE pAstNode) { AssertMsgReturnVoid(pAstNode->enmClass == VDSCRIPTASTCLASS_EXPRESSION, ("Given AST node is not a statement\n")); PVDSCRIPTASTEXPR pExpr = (PVDSCRIPTASTEXPR)pAstNode; switch (pExpr->enmType) { case VDSCRIPTEXPRTYPE_PRIMARY_NUMCONST: case VDSCRIPTEXPRTYPE_PRIMARY_BOOLEAN: break; case VDSCRIPTEXPRTYPE_PRIMARY_STRINGCONST: RTStrFree((char *)pExpr->pszStr); break; case VDSCRIPTEXPRTYPE_PRIMARY_IDENTIFIER: { RTListAppend(pList, &pExpr->pIde->Core.ListNode); break; } case VDSCRIPTEXPRTYPE_ASSIGNMENT_LIST: { while (!RTListIsEmpty(&pExpr->ListExpr)) { PVDSCRIPTASTCORE pNode = RTListGetFirst(&pExpr->ListExpr, VDSCRIPTASTCORE, ListNode); RTListNodeRemove(&pNode->ListNode); RTListAppend(pList, &pNode->ListNode); } break; } case VDSCRIPTEXPRTYPE_POSTFIX_FNCALL: { RTListAppend(pList, &pExpr->FnCall.pFnIde->Core.ListNode); while (!RTListIsEmpty(&pExpr->FnCall.ListArgs)) { PVDSCRIPTASTCORE pNode = RTListGetFirst(&pExpr->FnCall.ListArgs, VDSCRIPTASTCORE, ListNode); RTListNodeRemove(&pNode->ListNode); RTListAppend(pList, &pNode->ListNode); } break; } case VDSCRIPTEXPRTYPE_POSTFIX_DEREFERENCE: case VDSCRIPTEXPRTYPE_POSTFIX_DOT: { RTListAppend(pList, &pExpr->Deref.pIde->Core.ListNode); RTListAppend(pList, &pExpr->Deref.pExpr->Core.ListNode); break; } case VDSCRIPTEXPRTYPE_POSTFIX_INCREMENT: case VDSCRIPTEXPRTYPE_POSTFIX_DECREMENT: case VDSCRIPTEXPRTYPE_UNARY_INCREMENT: case VDSCRIPTEXPRTYPE_UNARY_DECREMENT: case VDSCRIPTEXPRTYPE_UNARY_POSSIGN: case VDSCRIPTEXPRTYPE_UNARY_NEGSIGN: case VDSCRIPTEXPRTYPE_UNARY_INVERT: case VDSCRIPTEXPRTYPE_UNARY_NEGATE: case VDSCRIPTEXPRTYPE_UNARY_REFERENCE: case VDSCRIPTEXPRTYPE_UNARY_DEREFERENCE: { RTListAppend(pList, &pExpr->pExpr->Core.ListNode); break; } case VDSCRIPTEXPRTYPE_MULTIPLICATION: case VDSCRIPTEXPRTYPE_DIVISION: case VDSCRIPTEXPRTYPE_MODULUS: case VDSCRIPTEXPRTYPE_ADDITION: case VDSCRIPTEXPRTYPE_SUBTRACTION: case VDSCRIPTEXPRTYPE_LSR: case VDSCRIPTEXPRTYPE_LSL: case VDSCRIPTEXPRTYPE_LOWER: case VDSCRIPTEXPRTYPE_HIGHER: case VDSCRIPTEXPRTYPE_LOWEREQUAL: case VDSCRIPTEXPRTYPE_HIGHEREQUAL: case VDSCRIPTEXPRTYPE_EQUAL: case VDSCRIPTEXPRTYPE_NOTEQUAL: case VDSCRIPTEXPRTYPE_BITWISE_AND: case VDSCRIPTEXPRTYPE_BITWISE_XOR: case VDSCRIPTEXPRTYPE_BITWISE_OR: case VDSCRIPTEXPRTYPE_LOGICAL_AND: case VDSCRIPTEXPRTYPE_LOGICAL_OR: case VDSCRIPTEXPRTYPE_ASSIGN: case VDSCRIPTEXPRTYPE_ASSIGN_MULT: case VDSCRIPTEXPRTYPE_ASSIGN_DIV: case VDSCRIPTEXPRTYPE_ASSIGN_MOD: case VDSCRIPTEXPRTYPE_ASSIGN_ADD: case VDSCRIPTEXPRTYPE_ASSIGN_SUB: case VDSCRIPTEXPRTYPE_ASSIGN_LSL: case VDSCRIPTEXPRTYPE_ASSIGN_LSR: case VDSCRIPTEXPRTYPE_ASSIGN_AND: case VDSCRIPTEXPRTYPE_ASSIGN_XOR: case VDSCRIPTEXPRTYPE_ASSIGN_OR: { RTListAppend(pList, &pExpr->BinaryOp.pLeftExpr->Core.ListNode); RTListAppend(pList, &pExpr->BinaryOp.pRightExpr->Core.ListNode); break; } case VDSCRIPTEXPRTYPE_INVALID: default: AssertMsgFailedReturnVoid(("Invalid AST node expression type %d\n", pExpr->enmType)); } } /** * Free a given statement AST node and put everything on the given to free list. * * @returns nothing. * @param pList The free list to append everything to. * @param pAstNode The statement node to free. */ static void vdScriptAstNodeStatmentPutOnFreeList(PRTLISTANCHOR pList, PVDSCRIPTASTCORE pAstNode) { AssertMsgReturnVoid(pAstNode->enmClass == VDSCRIPTASTCLASS_STATEMENT, ("Given AST node is not a statement\n")); PVDSCRIPTASTSTMT pStmt = (PVDSCRIPTASTSTMT)pAstNode; switch (pStmt->enmStmtType) { case VDSCRIPTSTMTTYPE_COMPOUND: { /* Put all declarations on the to free list. */ while (!RTListIsEmpty(&pStmt->Compound.ListDecls)) { PVDSCRIPTASTCORE pNode = RTListGetFirst(&pStmt->Compound.ListDecls, VDSCRIPTASTCORE, ListNode); RTListNodeRemove(&pNode->ListNode); RTListAppend(pList, &pNode->ListNode); } /* Put all statements on the to free list. */ while (!RTListIsEmpty(&pStmt->Compound.ListStmts)) { PVDSCRIPTASTCORE pNode = RTListGetFirst(&pStmt->Compound.ListStmts, VDSCRIPTASTCORE, ListNode); RTListNodeRemove(&pNode->ListNode); RTListAppend(pList, &pNode->ListNode); } break; } case VDSCRIPTSTMTTYPE_EXPRESSION: { if (pStmt->pExpr) RTListAppend(pList, &pStmt->pExpr->Core.ListNode); break; } case VDSCRIPTSTMTTYPE_IF: { RTListAppend(pList, &pStmt->If.pCond->Core.ListNode); RTListAppend(pList, &pStmt->If.pTrueStmt->Core.ListNode); if (pStmt->If.pElseStmt) RTListAppend(pList, &pStmt->If.pElseStmt->Core.ListNode); break; } case VDSCRIPTSTMTTYPE_SWITCH: { RTListAppend(pList, &pStmt->Switch.pCond->Core.ListNode); RTListAppend(pList, &pStmt->Switch.pStmt->Core.ListNode); break; } case VDSCRIPTSTMTTYPE_WHILE: { RTListAppend(pList, &pStmt->While.pCond->Core.ListNode); RTListAppend(pList, &pStmt->While.pStmt->Core.ListNode); break; } case VDSCRIPTSTMTTYPE_FOR: { RTListAppend(pList, &pStmt->For.pExprStart->Core.ListNode); RTListAppend(pList, &pStmt->For.pExprCond->Core.ListNode); RTListAppend(pList, &pStmt->For.pExpr3->Core.ListNode); RTListAppend(pList, &pStmt->For.pStmt->Core.ListNode); break; } case VDSCRIPTSTMTTYPE_RETURN: { if (pStmt->pExpr) RTListAppend(pList, &pStmt->pExpr->Core.ListNode); break; } case VDSCRIPTSTMTTYPE_CASE: { RTListAppend(pList, &pStmt->Case.pExpr->Core.ListNode); RTListAppend(pList, &pStmt->Case.pStmt->Core.ListNode); break; } case VDSCRIPTSTMTTYPE_DEFAULT: { RTListAppend(pList, &pStmt->Case.pStmt->Core.ListNode); break; } case VDSCRIPTSTMTTYPE_CONTINUE: case VDSCRIPTSTMTTYPE_BREAK: break; case VDSCRIPTSTMTTYPE_INVALID: default: AssertMsgFailedReturnVoid(("Invalid AST node statement type %d\n", pStmt->enmStmtType)); } } DECLHIDDEN(void) vdScriptAstNodeFree(PVDSCRIPTASTCORE pAstNode) { RTLISTANCHOR ListFree; /* * The node is not allowed to be part of a list because we need it * for the nodes to free list. */ Assert(RTListIsEmpty(&pAstNode->ListNode)); RTListInit(&ListFree); RTListAppend(&ListFree, &pAstNode->ListNode); do { pAstNode = RTListGetFirst(&ListFree, VDSCRIPTASTCORE, ListNode); RTListNodeRemove(&pAstNode->ListNode); switch (pAstNode->enmClass) { case VDSCRIPTASTCLASS_FUNCTION: { PVDSCRIPTASTFN pFn = (PVDSCRIPTASTFN)pAstNode; if (pFn->pRetType) RTListAppend(&ListFree, &pFn->pRetType->Core.ListNode); if (pFn->pFnIde) RTListAppend(&ListFree, &pFn->pFnIde->Core.ListNode); /* Put argument list on the to free list. */ while (!RTListIsEmpty(&pFn->ListArgs)) { PVDSCRIPTASTCORE pArg = RTListGetFirst(&pFn->ListArgs, VDSCRIPTASTCORE, ListNode); RTListNodeRemove(&pArg->ListNode); RTListAppend(&ListFree, &pArg->ListNode); } /* Put compound statement onto the list. */ RTListAppend(&ListFree, &pFn->pCompoundStmts->Core.ListNode); break; } case VDSCRIPTASTCLASS_FUNCTIONARG: { PVDSCRIPTASTFNARG pAstNodeArg = (PVDSCRIPTASTFNARG)pAstNode; if (pAstNodeArg->pType) RTListAppend(&ListFree, &pAstNodeArg->pType->Core.ListNode); if (pAstNodeArg->pArgIde) RTListAppend(&ListFree, &pAstNodeArg->pArgIde->Core.ListNode); break; } case VDSCRIPTASTCLASS_IDENTIFIER: break; case VDSCRIPTASTCLASS_DECLARATION: case VDSCRIPTASTCLASS_TYPENAME: { AssertMsgFailed(("TODO\n")); break; } case VDSCRIPTASTCLASS_STATEMENT: { vdScriptAstNodeStatmentPutOnFreeList(&ListFree, pAstNode); break; } case VDSCRIPTASTCLASS_EXPRESSION: { vdScriptAstNodeExpressionPutOnFreeList(&ListFree, pAstNode); break; } case VDSCRIPTASTCLASS_INVALID: default: AssertMsgFailedReturnVoid(("Invalid AST node class given %d\n", pAstNode->enmClass)); } RTMemFree(pAstNode); } while (!RTListIsEmpty(&ListFree)); } DECLHIDDEN(PVDSCRIPTASTCORE) vdScriptAstNodeAlloc(VDSCRIPTASTCLASS enmClass) { size_t cbAlloc = 0; switch (enmClass) { case VDSCRIPTASTCLASS_FUNCTION: cbAlloc = sizeof(VDSCRIPTASTFN); break; case VDSCRIPTASTCLASS_FUNCTIONARG: cbAlloc = sizeof(VDSCRIPTASTFNARG); break; case VDSCRIPTASTCLASS_DECLARATION: cbAlloc = sizeof(VDSCRIPTASTDECL); break; case VDSCRIPTASTCLASS_STATEMENT: cbAlloc = sizeof(VDSCRIPTASTSTMT); break; case VDSCRIPTASTCLASS_EXPRESSION: cbAlloc = sizeof(VDSCRIPTASTEXPR); break; case VDSCRIPTASTCLASS_TYPENAME: cbAlloc = sizeof(VDSCRIPTASTTYPENAME); break; case VDSCRIPTASTCLASS_IDENTIFIER: case VDSCRIPTASTCLASS_INVALID: default: AssertMsgFailedReturn(("Invalid AST node class given %d\n", enmClass), NULL); } PVDSCRIPTASTCORE pAstNode = (PVDSCRIPTASTCORE)RTMemAllocZ(cbAlloc); if (pAstNode) { pAstNode->enmClass = enmClass; RTListInit(&pAstNode->ListNode); } return pAstNode; } DECLHIDDEN(PVDSCRIPTASTIDE) vdScriptAstNodeIdeAlloc(size_t cchIde) { PVDSCRIPTASTIDE pAstNode = (PVDSCRIPTASTIDE)RTMemAllocZ(RT_UOFFSETOF_DYN(VDSCRIPTASTIDE, aszIde[cchIde + 1])); if (pAstNode) { pAstNode->Core.enmClass = VDSCRIPTASTCLASS_IDENTIFIER; RTListInit(&pAstNode->Core.ListNode); } return pAstNode; }