In general, you're always safe passing constant strings only to
eval. Issues only arise once anything external passes unmodified into the code string.
However, you almost never actually need to use
eval. If there's a specific use case you have in mind that you're wondering about, do tell—there may be a way to avoid it.
The few cases where
eval is actually necessary are things such as calling
methods with the name as an expression (
%x.%y(...)), defining functions (code generation tends to help with TS performance), defining packages (you really shouldn't need to do this), etc.
When you actually end up needing to use it, however, try your best to never introduce external data into the code string (for example,
eval(%x @ "...")). This is necessary for certain parts of the AST (such as identifiers when calling methods or defining functions), but isn't in the vast majority of cases, as you can use variables from the local scope directly.
Example:
function SimObject::call(%this, %name, %a, %b, %c, %d, %e, %f, %g, %h, %i, %j, %k, %l, %m, %n, %o, %p, %q, %r) {
return eval("return %this." @ %name @ "(%a, %b, %c, %d, %e, %f, %g, %h, %i, %j, %k, %l, %m, %n, %o, %p, %q, %r);");
}Do note that even the above function allows code injection (through
%name). This is why when you
do end up using
eval like this, make sure you keep track of what variables are passed to it unmodified. In this case, since
%name is passed to it directly, the same rules for normal
eval (not passing external data directly) would apply to any user of the above method (not passing external data to
%name directly, however if you do the chain continues).
Notable things you
don't need
eval for:
- Calling functions (see the default call function)
- Accessing fields on objects by full name (use a switch + the x.y[z] expression)
- Inheriting from objects stored in a variable (temporarily rename the base object)
- Creating datablocks dynamically (this one is debatable as changing the name of a datablock is a bit hacky, but even if you do end up using eval here, make sure you use variables/expressions directly when assigning the various fields rather than passing them in with string concatenation). I'm not actually sure about this one; it's been a while, and I really don't remember if you can use datablock statements anywhere but the top level. I distinctly remember doing so, though. Try it first before eval regardless.
If you must concatenate external strings, consider identifier sanitizing for identifiers and always use
expandEscape on arbitrary strings.
I'm so tired