Skip to content

Commit

Permalink
feat: covering more errors (#165)
Browse files Browse the repository at this point in the history
  • Loading branch information
zaucy authored Apr 22, 2023
1 parent 4036bdd commit 4f78e3e
Show file tree
Hide file tree
Showing 17 changed files with 364 additions and 70 deletions.
18 changes: 18 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,24 @@
"E:/.cache/bazel/output_base/execroot/ecsact_interpret": "${workspaceFolder}"
}
},
{
"name": "test //test/extra:extra",
"request": "launch",
"program": "${workspaceRoot}/bazel-bin/test/extra/extra",
"cwd": "${workspaceFolder}",
"type": "lldb",
"windows": {
"type": "cppvsdbg",
"program": "${workspaceRoot}/bazel-bin/test/extra/extra.exe"
},
"args": [
"--gtest_break_on_failure"
],
"preLaunchTask": "build //test/extra:extra",
"sourceMap": {
"E:/.cache/bazel/output_base/execroot/ecsact_interpret": "${workspaceFolder}"
}
},
{
"name": "test //test/errors:no_capabilities",
"request": "launch",
Expand Down
10 changes: 10 additions & 0 deletions .vscode/tasks.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,16 @@
],
"group": "build"
},
{
"label": "build //test/extra:extra",
"command": "bazel",
"type": "shell",
"args": [
"build",
"//test/extra:extra"
],
"group": "build"
},
{
"label": "build //test/errors:no_capabilities",
"command": "bazel",
Expand Down
2 changes: 1 addition & 1 deletion cli/ecsact_interpreter_cli.cc
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ int main() {
<< ecsact::meta::package_name(*current_package)
<< COLOR_GREY " ]\n" COLOR_RESET;
} else if(last_statement.type == ECSACT_STATEMENT_UNKNOWN) {
std::string err_highlight;
auto err_highlight = std::string{};
err_highlight.reserve(last_source.size() + 3);
err_highlight += " ";
for(auto c : last_source) {
Expand Down
13 changes: 12 additions & 1 deletion ecsact/interpret/detail/eval_parse.hh
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,12 @@
#include "./string_util.hh"
#include "./read_util.hh"

template<>
struct magic_enum::customize::enum_range<ecsact_eval_error_code> {
static constexpr int min = 0;
static constexpr int max = 2000;
};

namespace ecsact::detail {

constexpr std::array statement_ending_chars{';', '{', '}', '\n'};
Expand Down Expand Up @@ -189,7 +195,12 @@ parse_eval_error to_parse_eval_error(
std::string err_code_str;
switch(eval_err.code) {
default:
err_code_str = magic_enum::enum_name(eval_err.code).substr(16);
err_code_str = magic_enum::enum_name(eval_err.code);
if(!err_code_str.empty()) {
err_code_str = magic_enum::enum_name(eval_err.code).substr(16);
} else {
assert(false && "Magic Enum failed to get error name");
}
break;
}

Expand Down
172 changes: 111 additions & 61 deletions ecsact/interpret/eval.cc
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,46 @@

using namespace std::string_literals;

static auto expect_context(
std::span<const ecsact_statement>& context_stack,
std::vector<ecsact_statement_type> context_types
) -> std::tuple<const ecsact_statement*, ecsact_eval_error> {
if(context_stack.empty()) {
for(auto context_type : context_types) {
if(context_type == ECSACT_STATEMENT_NONE) {
return {nullptr, ecsact_eval_error{}};
}
}
}

if(context_stack.empty()) {
return {
nullptr,
ecsact_eval_error{
.code = ECSACT_EVAL_ERR_INVALID_CONTEXT,
.relevant_content = {},
.context_type = ECSACT_STATEMENT_NONE,
},
};
}

auto& context = context_stack.back();
for(auto context_type : context_types) {
if(context.type == context_type) {
return {&context, ecsact_eval_error{}};
}
}

return {
&context,
ecsact_eval_error{
.code = ECSACT_EVAL_ERR_INVALID_CONTEXT,
.relevant_content = {},
.context_type = context.type,
},
};
}

std::optional<ecsact_field_id> find_field_by_name(
ecsact_composite_id compo_id,
std::string_view target_field_name
Expand Down Expand Up @@ -404,8 +444,16 @@ static ecsact_eval_error eval_import_statement(
const ecsact_statement& statement
) {
auto& data = statement.data.import_statement;
auto import_name =
std::string(data.import_package_name.data, data.import_package_name.length);
auto [context, err] = expect_context(context_stack, {ECSACT_STATEMENT_NONE});
if(err.code != ECSACT_EVAL_OK) {
err.relevant_content = data.import_package_name;
return err;
}

auto import_name = std::string{
data.import_package_name.data,
static_cast<size_t>(data.import_package_name.length),
};

for(auto dep_pkg_id : ecsact::meta::get_package_ids()) {
if(dep_pkg_id == package_id) {
Expand All @@ -428,14 +476,13 @@ static ecsact_eval_error eval_component_statement(
std::span<const ecsact_statement>& context_stack,
const ecsact_statement& statement
) {
if(!context_stack.empty()) {
return ecsact_eval_error{
.code = ECSACT_EVAL_ERR_INVALID_CONTEXT,
.relevant_content = {},
};
auto& data = statement.data.component_statement;
auto [context, err] = expect_context(context_stack, {ECSACT_STATEMENT_NONE});
if(err.code != ECSACT_EVAL_OK) {
err.relevant_content = data.component_name;
return err;
}

auto& data = statement.data.component_statement;
auto name = std::string(data.component_name.data, data.component_name.length);

auto existing_decl = find_by_name<ecsact_decl_id>(package_id, name);
Expand All @@ -460,16 +507,14 @@ static ecsact_eval_error eval_transient_statement(
std::span<const ecsact_statement>& context_stack,
const ecsact_statement& statement
) {
if(!context_stack.empty()) {
return ecsact_eval_error{
.code = ECSACT_EVAL_ERR_INVALID_CONTEXT,
.relevant_content = {},
};
auto& data = statement.data.transient_statement;
auto [context, err] = expect_context(context_stack, {ECSACT_STATEMENT_NONE});
if(err.code != ECSACT_EVAL_OK) {
err.relevant_content = data.transient_name;
return err;
}

auto& data = statement.data.transient_statement;
auto name = std::string(data.transient_name.data, data.transient_name.length);

auto existing_decl = find_by_name<ecsact_decl_id>(package_id, name);
if(existing_decl) {
return ecsact_eval_error{
Expand All @@ -492,12 +537,25 @@ static ecsact_eval_error eval_system_statement(
std::span<const ecsact_statement>& context_stack,
const ecsact_statement& statement
) {
std::optional<ecsact_system_like_id> parent_sys_like_id{};
if(!context_stack.empty()) {
parent_sys_like_id = find_by_statement<ecsact_system_like_id>(
package_id,
context_stack.back()
);
auto& data = statement.data.system_statement;
auto parent_sys_like_id = std::optional<ecsact_system_like_id>{};
auto [context, err] = expect_context(
context_stack,
{
ECSACT_STATEMENT_NONE,
ECSACT_STATEMENT_SYSTEM,
ECSACT_STATEMENT_ACTION,
}
);

if(err.code != ECSACT_EVAL_OK) {
err.relevant_content = data.system_name;
return err;
}

if(context != nullptr) {
parent_sys_like_id =
find_by_statement<ecsact_system_like_id>(package_id, *context);
if(!parent_sys_like_id) {
return ecsact_eval_error{
.code = ECSACT_EVAL_ERR_INVALID_CONTEXT,
Expand All @@ -506,8 +564,7 @@ static ecsact_eval_error eval_system_statement(
}
}

auto& data = statement.data.system_statement;
auto name = std::string(data.system_name.data, data.system_name.length);
auto name = std::string(data.system_name.data, data.system_name.length);

auto existing_decl = find_by_name<ecsact_decl_id>(package_id, name);
if(existing_decl) {
Expand Down Expand Up @@ -535,15 +592,14 @@ static ecsact_eval_error eval_action_statement(
std::span<const ecsact_statement>& context_stack,
const ecsact_statement& statement
) {
if(!context_stack.empty()) {
return ecsact_eval_error{
.code = ECSACT_EVAL_ERR_INVALID_CONTEXT,
.relevant_content = {},
};
auto& data = statement.data.action_statement;
auto [context, err] = expect_context(context_stack, {ECSACT_STATEMENT_NONE});
if(err.code != ECSACT_EVAL_OK) {
err.relevant_content = data.action_name;
return err;
}

auto& data = statement.data.action_statement;
auto name = std::string(data.action_name.data, data.action_name.length);
auto name = std::string(data.action_name.data, data.action_name.length);

auto existing_decl = find_by_name<ecsact_decl_id>(package_id, name);
if(existing_decl) {
Expand All @@ -567,15 +623,14 @@ static ecsact_eval_error eval_enum_statement(
std::span<const ecsact_statement>& context_stack,
const ecsact_statement& statement
) {
if(!context_stack.empty()) {
return ecsact_eval_error{
.code = ECSACT_EVAL_ERR_INVALID_CONTEXT,
.relevant_content = {},
};
auto& data = statement.data.enum_statement;
auto [context, err] = expect_context(context_stack, {ECSACT_STATEMENT_NONE});
if(err.code != ECSACT_EVAL_OK) {
err.relevant_content = data.enum_name;
return err;
}

auto& data = statement.data.enum_statement;
auto name = std::string(data.enum_name.data, data.enum_name.length);
auto name = std::string(data.enum_name.data, data.enum_name.length);

auto existing_decl = find_by_name<ecsact_decl_id>(package_id, name);
if(existing_decl) {
Expand All @@ -596,22 +651,13 @@ static ecsact_eval_error eval_enum_value_statement(
const ecsact_statement& statement
) {
auto& data = statement.data.enum_value_statement;

if(context_stack.empty()) {
return ecsact_eval_error{
.code = ECSACT_EVAL_ERR_INVALID_CONTEXT,
.relevant_content = data.name,
};
}

if(context_stack.back().type != ECSACT_STATEMENT_ENUM) {
return ecsact_eval_error{
.code = ECSACT_EVAL_ERR_INVALID_CONTEXT,
.relevant_content = data.name,
};
auto [context, err] = expect_context(context_stack, {ECSACT_STATEMENT_ENUM});
if(err.code != ECSACT_EVAL_OK) {
err.relevant_content = data.name;
return err;
}

auto& context_data = context_stack.back().data.enum_statement;
auto& context_data = context->data.enum_statement;
auto enum_name =
std::string(context_data.enum_name.data, context_data.enum_name.length);

Expand All @@ -634,16 +680,20 @@ static ecsact_eval_error eval_builtin_type_field_statement(
const ecsact_statement& statement
) {
auto& data = statement.data.field_statement;

if(context_stack.empty()) {
return ecsact_eval_error{
.code = ECSACT_EVAL_ERR_INVALID_CONTEXT,
.relevant_content = {},
};
auto [context, err] = expect_context(
context_stack,
{
ECSACT_STATEMENT_COMPONENT,
ECSACT_STATEMENT_TRANSIENT,
ECSACT_STATEMENT_ACTION,
}
);
if(err.code != ECSACT_EVAL_OK) {
err.relevant_content = data.field_name;
return err;
}

auto compo_id =
find_by_statement<ecsact_composite_id>(package_id, context_stack.back());
auto compo_id = find_by_statement<ecsact_composite_id>(package_id, *context);
if(!compo_id) {
return ecsact_eval_error{
.code = ECSACT_EVAL_ERR_INVALID_CONTEXT,
Expand Down Expand Up @@ -812,7 +862,7 @@ static ecsact_eval_error eval_system_component_statement(

if(!assoc_comp_field) {
return ecsact_eval_error{
.code = ECSACT_EVAL_ERR_INVALID_CONTEXT,
.code = ECSACT_EVAL_ERR_UNKNOWN_FIELD_NAME,
.relevant_content = data.with_entity_field_name,
};
}
Expand Down Expand Up @@ -1004,7 +1054,7 @@ static ecsact_eval_error eval_system_with_entity_statement(
data.with_entity_field_name.length
);

std::optional<ecsact_field_id> entity_field_id{};
auto entity_field_id = std::optional<ecsact_field_id>{};
for(auto field_id : ecsact::meta::get_field_ids(*comp_like_id)) {
std::string field_name = ecsact_meta_field_name(
ecsact_id_cast<ecsact_composite_id>(*comp_like_id),
Expand Down
1 change: 1 addition & 0 deletions ecsact/interpret/eval.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
typedef struct ecsact_eval_error {
ecsact_eval_error_code code;
ecsact_statement_sv relevant_content;
ecsact_statement_type context_type;
} ecsact_eval_error;

ecsact_package_id ecsact_eval_package_statement(
Expand Down
7 changes: 5 additions & 2 deletions ecsact/interpret/eval_error.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,18 +50,21 @@ typedef enum ecsact_eval_error_code {
/// The given statement was not expected in the given context.
ECSACT_EVAL_ERR_UNEXPECTED_STATEMENT,

/// The given field name was not found
ECSACT_EVAL_ERR_UNKNOWN_FIELD_NAME,

/// Not an error code. Start of file only errors.
/// File error codes only applies when parsing complete Ecsact files or
/// buffers. Individual evaluations do not have conceptual endings of
/// statements.
ECSACT_EVAL_BEGIN_ERR_FILE_ONLY,
ECSACT_EVAL_BEGIN_ERR_FILE_ONLY = 1000,

/// System or action has no capabilities.
ECSACT_EVAL_ERR_NO_CAPABILITIES,

/// Not an error code. End of file only errors.
/// SEE: ECSACT_EVAL_BEGIN_ERR_FILE_ONLY,
ECSACT_EVAL_END_ERR_FILE_ONLY,
ECSACT_EVAL_END_ERR_FILE_ONLY = 2000,
} ecsact_eval_error_code;

#endif // ECSACT_EVAL_ERROR_H
2 changes: 2 additions & 0 deletions test/errors/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@ load("//bazel:copts.bzl", "copts")
_TESTS = [
"no_capabilities",
"no_package_statement_first",
"unknown_association_field",
]

[cc_test(
name = test,
srcs = ["{}.cc".format(test)],
copts = copts,
data = ["{}.ecsact".format(test)],
args = ["--gtest_catch_exceptions=0"],
deps = [
"//test:test_lib",
"@com_google_googletest//:gtest",
Expand Down
Loading

0 comments on commit 4f78e3e

Please sign in to comment.