tscript change

Adds the ability to declare defaults for function arguments

eg
function testFunc(%x = 1, %y = 1)
{
    return %x + %y;
}

can now be called as
testFunc(10) and it will return the value of 11.
This commit is contained in:
marauder2k7 2025-11-15 17:34:33 +00:00
parent 7e64493dbf
commit b0f8a5f9bd
8 changed files with 1375 additions and 1206 deletions

View file

@ -671,10 +671,15 @@ Namespace::Entry::Entry()
mNext = NULL; mNext = NULL;
mPackage = StringTable->EmptyString(); mPackage = StringTable->EmptyString();
mToolOnly = false; mToolOnly = false;
VECTOR_SET_ASSOCIATION(mArgFlags);
VECTOR_SET_ASSOCIATION(mDefaultValues);
} }
void Namespace::Entry::clear() void Namespace::Entry::clear()
{ {
mArgFlags.clear();
mDefaultValues.clear();
if (mModule) if (mModule)
{ {
mModule->decRefCount(); mModule->decRefCount();

View file

@ -130,6 +130,10 @@ public:
/// The offset in the compiled script code at which this function begins. /// The offset in the compiled script code at which this function begins.
U32 mFunctionOffset; U32 mFunctionOffset;
// Offsets to get default values for arguments.
Vector<U32> mArgFlags;
Vector<ConsoleValue> mDefaultValues;
/// If it's a script function, this is the line of the declaration in code. /// If it's a script function, this is the line of the declaration in code.
/// @note 0 for functions read from legacy DSOs that have no line number information. /// @note 0 for functions read from legacy DSOs that have no line number information.
U32 mFunctionLineNumber; U32 mFunctionLineNumber;

View file

@ -138,6 +138,7 @@ struct Token
%type <slot> slot_acc %type <slot> slot_acc
%type <intslot> intslot_acc %type <intslot> intslot_acc
%type <stmt> expression_stmt %type <stmt> expression_stmt
%type <var> param
%type <var> var_list %type <var> var_list
%type <var> var_list_decl %type <var> var_list_decl
%type <asn> assign_op_struct %type <asn> assign_op_struct
@ -242,12 +243,31 @@ var_list_decl
; ;
var_list var_list
: VAR : param
{ $$ = VarNode::alloc( $1.lineNumber, $1.value, NULL ); } { $$ = $1; }
| var_list ',' VAR | var_list ',' param
{ $$ = $1; ((StmtNode*)($1))->append((StmtNode*)VarNode::alloc( $3.lineNumber, $3.value, NULL ) ); } { $$ = $1; ((StmtNode*)($1))->append((StmtNode*)$3 ); }
; ;
param
: VAR
{
$$ = VarNode::allocParam($1.lineNumber, $1.value, NULL);
}
| VAR '?'
{
$$ = VarNode::allocParam($1.lineNumber, $1.value, NULL);
}
| VAR '=' expr
{
$$ = VarNode::allocParam($1.lineNumber, $1.value, $3);
}
| VAR '?' '=' expr
{
$$ = VarNode::allocParam($1.lineNumber, $1.value, $4);
}
;
datablock_decl datablock_decl
: rwDATABLOCK class_name_expr '(' expr parent_block ')' '{' slot_assign_list_opt '}' ';' : rwDATABLOCK class_name_expr '(' expr parent_block ')' '{' slot_assign_list_opt '}' ';'
{ $$ = ObjectDeclNode::alloc( $1.lineNumber, $2, $4, NULL, $5.value, $8, NULL, true, false, false); } { $$ = ObjectDeclNode::alloc( $1.lineNumber, $2, $4, NULL, $5.value, $8, NULL, true, false, false); }

View file

@ -311,8 +311,13 @@ struct VarNode : ExprNode
StringTableEntry varName; StringTableEntry varName;
ExprNode* arrayIndex; ExprNode* arrayIndex;
ExprNode* defaultValue; // optional expression
static VarNode* alloc(S32 lineNumber, StringTableEntry varName, ExprNode* arrayIndex); static VarNode* alloc(S32 lineNumber, StringTableEntry varName, ExprNode* arrayIndex);
// function params initialization.
static VarNode* allocParam(S32 lineNumber, StringTableEntry varName, ExprNode* defaultValue);
U32 compile(CodeStream& codeStream, U32 ip, TypeReq type) override; U32 compile(CodeStream& codeStream, U32 ip, TypeReq type) override;
TypeReq getPreferredType() override; TypeReq getPreferredType() override;
ExprNodeName getExprNodeNameEnum() const override { return NameVarNode; } ExprNodeName getExprNodeNameEnum() const override { return NameVarNode; }

View file

@ -206,6 +206,19 @@ VarNode* VarNode::alloc(S32 lineNumber, StringTableEntry varName, ExprNode* arra
ret->optimizedNode = NULL; ret->optimizedNode = NULL;
ret->varName = varName; ret->varName = varName;
ret->arrayIndex = arrayIndex; ret->arrayIndex = arrayIndex;
ret->defaultValue = NULL;
return ret;
}
VarNode* VarNode::allocParam(S32 lineNumber, StringTableEntry varName, ExprNode* defaultValue)
{
VarNode* ret = (VarNode*)consoleAlloc(sizeof(VarNode));
constructInPlace(ret);
ret->dbgLineNumber = lineNumber;
ret->optimizedNode = NULL;
ret->varName = varName;
ret->arrayIndex = NULL;
ret->defaultValue = defaultValue;
return ret; return ret;
} }

View file

@ -1529,6 +1529,19 @@ U32 FunctionDeclStmtNode::compileStmt(CodeStream& codeStream, U32 ip)
CodeBlock::smInFunction = false; CodeBlock::smInFunction = false;
// check for argument setup
for (VarNode* walk = args; walk; walk = (VarNode*)((StmtNode*)walk)->getNext())
{
if (walk->defaultValue)
{
TypeReq walkType = walk->defaultValue->getPreferredType();
if (walkType == TypeReqNone)
walkType = TypeReqString;
ip = walk->defaultValue->compile(codeStream, ip, walkType);
}
}
codeStream.emit(OP_FUNC_DECL); codeStream.emit(OP_FUNC_DECL);
codeStream.emitSTE(fnName); codeStream.emitSTE(fnName);
codeStream.emitSTE(nameSpace); codeStream.emitSTE(nameSpace);
@ -1538,11 +1551,22 @@ U32 FunctionDeclStmtNode::compileStmt(CodeStream& codeStream, U32 ip)
const U32 endIp = codeStream.emit(0); const U32 endIp = codeStream.emit(0);
codeStream.emit(argc); codeStream.emit(argc);
const U32 localNumVarsIP = codeStream.emit(0); const U32 localNumVarsIP = codeStream.emit(0);
for (VarNode* walk = args; walk; walk = (VarNode*)((StmtNode*)walk)->getNext()) for (VarNode* walk = args; walk; walk = (VarNode*)((StmtNode*)walk)->getNext())
{ {
StringTableEntry name = walk->varName; StringTableEntry name = walk->varName;
codeStream.emit(getFuncVars(dbgLineNumber)->lookup(name, dbgLineNumber)); codeStream.emit(getFuncVars(dbgLineNumber)->lookup(name, dbgLineNumber));
} }
// check for argument setup
for (VarNode* walk = args; walk; walk = (VarNode*)((StmtNode*)walk)->getNext())
{
U32 flags = 0;
if (walk->defaultValue) flags |= 0x1;
codeStream.emit(flags);
}
CodeBlock::smInFunction = true; CodeBlock::smInFunction = true;
ip = compileBlock(stmts, codeStream, ip); ip = compileBlock(stmts, codeStream, ip);

File diff suppressed because it is too large Load diff

View file

@ -614,7 +614,22 @@ Con::EvalResult CodeBlock::exec(U32 ip, const char* functionName, Namespace* thi
ConsoleValue& value = argv[i + 1]; ConsoleValue& value = argv[i + 1];
Script::gEvalState.moveConsoleValue(reg, (value)); Script::gEvalState.moveConsoleValue(reg, (value));
} }
ip = ip + fnArgc + (2 + 6 + 1 + 1);
if (wantedArgc < fnArgc)
{
Namespace::Entry* temp = thisNamespace->lookup(thisFunctionName);
for (; i < fnArgc; i++)
{
S32 reg = code[ip + (2 + 6 + 1 + 1) + i];
if (temp->mArgFlags[i] & 0x1)
{
ConsoleValue& value = temp->mDefaultValues[i];
Script::gEvalState.moveConsoleValue(reg, (value));
}
}
}
ip = ip + fnArgc + (2 + 6 + 1 + 1) + fnArgc;
curFloatTable = functionFloats; curFloatTable = functionFloats;
curStringTable = functionStrings; curStringTable = functionStrings;
curStringTableLen = functionStringsMaxLen; curStringTableLen = functionStringsMaxLen;
@ -736,8 +751,39 @@ Con::EvalResult CodeBlock::exec(U32 ip, const char* functionName, Namespace* thi
curNSDocBlock = NULL; curNSDocBlock = NULL;
} }
} }
Namespace::relinkPackages();
U32 fnArgc = code[ip + 2 + 6];
// Compute pointer to the register mapping like exec() does.
U32 readPtr = ip + 2 + 6 + 1; // points to the slot after argc (localNumVarsIP)
readPtr += 1; // skip localNumVarsIP
readPtr += fnArgc; // skip register mapping
Namespace::Entry* temp = ns->lookup(fnName);
temp->mArgFlags.setSize(fnArgc);
temp->mDefaultValues.setSize(fnArgc);
// Read flags sequentially
for (U32 fa = 0; fa < fnArgc; ++fa)
{
temp->mArgFlags[fa] = code[readPtr++];
}
// this might seem weird but because of the order
// the stack accumulates consoleValues we cant be sure
// all args have a console value, and we need to pop
// the stack, do this in reverse order.
for (S32 fa = S32(fnArgc - 1); fa >= 0; fa--)
{
if (temp->mArgFlags[fa] & 0x1)
{
temp->mDefaultValues[fa] = stack[_STK--];
}
}
Namespace::relinkPackages();
// If we had a docblock, it's definitely not valid anymore, so clear it out. // If we had a docblock, it's definitely not valid anymore, so clear it out.
curFNDocBlock = NULL; curFNDocBlock = NULL;