Skip to content

Commit

Permalink
Fix compile not flushing resolved vars via USR when not keeping them
Browse files Browse the repository at this point in the history
Explain that evaluate() will not cause a USR to be called a again due to the vars in the expression being optimized away
#10
  • Loading branch information
Blake-Madden committed Nov 1, 2023
1 parent c1c6a24 commit dbf65df
Show file tree
Hide file tree
Showing 4 changed files with 37 additions and 12 deletions.
7 changes: 6 additions & 1 deletion docs/manual/24-UnknownSymbolResolution.Rmd
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,8 @@ With subsequent evaluations, the previously unrecognized symbols you resolved wi
This means that it will not to be resolved again and will result in the value that your USR returned from before.
If you prefer to not have resolved symbols added to the parser, then pass `false` to the second parameter to `set_unknown_symbol_resolver()`.
This will force the same unknown symbols to be resolved again with every evaluation.
This will force the same unknown symbols to be resolved again with every call to `compile(expression)` or `evaluate(expression)`.
(The version of `evaluate()` which does not take any parameters will not force calling the USR again, see below.)
This can be useful for when your USR's symbol resolutions are dynamic and may change with each call.
::: {.minipage data-latex="{\textwidth}"}
Expand Down Expand Up @@ -166,3 +167,7 @@ tep.evaluate("STRESS_LEVEL"); // 5
tep.evaluate("STRESS_LEVEL"); // 6
```
:::

As a final note, if you are not keeping resolved variables, your USR will only be called again if you call `evaluate` or `compile` with an expression.
Because the original expression gets optimized, `evaluate()` it will not re-evaluate any variables. Calling `evaluate` with the original expression
will force a re-compilation and in turn call the USR again.
22 changes: 16 additions & 6 deletions tests/tetests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2022,9 +2022,6 @@ TEST_CASE("Unknown symbol resolve funct pointer keep resolved", "[usr]")
te_parser tep;
tep.set_unknown_symbol_resolver(ResolveResolutionSymbols);

CHECK(tep.evaluate("RES * 3") == 3 * 96);
// case sensitive, won't recognize it
CHECK(std::isnan(tep.evaluate("resolution * 5")));
CHECK(tep.evaluate("RESOLUTION * 3") == 3 * 96);
// is in the parser now and can be recognized case sensitively
CHECK(tep.evaluate("resolution * 5") == 480);
Expand All @@ -2035,14 +2032,27 @@ TEST_CASE("Unknown symbol resolve funct pointer purge resolved", "[usr]")
te_parser tep;
tep.set_unknown_symbol_resolver(ResolveResolutionSymbols, false);

CHECK(tep.evaluate("RES * 3") == 3 * 96);
// case sensitive, won't recognize it
CHECK(std::isnan(tep.evaluate("resolution * 5")));
CHECK(tep.evaluate("RESOLUTION * 3") == 3 * 96);
// not in the parser, so case sensitive look up will fail
CHECK(std::isnan(tep.evaluate("resolution * 5")));
}

TEST_CASE("Unknown symbol resolve funct pointer purge resolved 2", "[usr]")
{
std::string str("id.temperature < 51");
te_parser parser;
parser.set_unknown_symbol_resolver([](std::string_view symbol)
{
static double temperature = 49.0;
return temperature += 1.0;
}, false);
CHECK(parser.compile(str)); // 50
CHECK_FALSE(parser.evaluate(str)); // 51
CHECK_FALSE(parser.evaluate(str)); // 52
CHECK(parser.evaluate("id.temperature") == 53);
}


TEST_CASE("Unknown symbol resolve 1 param purged", "[usr]")
{
te_parser tep;
Expand Down
10 changes: 5 additions & 5 deletions tinyexpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1349,6 +1349,9 @@ bool te_parser::compile(const std::string_view expression)
m_result = te_nan;
m_lastErrorMessage = expt.what();
}

reset_usr_resolved_if_necessary();

return m_parseSuccess;
}

Expand All @@ -1368,11 +1371,8 @@ double te_parser::evaluate()
m_lastErrorMessage = expt.what();
}

if (!m_keepResolvedVarialbes && resolvedVariables.size())
{
for (const auto& resolvedVar : resolvedVariables)
{ remove_variable_or_function(resolvedVar); }
}
reset_usr_resolved_if_necessary();

return m_result;
}

Expand Down
10 changes: 10 additions & 0 deletions tinyexpr.h
Original file line number Diff line number Diff line change
Expand Up @@ -437,6 +437,16 @@ class te_parser
const std::string& get_expression() const noexcept
{ return m_expression; };
private:
/// @brief Resets any resolved variables from USR if not being cached.
void reset_usr_resolved_if_necessary()
{
if (!m_keepResolvedVarialbes && resolvedVariables.size())
{
for (const auto& resolvedVar : resolvedVariables)
{ remove_variable_or_function(resolvedVar); }
resolvedVariables.clear();
}
}
/// @brief Gets the compiled expression, which will the optimized version
/// of the original expression.
/// @returns The compiled expression.
Expand Down

0 comments on commit dbf65df

Please sign in to comment.