mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-07-15 00:24:40 +00:00
Merging
This commit is contained in:
parent
03794ad3eb
commit
407bbce509
23 changed files with 9203 additions and 7477 deletions
|
|
@ -45,6 +45,7 @@
|
||||||
#include "console/debugOutputConsumer.h"
|
#include "console/debugOutputConsumer.h"
|
||||||
#include "console/consoleTypes.h"
|
#include "console/consoleTypes.h"
|
||||||
#include "console/engineAPI.h"
|
#include "console/engineAPI.h"
|
||||||
|
#include "console/codeInterpreter.h"
|
||||||
|
|
||||||
#include "gfx/bitmap/gBitmap.h"
|
#include "gfx/bitmap/gBitmap.h"
|
||||||
#include "gfx/gFont.h"
|
#include "gfx/gFont.h"
|
||||||
|
|
@ -227,6 +228,9 @@ void StandardMainLoop::init()
|
||||||
ManagedSingleton< ThreadManager >::createSingleton();
|
ManagedSingleton< ThreadManager >::createSingleton();
|
||||||
FrameAllocator::init(TORQUE_FRAME_SIZE); // See comments in torqueConfig.h
|
FrameAllocator::init(TORQUE_FRAME_SIZE); // See comments in torqueConfig.h
|
||||||
|
|
||||||
|
// Initialize the TorqueScript interpreter.
|
||||||
|
CodeInterpreter::init();
|
||||||
|
|
||||||
// Yell if we can't initialize the network.
|
// Yell if we can't initialize the network.
|
||||||
if(!Net::init())
|
if(!Net::init())
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -496,9 +496,9 @@ class_name_expr
|
||||||
|
|
||||||
assign_op_struct
|
assign_op_struct
|
||||||
: opPLUSPLUS
|
: opPLUSPLUS
|
||||||
{ $$.lineNumber = $1.lineNumber; $$.token = '+'; $$.expr = FloatNode::alloc( $1.lineNumber, 1 ); }
|
{ $$.lineNumber = $1.lineNumber; $$.token = opPLUSPLUS; $$.expr = FloatNode::alloc( $1.lineNumber, 1 ); }
|
||||||
| opMINUSMINUS
|
| opMINUSMINUS
|
||||||
{ $$.lineNumber = $1.lineNumber; $$.token = '-'; $$.expr = FloatNode::alloc( $1.lineNumber, 1 ); }
|
{ $$.lineNumber = $1.lineNumber; $$.token = opMINUSMINUS; $$.expr = FloatNode::alloc( $1.lineNumber, 1 ); }
|
||||||
| opPLASN expr
|
| opPLASN expr
|
||||||
{ $$.lineNumber = $1.lineNumber; $$.token = '+'; $$.expr = $2; }
|
{ $$.lineNumber = $1.lineNumber; $$.token = '+'; $$.expr = $2; }
|
||||||
| opMIASN expr
|
| opMIASN expr
|
||||||
|
|
@ -551,6 +551,8 @@ funcall_expr
|
||||||
{ $$ = FuncCallExprNode::alloc( $1.lineNumber, $3.value, $1.value, $5, false); }
|
{ $$ = FuncCallExprNode::alloc( $1.lineNumber, $3.value, $1.value, $5, false); }
|
||||||
| expr '.' IDENT '(' expr_list_decl ')'
|
| expr '.' IDENT '(' expr_list_decl ')'
|
||||||
{ $1->append($5); $$ = FuncCallExprNode::alloc( $1->dbgLineNumber, $3.value, NULL, $1, true); }
|
{ $1->append($5); $$ = FuncCallExprNode::alloc( $1->dbgLineNumber, $3.value, NULL, $1, true); }
|
||||||
|
| expr '(' expr_list_decl ')'
|
||||||
|
{ $$ = FuncPointerCallExprNode::alloc( $1->dbgLineNumber, $1, $3); }
|
||||||
;
|
;
|
||||||
|
|
||||||
assert_expr
|
assert_expr
|
||||||
|
|
|
||||||
|
|
@ -774,9 +774,9 @@ YY_MALLOC_DECL
|
||||||
|
|
||||||
YY_DECL
|
YY_DECL
|
||||||
{
|
{
|
||||||
yy_state_type yy_current_state;
|
register yy_state_type yy_current_state;
|
||||||
char *yy_cp, *yy_bp;
|
register char *yy_cp, *yy_bp;
|
||||||
int yy_act;
|
register int yy_act;
|
||||||
|
|
||||||
#line 105 "CMDscan.l"
|
#line 105 "CMDscan.l"
|
||||||
|
|
||||||
|
|
@ -823,7 +823,7 @@ YY_DECL
|
||||||
yy_match:
|
yy_match:
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
|
register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
|
||||||
if (yy_accept[yy_current_state])
|
if (yy_accept[yy_current_state])
|
||||||
{
|
{
|
||||||
yy_last_accepting_state = yy_current_state;
|
yy_last_accepting_state = yy_current_state;
|
||||||
|
|
@ -837,8 +837,7 @@ yy_match:
|
||||||
}
|
}
|
||||||
yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int)yy_c];
|
yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int)yy_c];
|
||||||
++yy_cp;
|
++yy_cp;
|
||||||
}
|
} while (yy_base[yy_current_state] != 338);
|
||||||
while ( yy_base[yy_current_state] != 338 );
|
|
||||||
|
|
||||||
yy_find_action:
|
yy_find_action:
|
||||||
yy_act = yy_accept[yy_current_state];
|
yy_act = yy_accept[yy_current_state];
|
||||||
|
|
@ -1430,9 +1429,9 @@ case YY_STATE_EOF(INITIAL):
|
||||||
|
|
||||||
static int yy_get_next_buffer()
|
static int yy_get_next_buffer()
|
||||||
{
|
{
|
||||||
char *dest = yy_current_buffer->yy_ch_buf;
|
register char *dest = yy_current_buffer->yy_ch_buf;
|
||||||
char *source = yytext_ptr;
|
register char *source = yytext_ptr;
|
||||||
int number_to_move, i;
|
register int number_to_move, i;
|
||||||
int ret_val;
|
int ret_val;
|
||||||
|
|
||||||
if (yy_c_buf_p > &yy_current_buffer->yy_ch_buf[yy_n_chars + 1])
|
if (yy_c_buf_p > &yy_current_buffer->yy_ch_buf[yy_n_chars + 1])
|
||||||
|
|
@ -1560,14 +1559,14 @@ static int yy_get_next_buffer()
|
||||||
|
|
||||||
static yy_state_type yy_get_previous_state()
|
static yy_state_type yy_get_previous_state()
|
||||||
{
|
{
|
||||||
yy_state_type yy_current_state;
|
register yy_state_type yy_current_state;
|
||||||
char *yy_cp;
|
register char *yy_cp;
|
||||||
|
|
||||||
yy_current_state = yy_start;
|
yy_current_state = yy_start;
|
||||||
|
|
||||||
for (yy_cp = yytext_ptr + YY_MORE_ADJ; yy_cp < yy_c_buf_p; ++yy_cp)
|
for (yy_cp = yytext_ptr + YY_MORE_ADJ; yy_cp < yy_c_buf_p; ++yy_cp)
|
||||||
{
|
{
|
||||||
YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
|
register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
|
||||||
if (yy_accept[yy_current_state])
|
if (yy_accept[yy_current_state])
|
||||||
{
|
{
|
||||||
yy_last_accepting_state = yy_current_state;
|
yy_last_accepting_state = yy_current_state;
|
||||||
|
|
@ -1599,10 +1598,10 @@ static yy_state_type yy_try_NUL_trans( yy_current_state )
|
||||||
yy_state_type yy_current_state;
|
yy_state_type yy_current_state;
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
int yy_is_jam;
|
register int yy_is_jam;
|
||||||
char *yy_cp = yy_c_buf_p;
|
register char *yy_cp = yy_c_buf_p;
|
||||||
|
|
||||||
YY_CHAR yy_c = 1;
|
register YY_CHAR yy_c = 1;
|
||||||
if (yy_accept[yy_current_state])
|
if (yy_accept[yy_current_state])
|
||||||
{
|
{
|
||||||
yy_last_accepting_state = yy_current_state;
|
yy_last_accepting_state = yy_current_state;
|
||||||
|
|
@ -1623,14 +1622,14 @@ yy_state_type yy_current_state;
|
||||||
|
|
||||||
#ifndef YY_NO_UNPUT
|
#ifndef YY_NO_UNPUT
|
||||||
#ifdef YY_USE_PROTOS
|
#ifdef YY_USE_PROTOS
|
||||||
static void yyunput( int c, char *yy_bp )
|
static void yyunput(int c, register char *yy_bp)
|
||||||
#else
|
#else
|
||||||
static void yyunput(c, yy_bp)
|
static void yyunput(c, yy_bp)
|
||||||
int c;
|
int c;
|
||||||
char *yy_bp;
|
register char *yy_bp;
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
char *yy_cp = yy_c_buf_p;
|
register char *yy_cp = yy_c_buf_p;
|
||||||
|
|
||||||
/* undo effects of setting up yytext */
|
/* undo effects of setting up yytext */
|
||||||
*yy_cp = yy_hold_char;
|
*yy_cp = yy_hold_char;
|
||||||
|
|
@ -1638,10 +1637,10 @@ char *yy_bp;
|
||||||
if (yy_cp < yy_current_buffer->yy_ch_buf + 2)
|
if (yy_cp < yy_current_buffer->yy_ch_buf + 2)
|
||||||
{ /* need to shift things up to make room */
|
{ /* need to shift things up to make room */
|
||||||
/* +2 for EOB chars. */
|
/* +2 for EOB chars. */
|
||||||
int number_to_move = yy_n_chars + 2;
|
register int number_to_move = yy_n_chars + 2;
|
||||||
char *dest = &yy_current_buffer->yy_ch_buf[
|
register char *dest = &yy_current_buffer->yy_ch_buf[
|
||||||
yy_current_buffer->yy_buf_size + 2];
|
yy_current_buffer->yy_buf_size + 2];
|
||||||
char *source =
|
register char *source =
|
||||||
&yy_current_buffer->yy_ch_buf[number_to_move];
|
&yy_current_buffer->yy_ch_buf[number_to_move];
|
||||||
|
|
||||||
while (source > yy_current_buffer->yy_ch_buf)
|
while (source > yy_current_buffer->yy_ch_buf)
|
||||||
|
|
@ -2095,7 +2094,7 @@ yyconst char *s2;
|
||||||
int n;
|
int n;
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
int i;
|
register int i;
|
||||||
for (i = 0; i < n; ++i)
|
for (i = 0; i < n; ++i)
|
||||||
s1[i] = s2[i];
|
s1[i] = s2[i];
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -446,6 +446,18 @@ struct FuncCallExprNode : ExprNode
|
||||||
DBG_STMT_TYPE(FuncCallExprNode);
|
DBG_STMT_TYPE(FuncCallExprNode);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct FuncPointerCallExprNode : ExprNode
|
||||||
|
{
|
||||||
|
ExprNode *funcPointer;
|
||||||
|
ExprNode *args;
|
||||||
|
|
||||||
|
static FuncPointerCallExprNode *alloc(S32 lineNumber, ExprNode *stmt, ExprNode *args);
|
||||||
|
|
||||||
|
U32 compile(CodeStream &codeStream, U32 ip, TypeReq type);
|
||||||
|
TypeReq getPreferredType();
|
||||||
|
DBG_STMT_TYPE(FuncPointerCallExprNode);
|
||||||
|
};
|
||||||
|
|
||||||
struct AssertCallExprNode : ExprNode
|
struct AssertCallExprNode : ExprNode
|
||||||
{
|
{
|
||||||
ExprNode *testExpr;
|
ExprNode *testExpr;
|
||||||
|
|
|
||||||
|
|
@ -328,6 +328,16 @@ FuncCallExprNode *FuncCallExprNode::alloc( S32 lineNumber, StringTableEntry func
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FuncPointerCallExprNode *FuncPointerCallExprNode::alloc(S32 lineNumber, ExprNode *funcPointer, ExprNode *args)
|
||||||
|
{
|
||||||
|
FuncPointerCallExprNode *ret = (FuncPointerCallExprNode *)consoleAlloc(sizeof(FuncPointerCallExprNode));
|
||||||
|
constructInPlace(ret);
|
||||||
|
ret->dbgLineNumber = lineNumber;
|
||||||
|
ret->funcPointer = funcPointer;
|
||||||
|
ret->args = args;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
AssertCallExprNode *AssertCallExprNode::alloc(S32 lineNumber, ExprNode *testExpr, const char *message)
|
AssertCallExprNode *AssertCallExprNode::alloc(S32 lineNumber, ExprNode *testExpr, const char *message)
|
||||||
{
|
{
|
||||||
#ifdef TORQUE_ENABLE_SCRIPTASSERTS
|
#ifdef TORQUE_ENABLE_SCRIPTASSERTS
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,6 @@ struct Token
|
||||||
};
|
};
|
||||||
#include "console/cmdgram.h"
|
#include "console/cmdgram.h"
|
||||||
|
|
||||||
|
|
||||||
namespace Compiler
|
namespace Compiler
|
||||||
{
|
{
|
||||||
U32 compileBlock(StmtNode *block, CodeStream &codeStream, U32 ip)
|
U32 compileBlock(StmtNode *block, CodeStream &codeStream, U32 ip)
|
||||||
|
|
@ -51,6 +50,81 @@ namespace Compiler
|
||||||
ip = walk->compileStmt(codeStream, ip);
|
ip = walk->compileStmt(codeStream, ip);
|
||||||
return codeStream.tell();
|
return codeStream.tell();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline bool isSimpleVarLookup(ExprNode *arrayExpr, StringTableEntry &varName)
|
||||||
|
{
|
||||||
|
if (arrayExpr == nullptr)
|
||||||
|
{
|
||||||
|
varName = StringTable->insert("");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// No double arrays allowed for optimization.
|
||||||
|
VarNode *var = dynamic_cast<VarNode*>(arrayExpr);
|
||||||
|
if (var && !var->arrayIndex)
|
||||||
|
{
|
||||||
|
StringTableEntry arrayVar = StringTable->insert(var->varName);
|
||||||
|
precompileIdent(arrayVar);
|
||||||
|
varName = arrayVar;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do not allow 'recursive' %this optimizations. It can lead to weird bytecode
|
||||||
|
// generation since we can only optimize one expression at a time.
|
||||||
|
static bool OnlyOneThisOptimization = false;
|
||||||
|
|
||||||
|
inline bool isThisVar(ExprNode *objectExpr)
|
||||||
|
{
|
||||||
|
// If we are currently optimizing a this var, don't allow extra optimization.
|
||||||
|
if (objectExpr == nullptr || OnlyOneThisOptimization)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
VarNode *thisVar = dynamic_cast<VarNode*>(objectExpr);
|
||||||
|
if (thisVar && thisVar->varName == StringTable->insert("%this"))
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void optimizeThisPointer(CodeStream &codeStream, ExprNode *arrayExpr, U32 &ip, StringTableEntry slotName)
|
||||||
|
{
|
||||||
|
OnlyOneThisOptimization = true;
|
||||||
|
|
||||||
|
// Is the array a simple variable? If so, we can optimize that.
|
||||||
|
StringTableEntry varName = nullptr;
|
||||||
|
bool simple = false;
|
||||||
|
|
||||||
|
if (arrayExpr)
|
||||||
|
{
|
||||||
|
simple = isSimpleVarLookup(arrayExpr, varName);
|
||||||
|
if (!simple)
|
||||||
|
{
|
||||||
|
// Less optimized array setting.
|
||||||
|
codeStream.emit(OP_ADVANCE_STR);
|
||||||
|
ip = arrayExpr->compile(codeStream, ip, TypeReqString);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
codeStream.emit(OP_SETCURFIELD_THIS);
|
||||||
|
codeStream.emitSTE(slotName);
|
||||||
|
|
||||||
|
if (arrayExpr)
|
||||||
|
{
|
||||||
|
if (simple)
|
||||||
|
{
|
||||||
|
codeStream.emit(OP_SETCURFIELD_ARRAY_VAR);
|
||||||
|
codeStream.emitSTE(varName);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
codeStream.emit(OP_SETCURFIELD_ARRAY);
|
||||||
|
codeStream.emit(OP_TERMINATE_REWIND_STR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
OnlyOneThisOptimization = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
using namespace Compiler;
|
using namespace Compiler;
|
||||||
|
|
@ -692,7 +766,13 @@ TypeReq FloatUnaryExprNode::getPreferredType()
|
||||||
|
|
||||||
U32 VarNode::compile(CodeStream &codeStream, U32 ip, TypeReq type)
|
U32 VarNode::compile(CodeStream &codeStream, U32 ip, TypeReq type)
|
||||||
{
|
{
|
||||||
// if this has an arrayIndex...
|
// if this has an arrayIndex and we are not short circuiting from a constant.
|
||||||
|
// if we are a var node
|
||||||
|
// OP_SETCURVAR_ARRAY_VARLOOKUP
|
||||||
|
// varName
|
||||||
|
// varNodeVarName
|
||||||
|
|
||||||
|
// else
|
||||||
// OP_LOADIMMED_IDENT
|
// OP_LOADIMMED_IDENT
|
||||||
// varName
|
// varName
|
||||||
// OP_ADVANCE_STR
|
// OP_ADVANCE_STR
|
||||||
|
|
@ -709,18 +789,54 @@ U32 VarNode::compile(CodeStream &codeStream, U32 ip, TypeReq type)
|
||||||
if (type == TypeReqNone)
|
if (type == TypeReqNone)
|
||||||
return codeStream.tell();
|
return codeStream.tell();
|
||||||
|
|
||||||
precompileIdent(varName);
|
bool shortCircuit = false;
|
||||||
|
|
||||||
codeStream.emit(arrayIndex ? OP_LOADIMMED_IDENT : OP_SETCURVAR);
|
|
||||||
codeStream.emitSTE(varName);
|
|
||||||
|
|
||||||
if (arrayIndex)
|
if (arrayIndex)
|
||||||
{
|
{
|
||||||
|
// If we have a constant, shortcircuit the array logic.
|
||||||
|
|
||||||
|
IntNode *intNode = dynamic_cast<IntNode*>(arrayIndex);
|
||||||
|
StrConstNode *strNode = dynamic_cast<StrConstNode*>(arrayIndex);
|
||||||
|
if (intNode)
|
||||||
|
{
|
||||||
|
varName = StringTable->insert(avar("%s%d", varName, intNode->value));
|
||||||
|
shortCircuit = true;
|
||||||
|
}
|
||||||
|
else if (strNode)
|
||||||
|
{
|
||||||
|
varName = StringTable->insert(avar("%s%s", varName, strNode->str));
|
||||||
|
shortCircuit = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
precompileIdent(varName);
|
||||||
|
|
||||||
|
if (arrayIndex && !shortCircuit)
|
||||||
|
{
|
||||||
|
// Ok, lets try to optimize %var[%someothervar] as this is
|
||||||
|
// a common case for array usage.
|
||||||
|
StringTableEntry varNodeVarName;
|
||||||
|
if (isSimpleVarLookup(arrayIndex, varNodeVarName))
|
||||||
|
{
|
||||||
|
codeStream.emit(OP_SETCURVAR_ARRAY_VARLOOKUP);
|
||||||
|
codeStream.emitSTE(varName);
|
||||||
|
codeStream.emitSTE(varNodeVarName);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
codeStream.emit(OP_LOADIMMED_IDENT);
|
||||||
|
codeStream.emitSTE(varName);
|
||||||
codeStream.emit(OP_ADVANCE_STR);
|
codeStream.emit(OP_ADVANCE_STR);
|
||||||
ip = arrayIndex->compile(codeStream, ip, TypeReqString);
|
ip = arrayIndex->compile(codeStream, ip, TypeReqString);
|
||||||
codeStream.emit(OP_REWIND_STR);
|
codeStream.emit(OP_REWIND_STR);
|
||||||
codeStream.emit(OP_SETCURVAR_ARRAY);
|
codeStream.emit(OP_SETCURVAR_ARRAY);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
codeStream.emit(OP_SETCURVAR);
|
||||||
|
codeStream.emitSTE(varName);
|
||||||
|
}
|
||||||
|
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case TypeReqUInt:
|
case TypeReqUInt:
|
||||||
|
|
@ -934,15 +1050,29 @@ U32 AssignExprNode::compile(CodeStream &codeStream, U32 ip, TypeReq type)
|
||||||
subType = TypeReqString;
|
subType = TypeReqString;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// if it's an array expr, the formula is:
|
|
||||||
|
//if we are an array index and we are gonna short circuit
|
||||||
|
// eval expr
|
||||||
|
// compute new varName
|
||||||
|
// OP_SETCURVAR_CREATE
|
||||||
|
// varName
|
||||||
|
// OP_SAVEVAR
|
||||||
|
|
||||||
|
//else if it's an array expr and we don't short circuit, the formula is:
|
||||||
// eval expr
|
// eval expr
|
||||||
// (push and pop if it's TypeReqString) OP_ADVANCE_STR
|
// (push and pop if it's TypeReqString) OP_ADVANCE_STR
|
||||||
|
// if array lookup is varnode
|
||||||
|
// OP_SETCURVAR_ARRAY_CREATE_VARLOOKUP
|
||||||
|
// varName
|
||||||
|
// varNodeVarName
|
||||||
|
// else
|
||||||
// OP_LOADIMMED_IDENT
|
// OP_LOADIMMED_IDENT
|
||||||
// varName
|
// varName
|
||||||
// OP_ADVANCE_STR
|
// OP_ADVANCE_STR
|
||||||
// eval array
|
// eval array
|
||||||
// OP_REWIND_STR
|
// OP_REWIND_STR
|
||||||
// OP_SETCURVAR_ARRAY_CREATE
|
// OP_SETCURVAR_ARRAY_CREATE
|
||||||
|
// endif
|
||||||
// OP_TERMINATE_REWIND_STR
|
// OP_TERMINATE_REWIND_STR
|
||||||
// OP_SAVEVAR
|
// OP_SAVEVAR
|
||||||
|
|
||||||
|
|
@ -952,15 +1082,45 @@ U32 AssignExprNode::compile(CodeStream &codeStream, U32 ip, TypeReq type)
|
||||||
// varname
|
// varname
|
||||||
// OP_SAVEVAR
|
// OP_SAVEVAR
|
||||||
|
|
||||||
precompileIdent(varName);
|
|
||||||
|
|
||||||
ip = expr->compile(codeStream, ip, subType);
|
ip = expr->compile(codeStream, ip, subType);
|
||||||
|
|
||||||
|
bool shortCircuit = false;
|
||||||
if (arrayIndex)
|
if (arrayIndex)
|
||||||
|
{
|
||||||
|
// If we have a constant, shortcircuit the array logic.
|
||||||
|
|
||||||
|
IntNode *intNode = dynamic_cast<IntNode*>(arrayIndex);
|
||||||
|
StrConstNode *strNode = dynamic_cast<StrConstNode*>(arrayIndex);
|
||||||
|
if (intNode)
|
||||||
|
{
|
||||||
|
varName = StringTable->insert(avar("%s%d", varName, intNode->value));
|
||||||
|
shortCircuit = true;
|
||||||
|
}
|
||||||
|
else if (strNode)
|
||||||
|
{
|
||||||
|
varName = StringTable->insert(avar("%s%s", varName, strNode->str));
|
||||||
|
shortCircuit = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
precompileIdent(varName);
|
||||||
|
|
||||||
|
if (arrayIndex && !shortCircuit)
|
||||||
{
|
{
|
||||||
if (subType == TypeReqString)
|
if (subType == TypeReqString)
|
||||||
codeStream.emit(OP_ADVANCE_STR);
|
codeStream.emit(OP_ADVANCE_STR);
|
||||||
|
|
||||||
|
// Ok, lets try to optimize %var[%someothervar] as this is
|
||||||
|
// a common case for array usage.
|
||||||
|
StringTableEntry varNodeVarName;
|
||||||
|
if (isSimpleVarLookup(arrayIndex, varNodeVarName))
|
||||||
|
{
|
||||||
|
codeStream.emit(OP_SETCURVAR_ARRAY_CREATE_VARLOOKUP);
|
||||||
|
codeStream.emitSTE(varName);
|
||||||
|
codeStream.emitSTE(varNodeVarName);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
codeStream.emit(OP_LOADIMMED_IDENT);
|
codeStream.emit(OP_LOADIMMED_IDENT);
|
||||||
codeStream.emitSTE(varName);
|
codeStream.emitSTE(varName);
|
||||||
|
|
||||||
|
|
@ -968,6 +1128,8 @@ U32 AssignExprNode::compile(CodeStream &codeStream, U32 ip, TypeReq type)
|
||||||
ip = arrayIndex->compile(codeStream, ip, TypeReqString);
|
ip = arrayIndex->compile(codeStream, ip, TypeReqString);
|
||||||
codeStream.emit(OP_REWIND_STR);
|
codeStream.emit(OP_REWIND_STR);
|
||||||
codeStream.emit(OP_SETCURVAR_ARRAY_CREATE);
|
codeStream.emit(OP_SETCURVAR_ARRAY_CREATE);
|
||||||
|
}
|
||||||
|
|
||||||
if (subType == TypeReqString)
|
if (subType == TypeReqString)
|
||||||
codeStream.emit(OP_TERMINATE_REWIND_STR);
|
codeStream.emit(OP_TERMINATE_REWIND_STR);
|
||||||
}
|
}
|
||||||
|
|
@ -1010,10 +1172,12 @@ static void getAssignOpTypeOp(S32 op, TypeReq &type, U32 &operand)
|
||||||
switch (op)
|
switch (op)
|
||||||
{
|
{
|
||||||
case '+':
|
case '+':
|
||||||
|
case opPLUSPLUS:
|
||||||
type = TypeReqFloat;
|
type = TypeReqFloat;
|
||||||
operand = OP_ADD;
|
operand = OP_ADD;
|
||||||
break;
|
break;
|
||||||
case '-':
|
case '-':
|
||||||
|
case opMINUSMINUS:
|
||||||
type = TypeReqFloat;
|
type = TypeReqFloat;
|
||||||
operand = OP_SUB;
|
operand = OP_SUB;
|
||||||
break;
|
break;
|
||||||
|
|
@ -1056,35 +1220,112 @@ U32 AssignOpExprNode::compile(CodeStream &codeStream, U32 ip, TypeReq type)
|
||||||
{
|
{
|
||||||
|
|
||||||
// goes like this...
|
// goes like this...
|
||||||
|
//
|
||||||
|
// IF no array index && (op == OPPLUSPLUS or op == OPMINUSMINUS)
|
||||||
|
// if op == OPPLUSPLUS
|
||||||
|
// OP_INC
|
||||||
|
// varName
|
||||||
|
// else if op == OPMINUSMINUS
|
||||||
|
// OP_DEC
|
||||||
|
// varName
|
||||||
|
// else
|
||||||
|
// OP_INVALID
|
||||||
|
// endif
|
||||||
|
// ELSE
|
||||||
// eval expr as float or int
|
// eval expr as float or int
|
||||||
// if there's an arrayIndex
|
// if there's an arrayIndex and we don't short circuit
|
||||||
|
// if arrayIndex is a var node
|
||||||
|
// OP_SETCURVAR_ARRAY_CREATE_VARLOOKUP
|
||||||
|
// varName
|
||||||
|
// varNodeVarName
|
||||||
|
// else
|
||||||
// OP_LOADIMMED_IDENT
|
// OP_LOADIMMED_IDENT
|
||||||
// varName
|
// varName
|
||||||
// OP_ADVANCE_STR
|
// OP_ADVANCE_STR
|
||||||
// eval arrayIndex stringwise
|
// eval arrayIndex stringwise
|
||||||
// OP_REWIND_STR
|
// OP_REWIND_STR
|
||||||
// OP_SETCURVAR_ARRAY_CREATE
|
// OP_SETCURVAR_ARRAY_CREATE
|
||||||
|
// endif
|
||||||
// else
|
// else
|
||||||
// OP_SETCURVAR_CREATE
|
// OP_SETCURVAR_CREATE
|
||||||
// varName
|
// varName
|
||||||
|
// endif
|
||||||
// OP_LOADVAR_FLT or UINT
|
// OP_LOADVAR_FLT or UINT
|
||||||
// operand
|
// operand
|
||||||
// OP_SAVEVAR_FLT or UINT
|
// OP_SAVEVAR_FLT or UINT
|
||||||
|
// ENDIF
|
||||||
|
//
|
||||||
|
// if subtype != type
|
||||||
|
// convert type
|
||||||
|
// endif
|
||||||
|
|
||||||
// conversion OP if necessary.
|
// conversion OP if necessary.
|
||||||
getAssignOpTypeOp(op, subType, operand);
|
getAssignOpTypeOp(op, subType, operand);
|
||||||
|
|
||||||
|
// ++ or -- optimization support for non indexed variables.
|
||||||
|
if ((!arrayIndex) && (op == opPLUSPLUS || op == opMINUSMINUS))
|
||||||
|
{
|
||||||
precompileIdent(varName);
|
precompileIdent(varName);
|
||||||
|
|
||||||
|
if (op == opPLUSPLUS)
|
||||||
|
{
|
||||||
|
codeStream.emit(OP_INC);
|
||||||
|
codeStream.emitSTE(varName);
|
||||||
|
}
|
||||||
|
else if (op == opMINUSMINUS)
|
||||||
|
{
|
||||||
|
codeStream.emit(OP_DEC);
|
||||||
|
codeStream.emitSTE(varName);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// This should NEVER happen. This is just for sanity.
|
||||||
|
AssertISV(false, "Tried to use ++ or -- but something weird happened.");
|
||||||
|
codeStream.emit(OP_INVALID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
ip = expr->compile(codeStream, ip, subType);
|
ip = expr->compile(codeStream, ip, subType);
|
||||||
if(!arrayIndex)
|
|
||||||
|
bool shortCircuit = false;
|
||||||
|
if (arrayIndex)
|
||||||
|
{
|
||||||
|
// If we have a constant, shortcircuit the array logic.
|
||||||
|
|
||||||
|
IntNode *intNode = dynamic_cast<IntNode*>(arrayIndex);
|
||||||
|
StrConstNode *strNode = dynamic_cast<StrConstNode*>(arrayIndex);
|
||||||
|
if (intNode)
|
||||||
|
{
|
||||||
|
varName = StringTable->insert(avar("%s%d", varName, intNode->value));
|
||||||
|
shortCircuit = true;
|
||||||
|
}
|
||||||
|
else if (strNode)
|
||||||
|
{
|
||||||
|
varName = StringTable->insert(avar("%s%s", varName, strNode->str));
|
||||||
|
shortCircuit = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
precompileIdent(varName);
|
||||||
|
|
||||||
|
if (!arrayIndex || shortCircuit)
|
||||||
{
|
{
|
||||||
codeStream.emit(OP_SETCURVAR_CREATE);
|
codeStream.emit(OP_SETCURVAR_CREATE);
|
||||||
codeStream.emitSTE(varName);
|
codeStream.emitSTE(varName);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
|
// Ok, lets try to optimize %var[%someothervar] as this is
|
||||||
|
// a common case for array usage.
|
||||||
|
StringTableEntry varNodeVarName;
|
||||||
|
if (isSimpleVarLookup(arrayIndex, varNodeVarName))
|
||||||
|
{
|
||||||
|
codeStream.emit(OP_SETCURVAR_ARRAY_CREATE_VARLOOKUP);
|
||||||
|
codeStream.emitSTE(varName);
|
||||||
|
codeStream.emitSTE(varNodeVarName);
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
codeStream.emit(OP_LOADIMMED_IDENT);
|
codeStream.emit(OP_LOADIMMED_IDENT);
|
||||||
codeStream.emitSTE(varName);
|
codeStream.emitSTE(varName);
|
||||||
|
|
@ -1094,9 +1335,11 @@ U32 AssignOpExprNode::compile(CodeStream &codeStream, U32 ip, TypeReq type)
|
||||||
codeStream.emit(OP_REWIND_STR);
|
codeStream.emit(OP_REWIND_STR);
|
||||||
codeStream.emit(OP_SETCURVAR_ARRAY_CREATE);
|
codeStream.emit(OP_SETCURVAR_ARRAY_CREATE);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
codeStream.emit((subType == TypeReqFloat) ? OP_LOADVAR_FLT : OP_LOADVAR_UINT);
|
codeStream.emit((subType == TypeReqFloat) ? OP_LOADVAR_FLT : OP_LOADVAR_UINT);
|
||||||
codeStream.emit(operand);
|
codeStream.emit(operand);
|
||||||
codeStream.emit((subType == TypeReqFloat) ? OP_SAVEVAR_FLT : OP_SAVEVAR_UINT);
|
codeStream.emit((subType == TypeReqFloat) ? OP_SAVEVAR_FLT : OP_SAVEVAR_UINT);
|
||||||
|
}
|
||||||
if (subType != type)
|
if (subType != type)
|
||||||
codeStream.emit(conversionOp(subType, type));
|
codeStream.emit(conversionOp(subType, type));
|
||||||
return codeStream.tell();
|
return codeStream.tell();
|
||||||
|
|
@ -1156,6 +1399,31 @@ U32 FuncCallExprNode::compile(CodeStream &codeStream, U32 ip, TypeReq type)
|
||||||
precompileIdent(nameSpace);
|
precompileIdent(nameSpace);
|
||||||
|
|
||||||
codeStream.emit(OP_PUSH_FRAME);
|
codeStream.emit(OP_PUSH_FRAME);
|
||||||
|
|
||||||
|
bool isThisCall = false;
|
||||||
|
|
||||||
|
// Try to optimize the this pointer call if it is a variable
|
||||||
|
// that we are loading.
|
||||||
|
if (callType == MethodCall)
|
||||||
|
{
|
||||||
|
// We cannot optimize array indices because it can have quite
|
||||||
|
// a bit of code to figure out the array index.
|
||||||
|
VarNode *var = dynamic_cast<VarNode*>(args);
|
||||||
|
if (var && !var->arrayIndex)
|
||||||
|
{
|
||||||
|
precompileIdent(var->varName);
|
||||||
|
|
||||||
|
// Are we a %this call?
|
||||||
|
isThisCall = (var->varName == StringTable->insert("%this"));
|
||||||
|
|
||||||
|
codeStream.emit(OP_PUSH_THIS);
|
||||||
|
codeStream.emitSTE(var->varName);
|
||||||
|
|
||||||
|
// inc args since we took care of first arg.
|
||||||
|
args = static_cast<ExprNode*>(args->getNext());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (ExprNode *walk = args; walk; walk = (ExprNode *)walk->getNext())
|
for (ExprNode *walk = args; walk; walk = (ExprNode *)walk->getNext())
|
||||||
{
|
{
|
||||||
TypeReq walkType = walk->getPreferredType();
|
TypeReq walkType = walk->getPreferredType();
|
||||||
|
|
@ -1174,6 +1442,14 @@ U32 FuncCallExprNode::compile(CodeStream &codeStream, U32 ip, TypeReq type)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isThisCall)
|
||||||
|
{
|
||||||
|
codeStream.emit(OP_CALLFUNC_THIS);
|
||||||
|
codeStream.emitSTE(funcName);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
if (callType == MethodCall || callType == ParentCall)
|
if (callType == MethodCall || callType == ParentCall)
|
||||||
codeStream.emit(OP_CALLFUNC);
|
codeStream.emit(OP_CALLFUNC);
|
||||||
else
|
else
|
||||||
|
|
@ -1181,8 +1457,9 @@ U32 FuncCallExprNode::compile(CodeStream &codeStream, U32 ip, TypeReq type)
|
||||||
|
|
||||||
codeStream.emitSTE(funcName);
|
codeStream.emitSTE(funcName);
|
||||||
codeStream.emitSTE(nameSpace);
|
codeStream.emitSTE(nameSpace);
|
||||||
|
|
||||||
codeStream.emit(callType);
|
codeStream.emit(callType);
|
||||||
|
}
|
||||||
|
|
||||||
if (type != TypeReqString)
|
if (type != TypeReqString)
|
||||||
codeStream.emit(conversionOp(TypeReqString, type));
|
codeStream.emit(conversionOp(TypeReqString, type));
|
||||||
return codeStream.tell();
|
return codeStream.tell();
|
||||||
|
|
@ -1193,6 +1470,49 @@ TypeReq FuncCallExprNode::getPreferredType()
|
||||||
return TypeReqString;
|
return TypeReqString;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------
|
||||||
|
|
||||||
|
U32 FuncPointerCallExprNode::compile(CodeStream &codeStream, U32 ip, TypeReq type)
|
||||||
|
{
|
||||||
|
// OP_PUSH_FRAME
|
||||||
|
// arg OP_PUSH arg OP_PUSH arg OP_PUSH
|
||||||
|
// eval all the args, then call the function.
|
||||||
|
|
||||||
|
// eval fn pointer
|
||||||
|
// OP_CALLFUNC_POINTER
|
||||||
|
|
||||||
|
codeStream.emit(OP_PUSH_FRAME);
|
||||||
|
for (ExprNode *walk = args; walk; walk = (ExprNode *)walk->getNext())
|
||||||
|
{
|
||||||
|
TypeReq walkType = walk->getPreferredType();
|
||||||
|
if (walkType == TypeReqNone) walkType = TypeReqString;
|
||||||
|
ip = walk->compile(codeStream, ip, walkType);
|
||||||
|
switch (walk->getPreferredType())
|
||||||
|
{
|
||||||
|
case TypeReqFloat:
|
||||||
|
codeStream.emit(OP_PUSH_FLT);
|
||||||
|
break;
|
||||||
|
case TypeReqUInt:
|
||||||
|
codeStream.emit(OP_PUSH_UINT);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
codeStream.emit(OP_PUSH);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ip = funcPointer->compile(codeStream, ip, TypeReqString);
|
||||||
|
codeStream.emit(OP_CALLFUNC_POINTER);
|
||||||
|
|
||||||
|
if (type != TypeReqString)
|
||||||
|
codeStream.emit(conversionOp(TypeReqString, type));
|
||||||
|
return codeStream.tell();
|
||||||
|
}
|
||||||
|
|
||||||
|
TypeReq FuncPointerCallExprNode::getPreferredType()
|
||||||
|
{
|
||||||
|
return TypeReqString;
|
||||||
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------
|
//------------------------------------------------------------
|
||||||
|
|
||||||
|
|
@ -1225,6 +1545,13 @@ U32 SlotAccessNode::compile(CodeStream &codeStream, U32 ip, TypeReq type)
|
||||||
|
|
||||||
precompileIdent(slotName);
|
precompileIdent(slotName);
|
||||||
|
|
||||||
|
// check if object is %this. If we are, we can do additional optimizations.
|
||||||
|
if (isThisVar(objectExpr))
|
||||||
|
{
|
||||||
|
optimizeThisPointer(codeStream, arrayExpr, ip, slotName);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
if (arrayExpr)
|
if (arrayExpr)
|
||||||
{
|
{
|
||||||
// eval array
|
// eval array
|
||||||
|
|
@ -1249,6 +1576,7 @@ U32 SlotAccessNode::compile(CodeStream &codeStream, U32 ip, TypeReq type)
|
||||||
codeStream.emit(OP_TERMINATE_REWIND_STR);
|
codeStream.emit(OP_TERMINATE_REWIND_STR);
|
||||||
codeStream.emit(OP_SETCURFIELD_ARRAY);
|
codeStream.emit(OP_SETCURFIELD_ARRAY);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
|
|
@ -1331,6 +1659,13 @@ U32 SlotAssignNode::compile(CodeStream &codeStream, U32 ip, TypeReq type)
|
||||||
precompileIdent(slotName);
|
precompileIdent(slotName);
|
||||||
|
|
||||||
ip = valueExpr->compile(codeStream, ip, TypeReqString);
|
ip = valueExpr->compile(codeStream, ip, TypeReqString);
|
||||||
|
|
||||||
|
if (isThisVar(objectExpr))
|
||||||
|
{
|
||||||
|
optimizeThisPointer(codeStream, arrayExpr, ip, slotName);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
codeStream.emit(OP_ADVANCE_STR);
|
codeStream.emit(OP_ADVANCE_STR);
|
||||||
if (arrayExpr)
|
if (arrayExpr)
|
||||||
{
|
{
|
||||||
|
|
@ -1354,6 +1689,8 @@ U32 SlotAssignNode::compile(CodeStream &codeStream, U32 ip, TypeReq type)
|
||||||
}
|
}
|
||||||
|
|
||||||
codeStream.emit(OP_TERMINATE_REWIND_STR);
|
codeStream.emit(OP_TERMINATE_REWIND_STR);
|
||||||
|
}
|
||||||
|
|
||||||
codeStream.emit(OP_SAVEFIELD_STR);
|
codeStream.emit(OP_SAVEFIELD_STR);
|
||||||
|
|
||||||
if (typeID != -1)
|
if (typeID != -1)
|
||||||
|
|
@ -1403,6 +1740,13 @@ U32 SlotAssignOpNode::compile(CodeStream &codeStream, U32 ip, TypeReq type)
|
||||||
precompileIdent(slotName);
|
precompileIdent(slotName);
|
||||||
|
|
||||||
ip = valueExpr->compile(codeStream, ip, subType);
|
ip = valueExpr->compile(codeStream, ip, subType);
|
||||||
|
|
||||||
|
if (isThisVar(objectExpr))
|
||||||
|
{
|
||||||
|
optimizeThisPointer(codeStream, arrayExpr, ip, slotName);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
if (arrayExpr)
|
if (arrayExpr)
|
||||||
{
|
{
|
||||||
ip = arrayExpr->compile(codeStream, ip, TypeReqString);
|
ip = arrayExpr->compile(codeStream, ip, TypeReqString);
|
||||||
|
|
@ -1418,6 +1762,7 @@ U32 SlotAssignOpNode::compile(CodeStream &codeStream, U32 ip, TypeReq type)
|
||||||
codeStream.emit(OP_TERMINATE_REWIND_STR);
|
codeStream.emit(OP_TERMINATE_REWIND_STR);
|
||||||
codeStream.emit(OP_SETCURFIELD_ARRAY);
|
codeStream.emit(OP_SETCURFIELD_ARRAY);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
codeStream.emit((subType == TypeReqFloat) ? OP_LOADFIELD_FLT : OP_LOADFIELD_UINT);
|
codeStream.emit((subType == TypeReqFloat) ? OP_LOADFIELD_FLT : OP_LOADFIELD_UINT);
|
||||||
codeStream.emit(operand);
|
codeStream.emit(operand);
|
||||||
codeStream.emit((subType == TypeReqFloat) ? OP_SAVEFIELD_FLT : OP_SAVEFIELD_UINT);
|
codeStream.emit((subType == TypeReqFloat) ? OP_SAVEFIELD_FLT : OP_SAVEFIELD_UINT);
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -1007,6 +1007,20 @@ void CodeBlock::dumpInstructions( U32 startIp, bool upToReturn )
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case OP_INC:
|
||||||
|
{
|
||||||
|
Con::printf("%i: OP_INC varName=%s", ip - 1, CodeToSTE(code, ip));
|
||||||
|
ip += 2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case OP_DEC:
|
||||||
|
{
|
||||||
|
Con::printf("%i: OP_DEC varName=%s", ip - 1, CodeToSTE(code, ip));
|
||||||
|
ip += 2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case OP_SETCURVAR:
|
case OP_SETCURVAR:
|
||||||
{
|
{
|
||||||
StringTableEntry var = CodeToSTE(code, ip);
|
StringTableEntry var = CodeToSTE(code, ip);
|
||||||
|
|
@ -1031,12 +1045,32 @@ void CodeBlock::dumpInstructions( U32 startIp, bool upToReturn )
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case OP_SETCURVAR_ARRAY_VARLOOKUP:
|
||||||
|
{
|
||||||
|
StringTableEntry arrayName = CodeToSTE(code, ip);
|
||||||
|
StringTableEntry arrayLookup = CodeToSTE(code, ip + 2);
|
||||||
|
|
||||||
|
Con::printf("%i: OP_SETCURVAR_ARRAY_VARLOOKUP arrayName=%s arrayLookup=%s", ip - 1, arrayName, arrayLookup);
|
||||||
|
ip += 4;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case OP_SETCURVAR_ARRAY_CREATE:
|
case OP_SETCURVAR_ARRAY_CREATE:
|
||||||
{
|
{
|
||||||
Con::printf("%i: OP_SETCURVAR_ARRAY_CREATE", ip - 1);
|
Con::printf("%i: OP_SETCURVAR_ARRAY_CREATE", ip - 1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case OP_SETCURVAR_ARRAY_CREATE_VARLOOKUP:
|
||||||
|
{
|
||||||
|
StringTableEntry arrayName = CodeToSTE(code, ip);
|
||||||
|
StringTableEntry arrayLookup = CodeToSTE(code, ip + 2);
|
||||||
|
|
||||||
|
Con::printf("%i: OP_SETCURVAR_ARRAY_CREATE_VARLOOKUP arrayName=%s arrayLookup=%s", ip - 1, arrayName, arrayLookup);
|
||||||
|
ip += 4;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case OP_LOADVAR_UINT:
|
case OP_LOADVAR_UINT:
|
||||||
{
|
{
|
||||||
Con::printf("%i: OP_LOADVAR_UINT", ip - 1);
|
Con::printf("%i: OP_LOADVAR_UINT", ip - 1);
|
||||||
|
|
@ -1118,6 +1152,22 @@ void CodeBlock::dumpInstructions( U32 startIp, bool upToReturn )
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case OP_SETCURFIELD_ARRAY_VAR:
|
||||||
|
{
|
||||||
|
StringTableEntry var = CodeToSTE(code, ip);
|
||||||
|
Con::printf("%i: OP_SETCURFIELD_ARRAY_VAR var=%s", ip - 1, var);
|
||||||
|
ip += 2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case OP_SETCURFIELD_THIS:
|
||||||
|
{
|
||||||
|
StringTableEntry curField = CodeToSTE(code, ip);
|
||||||
|
Con::printf("%i: OP_SETCURFIELD_THIS field=%s", ip - 1, curField);
|
||||||
|
ip += 2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case OP_SETCURFIELD_TYPE:
|
case OP_SETCURFIELD_TYPE:
|
||||||
{
|
{
|
||||||
U32 type = code[ip];
|
U32 type = code[ip];
|
||||||
|
|
@ -1298,6 +1348,21 @@ void CodeBlock::dumpInstructions( U32 startIp, bool upToReturn )
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case OP_CALLFUNC_POINTER:
|
||||||
|
{
|
||||||
|
Con::printf("%i: OP_CALLFUNC_POINTER", ip - 1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case OP_CALLFUNC_THIS:
|
||||||
|
{
|
||||||
|
StringTableEntry fnName = CodeToSTE(code, ip);
|
||||||
|
Con::printf("%i: OP_CALLFUNC_THIS name=%s ", ip - 1, fnName);
|
||||||
|
|
||||||
|
ip += 2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case OP_ADVANCE_STR:
|
case OP_ADVANCE_STR:
|
||||||
{
|
{
|
||||||
Con::printf("%i: OP_ADVANCE_STR", ip - 1);
|
Con::printf("%i: OP_ADVANCE_STR", ip - 1);
|
||||||
|
|
@ -1366,6 +1431,13 @@ void CodeBlock::dumpInstructions( U32 startIp, bool upToReturn )
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case OP_PUSH_THIS:
|
||||||
|
{
|
||||||
|
Con::printf("%i: OP_PUSH_THIS varName=%s", ip - 1, CodeToSTE(code, ip));
|
||||||
|
ip += 2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case OP_PUSH_FRAME:
|
case OP_PUSH_FRAME:
|
||||||
{
|
{
|
||||||
Con::printf("%i: OP_PUSH_FRAME", ip - 1);
|
Con::printf("%i: OP_PUSH_FRAME", ip - 1);
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,7 @@ class ConsoleValueRef;
|
||||||
/// This class represents a block of code, usually mapped directly to a file.
|
/// This class represents a block of code, usually mapped directly to a file.
|
||||||
class CodeBlock
|
class CodeBlock
|
||||||
{
|
{
|
||||||
|
friend class CodeInterpreter;
|
||||||
private:
|
private:
|
||||||
static CodeBlock* smCodeBlockList;
|
static CodeBlock* smCodeBlockList;
|
||||||
static CodeBlock* smCurrentCodeBlock;
|
static CodeBlock* smCurrentCodeBlock;
|
||||||
|
|
|
||||||
2979
Engine/source/console/codeInterpreter.cpp
Normal file
2979
Engine/source/console/codeInterpreter.cpp
Normal file
File diff suppressed because it is too large
Load diff
262
Engine/source/console/codeInterpreter.h
Normal file
262
Engine/source/console/codeInterpreter.h
Normal file
|
|
@ -0,0 +1,262 @@
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Copyright (c) 2012 GarageGames, LLC
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to
|
||||||
|
// deal in the Software without restriction, including without limitation the
|
||||||
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
// sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
// IN THE SOFTWARE.
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#ifndef _CODEINTERPRETER_H_
|
||||||
|
#define _CODEINTERPRETER_H_
|
||||||
|
|
||||||
|
#include "console/codeBlock.h"
|
||||||
|
#include "console/console.h"
|
||||||
|
#include "console/consoleInternal.h"
|
||||||
|
|
||||||
|
/// Frame data for a foreach/foreach$ loop.
|
||||||
|
struct IterStackRecord
|
||||||
|
{
|
||||||
|
/// If true, this is a foreach$ loop; if not, it's a foreach loop.
|
||||||
|
bool mIsStringIter;
|
||||||
|
|
||||||
|
/// The iterator variable.
|
||||||
|
Dictionary::Entry* mVariable;
|
||||||
|
|
||||||
|
/// Information for an object iterator loop.
|
||||||
|
struct ObjectPos
|
||||||
|
{
|
||||||
|
/// The set being iterated over.
|
||||||
|
SimSet* mSet;
|
||||||
|
|
||||||
|
/// Current index in the set.
|
||||||
|
U32 mIndex;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Information for a string iterator loop.
|
||||||
|
struct StringPos
|
||||||
|
{
|
||||||
|
/// The raw string data on the string stack.
|
||||||
|
StringStackPtr mString;
|
||||||
|
|
||||||
|
/// Current parsing position.
|
||||||
|
U32 mIndex;
|
||||||
|
};
|
||||||
|
|
||||||
|
union
|
||||||
|
{
|
||||||
|
ObjectPos mObj;
|
||||||
|
StringPos mStr;
|
||||||
|
} mData;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum OPCodeReturn
|
||||||
|
{
|
||||||
|
exitCode = -1,
|
||||||
|
success = 0,
|
||||||
|
breakContinue = 1
|
||||||
|
};
|
||||||
|
|
||||||
|
class CodeInterpreter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CodeInterpreter(CodeBlock *cb);
|
||||||
|
~CodeInterpreter();
|
||||||
|
|
||||||
|
ConsoleValueRef exec(U32 ip,
|
||||||
|
StringTableEntry functionName,
|
||||||
|
Namespace *thisNamespace,
|
||||||
|
U32 argc,
|
||||||
|
ConsoleValueRef *argv,
|
||||||
|
bool noCalls,
|
||||||
|
StringTableEntry packageName,
|
||||||
|
S32 setFrame);
|
||||||
|
|
||||||
|
static void init();
|
||||||
|
|
||||||
|
// Methods
|
||||||
|
private:
|
||||||
|
void parseArgs(U32 &ip);
|
||||||
|
|
||||||
|
/// Group op codes
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
OPCodeReturn op_func_decl(U32 &ip);
|
||||||
|
OPCodeReturn op_create_object(U32 &ip);
|
||||||
|
OPCodeReturn op_add_object(U32 &ip);
|
||||||
|
OPCodeReturn op_end_object(U32 &ip);
|
||||||
|
OPCodeReturn op_finish_object(U32 &ip);
|
||||||
|
OPCodeReturn op_jmpiffnot(U32 &ip);
|
||||||
|
OPCodeReturn op_jmpifnot(U32 &ip);
|
||||||
|
OPCodeReturn op_jmpiff(U32 &ip);
|
||||||
|
OPCodeReturn op_jmpif(U32 &ip);
|
||||||
|
OPCodeReturn op_jmpifnot_np(U32 &ip);
|
||||||
|
OPCodeReturn op_jmpif_np(U32 &ip);
|
||||||
|
OPCodeReturn op_jmp(U32 &ip);
|
||||||
|
OPCodeReturn op_return_void(U32 &ip);
|
||||||
|
OPCodeReturn op_return(U32 &ip);
|
||||||
|
OPCodeReturn op_return_flt(U32 &ip);
|
||||||
|
OPCodeReturn op_return_uint(U32 &ip);
|
||||||
|
OPCodeReturn op_cmpeq(U32 &ip);
|
||||||
|
OPCodeReturn op_cmpgr(U32 &ip);
|
||||||
|
OPCodeReturn op_cmpge(U32 &ip);
|
||||||
|
OPCodeReturn op_cmplt(U32 &ip);
|
||||||
|
OPCodeReturn op_cmple(U32 &ip);
|
||||||
|
OPCodeReturn op_cmpne(U32 &ip);
|
||||||
|
OPCodeReturn op_xor(U32 &ip);
|
||||||
|
OPCodeReturn op_mod(U32 &ip);
|
||||||
|
OPCodeReturn op_bitand(U32 &ip);
|
||||||
|
OPCodeReturn op_bitor(U32 &ip);
|
||||||
|
OPCodeReturn op_not(U32 &ip);
|
||||||
|
OPCodeReturn op_notf(U32 &ip);
|
||||||
|
OPCodeReturn op_onescomplement(U32 &ip);
|
||||||
|
OPCodeReturn op_shr(U32 &ip);
|
||||||
|
OPCodeReturn op_shl(U32 &ip);
|
||||||
|
OPCodeReturn op_and(U32 &ip);
|
||||||
|
OPCodeReturn op_or(U32 &ip);
|
||||||
|
OPCodeReturn op_add(U32 &ip);
|
||||||
|
OPCodeReturn op_sub(U32 &ip);
|
||||||
|
OPCodeReturn op_mul(U32 &ip);
|
||||||
|
OPCodeReturn op_div(U32 &ip);
|
||||||
|
OPCodeReturn op_neg(U32 &ip);
|
||||||
|
OPCodeReturn op_inc(U32 &ip);
|
||||||
|
OPCodeReturn op_dec(U32 &ip);
|
||||||
|
OPCodeReturn op_setcurvar(U32 &ip);
|
||||||
|
OPCodeReturn op_setcurvar_create(U32 &ip);
|
||||||
|
OPCodeReturn op_setcurvar_array(U32 &ip);
|
||||||
|
OPCodeReturn op_setcurvar_array_varlookup(U32 &ip);
|
||||||
|
OPCodeReturn op_setcurvar_array_create(U32 &ip);
|
||||||
|
OPCodeReturn op_setcurvar_array_create_varlookup(U32 &ip);
|
||||||
|
OPCodeReturn op_loadvar_uint(U32 &ip);
|
||||||
|
OPCodeReturn op_loadvar_flt(U32 &ip);
|
||||||
|
OPCodeReturn op_loadvar_str(U32 &ip);
|
||||||
|
OPCodeReturn op_loadvar_var(U32 &ip);
|
||||||
|
OPCodeReturn op_savevar_uint(U32 &ip);
|
||||||
|
OPCodeReturn op_savevar_flt(U32 &ip);
|
||||||
|
OPCodeReturn op_savevar_str(U32 &ip);
|
||||||
|
OPCodeReturn op_savevar_var(U32 &ip);
|
||||||
|
OPCodeReturn op_setcurobject(U32 &ip);
|
||||||
|
OPCodeReturn op_setcurobject_internal(U32 &ip);
|
||||||
|
OPCodeReturn op_setcurobject_new(U32 &ip);
|
||||||
|
OPCodeReturn op_setcurfield(U32 &ip);
|
||||||
|
OPCodeReturn op_setcurfield_array(U32 &ip);
|
||||||
|
OPCodeReturn op_setcurfield_type(U32 &ip);
|
||||||
|
OPCodeReturn op_setcurfield_this(U32 &ip);
|
||||||
|
OPCodeReturn op_setcurfield_array_var(U32 &ip);
|
||||||
|
OPCodeReturn op_loadfield_uint(U32 &ip);
|
||||||
|
OPCodeReturn op_loadfield_flt(U32 &ip);
|
||||||
|
OPCodeReturn op_loadfield_str(U32 &ip);
|
||||||
|
OPCodeReturn op_savefield_uint(U32 &ip);
|
||||||
|
OPCodeReturn op_savefield_flt(U32 &ip);
|
||||||
|
OPCodeReturn op_savefield_str(U32 &ip);
|
||||||
|
OPCodeReturn op_str_to_uint(U32 &ip);
|
||||||
|
OPCodeReturn op_str_to_flt(U32 &ip);
|
||||||
|
OPCodeReturn op_str_to_none(U32 &ip);
|
||||||
|
OPCodeReturn op_flt_to_uint(U32 &ip);
|
||||||
|
OPCodeReturn op_flt_to_str(U32 &ip);
|
||||||
|
OPCodeReturn op_flt_to_none(U32 &ip);
|
||||||
|
OPCodeReturn op_uint_to_flt(U32 &ip);
|
||||||
|
OPCodeReturn op_uint_to_str(U32 &ip);
|
||||||
|
OPCodeReturn op_uint_to_none(U32 &ip);
|
||||||
|
OPCodeReturn op_copyvar_to_none(U32 &ip);
|
||||||
|
OPCodeReturn op_loadimmed_uint(U32 &ip);
|
||||||
|
OPCodeReturn op_loadimmed_flt(U32 &ip);
|
||||||
|
OPCodeReturn op_tag_to_str(U32 &ip);
|
||||||
|
OPCodeReturn op_loadimmed_str(U32 &ip);
|
||||||
|
OPCodeReturn op_docblock_str(U32 &ip);
|
||||||
|
OPCodeReturn op_loadimmed_ident(U32 &ip);
|
||||||
|
OPCodeReturn op_callfunc_resolve(U32 &ip);
|
||||||
|
OPCodeReturn op_callfunc(U32 &ip);
|
||||||
|
OPCodeReturn op_callfunc_pointer(U32 &ip);
|
||||||
|
OPCodeReturn op_callfunc_this(U32 &ip);
|
||||||
|
OPCodeReturn op_advance_str(U32 &ip);
|
||||||
|
OPCodeReturn op_advance_str_appendchar(U32 &ip);
|
||||||
|
OPCodeReturn op_advance_str_comma(U32 &ip);
|
||||||
|
OPCodeReturn op_advance_str_nul(U32 &ip);
|
||||||
|
OPCodeReturn op_rewind_str(U32 &ip);
|
||||||
|
OPCodeReturn op_terminate_rewind_str(U32 &ip);
|
||||||
|
OPCodeReturn op_compare_str(U32 &ip);
|
||||||
|
OPCodeReturn op_push(U32 &ip);
|
||||||
|
OPCodeReturn op_push_uint(U32 &ip);
|
||||||
|
OPCodeReturn op_push_flt(U32 &ip);
|
||||||
|
OPCodeReturn op_push_var(U32 &ip);
|
||||||
|
OPCodeReturn op_push_this(U32 &ip);
|
||||||
|
OPCodeReturn op_push_frame(U32 &ip);
|
||||||
|
OPCodeReturn op_assert(U32 &ip);
|
||||||
|
OPCodeReturn op_break(U32 &ip);
|
||||||
|
OPCodeReturn op_iter_begin_str(U32 &ip);
|
||||||
|
OPCodeReturn op_iter_begin(U32 &ip);
|
||||||
|
OPCodeReturn op_iter(U32 &ip);
|
||||||
|
OPCodeReturn op_iter_end(U32 &ip);
|
||||||
|
OPCodeReturn op_invalid(U32 &ip);
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
private:
|
||||||
|
CodeBlock *mCodeBlock;
|
||||||
|
|
||||||
|
/// Group exec arguments.
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
StringTableEntry functionName;
|
||||||
|
Namespace *thisNamespace;
|
||||||
|
U32 argc;
|
||||||
|
ConsoleValueRef *argv;
|
||||||
|
bool noCalls;
|
||||||
|
StringTableEntry packageName;
|
||||||
|
S32 setFrame;
|
||||||
|
} mExec;
|
||||||
|
|
||||||
|
U32 mIterDepth;
|
||||||
|
F64 *mCurFloatTable;
|
||||||
|
char *mCurStringTable;
|
||||||
|
StringTableEntry mThisFunctionName;
|
||||||
|
bool mPopFrame;
|
||||||
|
|
||||||
|
// Add local object creation stack [7/9/2007 Black]
|
||||||
|
static const U32 objectCreationStackSize = 32;
|
||||||
|
U32 mObjectCreationStackIndex;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
SimObject *newObject;
|
||||||
|
U32 failJump;
|
||||||
|
} mObjectCreationStack[objectCreationStackSize];
|
||||||
|
|
||||||
|
SimObject *mCurrentNewObject;
|
||||||
|
U32 mFailJump;
|
||||||
|
StringTableEntry mPrevField;
|
||||||
|
StringTableEntry mCurField;
|
||||||
|
SimObject *mPrevObject;
|
||||||
|
SimObject *mCurObject;
|
||||||
|
SimObject *mSaveObject;
|
||||||
|
SimObject *mThisObject;
|
||||||
|
Namespace::Entry *mNSEntry;
|
||||||
|
StringTableEntry mCurFNDocBlock;
|
||||||
|
StringTableEntry mCurNSDocBlock;
|
||||||
|
U32 mCallArgc;
|
||||||
|
ConsoleValueRef *mCallArgv;
|
||||||
|
CodeBlock *mSaveCodeBlock;
|
||||||
|
|
||||||
|
// note: anything returned is pushed to CSTK and will be invalidated on the next exec()
|
||||||
|
ConsoleValueRef mReturnValue;
|
||||||
|
|
||||||
|
U32 mCurrentInstruction;
|
||||||
|
|
||||||
|
static const S32 nsDocLength = 128;
|
||||||
|
char mNSDocBlockClass[nsDocLength];
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -165,6 +165,10 @@ U32 CompilerStringTable::add(const char *str, bool caseSens, bool tag)
|
||||||
newStr->len = len;
|
newStr->len = len;
|
||||||
newStr->tag = tag;
|
newStr->tag = tag;
|
||||||
dStrcpy(newStr->string, str);
|
dStrcpy(newStr->string, str);
|
||||||
|
|
||||||
|
// Put into the hash table.
|
||||||
|
hashTable[str] = newStr;
|
||||||
|
|
||||||
return newStr->start;
|
return newStr->start;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -189,6 +193,7 @@ void CompilerStringTable::reset()
|
||||||
char *CompilerStringTable::build()
|
char *CompilerStringTable::build()
|
||||||
{
|
{
|
||||||
char *ret = new char[totalLen];
|
char *ret = new char[totalLen];
|
||||||
|
dMemset(ret, 0, totalLen);
|
||||||
for (Entry *walk = list; walk; walk = walk->next)
|
for (Entry *walk = list; walk; walk = walk->next)
|
||||||
dStrcpy(ret + walk->start, walk->string);
|
dStrcpy(ret + walk->start, walk->string);
|
||||||
return ret;
|
return ret;
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,9 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
class Stream;
|
class Stream;
|
||||||
class DataChunker;
|
class DataChunker;
|
||||||
|
|
||||||
|
|
@ -91,10 +94,15 @@ namespace Compiler
|
||||||
OP_DIV,
|
OP_DIV,
|
||||||
OP_NEG,
|
OP_NEG,
|
||||||
|
|
||||||
|
OP_INC,
|
||||||
|
OP_DEC,
|
||||||
|
|
||||||
OP_SETCURVAR,
|
OP_SETCURVAR,
|
||||||
OP_SETCURVAR_CREATE,
|
OP_SETCURVAR_CREATE,
|
||||||
OP_SETCURVAR_ARRAY,
|
OP_SETCURVAR_ARRAY,
|
||||||
|
OP_SETCURVAR_ARRAY_VARLOOKUP,
|
||||||
OP_SETCURVAR_ARRAY_CREATE,
|
OP_SETCURVAR_ARRAY_CREATE,
|
||||||
|
OP_SETCURVAR_ARRAY_CREATE_VARLOOKUP,
|
||||||
|
|
||||||
OP_LOADVAR_UINT,// 40
|
OP_LOADVAR_UINT,// 40
|
||||||
OP_LOADVAR_FLT,
|
OP_LOADVAR_FLT,
|
||||||
|
|
@ -113,6 +121,8 @@ namespace Compiler
|
||||||
OP_SETCURFIELD,
|
OP_SETCURFIELD,
|
||||||
OP_SETCURFIELD_ARRAY, // 50
|
OP_SETCURFIELD_ARRAY, // 50
|
||||||
OP_SETCURFIELD_TYPE,
|
OP_SETCURFIELD_TYPE,
|
||||||
|
OP_SETCURFIELD_ARRAY_VAR,
|
||||||
|
OP_SETCURFIELD_THIS,
|
||||||
|
|
||||||
OP_LOADFIELD_UINT,
|
OP_LOADFIELD_UINT,
|
||||||
OP_LOADFIELD_FLT,
|
OP_LOADFIELD_FLT,
|
||||||
|
|
@ -142,6 +152,8 @@ namespace Compiler
|
||||||
|
|
||||||
OP_CALLFUNC_RESOLVE,
|
OP_CALLFUNC_RESOLVE,
|
||||||
OP_CALLFUNC,
|
OP_CALLFUNC,
|
||||||
|
OP_CALLFUNC_POINTER,
|
||||||
|
OP_CALLFUNC_THIS,
|
||||||
|
|
||||||
OP_ADVANCE_STR,
|
OP_ADVANCE_STR,
|
||||||
OP_ADVANCE_STR_APPENDCHAR,
|
OP_ADVANCE_STR_APPENDCHAR,
|
||||||
|
|
@ -155,6 +167,7 @@ namespace Compiler
|
||||||
OP_PUSH_UINT, // Integer
|
OP_PUSH_UINT, // Integer
|
||||||
OP_PUSH_FLT, // Float
|
OP_PUSH_FLT, // Float
|
||||||
OP_PUSH_VAR, // Variable
|
OP_PUSH_VAR, // Variable
|
||||||
|
OP_PUSH_THIS, // This pointer
|
||||||
OP_PUSH_FRAME, // Frame
|
OP_PUSH_FRAME, // Frame
|
||||||
|
|
||||||
OP_ASSERT,
|
OP_ASSERT,
|
||||||
|
|
@ -165,7 +178,9 @@ namespace Compiler
|
||||||
OP_ITER, ///< Enter foreach loop.
|
OP_ITER, ///< Enter foreach loop.
|
||||||
OP_ITER_END, ///< End foreach loop.
|
OP_ITER_END, ///< End foreach loop.
|
||||||
|
|
||||||
OP_INVALID // 90
|
OP_INVALID, // 90
|
||||||
|
|
||||||
|
MAX_OP_CODELEN ///< The amount of op codes.
|
||||||
};
|
};
|
||||||
|
|
||||||
//------------------------------------------------------------
|
//------------------------------------------------------------
|
||||||
|
|
@ -207,6 +222,7 @@ namespace Compiler
|
||||||
Entry *list;
|
Entry *list;
|
||||||
|
|
||||||
char buf[256];
|
char buf[256];
|
||||||
|
std::unordered_map<std::string, Entry*> hashTable;
|
||||||
|
|
||||||
U32 add(const char *str, bool caseSens = true, bool tag = false);
|
U32 add(const char *str, bool caseSens = true, bool tag = false);
|
||||||
U32 addIntString(U32 value);
|
U32 addIntString(U32 value);
|
||||||
|
|
|
||||||
|
|
@ -361,20 +361,22 @@ namespace Con
|
||||||
/// 12/29/04 - BJG - 33->34 Removed some opcodes, part of namespace upgrade.
|
/// 12/29/04 - BJG - 33->34 Removed some opcodes, part of namespace upgrade.
|
||||||
/// 12/30/04 - BJG - 34->35 Reordered some things, further general shuffling.
|
/// 12/30/04 - BJG - 34->35 Reordered some things, further general shuffling.
|
||||||
/// 11/03/05 - BJG - 35->36 Integrated new debugger code.
|
/// 11/03/05 - BJG - 35->36 Integrated new debugger code.
|
||||||
// 09/08/06 - THB - 36->37 New opcode for internal names
|
/// 09/08/06 - THB - 36->37 New opcode for internal names
|
||||||
// 09/15/06 - THB - 37->38 Added unit conversions
|
/// 09/15/06 - THB - 37->38 Added unit conversions
|
||||||
// 11/23/06 - THB - 38->39 Added recursive internal name operator
|
/// 11/23/06 - THB - 38->39 Added recursive internal name operator
|
||||||
// 02/15/07 - THB - 39->40 Bumping to 40 for TGB since the console has been
|
/// 02/15/07 - THB - 39->40 Bumping to 40 for TGB since the console has been
|
||||||
// majorly hacked without the version number being bumped
|
/// majorly hacked without the version number being bumped
|
||||||
// 02/16/07 - THB - 40->41 newmsg operator
|
/// 02/16/07 - THB - 40->41 newmsg operator
|
||||||
// 06/15/07 - THB - 41->42 script types
|
/// 06/15/07 - THB - 41->42 script types
|
||||||
/// 07/31/07 - THB - 42->43 Patch from Andreas Kirsch: Added opcode to support nested new declarations.
|
/// 07/31/07 - THB - 42->43 Patch from Andreas Kirsch: Added opcode to support nested new declarations.
|
||||||
/// 09/12/07 - CAF - 43->44 remove newmsg operator
|
/// 09/12/07 - CAF - 43->44 remove newmsg operator
|
||||||
/// 09/27/07 - RDB - 44->45 Patch from Andreas Kirsch: Added opcode to support correct void return
|
/// 09/27/07 - RDB - 44->45 Patch from Andreas Kirsch: Added opcode to support correct void return
|
||||||
/// 01/13/09 - TMS - 45->46 Added script assert
|
/// 01/13/09 - TMS - 45->46 Added script assert
|
||||||
/// 09/07/14 - jamesu - 46->47 64bit support
|
/// 09/07/14 - jamesu - 46->47 64bit support
|
||||||
/// 10/14/14 - jamesu - 47->48 Added opcodes to reduce reliance on strings in function calls
|
/// 10/14/14 - jamesu - 47->48 Added opcodes to reduce reliance on strings in function calls
|
||||||
DSOVersion = 48,
|
/// 10/07/17 - JTH - 48->49 Added opcode for function pointers and revamp of interpreter
|
||||||
|
/// from switch to function calls.
|
||||||
|
DSOVersion = 49,
|
||||||
|
|
||||||
MaxLineLength = 512, ///< Maximum length of a line of console input.
|
MaxLineLength = 512, ///< Maximum length of a line of console input.
|
||||||
MaxDataTypes = 256 ///< Maximum number of registered data types.
|
MaxDataTypes = 256 ///< Maximum number of registered data types.
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,8 @@
|
||||||
// IN THE SOFTWARE.
|
// IN THE SOFTWARE.
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
#include "platform/platform.h"
|
#include "platform/platform.h"
|
||||||
#include "console/console.h"
|
#include "console/console.h"
|
||||||
|
|
||||||
|
|
@ -43,6 +45,20 @@ DataChunker Namespace::mAllocator;
|
||||||
Namespace *Namespace::mNamespaceList = NULL;
|
Namespace *Namespace::mNamespaceList = NULL;
|
||||||
Namespace *Namespace::mGlobalNamespace = NULL;
|
Namespace *Namespace::mGlobalNamespace = NULL;
|
||||||
|
|
||||||
|
namespace std
|
||||||
|
{
|
||||||
|
template<> struct hash<std::pair<StringTableEntry, StringTableEntry>>
|
||||||
|
{
|
||||||
|
typedef std::pair<StringTableEntry, StringTableEntry> argument_type;
|
||||||
|
typedef size_t result_type;
|
||||||
|
result_type operator()(argument_type const& s) const
|
||||||
|
{
|
||||||
|
return HashPointer(s.first) ^ (HashPointer(s.second) << 1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
std::unordered_map<std::pair<StringTableEntry, StringTableEntry>, Namespace*> gNamespaceCache;
|
||||||
|
|
||||||
bool canTabComplete(const char *prevText, const char *bestMatch,
|
bool canTabComplete(const char *prevText, const char *bestMatch,
|
||||||
const char *newText, S32 baseLen, bool fForward)
|
const char *newText, S32 baseLen, bool fForward)
|
||||||
|
|
@ -967,11 +983,10 @@ Namespace *Namespace::find(StringTableEntry name, StringTableEntry package)
|
||||||
if (name == NULL && package == NULL)
|
if (name == NULL && package == NULL)
|
||||||
return mGlobalNamespace;
|
return mGlobalNamespace;
|
||||||
|
|
||||||
for(Namespace *walk = mNamespaceList; walk; walk = walk->mNext)
|
auto pair = std::make_pair(name, package);
|
||||||
{
|
auto pos = gNamespaceCache.find(pair);
|
||||||
if(walk->mName == name && walk->mPackage == package)
|
if (pos != gNamespaceCache.end())
|
||||||
return walk;
|
return pos->second;
|
||||||
}
|
|
||||||
|
|
||||||
Namespace *ret = (Namespace *)mAllocator.alloc(sizeof(Namespace));
|
Namespace *ret = (Namespace *)mAllocator.alloc(sizeof(Namespace));
|
||||||
constructInPlace(ret);
|
constructInPlace(ret);
|
||||||
|
|
@ -979,6 +994,10 @@ Namespace *Namespace::find(StringTableEntry name, StringTableEntry package)
|
||||||
ret->mName = name;
|
ret->mName = name;
|
||||||
ret->mNext = mNamespaceList;
|
ret->mNext = mNamespaceList;
|
||||||
mNamespaceList = ret;
|
mNamespaceList = ret;
|
||||||
|
|
||||||
|
// insert into namespace cache.
|
||||||
|
gNamespaceCache[pair] = ret;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1143,6 +1162,9 @@ void Namespace::init()
|
||||||
mGlobalNamespace->mName = NULL;
|
mGlobalNamespace->mName = NULL;
|
||||||
mGlobalNamespace->mNext = NULL;
|
mGlobalNamespace->mNext = NULL;
|
||||||
mNamespaceList = mGlobalNamespace;
|
mNamespaceList = mGlobalNamespace;
|
||||||
|
|
||||||
|
// Insert into namespace cache.
|
||||||
|
gNamespaceCache[std::make_pair(mGlobalNamespace->mName, mGlobalNamespace->mPackage)] = mGlobalNamespace;
|
||||||
}
|
}
|
||||||
|
|
||||||
Namespace *Namespace::global()
|
Namespace *Namespace::global()
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,6 @@
|
||||||
#include "core/dataChunker.h"
|
#include "core/dataChunker.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/// @ingroup console_system Console System
|
/// @ingroup console_system Console System
|
||||||
/// @{
|
/// @{
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -150,7 +150,7 @@ void SimNameDictionary::remove(SimObject* obj)
|
||||||
if (*walk == obj)
|
if (*walk == obj)
|
||||||
{
|
{
|
||||||
*walk = obj->nextNameObject;
|
*walk = obj->nextNameObject;
|
||||||
obj->nextNameObject = (SimObject*)-1;
|
obj->nextNameObject = nullptr;
|
||||||
hashEntryCount--;
|
hashEntryCount--;
|
||||||
|
|
||||||
Mutex::unlockMutex(mutex);
|
Mutex::unlockMutex(mutex);
|
||||||
|
|
@ -279,7 +279,7 @@ void SimManagerNameDictionary::remove(SimObject* obj)
|
||||||
if (*walk == obj)
|
if (*walk == obj)
|
||||||
{
|
{
|
||||||
*walk = obj->nextManagerNameObject;
|
*walk = obj->nextManagerNameObject;
|
||||||
obj->nextManagerNameObject = (SimObject*)-1;
|
obj->nextManagerNameObject = nullptr;
|
||||||
hashEntryCount--;
|
hashEntryCount--;
|
||||||
|
|
||||||
Mutex::unlockMutex(mutex);
|
Mutex::unlockMutex(mutex);
|
||||||
|
|
|
||||||
|
|
@ -32,10 +32,6 @@
|
||||||
#include "console/consoleInternal.h"
|
#include "console/consoleInternal.h"
|
||||||
#include "core/frameAllocator.h"
|
#include "core/frameAllocator.h"
|
||||||
|
|
||||||
SimFieldDictionary::Entry *SimFieldDictionary::smFreeList = NULL;
|
|
||||||
|
|
||||||
static Chunker<SimFieldDictionary::Entry> fieldChunker;
|
|
||||||
|
|
||||||
U32 SimFieldDictionary::getHashValue(StringTableEntry slotName)
|
U32 SimFieldDictionary::getHashValue(StringTableEntry slotName)
|
||||||
{
|
{
|
||||||
return HashPointer(slotName) % HashTableSize;
|
return HashPointer(slotName) % HashTableSize;
|
||||||
|
|
@ -48,58 +44,43 @@ U32 SimFieldDictionary::getHashValue( const String& fieldName )
|
||||||
|
|
||||||
SimFieldDictionary::Entry *SimFieldDictionary::addEntry(U32 bucket, StringTableEntry slotName, ConsoleBaseType* type, char* value)
|
SimFieldDictionary::Entry *SimFieldDictionary::addEntry(U32 bucket, StringTableEntry slotName, ConsoleBaseType* type, char* value)
|
||||||
{
|
{
|
||||||
Entry* ret;
|
Entry ret;
|
||||||
if(smFreeList)
|
ret.slotName = slotName;
|
||||||
{
|
ret.type = type;
|
||||||
ret = smFreeList;
|
ret.value = value;
|
||||||
smFreeList = ret->next;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
ret = fieldChunker.alloc();
|
|
||||||
|
|
||||||
ret->next = mHashTable[ bucket ];
|
|
||||||
ret->slotName = slotName;
|
|
||||||
ret->type = type;
|
|
||||||
ret->value = value;
|
|
||||||
|
|
||||||
mHashTable[ bucket ] = ret;
|
|
||||||
mNumFields++;
|
mNumFields++;
|
||||||
mVersion++;
|
mVersion++;
|
||||||
|
|
||||||
return ret;
|
mHashTable[bucket].push_back(std::move(ret));
|
||||||
|
return &mHashTable[bucket].back();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SimFieldDictionary::freeEntry(SimFieldDictionary::Entry *ent)
|
void SimFieldDictionary::freeEntry(SimFieldDictionary::Entry *ent)
|
||||||
{
|
{
|
||||||
ent->next = smFreeList;
|
auto &vec = mHashTable[getHashValue(ent->slotName)];
|
||||||
smFreeList = ent;
|
|
||||||
|
|
||||||
|
// Find the slot.
|
||||||
|
auto iter = std::find_if(vec.begin(), vec.end(), [&](const Entry &ref) -> bool {
|
||||||
|
return ref.slotName == ent->slotName;
|
||||||
|
});
|
||||||
|
if (iter != vec.end())
|
||||||
|
{
|
||||||
|
vec.erase(iter);
|
||||||
mNumFields--;
|
mNumFields--;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
SimFieldDictionary::SimFieldDictionary()
|
SimFieldDictionary::SimFieldDictionary()
|
||||||
: mNumFields(0),
|
: mNumFields(0),
|
||||||
mVersion(0)
|
mVersion(0)
|
||||||
{
|
{
|
||||||
dMemset( mHashTable, 0, sizeof( mHashTable ) );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SimFieldDictionary::~SimFieldDictionary()
|
SimFieldDictionary::~SimFieldDictionary()
|
||||||
{
|
{
|
||||||
for(U32 i = 0; i < HashTableSize; i++)
|
|
||||||
{
|
|
||||||
for(Entry *walk = mHashTable[i]; walk;)
|
|
||||||
{
|
|
||||||
Entry *temp = walk;
|
|
||||||
walk = temp->next;
|
|
||||||
|
|
||||||
if( temp->value )
|
|
||||||
dFree(temp->value);
|
|
||||||
freeEntry(temp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
AssertFatal( mNumFields == 0, "Incorrect count on field dictionary" );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SimFieldDictionary::setFieldType(StringTableEntry slotName, const char *typeString)
|
void SimFieldDictionary::setFieldType(StringTableEntry slotName, const char *typeString)
|
||||||
|
|
@ -119,12 +100,12 @@ void SimFieldDictionary::setFieldType(StringTableEntry slotName, ConsoleBaseType
|
||||||
// If the field exists on the object, set the type
|
// If the field exists on the object, set the type
|
||||||
U32 bucket = getHashValue(slotName);
|
U32 bucket = getHashValue(slotName);
|
||||||
|
|
||||||
for( Entry *walk = mHashTable[bucket]; walk; walk = walk->next )
|
for (Entry &ref : mHashTable[bucket])
|
||||||
{
|
{
|
||||||
if( walk->slotName == slotName )
|
if (ref.slotName == slotName)
|
||||||
{
|
{
|
||||||
// Found and type assigned, let's bail
|
// Found and type assigned, let's bail
|
||||||
walk->type = type;
|
ref.type = type;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -137,9 +118,14 @@ U32 SimFieldDictionary::getFieldType(StringTableEntry slotName) const
|
||||||
{
|
{
|
||||||
U32 bucket = getHashValue(slotName);
|
U32 bucket = getHashValue(slotName);
|
||||||
|
|
||||||
for( Entry *walk = mHashTable[bucket]; walk; walk = walk->next )
|
const std::vector<Entry> &vec = mHashTable[bucket];
|
||||||
if( walk->slotName == slotName )
|
size_t size = vec.size();
|
||||||
return walk->type ? walk->type->getTypeID() : TypeString;
|
for (size_t i = 0; i < size; ++i)
|
||||||
|
{
|
||||||
|
const Entry &ref = vec[i];
|
||||||
|
if (ref.slotName == slotName)
|
||||||
|
return ref.type ? ref.type->getTypeID() : TypeString;
|
||||||
|
}
|
||||||
|
|
||||||
return TypeString;
|
return TypeString;
|
||||||
}
|
}
|
||||||
|
|
@ -148,10 +134,13 @@ SimFieldDictionary::Entry *SimFieldDictionary::findDynamicField(const String &f
|
||||||
{
|
{
|
||||||
U32 bucket = getHashValue(fieldName);
|
U32 bucket = getHashValue(fieldName);
|
||||||
|
|
||||||
for( Entry *walk = mHashTable[bucket]; walk; walk = walk->next )
|
const std::vector<Entry> &vec = mHashTable[bucket];
|
||||||
|
size_t size = vec.size();
|
||||||
|
for (size_t i = 0; i < size; ++i)
|
||||||
{
|
{
|
||||||
if( fieldName.equal(walk->slotName, String::NoCase) )
|
const Entry &ref = vec[i];
|
||||||
return walk;
|
if (fieldName.equal(ref.slotName, String::NoCase))
|
||||||
|
return const_cast<Entry*>(&ref);
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
@ -161,11 +150,13 @@ SimFieldDictionary::Entry *SimFieldDictionary::findDynamicField( StringTableEntr
|
||||||
{
|
{
|
||||||
U32 bucket = getHashValue(fieldName);
|
U32 bucket = getHashValue(fieldName);
|
||||||
|
|
||||||
for( Entry *walk = mHashTable[bucket]; walk; walk = walk->next )
|
const std::vector<Entry> &vec = mHashTable[bucket];
|
||||||
|
size_t size = vec.size();
|
||||||
|
for (size_t i = 0; i < size; ++i)
|
||||||
{
|
{
|
||||||
if( walk->slotName == fieldName )
|
if (vec[i].slotName == fieldName)
|
||||||
{
|
{
|
||||||
return walk;
|
return const_cast<Entry*>(&vec[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -176,45 +167,43 @@ SimFieldDictionary::Entry *SimFieldDictionary::findDynamicField( StringTableEntr
|
||||||
void SimFieldDictionary::setFieldValue(StringTableEntry slotName, const char *value)
|
void SimFieldDictionary::setFieldValue(StringTableEntry slotName, const char *value)
|
||||||
{
|
{
|
||||||
U32 bucket = getHashValue(slotName);
|
U32 bucket = getHashValue(slotName);
|
||||||
Entry **walk = &mHashTable[bucket];
|
|
||||||
while(*walk && (*walk)->slotName != slotName)
|
|
||||||
walk = &((*walk)->next);
|
|
||||||
|
|
||||||
Entry *field = *walk;
|
for (Entry &ref : mHashTable[bucket])
|
||||||
if( !value || !*value )
|
|
||||||
{
|
{
|
||||||
if(field)
|
if (ref.slotName == slotName)
|
||||||
|
{
|
||||||
|
if (!value || !*value)
|
||||||
{
|
{
|
||||||
mVersion++;
|
mVersion++;
|
||||||
|
|
||||||
if( field->value )
|
if (ref.value)
|
||||||
dFree(field->value);
|
dFree(ref.value);
|
||||||
|
|
||||||
*walk = field->next;
|
freeEntry(&ref);
|
||||||
freeEntry(field);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if(field)
|
if (ref.value)
|
||||||
{
|
dFree(ref.value);
|
||||||
if( field->value )
|
|
||||||
dFree(field->value);
|
|
||||||
|
|
||||||
field->value = dStrdup(value);
|
ref.value = dStrdup(value);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// no field, add entry.
|
||||||
addEntry(bucket, slotName, 0, dStrdup(value));
|
addEntry(bucket, slotName, 0, dStrdup(value));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
const char *SimFieldDictionary::getFieldValue(StringTableEntry slotName)
|
const char *SimFieldDictionary::getFieldValue(StringTableEntry slotName)
|
||||||
{
|
{
|
||||||
U32 bucket = getHashValue(slotName);
|
U32 bucket = getHashValue(slotName);
|
||||||
|
|
||||||
for(Entry *walk = mHashTable[bucket];walk;walk = walk->next)
|
for (const Entry &ref : mHashTable[bucket])
|
||||||
if(walk->slotName == slotName)
|
if (ref.slotName == slotName)
|
||||||
return walk->value;
|
return ref.value;
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
@ -225,41 +214,41 @@ void SimFieldDictionary::assignFrom(SimFieldDictionary *dict)
|
||||||
|
|
||||||
for (U32 i = 0; i < HashTableSize; i++)
|
for (U32 i = 0; i < HashTableSize; i++)
|
||||||
{
|
{
|
||||||
for(Entry *walk = dict->mHashTable[i];walk; walk = walk->next)
|
for (const Entry &ref : mHashTable[i])
|
||||||
{
|
{
|
||||||
setFieldValue(walk->slotName, walk->value);
|
setFieldValue(ref.slotName, ref.value);
|
||||||
setFieldType(walk->slotName, walk->type);
|
setFieldType(ref.slotName, ref.type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static S32 QSORT_CALLBACK compareEntries(const void* a, const void* b)
|
static S32 QSORT_CALLBACK compareEntries(const void* a, const void* b)
|
||||||
{
|
{
|
||||||
SimFieldDictionary::Entry *fa = *((SimFieldDictionary::Entry **)a);
|
const SimFieldDictionary::Entry *fa = reinterpret_cast<const SimFieldDictionary::Entry*>(a);
|
||||||
SimFieldDictionary::Entry *fb = *((SimFieldDictionary::Entry **)b);
|
const SimFieldDictionary::Entry *fb = reinterpret_cast<const SimFieldDictionary::Entry*>(b);
|
||||||
return dStricmp(fa->slotName, fb->slotName);
|
return dStricmp(fa->slotName, fb->slotName);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SimFieldDictionary::writeFields(SimObject *obj, Stream &stream, U32 tabStop)
|
void SimFieldDictionary::writeFields(SimObject *obj, Stream &stream, U32 tabStop)
|
||||||
{
|
{
|
||||||
const AbstractClassRep::FieldList &list = obj->getFieldList();
|
const AbstractClassRep::FieldList &list = obj->getFieldList();
|
||||||
Vector<Entry *> flist(__FILE__, __LINE__);
|
Vector<Entry> flist(__FILE__, __LINE__);
|
||||||
|
|
||||||
for (U32 i = 0; i < HashTableSize; i++)
|
for (U32 i = 0; i < HashTableSize; i++)
|
||||||
{
|
{
|
||||||
for(Entry *walk = mHashTable[i];walk; walk = walk->next)
|
for (const Entry &walk : mHashTable[i])
|
||||||
{
|
{
|
||||||
// make sure we haven't written this out yet:
|
// make sure we haven't written this out yet:
|
||||||
U32 i;
|
U32 j;
|
||||||
for(i = 0; i < list.size(); i++)
|
for (j = 0; j < list.size(); j++)
|
||||||
if(list[i].pFieldname == walk->slotName)
|
if (list[j].pFieldname == walk.slotName)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if(i != list.size())
|
if (j != list.size())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
|
||||||
if (!obj->writeField(walk->slotName, walk->value))
|
if (!obj->writeField(walk.slotName, walk.value))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
flist.push_back(walk);
|
flist.push_back(walk);
|
||||||
|
|
@ -267,20 +256,20 @@ void SimFieldDictionary::writeFields(SimObject *obj, Stream &stream, U32 tabStop
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sort Entries to prevent version control conflicts
|
// Sort Entries to prevent version control conflicts
|
||||||
dQsort(flist.address(),flist.size(),sizeof(Entry *),compareEntries);
|
dQsort(flist.address(), flist.size(), sizeof(Entry), compareEntries);
|
||||||
|
|
||||||
// Save them out
|
// Save them out
|
||||||
for(Vector<Entry *>::iterator itr = flist.begin(); itr != flist.end(); itr++)
|
for (const Entry &ref : flist)
|
||||||
{
|
{
|
||||||
U32 nBufferSize = (dStrlen( (*itr)->value ) * 2) + dStrlen( (*itr)->slotName ) + 16;
|
U32 nBufferSize = (dStrlen(ref.value) * 2) + dStrlen(ref.slotName) + 16;
|
||||||
FrameTemp<char> expandedBuffer(nBufferSize);
|
FrameTemp<char> expandedBuffer(nBufferSize);
|
||||||
|
|
||||||
stream.writeTabs(tabStop + 1);
|
stream.writeTabs(tabStop + 1);
|
||||||
|
|
||||||
const char *typeName = (*itr)->type && (*itr)->type->getTypeID() != TypeString ? (*itr)->type->getTypeName() : "";
|
const char *typeName = ref.type && ref.type->getTypeID() != TypeString ? ref.type->getTypeName() : "";
|
||||||
dSprintf(expandedBuffer, nBufferSize, "%s%s%s = \"", typeName, *typeName ? " " : "", (*itr)->slotName);
|
dSprintf(expandedBuffer, nBufferSize, "%s%s%s = \"", typeName, *typeName ? " " : "", ref.slotName);
|
||||||
if ( (*itr)->value )
|
if (ref.value)
|
||||||
expandEscape((char*)expandedBuffer + dStrlen(expandedBuffer), (*itr)->value);
|
expandEscape((char*)expandedBuffer + dStrlen(expandedBuffer), ref.value);
|
||||||
dStrcat(expandedBuffer, "\";\r\n");
|
dStrcat(expandedBuffer, "\";\r\n");
|
||||||
|
|
||||||
stream.write(dStrlen(expandedBuffer), expandedBuffer);
|
stream.write(dStrlen(expandedBuffer), expandedBuffer);
|
||||||
|
|
@ -291,35 +280,35 @@ void SimFieldDictionary::printFields(SimObject *obj)
|
||||||
{
|
{
|
||||||
const AbstractClassRep::FieldList &list = obj->getFieldList();
|
const AbstractClassRep::FieldList &list = obj->getFieldList();
|
||||||
char expandedBuffer[4096];
|
char expandedBuffer[4096];
|
||||||
Vector<Entry *> flist(__FILE__, __LINE__);
|
Vector<Entry> flist(__FILE__, __LINE__);
|
||||||
|
|
||||||
for (U32 i = 0; i < HashTableSize; i++)
|
for (U32 i = 0; i < HashTableSize; i++)
|
||||||
{
|
{
|
||||||
for(Entry *walk = mHashTable[i];walk; walk = walk->next)
|
for (const Entry &walk : mHashTable[i])
|
||||||
{
|
{
|
||||||
// make sure we haven't written this out yet:
|
// make sure we haven't written this out yet:
|
||||||
U32 i;
|
U32 j;
|
||||||
for(i = 0; i < list.size(); i++)
|
for (j = 0; j < list.size(); j++)
|
||||||
if(list[i].pFieldname == walk->slotName)
|
if (list[i].pFieldname == walk.slotName)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if(i != list.size())
|
if (j != list.size())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
flist.push_back(walk);
|
flist.push_back(walk);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
dQsort(flist.address(),flist.size(),sizeof(Entry *),compareEntries);
|
dQsort(flist.address(), flist.size(), sizeof(Entry), compareEntries);
|
||||||
|
|
||||||
for(Vector<Entry *>::iterator itr = flist.begin(); itr != flist.end(); itr++)
|
for (const Entry &ref : flist)
|
||||||
{
|
{
|
||||||
const char* type = "string";
|
const char* type = "string";
|
||||||
if( ( *itr )->type )
|
if (ref.type)
|
||||||
type = ( *itr )->type->getTypeClassName();
|
type = ref.type->getTypeClassName();
|
||||||
|
|
||||||
dSprintf( expandedBuffer, sizeof( expandedBuffer ), " %s %s = \"", type, ( *itr )->slotName );
|
dSprintf(expandedBuffer, sizeof(expandedBuffer), " %s %s = \"", type, ref.slotName);
|
||||||
if ( (*itr)->value )
|
if (ref.value)
|
||||||
expandEscape(expandedBuffer + dStrlen(expandedBuffer), (*itr)->value);
|
expandEscape(expandedBuffer + dStrlen(expandedBuffer), ref.value);
|
||||||
Con::printf("%s\"", expandedBuffer);
|
Con::printf("%s\"", expandedBuffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -343,29 +332,44 @@ SimFieldDictionary::Entry *SimFieldDictionary::operator[](U32 index)
|
||||||
SimFieldDictionaryIterator::SimFieldDictionaryIterator(SimFieldDictionary * dictionary)
|
SimFieldDictionaryIterator::SimFieldDictionaryIterator(SimFieldDictionary * dictionary)
|
||||||
{
|
{
|
||||||
mDictionary = dictionary;
|
mDictionary = dictionary;
|
||||||
mHashIndex = -1;
|
mHashIndex = 0;
|
||||||
mEntry = 0;
|
mVecIndex = -1; // -1 since we immediately call operator++
|
||||||
|
mEntry = NULL;
|
||||||
operator++();
|
operator++();
|
||||||
}
|
}
|
||||||
|
|
||||||
SimFieldDictionary::Entry* SimFieldDictionaryIterator::operator++()
|
SimFieldDictionary::Entry* SimFieldDictionaryIterator::operator++()
|
||||||
{
|
{
|
||||||
if(!mDictionary)
|
if (!mDictionary || mHashIndex >= SimFieldDictionary::HashTableSize)
|
||||||
return(mEntry);
|
{
|
||||||
|
mEntry = NULL;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if(mEntry)
|
std::vector<SimFieldDictionary::Entry> &vec = mDictionary->mHashTable[mHashIndex];
|
||||||
mEntry = mEntry->next;
|
|
||||||
|
|
||||||
while(!mEntry && (mHashIndex < (SimFieldDictionary::HashTableSize-1)))
|
while (vec.size() == 0 && mHashIndex < (SimFieldDictionary::HashTableSize - 1))
|
||||||
mEntry = mDictionary->mHashTable[++mHashIndex];
|
{
|
||||||
|
vec = mDictionary->mHashTable[++mHashIndex];
|
||||||
|
mVecIndex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
return(mEntry);
|
if (mVecIndex >= vec.size() || mHashIndex >= SimFieldDictionary::HashTableSize)
|
||||||
|
{
|
||||||
|
mEntry = NULL;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
mEntry = &vec[mVecIndex];
|
||||||
|
++mVecIndex;
|
||||||
|
return mEntry;
|
||||||
}
|
}
|
||||||
|
|
||||||
SimFieldDictionary::Entry* SimFieldDictionaryIterator::operator*()
|
SimFieldDictionary::Entry* SimFieldDictionaryIterator::operator*()
|
||||||
{
|
{
|
||||||
return(mEntry);
|
return mEntry;
|
||||||
}
|
}
|
||||||
|
|
||||||
// A variation of the stock SimFieldDictionary::setFieldValue(), this method adds the
|
// A variation of the stock SimFieldDictionary::setFieldValue(), this method adds the
|
||||||
// <no_replace> argument which, when true, prohibits the replacement of fields that
|
// <no_replace> argument which, when true, prohibits the replacement of fields that
|
||||||
// already have a value.
|
// already have a value.
|
||||||
|
|
@ -385,13 +389,13 @@ void SimFieldDictionary::setFieldValue(StringTableEntry slotName, const char *va
|
||||||
return;
|
return;
|
||||||
|
|
||||||
U32 bucket = getHashValue(slotName);
|
U32 bucket = getHashValue(slotName);
|
||||||
Entry **walk = &mHashTable[bucket];
|
for (const Entry &walk : mHashTable[bucket])
|
||||||
while(*walk && (*walk)->slotName != slotName)
|
{
|
||||||
walk = &((*walk)->next);
|
if (walk.slotName == slotName)
|
||||||
|
{
|
||||||
Entry *field = *walk;
|
|
||||||
if (field)
|
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
addEntry(bucket, slotName, type, dStrdup(value));
|
addEntry(bucket, slotName, type, dStrdup(value));
|
||||||
}
|
}
|
||||||
|
|
@ -413,14 +417,22 @@ void SimFieldDictionary::assignFrom(SimFieldDictionary *dict, const char* filter
|
||||||
if (filter_len == 0)
|
if (filter_len == 0)
|
||||||
{
|
{
|
||||||
for (U32 i = 0; i < HashTableSize; i++)
|
for (U32 i = 0; i < HashTableSize; i++)
|
||||||
for(Entry *walk = dict->mHashTable[i];walk; walk = walk->next)
|
{
|
||||||
setFieldValue(walk->slotName, walk->value, walk->type, no_replace);
|
for (const Entry &walk : dict->mHashTable[i])
|
||||||
|
{
|
||||||
|
setFieldValue(walk.slotName, walk.value, walk.type, no_replace);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for (U32 i = 0; i < HashTableSize; i++)
|
for (U32 i = 0; i < HashTableSize; i++)
|
||||||
for(Entry *walk = dict->mHashTable[i];walk; walk = walk->next)
|
{
|
||||||
if (dStrncmp(walk->slotName, filter, filter_len) == 0)
|
for (const Entry &walk : dict->mHashTable[i])
|
||||||
setFieldValue(walk->slotName, walk->value, walk->type, no_replace);
|
{
|
||||||
|
if (dStrncmp(walk.slotName, filter, filter_len) == 0)
|
||||||
|
setFieldValue(walk.slotName, walk.value, walk.type, no_replace);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -32,6 +32,9 @@
|
||||||
class ConsoleBaseType;
|
class ConsoleBaseType;
|
||||||
class SimObject;
|
class SimObject;
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "core/stringTable.h"
|
#include "core/stringTable.h"
|
||||||
#include "core/stream/stream.h"
|
#include "core/stream/stream.h"
|
||||||
|
|
||||||
|
|
@ -51,18 +54,17 @@ public:
|
||||||
|
|
||||||
StringTableEntry slotName;
|
StringTableEntry slotName;
|
||||||
char *value;
|
char *value;
|
||||||
Entry *next;
|
|
||||||
ConsoleBaseType *type;
|
ConsoleBaseType *type;
|
||||||
};
|
};
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
HashTableSize = 19
|
HashTableSize = 19
|
||||||
};
|
};
|
||||||
Entry *mHashTable[HashTableSize];
|
//Entry *mHashTable[HashTableSize];
|
||||||
|
|
||||||
|
std::vector<Entry> mHashTable[HashTableSize];
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static Entry *smFreeList;
|
|
||||||
|
|
||||||
void freeEntry(Entry *entry);
|
void freeEntry(Entry *entry);
|
||||||
Entry* addEntry(U32 bucket, StringTableEntry slotName, ConsoleBaseType* type, char* value = 0);
|
Entry* addEntry(U32 bucket, StringTableEntry slotName, ConsoleBaseType* type, char* value = 0);
|
||||||
|
|
||||||
|
|
@ -103,6 +105,7 @@ class SimFieldDictionaryIterator
|
||||||
{
|
{
|
||||||
SimFieldDictionary * mDictionary;
|
SimFieldDictionary * mDictionary;
|
||||||
S32 mHashIndex;
|
S32 mHashIndex;
|
||||||
|
S32 mVecIndex;
|
||||||
SimFieldDictionary::Entry * mEntry;
|
SimFieldDictionary::Entry * mEntry;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
|
||||||
|
|
@ -72,8 +72,8 @@ SimObject::SimObject()
|
||||||
objectName = NULL;
|
objectName = NULL;
|
||||||
mOriginalName = NULL;
|
mOriginalName = NULL;
|
||||||
mInternalName = NULL;
|
mInternalName = NULL;
|
||||||
nextNameObject = (SimObject*)-1;
|
nextNameObject = nullptr;
|
||||||
nextManagerNameObject = (SimObject*)-1;
|
nextManagerNameObject = nullptr;
|
||||||
nextIdObject = NULL;
|
nextIdObject = NULL;
|
||||||
|
|
||||||
mFilename = NULL;
|
mFilename = NULL;
|
||||||
|
|
@ -86,6 +86,8 @@ SimObject::SimObject()
|
||||||
mNotifyList = NULL;
|
mNotifyList = NULL;
|
||||||
mFlags.set( ModStaticFields | ModDynamicFields );
|
mFlags.set( ModStaticFields | ModDynamicFields );
|
||||||
|
|
||||||
|
mProgenitorFile = StringTable->EmptyString();
|
||||||
|
|
||||||
mFieldDictionary = NULL;
|
mFieldDictionary = NULL;
|
||||||
mCanSaveFieldDictionary = true;
|
mCanSaveFieldDictionary = true;
|
||||||
|
|
||||||
|
|
@ -122,10 +124,10 @@ SimObject::~SimObject()
|
||||||
if( mCopySource )
|
if( mCopySource )
|
||||||
mCopySource->unregisterReference( &mCopySource );
|
mCopySource->unregisterReference( &mCopySource );
|
||||||
|
|
||||||
AssertFatal(nextNameObject == (SimObject*)-1,avar(
|
AssertFatal(nextNameObject == nullptr,avar(
|
||||||
"SimObject::~SimObject: Not removed from dictionary: name %s, id %i",
|
"SimObject::~SimObject: Not removed from dictionary: name %s, id %i",
|
||||||
objectName, mId));
|
objectName, mId));
|
||||||
AssertFatal(nextManagerNameObject == (SimObject*)-1,avar(
|
AssertFatal(nextManagerNameObject == nullptr,avar(
|
||||||
"SimObject::~SimObject: Not removed from manager dictionary: name %s, id %i",
|
"SimObject::~SimObject: Not removed from manager dictionary: name %s, id %i",
|
||||||
objectName,mId));
|
objectName,mId));
|
||||||
AssertFatal(mFlags.test(Added) == 0, "SimObject::object "
|
AssertFatal(mFlags.test(Added) == 0, "SimObject::object "
|
||||||
|
|
|
||||||
|
|
@ -774,18 +774,18 @@ void Taml::compileDynamicFields( TamlWriteNode* pTamlWriteNode )
|
||||||
// Fetch field count.
|
// Fetch field count.
|
||||||
const U32 fieldCount = fieldList.size();
|
const U32 fieldCount = fieldList.size();
|
||||||
|
|
||||||
Vector<SimFieldDictionary::Entry*> dynamicFieldList(__FILE__, __LINE__);
|
Vector<SimFieldDictionary::Entry> dynamicFieldList(__FILE__, __LINE__);
|
||||||
|
|
||||||
// Ensure the dynamic field doesn't conflict with static field.
|
// Ensure the dynamic field doesn't conflict with static field.
|
||||||
for( U32 hashIndex = 0; hashIndex < SimFieldDictionary::HashTableSize; ++hashIndex )
|
for( U32 hashIndex = 0; hashIndex < SimFieldDictionary::HashTableSize; ++hashIndex )
|
||||||
{
|
{
|
||||||
for( SimFieldDictionary::Entry* pEntry = pFieldDictionary->mHashTable[hashIndex]; pEntry; pEntry = pEntry->next )
|
for (const SimFieldDictionary::Entry &pEntry : pFieldDictionary->mHashTable[hashIndex])
|
||||||
{
|
{
|
||||||
// Iterate static fields.
|
// Iterate static fields.
|
||||||
U32 fieldIndex;
|
U32 fieldIndex;
|
||||||
for( fieldIndex = 0; fieldIndex < fieldCount; ++fieldIndex )
|
for( fieldIndex = 0; fieldIndex < fieldCount; ++fieldIndex )
|
||||||
{
|
{
|
||||||
if( fieldList[fieldIndex].pFieldname == pEntry->slotName)
|
if (fieldList[fieldIndex].pFieldname == pEntry.slotName)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -794,7 +794,7 @@ void Taml::compileDynamicFields( TamlWriteNode* pTamlWriteNode )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Skip if not writing field.
|
// Skip if not writing field.
|
||||||
if ( !pSimObject->writeField( pEntry->slotName, pEntry->value) )
|
if (!pSimObject->writeField(pEntry.slotName, pEntry.value))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
dynamicFieldList.push_back( pEntry );
|
dynamicFieldList.push_back( pEntry );
|
||||||
|
|
@ -803,16 +803,13 @@ void Taml::compileDynamicFields( TamlWriteNode* pTamlWriteNode )
|
||||||
|
|
||||||
// Sort Entries to prevent version control conflicts
|
// Sort Entries to prevent version control conflicts
|
||||||
if ( dynamicFieldList.size() > 1 )
|
if ( dynamicFieldList.size() > 1 )
|
||||||
dQsort(dynamicFieldList.address(), dynamicFieldList.size(), sizeof(SimFieldDictionary::Entry*), compareFieldEntries);
|
dQsort(dynamicFieldList.address(), dynamicFieldList.size(), sizeof(SimFieldDictionary::Entry), compareFieldEntries);
|
||||||
|
|
||||||
// Save the fields.
|
// Save the fields.
|
||||||
for( Vector<SimFieldDictionary::Entry*>::iterator entryItr = dynamicFieldList.begin(); entryItr != dynamicFieldList.end(); ++entryItr )
|
for (const SimFieldDictionary::Entry &pEntry : dynamicFieldList)
|
||||||
{
|
{
|
||||||
// Fetch entry.
|
|
||||||
SimFieldDictionary::Entry* pEntry = *entryItr;
|
|
||||||
|
|
||||||
// Save field/value.
|
// Save field/value.
|
||||||
TamlWriteNode::FieldValuePair* pFieldValuePair = new TamlWriteNode::FieldValuePair( pEntry->slotName, pEntry->value );
|
TamlWriteNode::FieldValuePair* pFieldValuePair = new TamlWriteNode::FieldValuePair(pEntry.slotName, pEntry.value);
|
||||||
pTamlWriteNode->mFields.push_back(pFieldValuePair);
|
pTamlWriteNode->mFields.push_back(pFieldValuePair);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue