Skip to content

Commit

Permalink
Added automatic naming to allow anonyomous function expressions.
Browse files Browse the repository at this point in the history
  • Loading branch information
Lexikos committed Aug 26, 2023
1 parent 85477d8 commit 30ad2e9
Showing 1 changed file with 18 additions and 12 deletions.
30 changes: 18 additions & 12 deletions source/script.cpp
Expand Up @@ -2421,11 +2421,14 @@ ResultType Script::LoadIncludedFile(TextStream *fp, int aFileIndex)
// was encountered by ParseAndAddLine(). expr->code includes up to (and including)
// the function name. Append this current line to form the final expression (unless
// there's another function definition, in which case, rinse and repeat).
if (!buf.EnsureCapacity(--buf_length + expr->length))
// If the function had no explicit name, AddFunc has given it one we can insert here.
size_t extra = !IS_IDENTIFIER_CHAR(expr->code[expr->length - 1]) ? _tcslen(expr->func->mName) : 0;
if (!buf.EnsureCapacity(--buf_length + expr->length + extra))
return MemoryError();
tmemmove(buf + expr->length, buf + 1, buf_length + 1);
tmemmove(buf + expr->length + extra, buf + 1, buf_length + 1);
tmemmove(buf, expr->code, expr->length);
buf_length += expr->length;
tmemmove(buf + expr->length, expr->func->mName, extra); // Insert automatic name, if any.
buf_length += expr->length + extra;
mCombinedLineNumber = expr->line_no;
// Restoring mPendingParentLine ensures that both the new line's mParentLine and the
// parent line's mRelatedLine will be set correctly. By contrast, mPendingRelatedLine
Expand Down Expand Up @@ -4189,8 +4192,6 @@ ResultType Script::ParseAndAddLine(LPTSTR aLineText, ActionTypeType aActionType,
LPTSTR id = open_paren;
while (id > aLineText && IS_IDENTIFIER_CHAR(id[-1]))
--id;
if (id == open_paren)
return ScriptError(_T("Function name required."), open_paren);
// Save everything up to (but not including) the open parentheses. When the close brace
// is found, anything following it will be appended to this code, effectively forming an
// expression which references the function by name.
Expand Down Expand Up @@ -5632,7 +5633,7 @@ ResultType Script::ParseFatArrow(DerefList &aDeref, LPTSTR aPrmStart, LPTSTR aPr
if (!AddLine(ACT_BLOCK_END))
return FAIL;

if (!*name) // Anonymous function is not yet preceded by a DT_VAR.
if (*aPrmStart == '(' || *aPrmEnd != ')') // Anonymous function is not yet preceded by a DT_VAR.
{
if (!aDeref.Push())
return FAIL;
Expand Down Expand Up @@ -6818,6 +6819,16 @@ UserFunc *Script::AddFunc(LPCTSTR aFuncName, size_t aFuncNameLength, Object *aCl
the_new_func->mIsStatic = true;
scope |= VAR_LOCAL_STATIC;
}
if (!aFuncNameLength) // Anonymous.
{
// Give it a name for debugging purposes and to allow function definition expressions to
// be anonymous (since they currently work by preprocessing/replacing the definition with
// just its name). Starting with a digit ensures it will never conflict.
TCHAR buf[16];
static UINT sCount = 0;
aFuncNameLength = _stprintf(buf, _T("%ufn"), ++sCount);
the_new_func->mName = aFuncName = SimpleHeap::Alloc(buf, aFuncNameLength); // The previous value of the_new_func->mName was the constant _T("").
}
Var *var = aFuncNameLength ? FindVar(aFuncName, aFuncNameLength, FINDVAR_NO_BIF | scope, &varlist, &insert_pos, &result) : NULL;
if (var)
{
Expand All @@ -6830,12 +6841,7 @@ UserFunc *Script::AddFunc(LPCTSTR aFuncName, size_t aFuncNameLength, Object *aCl
ConflictingDeclarationError(_T("function"), var);
return nullptr;
}
if (!aFuncNameLength)
{
insert_pos = 0;
varlist = g->CurrentFunc ? &g->CurrentFunc->mVars : GlobalVars();
}
var = AddVar(aFuncName, aFuncNameLength, varlist, insert_pos, scope);
var = AddVar(aFuncName, aFuncNameLength, varlist, insert_pos, scope | ADDVAR_NO_VALIDATE); // Already validated, or invalid in the case of anonymous functions.
if (!var)
return nullptr;
var->Assign(the_new_func);
Expand Down

3 comments on commit 30ad2e9

@PythonYunfei
Copy link

@PythonYunfei PythonYunfei commented on 30ad2e9 Aug 27, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Guido van Rossum, Father of Python, said in Zen of Python:" Flat is better than nested".
image
So, I wish this feature could be limited back:
image
As said by Guido van Rossum in his official website criticizing JavaScript, if this above usage is abused, the readability of code will decrease significantly. Therefore, unlike JS, he forbids this feature by design in Python.
A code reader reading flat blocks without nesting one by one, seems easier. However, it will become more difficult and really much slower to read, when one block is nested by another too many times.

@RaptorX
Copy link

@RaptorX RaptorX commented on 30ad2e9 Aug 27, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with you Yunfei, I really dislike this syntax.

It would also bring in some ambiguity with some commands.
For example:

Msgbox () ; this will result in a syntax error (note the space)

; what would this do? would it work normally?
Msgbox (){
; some code that will return a string
} 

@iseahound
Copy link

@iseahound iseahound commented on 30ad2e9 Aug 29, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this even implemented? It seems fine to me, most people know and understand Javascript.

If you really want to criticize it, just mention "symbol hell". There really shouldn't be a high concentration of symbols: SetTimer((){ because it leads to unreadability.

But really there shouldn't be anything wrong with extending () => (MsgBox) to () => {MsgBox}

Please sign in to comment.