/** $Id$ */
/** @file
*
* VBox HDD container test utility - scripting engine AST node related functions.
*/
/*
* Copyright (C) 2013 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 <iprt/list.h>
#include <iprt/mem.h>
#include <iprt/assert.h>
#include <iprt/string.h>
#include <VBox/log.h>
#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(unsigned cchIde)
{
PVDSCRIPTASTIDE pAstNode = (PVDSCRIPTASTIDE)RTMemAllocZ(RT_OFFSETOF(VDSCRIPTASTIDE, aszIde[cchIde + 1]));
if (pAstNode)
{
pAstNode->Core.enmClass = VDSCRIPTASTCLASS_IDENTIFIER;
RTListInit(&pAstNode->Core.ListNode);
}
return pAstNode;
}