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 );
149 if( std::holds_alternative<double>( aVal ) )
150 return std::get<double>( aVal ) != 0.0;
152 return !std::get<std::string>( aVal ).empty();
164 const auto leftVal = leftNum.GetValue();
165 const auto rightVal = rightNum.GetValue();
173 if( rightVal == 0.0 )
177 if( rightVal == 0.0 )
212 BIN_OP_DATA( std::unique_ptr<NODE> aLeft,
char aOperation, std::unique_ptr<NODE> aRight ) :
222 std::vector<std::unique_ptr<NODE>>
args;
224 FUNC_DATA( std::string aName, std::vector<std::unique_ptr<NODE>> aArguments ) :
234 std::variant<std::string, double, BIN_OP_DATA, FUNC_DATA>
data;
237 static auto CreateText( std::string aText ) -> std::unique_ptr<NODE>
239 auto node = std::make_unique<NODE>();
241 node->data = std::move( aText );
245 static auto CreateCalc( std::unique_ptr<NODE> aExpr ) -> std::unique_ptr<NODE>
247 auto node = std::make_unique<NODE>();
249 node->data =
BIN_OP_DATA( std::move( aExpr ),
'=',
nullptr );
253 static auto CreateVar( std::string aName ) -> std::unique_ptr<NODE>
255 auto node = std::make_unique<NODE>();
257 node->data = std::move( aName );
263 auto node = std::make_unique<NODE>();
269 static auto CreateString( std::string aValue ) -> std::unique_ptr<NODE>
271 auto node = std::make_unique<NODE>();
273 node->data = std::move( aValue );
277 static auto CreateBinOp( std::unique_ptr<NODE> aLeft,
char aOp, std::unique_ptr<NODE> aRight ) -> std::unique_ptr<NODE>
279 auto node = std::make_unique<NODE>();
281 node->data =
BIN_OP_DATA( std::move( aLeft ), aOp, std::move( aRight ) );
285 static auto CreateFunction( std::string aName, std::vector<std::unique_ptr<NODE>> aArgs ) -> std::unique_ptr<NODE>
287 auto node = std::make_unique<NODE>();
289 node->data =
FUNC_DATA( std::move( aName ), std::move( aArgs ) );
296 auto node =
new NODE();
298 node->data = std::move( aText );
304 auto node =
new NODE();
306 node->data =
BIN_OP_DATA( std::unique_ptr<NODE>( aExpr ),
'=',
nullptr );
312 auto node =
new NODE();
314 node->data = std::move( aName );
320 auto node =
new NODE();
328 auto node =
new NODE();
330 node->data = std::move( aValue );
336 auto node =
new NODE();
338 node->data =
BIN_OP_DATA( std::unique_ptr<NODE>( aLeft ), aOp, std::unique_ptr<NODE>( aRight ) );
344 auto node =
new NODE();
346 node->data =
FUNC_DATA( std::move( aName ), std::move( *aArgs ) );
352 template<
typename Visitor>
355 return std::forward<Visitor>( aVisitor )( *this );
362 std::vector<std::unique_ptr<NODE>>
nodes;
365 auto AddNode( std::unique_ptr<NODE> aNode ) ->
void
367 nodes.emplace_back( std::move( aNode ) );
372 nodes.emplace_back( std::unique_ptr<NODE>( aNode ) );
419 mutable std::random_device
m_rd;
450 -> std::pair<std::string, bool>;
459 -> 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
static auto ToChar(const Value &aVal) -> char
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.