20#include <fast_float/fast_float.h>
30#include <fmt/format.h>
40#include <unordered_map>
45#define M_PI 3.14159265358979323846
50 using Value = std::variant<double, std::string>;
66 strncpy(token.
text, str.c_str(),
sizeof(token.
text) - 1);
67 token.
text[
sizeof(token.
text) - 1] =
'\0';
82 return std::string(token.
text);
97 if( std::holds_alternative<double>( aVal ) )
98 return MakeValue( std::get<double>( aVal ) );
100 const auto& str = std::get<std::string>( aVal );
104 auto result = fast_float::from_chars( str.data(), str.data() + str.size(), value );
106 if(
result.ec != std::errc() ||
result.ptr != str.data() + str.size() )
107 throw std::invalid_argument(
"Invalid number format" );
120 if( std::holds_alternative<std::string>( aVal ) )
121 return std::get<std::string>( aVal );
123 const auto num = std::get<double>( aVal );
126 constexpr double tolerance = 1e-10;
127 double rounded = std::round( num );
131 return fmt::format(
"{:.0f}", rounded );
133 return fmt::format(
"{}", num );
139 if( std::holds_alternative<double>( aVal ) )
140 return std::get<double>( aVal ) != 0.0;
142 return !std::get<std::string>( aVal ).empty();
154 const auto leftVal = leftNum.GetValue();
155 const auto rightVal = rightNum.GetValue();
163 if( rightVal == 0.0 )
167 if( rightVal == 0.0 )
202 BIN_OP_DATA( std::unique_ptr<NODE> aLeft,
char aOperation, std::unique_ptr<NODE> aRight ) :
212 std::vector<std::unique_ptr<NODE>>
args;
214 FUNC_DATA( std::string aName, std::vector<std::unique_ptr<NODE>> aArguments ) :
224 std::variant<std::string, double, BIN_OP_DATA, FUNC_DATA>
data;
227 static auto CreateText( std::string aText ) -> std::unique_ptr<NODE>
229 auto node = std::make_unique<NODE>();
231 node->data = std::move( aText );
235 static auto CreateCalc( std::unique_ptr<NODE> aExpr ) -> std::unique_ptr<NODE>
237 auto node = std::make_unique<NODE>();
239 node->data =
BIN_OP_DATA( std::move( aExpr ),
'=',
nullptr );
243 static auto CreateVar( std::string aName ) -> std::unique_ptr<NODE>
245 auto node = std::make_unique<NODE>();
247 node->data = std::move( aName );
253 auto node = std::make_unique<NODE>();
259 static auto CreateString( std::string aValue ) -> std::unique_ptr<NODE>
261 auto node = std::make_unique<NODE>();
263 node->data = std::move( aValue );
267 static auto CreateBinOp( std::unique_ptr<NODE> aLeft,
char aOp, std::unique_ptr<NODE> aRight ) -> std::unique_ptr<NODE>
269 auto node = std::make_unique<NODE>();
271 node->data =
BIN_OP_DATA( std::move( aLeft ), aOp, std::move( aRight ) );
275 static auto CreateFunction( std::string aName, std::vector<std::unique_ptr<NODE>> aArgs ) -> std::unique_ptr<NODE>
277 auto node = std::make_unique<NODE>();
279 node->data =
FUNC_DATA( std::move( aName ), std::move( aArgs ) );
286 auto node =
new NODE();
288 node->data = std::move( aText );
294 auto node =
new NODE();
296 node->data =
BIN_OP_DATA( std::unique_ptr<NODE>( aExpr ),
'=',
nullptr );
302 auto node =
new NODE();
304 node->data = std::move( aName );
310 auto node =
new NODE();
318 auto node =
new NODE();
320 node->data = std::move( aValue );
326 auto node =
new NODE();
328 node->data =
BIN_OP_DATA( std::unique_ptr<NODE>( aLeft ), aOp, std::unique_ptr<NODE>( aRight ) );
334 auto node =
new NODE();
336 node->data =
FUNC_DATA( std::move( aName ), std::move( *aArgs ) );
342 template<
typename Visitor>
345 return std::forward<Visitor>( aVisitor )( *this );
352 std::vector<std::unique_ptr<NODE>>
nodes;
355 auto AddNode( std::unique_ptr<NODE> aNode ) ->
void
357 nodes.emplace_back( std::move( aNode ) );
362 nodes.emplace_back( std::unique_ptr<NODE>( aNode ) );
409 mutable std::random_device
m_rd;
440 -> std::pair<std::string, bool>;
449 -> std::tuple<std::string, std::vector<std::string>,
bool>;
static auto ProcessWithDetails(const DOC &aDoc, VariableCallback aVariableCallback) -> std::tuple< std::string, std::vector< std::string >, bool >
Process document with detailed error reporting.
EVAL_VISITOR::VariableCallback VariableCallback
static auto Process(const DOC &aDoc, VariableCallback aVariableCallback) -> std::pair< std::string, bool >
Process document using callback for variable resolution.
auto GetErrors() const -> const std::vector< std::string > &
auto HasErrors() const -> bool
auto AddNodeRaw(NODE *aNode) -> void
auto GetNodes() const -> const auto &
auto AddNode(std::unique_ptr< NODE > aNode) -> void
auto GetErrorSummary() const -> std::string
std::vector< std::unique_ptr< NODE > > nodes
auto operator()(const NODE &aNode) const -> Result< Value >
VariableCallback m_variableCallback
std::function< Result< Value >(const std::string &aVariableName)> VariableCallback
EVAL_VISITOR(VariableCallback aVariableCallback, ERROR_COLLECTOR &aErrorCollector)
Construct evaluator with variable callback function.
auto evaluateFunction(const FUNC_DATA &aFunc) const -> Result< Value >
ERROR_COLLECTOR & m_errors
static auto CreateVar(std::string aName) -> std::unique_ptr< NODE >
static auto CreateNumber(double aValue) -> std::unique_ptr< NODE >
static auto CreateFunction(std::string aName, std::vector< std::unique_ptr< NODE > > aArgs) -> std::unique_ptr< NODE >
static auto CreateText(std::string aText) -> std::unique_ptr< NODE >
static auto CreateBinOp(std::unique_ptr< NODE > aLeft, char aOp, std::unique_ptr< NODE > aRight) -> std::unique_ptr< NODE >
static auto CreateFunctionRaw(std::string aName, std::vector< std::unique_ptr< NODE > > *aArgs) -> NODE *
static auto CreateString(std::string aValue) -> std::unique_ptr< NODE >
static auto CreateTextRaw(std::string aText) -> NODE *
static auto CreateStringRaw(std::string aValue) -> NODE *
std::variant< std::string, double, BIN_OP_DATA, FUNC_DATA > data
static auto CreateNumberRaw(double aValue) -> NODE *
static auto CreateCalcRaw(NODE *aExpr) -> NODE *
auto Accept(Visitor &&aVisitor) const -> Result< Value >
static auto CreateCalc(std::unique_ptr< NODE > aExpr) -> std::unique_ptr< NODE >
static auto CreateVarRaw(std::string aName) -> NODE *
static auto CreateBinOpRaw(NODE *aLeft, char aOp, NODE *aRight) -> NODE *
PARSE_CONTEXT(const PARSE_CONTEXT &)=delete
PARSE_CONTEXT & operator=(const PARSE_CONTEXT &)=delete
PARSE_CONTEXT(PARSE_CONTEXT &&)=delete
PARSE_CONTEXT(ERROR_COLLECTOR &aErrorCollector)
PARSE_CONTEXT & operator=(PARSE_CONTEXT &&)=delete
static auto ArithmeticOp(const Value &aLeft, const Value &aRight, char aOp) -> Result< Value >
static auto ToString(const Value &aVal) -> std::string
static auto IsTruthy(const Value &aVal) -> bool
static auto ToDouble(const Value &aVal) -> Result< double >
static auto ConcatStrings(const Value &aLeft, const Value &aRight) -> Value
TOKEN_TYPE MakeNumberToken(double val)
thread_local ERROR_COLLECTOR * g_errorCollector
auto MakeValue(T aVal) -> Result< T >
std::variant< double, std::string > Value
TOKEN_TYPE MakeStringToken(const std::string &str)
std::string GetTokenString(const TOKEN_TYPE &token)
double GetTokenDouble(const TOKEN_TYPE &token)
auto MakeError(std::string aMsg) -> Result< T >
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
std::unique_ptr< NODE > right
BIN_OP_DATA(std::unique_ptr< NODE > aLeft, char aOperation, std::unique_ptr< NODE > aRight)
std::unique_ptr< NODE > left
FUNC_DATA(std::string aName, std::vector< std::unique_ptr< NODE > > aArguments)
std::vector< std::unique_ptr< NODE > > args
wxString result
Test unit parsing edge cases and error handling.