ENH: support field width for #eval expressions

For example,
```
entry #eval 10 { vector(rand(), 0, 0) };
```

ENH: be more generous and ignore trailing ';' in expressions

STYLE: adjust parse token name for tensor::I
This commit is contained in:
Mark Olesen 2021-03-29 14:03:10 +02:00
parent d4ac96cdf3
commit 21720bea12
18 changed files with 128 additions and 62 deletions

View File

@ -68,4 +68,8 @@ apiMonth #eval{ ($FOAM_API % 100) };
empty #eval ""; empty #eval "";
// Field of specified length
random #eval 4 { vector(rand(), 0, 0) ; /* trailing rubbish */ ; };
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com \\ / A nd | www.openfoam.com
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2019 OpenCFD Ltd. Copyright (C) 2019-2021 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -97,6 +97,7 @@ int main(int argc, char *argv[])
argList::addBoolOption("rules", "Print parser rules and exit"); argList::addBoolOption("rules", "Print parser rules and exit");
argList::addBoolOption("tokens", "Print token names and exit"); argList::addBoolOption("tokens", "Print token names and exit");
argList::addOption("precision", "int", "Output with specified precision"); argList::addOption("precision", "int", "Output with specified precision");
argList::addOption("size", "int", "Field output width (default: 1)");
// Flag arguments as optional so that -rules and -tokens works // Flag arguments as optional so that -rules and -tokens works
argList::noMandatoryArgs(); argList::noMandatoryArgs();
@ -110,6 +111,7 @@ int main(int argc, char *argv[])
const bool printRules = args.found("rules"); const bool printRules = args.found("rules");
const bool printNames = args.found("tokens"); const bool printNames = args.found("tokens");
const label fieldWidth = args.getOrDefault<label>("size", 1);
if (printNames || printRules) if (printNames || printRules)
{ {
@ -155,7 +157,7 @@ int main(int argc, char *argv[])
return 1; return 1;
} }
Info<< stringOps::evaluate(expr).c_str() << nl; Info<< stringOps::evaluate(fieldWidth, expr).c_str() << nl;
return 0; return 0;
} }

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com \\ / A nd | www.openfoam.com
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2019 OpenCFD Ltd. Copyright (C) 2019-2021 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -31,6 +31,7 @@ License
#include "stringOps.H" #include "stringOps.H"
#include "fieldExprDriver.H" #include "fieldExprDriver.H"
#include "addToMemberFunctionSelectionTable.H" #include "addToMemberFunctionSelectionTable.H"
#include <cctype>
#undef DetailInfo #undef DetailInfo
#define DetailInfo if (::Foam::infoDetailLevel > 0) InfoErr #define DetailInfo if (::Foam::infoDetailLevel > 0) InfoErr
@ -69,34 +70,35 @@ Foam::tokenList Foam::functionEntries::evalEntry::evaluate
<< is.lineNumber() << " in file " << parentDict.name() << nl; << is.lineNumber() << " in file " << parentDict.name() << nl;
#endif #endif
// String to evaluate
string s;
token tok(is); token tok(is);
label fieldWidth(1); // Field width for the result
if (!tok.good()) if (tok.isLabel())
{ {
FatalIOErrorInFunction(is) // - #eval INT "expr"
<< "Bad token - could not get string to evaluate" // - #eval INT { expr }
<< exit(FatalIOError); // - #eval INT #{ expr #}
fieldWidth = max(1, tok.labelToken());
return tokenList(); is >> tok;
} }
string s; // String to evaluate
if (tok.isString()) if (tok.isString())
{ {
// - #eval "expr"
// - #eval #{ expr #}
s = tok.stringToken(); s = tok.stringToken();
} }
else if (tok == token::BEGIN_BLOCK) else if (tok.isPunctuation(token::BEGIN_BLOCK))
{ {
// - #eval { expr }
dynamic_cast<ISstream&>(is).getLine(s, token::END_BLOCK); dynamic_cast<ISstream&>(is).getLine(s, token::END_BLOCK);
} }
else else
{ {
is.putBack(tok);
FatalIOErrorInFunction(is) FatalIOErrorInFunction(is)
<< "Invalid input for #eval" << nl << "Invalid input for #eval."
" Expecting a string or block to evaluate, but found" << nl
<< tok.info() << endl
<< exit(FatalIOError); << exit(FatalIOError);
} }
@ -111,15 +113,31 @@ Foam::tokenList Foam::functionEntries::evalEntry::evaluate
expressions::exprString::inplaceExpand(s, parentDict, true); expressions::exprString::inplaceExpand(s, parentDict, true);
stringOps::inplaceTrim(s); stringOps::inplaceTrim(s);
// An extraneous trailing ';' is a common input error, catch it now. // An extraneous trailing ';' is a common input error.
// May need to relax in the future, trim or something else // - trim if it does not influence the result
if (std::string::npos != s.find(';')) const auto trailing = s.find(';');
if (std::string::npos != trailing)
{ {
FatalIOErrorInFunction(is) bool ignore = true;
<< "Invalid input for #eval" << nl for (size_t other = trailing; ignore && other < s.length(); ++other)
<< s << endl {
<< exit(FatalIOError); ignore = s[other] == ';' || std::isspace(s[other]);
}
if (ignore)
{
// Can trim trailing without semantical change
s.erase(trailing);
stringOps::inplaceTrim(s);
}
else
{
FatalIOErrorInFunction(is)
<< "Invalid input (after trailing ';') for #eval" << nl
<< s << endl
<< exit(FatalIOError);
}
} }
#ifdef FULLDEBUG #ifdef FULLDEBUG
@ -138,7 +156,7 @@ Foam::tokenList Foam::functionEntries::evalEntry::evaluate
expressions::exprResult result; expressions::exprResult result;
{ {
expressions::fieldExprDriver driver(1); expressions::fieldExprDriver driver(fieldWidth);
driver.parse(s); driver.parse(s);
result = std::move(driver.result()); result = std::move(driver.result());
} }
@ -152,11 +170,15 @@ Foam::tokenList Foam::functionEntries::evalEntry::evaluate
return tokenList(); return tokenList();
} }
// Could average/reduce to a single value, but probably not needed
//// result.testIfSingleValue(false); // No parallel check
OTstream toks; OTstream toks;
result.writeValue(toks); if (result.size() <= 1)
{
result.writeValue(toks);
}
else
{
result.writeField(toks);
}
return std::move(toks); return std::move(toks);
} }

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com \\ / A nd | www.openfoam.com
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2019 OpenCFD Ltd. Copyright (C) 2019-2021 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -31,11 +31,12 @@ Description
with scalars, vectors etc. with scalars, vectors etc.
The input can any form of string or, for convenience, The input can any form of string or, for convenience,
a '{}' delimited string literal. In all cases, C/C++ comment stripping a '{}' delimited string literal.
is also performed. In all cases, C/C++ comment stripping is performed.
The default size of the evaluated field is one,
For example, which can be overridden by providing an initial integer value.
Some examples,
\verbatim \verbatim
a 1; a 1;
b 3; b 3;
@ -45,12 +46,15 @@ Description
// ignore: sin(pi()*$a/$b) // ignore: sin(pi()*$a/$b)
sin(degToRad(45)) sin(degToRad(45))
}; };
// With different field length:
points #eval 4 #{ vector(rand(), 0, 0) #};
\endverbatim \endverbatim
Note Note
The string expansions support use of environment variables. The string expansions support use of environment variables.
Unknown variables will expand to an empty string, so it can be advisable Unknown variables will expand to an empty string, so it can be advisable
to an expansion with an alternative. For example, to expand with an alternative. For example,
\verbatim \verbatim
d #eval{ sin(degToRad( ${angle:-0} )) }; d #eval{ sin(degToRad( ${angle:-0} )) };

View File

@ -62,7 +62,7 @@
#define TOK_VECTOR_ID 62 #define TOK_VECTOR_ID 62
#define TOK_SPH_TENSOR_ID 63 #define TOK_SPH_TENSOR_ID 63
#define TOK_SYM_TENSOR_ID 64 #define TOK_SYM_TENSOR_ID 64
#define TOK_UNIT_TENSOR 65 #define TOK_IDENTITY_TENSOR 65
#define TOK_TENSOR_ID 66 #define TOK_TENSOR_ID 66
#define TOK_LTRUE 67 #define TOK_LTRUE 67
#define TOK_LFALSE 68 #define TOK_LFALSE 68

View File

@ -7,7 +7,7 @@
\\ / A nd | www.openfoam.com \\ / A nd | www.openfoam.com
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2019-2020 OpenCFD Ltd. Copyright (C) 2019-2021 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -283,7 +283,7 @@ dnl
\*---------------------------------------------------------------------------*/ \*---------------------------------------------------------------------------*/
evaluate ::= _target_ (a) . { driver->setResult(a); } evaluate ::= _target_ (a) . { driver->setResult(a); }
tfield (lhs) ::= UNIT_TENSOR . { lhs = _new_tfield(Foam::tensor::I); } tfield (lhs) ::= IDENTITY_TENSOR . { lhs = _new_tfield(Foam::tensor::I); }
rule_get_field(_target_, TENSOR_ID) rule_get_field(_target_, TENSOR_ID)

View File

@ -7,7 +7,7 @@
\\ / A nd | www.openfoam.com \\ / A nd | www.openfoam.com
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2019-2020 OpenCFD Ltd. Copyright (C) 2019-2021 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -471,7 +471,7 @@ tr9:
goto st11; goto st11;
tr11: tr11:
#line 292 "fieldExprScanner.rl" #line 292 "fieldExprScanner.rl"
{te = p+1;{ EMIT_TOKEN(UNIT_TENSOR); }} {te = p+1;{ EMIT_TOKEN(IDENTITY_TENSOR); }}
goto st11; goto st11;
tr12: tr12:
#line 235 "fieldExprScanner.rl" #line 235 "fieldExprScanner.rl"

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com \\ / A nd | www.openfoam.com
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2019-2020 OpenCFD Ltd. Copyright (C) 2019-2021 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -289,7 +289,7 @@ static int driverTokenType
"Zero" =>{ EMIT_TOKEN(ZERO); }; "Zero" =>{ EMIT_TOKEN(ZERO); };
"true" =>{ EMIT_TOKEN(LTRUE); }; "true" =>{ EMIT_TOKEN(LTRUE); };
"false" =>{ EMIT_TOKEN(LFALSE); }; "false" =>{ EMIT_TOKEN(LFALSE); };
"tensor::I" =>{ EMIT_TOKEN(UNIT_TENSOR); }; "tensor::I" =>{ EMIT_TOKEN(IDENTITY_TENSOR); };
"arg" =>{ EMIT_TOKEN(ARG); }; "arg" =>{ EMIT_TOKEN(ARG); };
## "time" =>{ EMIT_TOKEN(TIME); }; ## "time" =>{ EMIT_TOKEN(TIME); };

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com \\ / A nd | www.openfoam.com
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2019 OpenCFD Ltd. Copyright (C) 2019-2021 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -35,11 +35,17 @@ License
Foam::string Foam::stringOps::evaluate Foam::string Foam::stringOps::evaluate
( (
label fieldWidth,
const std::string& str, const std::string& str,
size_t pos, size_t pos,
size_t len size_t len
) )
{ {
if (fieldWidth < 1)
{
fieldWidth = 1;
}
/// InfoErr<< "Evaluate " << str.substr(pos, len) << nl; /// InfoErr<< "Evaluate " << str.substr(pos, len) << nl;
const auto trimPoints = stringOps::findTrim(str, pos, len); const auto trimPoints = stringOps::findTrim(str, pos, len);
@ -49,14 +55,14 @@ Foam::string Foam::stringOps::evaluate
if (!len) if (!len)
{ {
return ""; return string();
} }
/// InfoErr<< "Evaluate " << str.substr(pos, len) << nl; /// InfoErr<< "Evaluate " << str.substr(pos, len) << nl;
expressions::exprResult result; expressions::exprResult result;
{ {
expressions::fieldExprDriver driver(1); expressions::fieldExprDriver driver(fieldWidth);
driver.parse(str, pos, len); driver.parse(str, pos, len);
result = std::move(driver.result()); result = std::move(driver.result());
} }
@ -67,14 +73,32 @@ Foam::string Foam::stringOps::evaluate
<< "Failed evaluation: " << "Failed evaluation: "
<< str.substr(pos, len) << nl; << str.substr(pos, len) << nl;
return ""; return string();
} }
OStringStream os; OStringStream os;
result.writeValue(os); if (result.size() <= 1)
{
result.writeValue(os);
}
else
{
result.writeField(os);
}
return os.str(); return os.str();
} }
Foam::string Foam::stringOps::evaluate
(
const std::string& str,
size_t pos,
size_t len
)
{
return stringOps::evaluate(1, str, pos, len);
}
// ************************************************************************* // // ************************************************************************* //

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com \\ / A nd | www.openfoam.com
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2019 OpenCFD Ltd. Copyright (C) 2019-2021 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -34,6 +34,7 @@ Description
#ifndef stringOpsEvaluate_H #ifndef stringOpsEvaluate_H
#define stringOpsEvaluate_H #define stringOpsEvaluate_H
#include "labelFwd.H"
#include "string.H" #include "string.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -42,6 +43,15 @@ namespace Foam
{ {
namespace stringOps namespace stringOps
{ {
//- String evaluation with specified (positive, non-zero) field width
string evaluate
(
label fieldWidth,
const std::string& s,
size_t pos = 0,
size_t len = std::string::npos
);
//- A simple string evaluation that handles various basic //- A simple string evaluation that handles various basic
//- expressions. For trivial input, use readScalar instead (faster). //- expressions. For trivial input, use readScalar instead (faster).
// //

View File

@ -67,7 +67,7 @@
#define TOK_SSPH_TENSOR_ID 67 #define TOK_SSPH_TENSOR_ID 67
#define TOK_SYM_TENSOR_ID 68 #define TOK_SYM_TENSOR_ID 68
#define TOK_SSYM_TENSOR_ID 69 #define TOK_SSYM_TENSOR_ID 69
#define TOK_UNIT_TENSOR 70 #define TOK_IDENTITY_TENSOR 70
#define TOK_TENSOR_ID 71 #define TOK_TENSOR_ID 71
#define TOK_STENSOR_ID 72 #define TOK_STENSOR_ID 72
#define TOK_LTRUE 73 #define TOK_LTRUE 73

View File

@ -7,7 +7,7 @@
\\ / A nd | www.openfoam.com \\ / A nd | www.openfoam.com
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2019-2020 OpenCFD Ltd. Copyright (C) 2019-2021 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -242,7 +242,7 @@ dnl
\*---------------------------------------------------------------------------*/ \*---------------------------------------------------------------------------*/
evaluate ::= _target_ (a) . { driver->setResult(a); } evaluate ::= _target_ (a) . { driver->setResult(a); }
tfield (lhs) ::= UNIT_TENSOR . { lhs = _new_tfield(Foam::tensor::I); } tfield (lhs) ::= IDENTITY_TENSOR . { lhs = _new_tfield(Foam::tensor::I); }
rule_get_field(_target_, TENSOR_ID) rule_get_field(_target_, TENSOR_ID)
rule_get_field(_target_, STENSOR_ID) rule_get_field(_target_, STENSOR_ID)

View File

@ -7,7 +7,7 @@
\\ / A nd | www.openfoam.com \\ / A nd | www.openfoam.com
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2019-2020 OpenCFD Ltd. Copyright (C) 2019-2021 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -595,7 +595,7 @@ tr9:
goto st11; goto st11;
tr11: tr11:
#line 418 "patchExprScanner.rl" #line 418 "patchExprScanner.rl"
{te = p+1;{ EMIT_TOKEN(UNIT_TENSOR); }} {te = p+1;{ EMIT_TOKEN(IDENTITY_TENSOR); }}
goto st11; goto st11;
tr12: tr12:
#line 359 "patchExprScanner.rl" #line 359 "patchExprScanner.rl"

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com \\ / A nd | www.openfoam.com
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2019-2020 OpenCFD Ltd. Copyright (C) 2019-2021 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -415,7 +415,7 @@ static int driverTokenType
"Zero" =>{ EMIT_TOKEN(ZERO); }; "Zero" =>{ EMIT_TOKEN(ZERO); };
"true" =>{ EMIT_TOKEN(LTRUE); }; "true" =>{ EMIT_TOKEN(LTRUE); };
"false" =>{ EMIT_TOKEN(LFALSE); }; "false" =>{ EMIT_TOKEN(LFALSE); };
"tensor::I" =>{ EMIT_TOKEN(UNIT_TENSOR); }; "tensor::I" =>{ EMIT_TOKEN(IDENTITY_TENSOR); };
"arg" =>{ EMIT_TOKEN(ARG); }; "arg" =>{ EMIT_TOKEN(ARG); };
"time" =>{ EMIT_TOKEN(TIME); }; "time" =>{ EMIT_TOKEN(TIME); };

View File

@ -63,7 +63,7 @@
#define TOK_VECTOR_ID 63 #define TOK_VECTOR_ID 63
#define TOK_SPH_TENSOR_ID 64 #define TOK_SPH_TENSOR_ID 64
#define TOK_SYM_TENSOR_ID 65 #define TOK_SYM_TENSOR_ID 65
#define TOK_UNIT_TENSOR 66 #define TOK_IDENTITY_TENSOR 66
#define TOK_TENSOR_ID 67 #define TOK_TENSOR_ID 67
#define TOK_LTRUE 68 #define TOK_LTRUE 68
#define TOK_LFALSE 69 #define TOK_LFALSE 69

View File

@ -7,7 +7,7 @@
\\ / A nd | www.openfoam.com \\ / A nd | www.openfoam.com
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2019-2020 OpenCFD Ltd. Copyright (C) 2019-2021 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -274,7 +274,7 @@ dnl
\*---------------------------------------------------------------------------*/ \*---------------------------------------------------------------------------*/
evaluate ::= _target_ (a) . { driver->setResult(a); } evaluate ::= _target_ (a) . { driver->setResult(a); }
tfield (lhs) ::= UNIT_TENSOR . { lhs = _new_tfield(Foam::tensor::I); } tfield (lhs) ::= IDENTITY_TENSOR . { lhs = _new_tfield(Foam::tensor::I); }
rule_get_field(_target_, TENSOR_ID) rule_get_field(_target_, TENSOR_ID)

View File

@ -7,7 +7,7 @@
\\ / A nd | www.openfoam.com \\ / A nd | www.openfoam.com
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2019-2020 OpenCFD Ltd. Copyright (C) 2019-2021 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -624,7 +624,7 @@ tr9:
goto st11; goto st11;
tr11: tr11:
#line 447 "volumeExprScanner.rl" #line 447 "volumeExprScanner.rl"
{te = p+1;{ EMIT_TOKEN(UNIT_TENSOR); }} {te = p+1;{ EMIT_TOKEN(IDENTITY_TENSOR); }}
goto st11; goto st11;
tr12: tr12:
#line 388 "volumeExprScanner.rl" #line 388 "volumeExprScanner.rl"

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com \\ / A nd | www.openfoam.com
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2019-2020 OpenCFD Ltd. Copyright (C) 2019-2021 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -444,7 +444,7 @@ static int driverTokenType
"Zero" =>{ EMIT_TOKEN(ZERO); }; "Zero" =>{ EMIT_TOKEN(ZERO); };
"true" =>{ EMIT_TOKEN(LTRUE); }; "true" =>{ EMIT_TOKEN(LTRUE); };
"false" =>{ EMIT_TOKEN(LFALSE); }; "false" =>{ EMIT_TOKEN(LFALSE); };
"tensor::I" =>{ EMIT_TOKEN(UNIT_TENSOR); }; "tensor::I" =>{ EMIT_TOKEN(IDENTITY_TENSOR); };
"arg" =>{ EMIT_TOKEN(ARG); }; "arg" =>{ EMIT_TOKEN(ARG); };
"time" =>{ EMIT_TOKEN(TIME); }; "time" =>{ EMIT_TOKEN(TIME); };