From b136ba309a66ca015d438e04329b8c326a16d92a Mon Sep 17 00:00:00 2001 From: James Cherry Date: Thu, 9 Apr 2026 15:13:40 -0700 Subject: [PATCH 1/6] PrimaDelayCalc::reportGateDelay resolves #418 Signed-off-by: James Cherry --- dcalc/PrimaDelayCalc.cc | 146 +++++++++++++++++++++++++++++----------- dcalc/PrimaDelayCalc.hh | 7 ++ 2 files changed, 113 insertions(+), 40 deletions(-) diff --git a/dcalc/PrimaDelayCalc.cc b/dcalc/PrimaDelayCalc.cc index 561b7953..93388a10 100644 --- a/dcalc/PrimaDelayCalc.cc +++ b/dcalc/PrimaDelayCalc.cc @@ -216,43 +216,8 @@ PrimaDelayCalc::gateDelays(ArcDcalcArgSeq &dcalc_args, parasitics_ = scene->parasitics(min_max); node_index_map_ = NodeIndexMap(ParasiticNodeLess(parasitics_, network_)); - bool failed = false; - output_waveforms_.resize(drvr_count_); - for (size_t drvr_idx = 0; drvr_idx < drvr_count_; drvr_idx++) { - ArcDcalcArg &dcalc_arg = dcalc_args[drvr_idx]; - GateTableModel *table_model = dcalc_arg.arc()->gateTableModel(scene, min_max); - if (table_model && dcalc_arg.parasitic()) { - OutputWaveforms *output_waveforms = table_model->outputWaveforms(); - float in_slew = dcalc_arg.inSlewFlt(); - if (output_waveforms - // Bounds check because extrapolating waveforms does not work for shit. - && output_waveforms->slewAxis()->inBounds(in_slew) - && output_waveforms->capAxis()->inBounds(dcalc_arg.loadCap())) { - output_waveforms_[drvr_idx] = output_waveforms; - debugPrint(debug_, "ccs_dcalc", 1, "{} {}", dcalc_arg.drvrCell()->name(), - drvr_rf_->shortName()); - LibertyCell *drvr_cell = dcalc_arg.drvrCell(); - const LibertyLibrary *drvr_library = drvr_cell->libertyLibrary(); - bool vdd_exists; - drvr_library->supplyVoltage("VDD", vdd_, vdd_exists); - if (!vdd_exists) - report_->error(1720, "VDD not defined in library {}", - drvr_library->name()); - drvr_cell->ensureVoltageWaveforms(scenes_); - if (drvr_idx == 0) { - vth_ = drvr_library->outputThreshold(drvr_rf_) * vdd_; - vl_ = drvr_library->slewLowerThreshold(drvr_rf_) * vdd_; - vh_ = drvr_library->slewUpperThreshold(drvr_rf_) * vdd_; - } - } - else - failed = true; - } - else - failed = true; - } - - if (failed) + bool arg_fail = checkArgs(dcalc_args, scene, min_max); + if (arg_fail) return tableDcalcResults(); else { simulate(); @@ -260,6 +225,100 @@ PrimaDelayCalc::gateDelays(ArcDcalcArgSeq &dcalc_args, } } +// Return true on failure. +// Use falureReason() to get failure string. +bool +PrimaDelayCalc::checkArgs(ArcDcalcArgSeq &dcalc_args, + const Scene *scene, + const MinMax *min_max) +{ + drvr_count_ = dcalc_args.size(); + output_waveforms_.resize(drvr_count_); + failure_reason_ = nullptr; + failure_arg_ = nullptr; + for (size_t drvr_idx = 0; drvr_idx < drvr_count_; drvr_idx++) { + ArcDcalcArg &dcalc_arg = dcalc_args[drvr_idx]; + GateTableModel *table_model = dcalc_arg.arc()->gateTableModel(scene, min_max); + if (table_model) { + if (dcalc_arg.parasitic()) { + OutputWaveforms *output_waveforms = table_model->outputWaveforms(); + float in_slew = dcalc_arg.inSlewFlt(); + if (output_waveforms) { + const LibertyLibrary *drvr_library = dcalc_arg.drvrLibrary(); + float vdd; + bool vdd_exists; + drvr_library->supplyVoltage("VDD", vdd, vdd_exists); + if (vdd_exists) { + if (drvr_idx == 0) { + // Assume drivers are in the same library. + const RiseFall *drvr_rf = dcalc_arg.drvrEdge(); + vdd_ = vdd; + vth_ = drvr_library->outputThreshold(drvr_rf) * vdd_; + vl_ = drvr_library->slewLowerThreshold(drvr_rf) * vdd_; + vh_ = drvr_library->slewUpperThreshold(drvr_rf) * vdd_; + } + } + else { + failure_reason_ = "vdd not defined"; + failure_arg_ = &dcalc_arg; + } + + // Bounds check because extrapolating waveforms does not work for shit. + if (output_waveforms->slewAxis()->inBounds(in_slew)) { + if (output_waveforms->capAxis()->inBounds(dcalc_arg.loadCap())) { + output_waveforms_[drvr_idx] = output_waveforms; + debugPrint(debug_, "prima", 1, "{} {}", + dcalc_arg.drvrCell()->name(), + dcalc_arg.drvrEdge()->to_string().c_str()); + LibertyCell *drvr_cell = dcalc_arg.drvrCell(); + drvr_cell->ensureVoltageWaveforms(scenes_); + } + else { + failure_reason_ = "load cap out of bounds"; + failure_arg_ = &dcalc_arg; + } + } + else { + failure_reason_ = "input slew out of bounds"; + failure_arg_ = &dcalc_arg; + } + } + else { + failure_reason_ = "no output waveforms"; + failure_arg_ = &dcalc_arg; + } + } + else { + failure_reason_ = "no parasitic"; + failure_arg_ = &dcalc_arg; + } + } + else { + failure_reason_ = "no table model"; + failure_arg_ = &dcalc_arg; + } + } + if (failure_reason_) { + std::string reason = failureReason(); + debugPrint(debug_,"prima", 1, "arg check failed {}.", reason.c_str()); + } + return failure_reason_ != nullptr; +} + +std::string +PrimaDelayCalc::failureReason() +{ + const Pin *drvr_pin = failure_arg_->drvrPin(); + const Instance *inst = network_->instance(drvr_pin); + LibertyPort *from = failure_arg_->arc()->from(); + LibertyPort *to = failure_arg_->arc()->to(); + return sta::format("{} {} -> {} {}", + sdc_network_->pathName(inst), + from->name(), + to->name(), + failure_reason_); +} + ArcDcalcResultSeq PrimaDelayCalc::tableDcalcResults() { @@ -938,8 +997,16 @@ PrimaDelayCalc::reportGateDelay(const Pin *drvr_pin, const MinMax *min_max, int digits) { - GateTimingModel *model = arc->gateModel(scene, min_max); - if (model) { + ArcDcalcArgSeq dcalc_args; + dcalc_args.emplace_back(nullptr, drvr_pin, nullptr, arc, in_slew, + load_cap, parasitic); + bool arg_fail = checkArgs(dcalc_args, scene, min_max); + if (arg_fail) + return table_dcalc_->reportGateDelay(drvr_pin, arc, in_slew, load_cap, + parasitic, load_pin_index_map, scene, + min_max, digits); + else { + GateTimingModel *model = arc->gateModel(scene, min_max); // Delay calc to find ceff. gateDelay(drvr_pin, arc, in_slew, load_cap, parasitic, load_pin_index_map, scene, min_max); @@ -949,7 +1016,6 @@ PrimaDelayCalc::reportGateDelay(const Pin *drvr_pin, in_slew1, ceff, min_max, PocvMode::scalar, digits); } - return ""; } //////////////////////////////////////////////////////////////// diff --git a/dcalc/PrimaDelayCalc.hh b/dcalc/PrimaDelayCalc.hh index c0b39ba7..086e29ce 100644 --- a/dcalc/PrimaDelayCalc.hh +++ b/dcalc/PrimaDelayCalc.hh @@ -100,6 +100,10 @@ public: const Scene *scene, const MinMax *min_max, int digits) override; + bool checkArgs(ArcDcalcArgSeq &dcalc_args, + const Scene *scene, + const MinMax *min_max); + std::string failureReason(); // Record waveform for drvr/load pin. void watchPin(const Pin *pin) override; @@ -253,6 +257,9 @@ protected: // Delay calculator to use when ccs waveforms are missing from liberty. ArcDelayCalc *table_dcalc_; + const char *failure_reason_; + ArcDcalcArg *failure_arg_; + using ArcDelayCalc::reduceParasitic; }; From d6268da88f93f695ee8b427959bd49422276c11f Mon Sep 17 00:00:00 2001 From: Mike Inouye Date: Fri, 10 Apr 2026 10:28:01 -0700 Subject: [PATCH 2/6] Consider multi-bit flops as having sequentials. (#419) --- liberty/Liberty.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/liberty/Liberty.cc b/liberty/Liberty.cc index 31e17cbe..ae375e21 100644 --- a/liberty/Liberty.cc +++ b/liberty/Liberty.cc @@ -1489,7 +1489,7 @@ LibertyCell::outputPortSequential(LibertyPort *port) bool LibertyCell::hasSequentials() const { - return !sequentials_.empty(); + return !sequentials_.empty() || statetable_ != nullptr; } void From 53f53e464a4d24109b246854bddd439846e9e03d Mon Sep 17 00:00:00 2001 From: James Cherry Date: Fri, 10 Apr 2026 10:22:17 -0700 Subject: [PATCH 3/6] CmakeLists Signed-off-by: James Cherry --- CMakeLists.txt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2f3495ba..57d080be 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -595,13 +595,13 @@ set(CXX_FLAGS -Wall -Wextra -pedantic -Wcast-qual -Wredundant-decls if(ENABLE_TSAN) message(STATUS "Thread sanitizer: ${ENABLE_TSAN}") set(CXX_FLAGS "${CXX_FLAGS};-fsanitize=thread") - set(CMAKE_EXE_LINKER_FLAGS "-fsanitize=thread") + string(APPEND CMAKE_EXE_LINKER_FLAGS " -fsanitize=thread") endif() if(ENABLE_ASAN) message(STATUS "Address sanitizer: ${ENABLE_ASAN}") set(CXX_FLAGS "${CXX_FLAGS};-fsanitize=address") - set(CMAKE_EXE_LINKER_FLAGS "-fsanitize=address") + string(APPEND CMAKE_EXE_LINKER_FLAGS " -fsanitize=address") endif() target_compile_options(OpenSTA @@ -627,6 +627,7 @@ message(STATUS "STA library: ${CMAKE_BINARY_DIR}/libOpenSTA.a") add_executable(sta app/Main.cc) target_link_libraries(sta + PRIVATE sta_swig OpenSTA ) From 6ef92c5fc09356b4691e6f29c09162534d5ac489 Mon Sep 17 00:00:00 2001 From: James Cherry Date: Fri, 10 Apr 2026 10:35:36 -0700 Subject: [PATCH 4/6] LibertyPort::less Signed-off-by: James Cherry --- liberty/Liberty.cc | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/liberty/Liberty.cc b/liberty/Liberty.cc index ae375e21..1817a7a2 100644 --- a/liberty/Liberty.cc +++ b/liberty/Liberty.cc @@ -2477,18 +2477,10 @@ bool LibertyPort::less(const LibertyPort *port1, const LibertyPort *port2) { - if (port1 == nullptr && port2 != nullptr) - return true; - if (port1 != nullptr && port2 == nullptr) - return false; - const std::string &name1 = port1->name(); - const std::string &name2 = port2->name(); - if (name1 == name2) { - PortDirection *dir1 = port1->direction(); - PortDirection *dir2 = port2->direction(); - return dir1->index() < dir2->index(); - } - return name1 < name2; + if (port1 && port2) + return port1->pinIndex() < port2->pinIndex(); + else + return port1 == nullptr && port2 != nullptr; } void From 094aa1adc4e7db14f89f6372ca05a0775df3f120 Mon Sep 17 00:00:00 2001 From: James Cherry Date: Fri, 10 Apr 2026 10:53:55 -0700 Subject: [PATCH 5/6] VerilogNamespace use string_view Signed-off-by: James Cherry --- include/sta/VerilogNamespace.hh | 17 ++++---- network/VerilogNamespace.cc | 76 ++++++++++++++++++++------------- 2 files changed, 56 insertions(+), 37 deletions(-) diff --git a/include/sta/VerilogNamespace.hh b/include/sta/VerilogNamespace.hh index bcdddb52..5b874189 100644 --- a/include/sta/VerilogNamespace.hh +++ b/include/sta/VerilogNamespace.hh @@ -25,25 +25,26 @@ #pragma once #include +#include namespace sta { std::string -cellVerilogName(std::string sta_name); +cellVerilogName(std::string_view sta_name); std::string -instanceVerilogName(std::string sta_name); +instanceVerilogName(std::string_view sta_name); std::string -netVerilogName(std::string sta_name); +netVerilogName(std::string_view sta_name); std::string -portVerilogName(std::string sta_name); +portVerilogName(std::string_view sta_name); std::string -moduleVerilogToSta(std::string sta_name); +moduleVerilogToSta(std::string_view sta_name); std::string -instanceVerilogToSta(std::string sta_name); +instanceVerilogToSta(std::string_view sta_name); std::string -netVerilogToSta(std::string sta_name); +netVerilogToSta(std::string_view sta_name); std::string -portVerilogToSta(std::string sta_name); +portVerilogToSta(std::string_view sta_name); } // namespace diff --git a/network/VerilogNamespace.cc b/network/VerilogNamespace.cc index b12d9c3a..28f07dc0 100644 --- a/network/VerilogNamespace.cc +++ b/network/VerilogNamespace.cc @@ -34,26 +34,26 @@ namespace sta { constexpr char verilog_escape = '\\'; static std::string -staToVerilog(std::string sta_name); +staToVerilog(std::string_view sta_name); static std::string -staToVerilog2(std::string sta_name); +staToVerilog2(std::string_view sta_name); static std::string -verilogToSta(const std::string verilog_name); +verilogToSta(const std::string_view verilog_name); std::string -cellVerilogName(std::string sta_name) +cellVerilogName(std::string_view sta_name) { return staToVerilog(sta_name); } std::string -instanceVerilogName(std::string sta_name) +instanceVerilogName(std::string_view sta_name) { return staToVerilog(sta_name); } std::string -netVerilogName(std::string sta_name) +netVerilogName(std::string_view sta_name) { bool is_bus; std::string bus_name; @@ -69,13 +69,20 @@ netVerilogName(std::string sta_name) } std::string -portVerilogName(std::string sta_name) +portVerilogName(std::string_view sta_name) { return staToVerilog2(sta_name); } +// functions expect a value representable as unsigned char or EOF. +static bool +isAlnumUnderscore(char ch) +{ + return std::isalnum(static_cast(ch)) != 0 || ch == '_'; +} + static std::string -staToVerilog(std::string sta_name) +staToVerilog(std::string_view sta_name) { // Leave room for leading escape and trailing space if the name // needs to be escaped. @@ -87,14 +94,18 @@ staToVerilog(std::string sta_name) char ch = sta_name[i]; if (ch == verilog_escape) { escaped = true; - char next_ch = sta_name[i + 1]; - if (next_ch == verilog_escape) { - escaped_name += next_ch; - i++; + if (i + 1 < sta_length) { + char next_ch = sta_name[i + 1]; + if (next_ch == verilog_escape) { + escaped_name += next_ch; + i++; + } } + else + escaped_name += ch; } else { - if ((!(isalnum(ch) || ch == '_'))) + if (!isAlnumUnderscore(ch)) escaped = true; escaped_name += ch; } @@ -105,11 +116,11 @@ staToVerilog(std::string sta_name) return escaped_name; } else - return sta_name; + return std::string(sta_name); } static std::string -staToVerilog2(std::string sta_name) +staToVerilog2(std::string_view sta_name) { constexpr char bus_brkt_left = '['; constexpr char bus_brkt_right = ']'; @@ -123,16 +134,19 @@ staToVerilog2(std::string sta_name) char ch = sta_name[i]; if (ch == verilog_escape) { escaped = true; - char next_ch = sta_name[i + 1]; - if (next_ch == verilog_escape) { - escaped_name += next_ch; - i++; + if (i + 1 < sta_length) { + char next_ch = sta_name[i + 1]; + if (next_ch == verilog_escape) { + escaped_name += next_ch; + i++; + } } + else + escaped_name += ch; } else { bool is_brkt = (ch == bus_brkt_left || ch == bus_brkt_right); - if ((!(isalnum(ch) || ch == '_') && !is_brkt) - || is_brkt) + if ((!isAlnumUnderscore(ch) && !is_brkt) || is_brkt) escaped = true; escaped_name += ch; } @@ -143,45 +157,49 @@ staToVerilog2(std::string sta_name) return escaped_name; } else - return sta_name; + return std::string(sta_name); } //////////////////////////////////////////////////////////////// std::string -moduleVerilogToSta(std::string module_name) +moduleVerilogToSta(std::string_view module_name) { return verilogToSta(module_name); } std::string -instanceVerilogToSta(std::string inst_name) +instanceVerilogToSta(std::string_view inst_name) { return verilogToSta(inst_name); } std::string -netVerilogToSta(std::string net_name) +netVerilogToSta(std::string_view net_name) { return verilogToSta(net_name); } std::string -portVerilogToSta(std::string port_name) +portVerilogToSta(std::string_view port_name) { return verilogToSta(port_name); } static std::string -verilogToSta(std::string verilog_name) +verilogToSta(std::string_view verilog_name) { + if (verilog_name.empty()) + return std::string(verilog_name); + if (verilog_name.front() == '\\') { constexpr char divider = '/'; constexpr char bus_brkt_left = '['; constexpr char bus_brkt_right = ']'; size_t verilog_name_length = verilog_name.size(); - if (isspace(verilog_name.back())) + if (verilog_name_length > 1 + && std::isspace(static_cast(verilog_name.back())) != 0) verilog_name_length--; std::string sta_name; // Ignore leading '\'. @@ -198,7 +216,7 @@ verilogToSta(std::string verilog_name) return sta_name; } else - return verilog_name; + return std::string(verilog_name); } } // namespace From 0a8a86d606f7db262b7611823ad1cb757498d5dc Mon Sep 17 00:00:00 2001 From: James Cherry Date: Fri, 10 Apr 2026 14:49:25 -0700 Subject: [PATCH 6/6] FilterObjects use string_view Signed-off-by: James Cherry --- CMakeLists.txt | 3 + include/sta/FilterObjects.hh | 1 + sdc/FilterObjects.cc | 111 +++++++++++++++++++---------------- 3 files changed, 66 insertions(+), 49 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 57d080be..b9308293 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -36,6 +36,9 @@ option(ENABLE_ASAN "Compile with address santizer enabled" OFF) # Turn on to debug compiler args. set(CMAKE_VERBOSE_MAKEFILE OFF) +# Write compile_commands.json to the build directory for clang-tidy. +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + set(STA_HOME ${PROJECT_SOURCE_DIR}) message(STATUS "STA version: ${PROJECT_VERSION}") diff --git a/include/sta/FilterObjects.hh b/include/sta/FilterObjects.hh index 7420b450..dbeec3c5 100644 --- a/include/sta/FilterObjects.hh +++ b/include/sta/FilterObjects.hh @@ -28,6 +28,7 @@ #include #include +#include "NetworkClass.hh" #include "SdcClass.hh" #include "SearchClass.hh" #include "StringUtil.hh" diff --git a/sdc/FilterObjects.cc b/sdc/FilterObjects.cc index 6e263037..45e59997 100644 --- a/sdc/FilterObjects.cc +++ b/sdc/FilterObjects.cc @@ -24,11 +24,17 @@ #include "FilterObjects.hh" -#include -#include #include #include +#include +#include +#include +#include +#include +#include "NetworkClass.hh" +#include "Network.hh" +#include "StringUtil.hh" #include "Property.hh" #include "PatternMatch.hh" #include "Sta.hh" @@ -52,22 +58,27 @@ public: undefined }; - Token(std::string text, + Token(std::string_view text, Kind kind); - - std::string text; - Kind kind; + const std::string &text() const { return text_; } + Kind kind() const { return kind_; } + + std::string text_; + Kind kind_; }; struct PredicateToken : public Token { - PredicateToken(std::string property, - std::string op, - std::string arg); + PredicateToken(std::string_view property, + std::string_view op, + std::string_view arg); + const std::string &property() const { return property_; } + const std::string &op() const { return op_; } + const std::string &arg() const { return arg_; } - std::string property; - std::string op; - std::string arg; + std::string property_; + std::string op_; + std::string arg_; }; FilterExpr(std::string_view expression, @@ -82,19 +93,21 @@ private: Report *report_; }; -FilterExpr::Token::Token(std::string text, +FilterExpr::Token::Token(std::string_view text, Token::Kind kind) : - text (text), - kind(kind) + text_(text), + kind_(kind) { } -FilterExpr::PredicateToken::PredicateToken(std::string property, - std::string op, - std::string arg) : - Token(property + " " + op + " " + arg, +FilterExpr::PredicateToken::PredicateToken(std::string_view property, + std::string_view op, + std::string_view arg) : + Token(sta::format("{} {} {}", property, op, arg), Token::Kind::predicate), - property(property), op(op), arg(arg) + property_(property), + op_(op), + arg_(arg) { } @@ -140,7 +153,7 @@ FilterExpr::lex() std::string property = token_match[1].str(); // The default operation on a predicate if an op and arg are - // omitted is 'prop == 1 || true'. + // omitted is 'prop == 1'. std::string op = "=="; std::string arg = "1"; @@ -175,7 +188,7 @@ FilterExpr::shuntingYard(std::vector> &infix) std::stack> operator_stack; for (auto &token : infix) { - switch (token->kind) { + switch (token->kind()) { case Token::Kind::predicate: output.push_back(std::move(token)); break; @@ -185,7 +198,7 @@ FilterExpr::shuntingYard(std::vector> &infix) // The operators' enum values are ascending by precedence: // inv > and > or while (operator_stack.size() - && operator_stack.top()->kind > token->kind) { + && operator_stack.top()->kind() > token->kind()) { output.push_back(std::move(operator_stack.top())); operator_stack.pop(); } @@ -208,7 +221,7 @@ FilterExpr::shuntingYard(std::vector> &infix) if (operator_stack.empty()) report_->error(2601, "-filter extraneous )."); while (operator_stack.size() - && operator_stack.top()->kind != Token::Kind::op_lparen) { + && operator_stack.top()->kind() != Token::Kind::op_lparen) { output.push_back(std::move(operator_stack.top())); operator_stack.pop(); if (operator_stack.empty()) @@ -224,7 +237,7 @@ FilterExpr::shuntingYard(std::vector> &infix) } while (operator_stack.size()) { - if (operator_stack.top()->kind == Token::Kind::op_lparen) + if (operator_stack.top()->kind() == Token::Kind::op_lparen) report_->error(2603, "-filter unmatched (."); output.push_back(std::move(operator_stack.top())); operator_stack.pop(); @@ -235,20 +248,20 @@ FilterExpr::shuntingYard(std::vector> &infix) //////////////////////////////////////////////////////////////// -template std::set -filterObjects(const char *property, - const char *op, - const char *pattern, +template static std::set +filterObjects(std::string_view property, + std::string_view op, + std::string_view pattern, std::set &all, Sta *sta) { Properties &properties = sta->properties(); Network *network = sta->network(); auto filtered_objects = std::set(); - bool exact_match = stringEq(op, "=="); - bool pattern_match = stringEq(op, "=~"); - bool not_match = stringEq(op, "!="); - bool not_pattern_match = stringEq(op, "!~"); + bool exact_match = (op == "=="); + bool pattern_match = (op == "=~"); + bool not_match = (op == "!="); + bool not_pattern_match = (op == "!~"); for (T *object : all) { PropertyValue value = properties.getProperty(object, property); std::string prop = value.to_string(network); @@ -259,8 +272,8 @@ filterObjects(const char *property, else if (stringEqual(pattern, "false")) pattern = "0"; } - if ((exact_match && stringEq(prop.c_str(), pattern)) - || (not_match && !stringEq(prop.c_str(), pattern)) + if ((exact_match && prop == pattern) + || (not_match && prop != pattern) || (pattern_match && patternMatch(pattern, prop)) || (not_pattern_match && !patternMatch(pattern, prop))) filtered_objects.insert(object); @@ -268,9 +281,9 @@ filterObjects(const char *property, return filtered_objects; } -template std::vector +template static std::vector filterObjects(std::string_view filter_expression, - std::vector *objects, + const std::vector *objects, Sta *sta) { Report *report = sta->report(); @@ -286,7 +299,7 @@ filterObjects(std::string_view filter_expression, auto postfix = filter.postfix(); std::stack> eval_stack; for (auto &token : postfix) { - if (token->kind == FilterExpr::Token::Kind::op_or) { + if (token->kind() == FilterExpr::Token::Kind::op_or) { if (eval_stack.size() < 2) report->error(2604, "-filter logical OR requires at least two operands."); auto arg0 = eval_stack.top(); @@ -298,7 +311,7 @@ filterObjects(std::string_view filter_expression, std::inserter(union_result, union_result.begin())); eval_stack.push(union_result); } - else if (token->kind == FilterExpr::Token::Kind::op_and) { + else if (token->kind() == FilterExpr::Token::Kind::op_and) { if (eval_stack.size() < 2) { report->error(2605, "-filter logical AND requires two operands."); } @@ -313,7 +326,7 @@ filterObjects(std::string_view filter_expression, intersection_result.begin())); eval_stack.push(intersection_result); } - else if (token->kind == FilterExpr::Token::Kind::op_inv) { + else if (token->kind() == FilterExpr::Token::Kind::op_inv) { if (eval_stack.size() < 1) { report->error(2606, "-filter NOT missing operand."); } @@ -327,13 +340,13 @@ filterObjects(std::string_view filter_expression, difference_result.begin())); eval_stack.push(difference_result); } - else if (token->kind == FilterExpr::Token::Kind::defined - || token->kind == FilterExpr::Token::Kind::undefined) { + else if (token->kind() == FilterExpr::Token::Kind::defined + || token->kind() == FilterExpr::Token::Kind::undefined) { bool should_be_defined = - (token->kind == FilterExpr::Token::Kind::defined); + (token->kind() == FilterExpr::Token::Kind::defined); auto result = std::set(); for (auto object : all) { - PropertyValue value = properties.getProperty(object, token->text); + PropertyValue value = properties.getProperty(object, token->text()); bool is_defined = false; switch (value.type()) { case PropertyValue::Type::float_: @@ -377,12 +390,12 @@ filterObjects(std::string_view filter_expression, } eval_stack.push(result); } - else if (token->kind == FilterExpr::Token::Kind::predicate) { + else if (token->kind() == FilterExpr::Token::Kind::predicate) { auto *predicate_token = static_cast(token.get()); - auto result = filterObjects(predicate_token->property.c_str(), - predicate_token->op.c_str(), - predicate_token->arg.c_str(), + auto result = filterObjects(predicate_token->property(), + predicate_token->op(), + predicate_token->arg(), all, sta); eval_stack.push(result); } @@ -495,7 +508,7 @@ filterExprToPostfix(std::string_view expr, auto postfix = filter.postfix(); StringSeq result; for (auto &token : postfix) - result.push_back(token->text); + result.push_back(token->text()); return result; }