Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
8ca7b19
tree: Working on making simfil more exception free
johannes-wolf Sep 14, 2025
d269973
tree: Make division by zero exception free
johannes-wolf Sep 14, 2025
4af0547
model: Remove some model exceptions
johannes-wolf Sep 22, 2025
d373da7
perf: Add some branch hints
johannes-wolf Sep 23, 2025
7d2e54c
perf: Improve result callback performance
johannes-wolf Sep 23, 2025
38a14f8
value: Remove unused getters
johannes-wolf Sep 23, 2025
173a4d2
value: Move ModelNode::Ptr into the Value Variant
johannes-wolf Sep 23, 2025
f4c1579
expr: Support better forwarding of values
johannes-wolf Sep 23, 2025
09df80c
function: Take values by reference
johannes-wolf Sep 25, 2025
92565c2
tests: Add benchmark that calls a function
johannes-wolf Sep 25, 2025
e7f18b0
operator: Use string_view if possible
johannes-wolf Sep 25, 2025
a903a49
model: Remove bad raise
johannes-wolf Sep 25, 2025
2edfd74
Remove std::function from scoped helper
johannes-wolf Sep 25, 2025
95730f2
tree: Forward ignored errors
johannes-wolf Sep 29, 2025
ef9c17d
completion: Fix SEGFAULT
johannes-wolf Oct 6, 2025
6ac2d4c
irange: Fix invalid expected access
johannes-wolf Oct 6, 2025
e6997bf
operator: Fix bitshift operator
johannes-wolf Oct 6, 2025
d659fcc
tests: Add more tests
johannes-wolf Oct 6, 2025
24faaa1
tests: More operator tests
johannes-wolf Oct 6, 2025
056751f
completion: Show a completion hint for ** mode
johannes-wolf Oct 6, 2025
2252b7e
tests: Add ** completion test
johannes-wolf Oct 6, 2025
02a20fa
tests: Add ** completion test
johannes-wolf Oct 6, 2025
faafa15
parser: Make parselets static (stack) objects
johannes-wolf Oct 12, 2025
ffa1793
completion: Generate hints for prepending **.
johannes-wolf Oct 12, 2025
b407a44
completion: Replace copy by const ref
johannes-wolf Oct 12, 2025
ae1a3b1
completion: Provide wildcard hints
johannes-wolf Oct 12, 2025
1277747
completion: Fix recursive field completion
johannes-wolf Oct 19, 2025
69fbd03
tests: Add erro + operator tests
johannes-wolf Oct 19, 2025
7aafd96
tests: Add more completion tests
johannes-wolf Oct 19, 2025
fa2c7b0
cmake: Set C++ standard to 20 for Catch2
johannes-wolf Oct 19, 2025
5ebe148
perf: Replace string concatenation with fmt
johannes-wolf Oct 19, 2025
0c7bb65
expr: Fix some error forwarding
johannes-wolf Oct 24, 2025
f4566b8
expr: Fix function error forwarding, add tests
johannes-wolf Oct 24, 2025
ea1568c
test: Add test cases for simfil::Value
johannes-wolf Oct 26, 2025
95a7fd8
test: Make test macros require semicolon
johannes-wolf Oct 26, 2025
6dc842c
test: Test range error forwarding
johannes-wolf Oct 26, 2025
1bebe28
sonar: Add sonar-project settings file
johannes-wolf Oct 26, 2025
a6bba7b
tree: Fix some SonarQube findings
johannes-wolf Oct 26, 2025
0977c1f
function: Fix error forwarding + panic tests
johannes-wolf Oct 26, 2025
e39cb9d
expr: Fix error forwarding for AnyChild expr
johannes-wolf Oct 26, 2025
62600be
value: Add ModelNode::Ptr visitor to getScalar
johannes-wolf Oct 26, 2025
78dc756
ci: Ignore low line coverage for now
johannes-wolf Oct 27, 2025
1d2ddae
util: Fix null-function call
johannes-wolf Oct 27, 2025
06fb09a
value: Fix field constructor with string_view
johannes-wolf Oct 27, 2025
8d8f561
model: Fix addFieldInternal return value
johannes-wolf Oct 27, 2025
fc76ae9
cursor: Fix false-positive shadowing bug warning
johannes-wolf Oct 27, 2025
d1e076c
ci: GCOVR ignore TRY_EXPECTED macro
johannes-wolf Oct 29, 2025
f597714
test: Add more unit-tests
johannes-wolf Oct 29, 2025
8518dae
completion: Require single expression
johannes-wolf Oct 30, 2025
90615c1
diagnostics: Remove “did you mean?” Diagnostics
johannes-wolf Oct 30, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .github/workflows/coverage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,10 @@ jobs:
run: |
mkdir coverage
gcovr --html-details coverage/coverage.html \
--exclude-lines-by-pattern 'TRY_EXPECTED' \
--filter src/ --filter include/
gcovr --cobertura coverage.xml \
--exclude-lines-by-pattern 'TRY_EXPECTED' \
--html coverage.html \
--filter src/ --filter include/
less coverage.xml
Expand All @@ -63,7 +65,7 @@ jobs:
with:
filename: coverage.xml
badge: false
fail_below_min: true
fail_below_min: false
format: markdown
hide_branch_rate: false
hide_complexity: true
Expand Down
2 changes: 0 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,8 +101,6 @@ The query language can be extended by additional functions and addititonal types

## Diagnostics
Simfil can output query diagnostics messages that can include a fixed query string.
Currently, it supports the following types of messages:
- "No matches for field '...'. Did you mean '...'?"

## Using the Library
### CMake FetchContent
Expand Down
8 changes: 7 additions & 1 deletion examples/minimal/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,13 @@ int main()
}

// Evalualte query and get result of type simfil::Value.
auto result = simfil::eval(env, **ast, *model->root(0), nullptr);
auto root = model->root(0);
if (!root) {
std::cerr << root.error().message << '\n';
return -1;
}

auto result = simfil::eval(env, **ast, **root, nullptr);
if (!result) {
std::cerr << result.error().message << '\n';
return -1;
Expand Down
5 changes: 3 additions & 2 deletions include/simfil/environment.h
Original file line number Diff line number Diff line change
Expand Up @@ -175,8 +175,8 @@ struct Debug
*/
struct CompletionOptions
{
// Auto insert a wildcard if the first token is a field name.
bool autoWildcard = false;
// Show hints about completing certain queries to a wildcard query.
bool showWildcardHints = true;

// Limit of candidates.
size_t limit = 15;
Expand All @@ -200,6 +200,7 @@ struct CompletionCandidate
CONSTANT = 1,
FIELD = 2,
FUNCTION = 3,
HINT = 4,
};

std::string text; // Text to insert
Expand Down
22 changes: 22 additions & 0 deletions include/simfil/error.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,41 @@ struct Token;
struct Error
{
enum Type {
// Parser Errors
ParserError,
InvalidType,
InvalidExpression,
ExpectedEOF,
NullModel,
IOError,

// Evaluation errors
DivisionByZero,
UnknownFunction,
RuntimeError,
InternalError,
InvalidOperator,
InvalidOperands,
InvalidArguments,
ExpectedSingleValue,
TypeMissmatch,

// Model related runtime errors
StringPoolOverflow,
EncodeDecodeError,
FieldNotFound,
IndexOutOfRange,

Unimplemented,
};

explicit Error(Type type);
Error(Type type, std::string message);
Error(Type type, std::string message, SourceLocation location);
Error(Type type, std::string message, const Token& token);

auto operator==(const Error& o) const -> bool = default;

Type type;
SourceLocation location;
std::string message;
Expand Down
2 changes: 2 additions & 0 deletions include/simfil/exception-handler.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ class ThrowHandler
template<typename ExceptionType, typename... Args>
[[noreturn]] void raise(Args&&... args)
{
// GCOVR_EXCL_START
ExceptionType exceptionInstance(std::forward<Args>(args)...);

if (auto const& excHandler = ThrowHandler::instance().get()) {
Expand All @@ -55,6 +56,7 @@ template<typename ExceptionType, typename... Args>
errorMessage = exceptionInstance.what();
excHandler(typeName, errorMessage);
}
// GCOVR_EXCL_STOP

throw std::move(exceptionInstance);
}
Expand Down
41 changes: 32 additions & 9 deletions include/simfil/expression.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,17 +50,35 @@ class Expr
/* Debug */
virtual auto toString() const -> std::string = 0;

/* Evaluation wrapper */
auto eval(Context ctx, Value val, const ResultFn& res) -> Result
auto eval(Context ctx, const Value& val, const ResultFn& res) -> tl::expected<Result, Error>
{
if (ctx.canceled())
return Result::Stop;

auto dbg = ctx.env->debug;
if (dbg) dbg->evalBegin(*this, ctx, val, res);
auto r = ieval(ctx, val, res);
if (dbg) dbg->evalEnd(*this);
return r;
if (auto dbg = ctx.env->debug) [[unlikely]] {
auto dbgVal = Value{val};
dbg->evalBegin(*this, ctx, dbgVal, res);
auto r = ieval(ctx, std::move(dbgVal), res);
dbg->evalEnd(*this);
return r;
}

return ieval(ctx, val, res);
}

auto eval(Context ctx, Value&& val, const ResultFn& res) -> tl::expected<Result, Error>
{
if (ctx.canceled())
return Result::Stop;

if (auto dbg = ctx.env->debug) [[unlikely]] {
dbg->evalBegin(*this, ctx, val, res);
auto r = ieval(ctx, std::move(val), res);
dbg->evalEnd(*this);
return r;
}

return ieval(ctx, std::move(val), res);
}

/* Recursive clone */
Expand All @@ -79,7 +97,12 @@ class Expr

private:
/* Abstract evaluation implementation */
virtual auto ieval(Context ctx, const Value& value, const ResultFn& result) -> Result = 0;
virtual auto ieval(Context ctx, const Value& value, const ResultFn& result) -> tl::expected<Result, Error> = 0;

/* Move-optimized evaluation implementation */
virtual auto ieval(Context ctx, Value&& value, const ResultFn& result) -> tl::expected<Result, Error> {
return ieval(ctx, value, result);
}

SourceLocation sourceLocation_;
};
Expand Down Expand Up @@ -110,7 +133,7 @@ class AST
/* The original query string of the AST */
std::string queryString_;

/* The actuall AST */
/* The actual AST */
ExprPtr expr_;
};

Expand Down
67 changes: 12 additions & 55 deletions include/simfil/function.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,49 +14,6 @@ namespace simfil
{
struct Context;

struct ArgumentCountError : std::exception
{
const Function* fn;
size_t min;
size_t max;
size_t have;

ArgumentCountError(const Function& fn, size_t min, size_t max, size_t have)
: fn(&fn), min(min), max(max), have(have)
{}

mutable std::string msg;
auto what() const noexcept -> const char* override;
};

struct ArgumentTypeError : std::exception
{
const Function* fn;
size_t index;
std::string want;
std::string have;

ArgumentTypeError(const Function& fn, size_t index, std::string want, std::string have)
: fn(&fn), index(index), want(std::move(want)), have(std::move(have))
{}

mutable std::string msg;
auto what() const noexcept -> const char* override;
};

struct ArgumentValueCountError : std::exception
{
const Function* fn;
size_t index;

ArgumentValueCountError(const Function& fn, size_t index)
: fn(&fn), index(index)
{}

mutable std::string msg;
auto what() const noexcept -> const char* override;
};

/**
* Function info.
*/
Expand All @@ -76,7 +33,7 @@ class Function
virtual ~Function() = default;

virtual auto ident() const -> const FnInfo& = 0;
virtual auto eval(Context, Value, const std::vector<ExprPtr>&, const ResultFn&) const -> Result = 0;
virtual auto eval(Context, const Value&, const std::vector<ExprPtr>&, const ResultFn&) const -> tl::expected<Result, Error> = 0;
};

class CountFn : public Function
Expand All @@ -87,7 +44,7 @@ class CountFn : public Function
CountFn();

auto ident() const -> const FnInfo& override;
auto eval(Context, Value, const std::vector<ExprPtr>&, const ResultFn&) const -> Result override;
auto eval(Context, const Value&, const std::vector<ExprPtr>&, const ResultFn&) const -> tl::expected<Result, Error> override;
};

class TraceFn : public Function
Expand All @@ -98,7 +55,7 @@ class TraceFn : public Function
TraceFn();

auto ident() const -> const FnInfo& override;
auto eval(Context, Value, const std::vector<ExprPtr>&, const ResultFn&) const -> Result override;
auto eval(Context, const Value&, const std::vector<ExprPtr>&, const ResultFn&) const -> tl::expected<Result, Error> override;
};

class RangeFn : public Function
Expand All @@ -109,7 +66,7 @@ class RangeFn : public Function
RangeFn();

auto ident() const -> const FnInfo& override;
auto eval(Context, Value, const std::vector<ExprPtr>&, const ResultFn&) const -> Result override;
auto eval(Context, const Value&, const std::vector<ExprPtr>&, const ResultFn&) const -> tl::expected<Result, Error> override;
};

class ReFn : public Function
Expand All @@ -120,7 +77,7 @@ class ReFn : public Function
ReFn();

auto ident() const -> const FnInfo& override;
auto eval(Context, Value, const std::vector<ExprPtr>&, const ResultFn&) const -> Result override;
auto eval(Context, const Value&, const std::vector<ExprPtr>&, const ResultFn&) const -> tl::expected<Result, Error> override;
};

class ArrFn : public Function
Expand All @@ -131,7 +88,7 @@ class ArrFn : public Function
ArrFn();

auto ident() const -> const FnInfo& override;
auto eval(Context, Value, const std::vector<ExprPtr>&, const ResultFn&) const -> Result override;
auto eval(Context, const Value&, const std::vector<ExprPtr>&, const ResultFn&) const -> tl::expected<Result, Error> override;
};

class SplitFn : public Function
Expand All @@ -142,7 +99,7 @@ class SplitFn : public Function
SplitFn();

auto ident() const -> const FnInfo& override;
auto eval(Context, Value, const std::vector<ExprPtr>&, const ResultFn&) const -> Result override;
auto eval(Context, const Value&, const std::vector<ExprPtr>&, const ResultFn&) const -> tl::expected<Result, Error> override;
};

class SelectFn : public Function
Expand All @@ -153,7 +110,7 @@ class SelectFn : public Function
SelectFn();

auto ident() const -> const FnInfo& override;
auto eval(Context, Value, const std::vector<ExprPtr>&, const ResultFn&) const -> Result override;
auto eval(Context, const Value&, const std::vector<ExprPtr>&, const ResultFn&) const -> tl::expected<Result, Error> override;
};

class SumFn : public Function
Expand All @@ -164,7 +121,7 @@ class SumFn : public Function
SumFn();

auto ident() const -> const FnInfo& override;
auto eval(Context, Value, const std::vector<ExprPtr>&, const ResultFn&) const -> Result override;
auto eval(Context, const Value&, const std::vector<ExprPtr>&, const ResultFn&) const -> tl::expected<Result, Error> override;
};

class KeysFn : public Function
Expand All @@ -175,14 +132,14 @@ class KeysFn : public Function
KeysFn();

auto ident() const -> const FnInfo& override;
auto eval(Context, Value, const std::vector<ExprPtr>&, const ResultFn&) const -> Result override;
auto eval(Context, const Value&, const std::vector<ExprPtr>&, const ResultFn&) const -> tl::expected<Result, Error> override;
};

/** Utility functions for working with arguments*/
namespace util
{

inline auto evalArg1Any(Context ctx, Value val, const ExprPtr& expr) -> std::tuple<bool, Value>
inline auto evalArg1Any(Context ctx, const Value& val, const ExprPtr& expr) -> std::tuple<bool, Value>
{
if (!expr)
return {false, Value::undef()};
Expand All @@ -198,7 +155,7 @@ inline auto evalArg1Any(Context ctx, Value val, const ExprPtr& expr) -> std::tup
}

template <class CType>
auto evalArg1(Context ctx, Value val, const ExprPtr& expr, CType fallback = {}) -> std::tuple<bool, CType>
auto evalArg1(Context ctx, const Value& val, const ExprPtr& expr, CType fallback = {}) -> std::tuple<bool, CType>
{
auto&& [ok, value] = evalArg1Any(ctx, val, expr);
if (ok)
Expand Down
Loading
Loading