Skip to content

Commit

Permalink
feat: interpret import statements (#159)
Browse files Browse the repository at this point in the history
  • Loading branch information
zaucy authored Mar 8, 2023
1 parent c9d47dc commit da2e08e
Show file tree
Hide file tree
Showing 12 changed files with 223 additions and 19 deletions.
30 changes: 30 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,24 @@
},
"preLaunchTask": "build //test:test",
},
{
"name": "test //test:multi_pkg",
"request": "launch",
"program": "${workspaceRoot}/bazel-bin/test/multi_pkg",
"cwd": "${workspaceFolder}",
"type": "lldb",
"windows": {
"type": "cppvsdbg",
"program": "${workspaceRoot}/bazel-bin/test/multi_pkg.exe"
},
"args": [
"--gtest_break_on_failure"
],
"preLaunchTask": "build //test:multi_pkg",
"sourceMap": {
"E:/.cache/bazel/output_base/execroot/ecsact_interpret": "${workspaceFolder}"
}
},
{
"name": "test //test/errors:no_capabilities",
"request": "launch",
Expand All @@ -25,6 +43,18 @@
},
"preLaunchTask": "build //test/errors:no_capabilities",
},
{
"name": "test //test:comment_before_package",
"request": "launch",
"program": "${workspaceRoot}/bazel-bin/test/comment_before_package",
"cwd": "${workspaceFolder}",
"type": "lldb",
"windows": {
"type": "cppvsdbg",
"program": "${workspaceRoot}/bazel-bin/test/comment_before_package.exe"
},
"preLaunchTask": "build //test:comment_before_package",
},
{
"name": "run //cli:ecsact_interpreter",
"request": "launch",
Expand Down
20 changes: 20 additions & 0 deletions .vscode/tasks.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,16 @@
],
"group": "build"
},
{
"label": "build //test:multi_pkg",
"command": "bazel",
"type": "shell",
"args": [
"build",
"//test:multi_pkg"
],
"group": "build"
},
{
"label": "build //test/errors:no_capabilities",
"command": "bazel",
Expand All @@ -31,6 +41,16 @@
],
"group": "build"
},
{
"label": "build //test:comment_before_package",
"command": "bazel",
"type": "shell",
"args": [
"build",
"//test:comment_before_package"
],
"group": "build"
},
{
"label": "build //cli:ecsact_interpreter",
"command": "bazel",
Expand Down
25 changes: 19 additions & 6 deletions ecsact/interpret/detail/eval_parse.hh
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <array>
#include <unordered_set>
#include <cassert>
#include <iostream> // TODO(ZAUCY): Remove this
#include "magic_enum.hpp"
#include "ecsact/runtime/dynamic.h"
#include "ecsact/runtime/meta.hh"
Expand Down Expand Up @@ -214,7 +215,7 @@ void parse_package_statements(
) {
auto source_index = 0;
for(auto& state : file_states) {
for(;;) {
while(state.reader.can_read_next()) {
state.reader.read_next();

if(ecsact_is_error_parse_status_code(state.reader.status.code)) {
Expand All @@ -225,6 +226,7 @@ void parse_package_statements(
auto& statement = state.reader.statements.top();

if(statement.type == ECSACT_STATEMENT_NONE) {
state.reader.pump_status_code();
continue;
}

Expand Down Expand Up @@ -260,13 +262,17 @@ void parse_imports(
) {
auto source_index = 0;
for(auto& state : file_states) {
for(;;) {
while(state.reader.can_read_next()) {
state.reader.read_next();

if(ecsact_is_error_parse_status_code(state.reader.status.code)) {
out_errors.push_back(to_parse_eval_error(source_index, state.reader));
} else {
ecsact_statement& statement = state.reader.statements.top();
if(statement.type == ECSACT_STATEMENT_NONE) {
state.reader.pump_status_code();
continue;
}
if(statement.type != ECSACT_STATEMENT_IMPORT) {
state.reader.pop_rewind();
break;
Expand Down Expand Up @@ -444,16 +450,22 @@ void parse_eval_declarations(
}

template<typename InputStream>
std::vector<std::reference_wrapper<eval_parse_state<InputStream>>>
get_sorted_states(std::vector<eval_parse_state<InputStream>>& file_states) {
std::vector<std::reference_wrapper<eval_parse_state<InputStream>>> result;
inline auto get_sorted_states(
std::vector<eval_parse_state<InputStream>>& file_states
) -> std::vector<std::reference_wrapper<eval_parse_state<InputStream>>> {
auto result =
std::vector<std::reference_wrapper<eval_parse_state<InputStream>>>{};
result.reserve(file_states.size());

std::unordered_set<std::string> resolved_packages;
auto resolved_packages = std::unordered_set<std::string>{};
resolved_packages.reserve(file_states.size());

while(resolved_packages.size() != file_states.size()) {
for(auto& state : file_states) {
if(resolved_packages.contains(state.package_name)) {
continue;
}

bool imports_resolved = true;
for(auto import_name : state.imports) {
if(!resolved_packages.contains(import_name)) {
Expand All @@ -465,6 +477,7 @@ get_sorted_states(std::vector<eval_parse_state<InputStream>>& file_states) {
if(imports_resolved) {
resolved_packages.insert(state.package_name);
result.push_back(std::ref(state));
break;
}
}
}
Expand Down
78 changes: 65 additions & 13 deletions ecsact/interpret/eval.cc
Original file line number Diff line number Diff line change
Expand Up @@ -98,28 +98,64 @@ std::optional<T> find_by_statement(
template<>
std::optional<ecsact_component_id> find_by_name(
ecsact_package_id package_id,
const std::string& name
const std::string& lookup_name
) {
auto pkg_name = ecsact::meta::package_name(package_id);
for(auto id : ecsact::meta::get_component_ids(package_id)) {
if(name == ecsact::meta::component_name(id)) {
auto comp_name = ecsact::meta::component_name(id);
if(lookup_name == comp_name) {
return id;
}

if(lookup_name == pkg_name + "." + comp_name) {
return id;
}
}

for(auto dep_pkg_id : ecsact::meta::get_dependencies(package_id)) {
auto dep_pkg_name = ecsact::meta::package_name(dep_pkg_id);

for(auto id : ecsact::meta::get_component_ids(dep_pkg_id)) {
auto comp_name = ecsact::meta::component_name(id);

if(lookup_name == dep_pkg_name + "." + comp_name) {
return id;
}
}
}

return {};
}

template<>
std::optional<ecsact_transient_id> find_by_name(
ecsact_package_id package_id,
const std::string& name
const std::string& lookup_name
) {
auto pkg_name = ecsact::meta::package_name(package_id);
for(auto id : ecsact::meta::get_transient_ids(package_id)) {
if(name == ecsact::meta::transient_name(id)) {
auto trans_name = ecsact::meta::transient_name(id);
if(lookup_name == trans_name) {
return id;
}

if(lookup_name == pkg_name + "." + trans_name) {
return id;
}
}

for(auto dep_pkg_id : ecsact::meta::get_dependencies(package_id)) {
auto dep_pkg_name = ecsact::meta::package_name(dep_pkg_id);

for(auto id : ecsact::meta::get_transient_ids(dep_pkg_id)) {
auto trans_name = ecsact::meta::transient_name(id);

if(lookup_name == dep_pkg_name + "." + trans_name) {
return id;
}
}
}

return {};
}

Expand Down Expand Up @@ -154,14 +190,32 @@ std::optional<ecsact_action_id> find_by_name(
template<>
std::optional<ecsact_enum_id> find_by_name(
ecsact_package_id package_id,
const std::string& name
const std::string& lookup_name
) {
auto pkg_name = ecsact::meta::package_name(package_id);
for(auto id : ecsact::meta::get_enum_ids(package_id)) {
if(name == ecsact::meta::enum_name(id)) {
auto enum_name = ecsact::meta::enum_name(id);
if(lookup_name == enum_name) {
return id;
}

if(lookup_name == pkg_name + "." + enum_name) {
return id;
}
}

for(auto dep_pkg_id : ecsact::meta::get_dependencies(package_id)) {
auto dep_pkg_name = ecsact::meta::package_name(dep_pkg_id);

for(auto id : ecsact::meta::get_enum_ids(dep_pkg_id)) {
auto enum_name = ecsact::meta::enum_name(id);

if(lookup_name == dep_pkg_name + "." + enum_name) {
return id;
}
}
}

return {};
}

Expand Down Expand Up @@ -349,18 +403,16 @@ static ecsact_eval_error eval_import_statement(
std::span<const ecsact_statement>& context_stack,
const ecsact_statement& statement
) {
auto& data = statement.data.import_statement;
std::string import_name(
data.import_package_name.data,
data.import_package_name.length
);
auto& data = statement.data.import_statement;
auto import_name =
std::string(data.import_package_name.data, data.import_package_name.length);

for(auto dep_pkg_id : ecsact::meta::get_package_ids()) {
if(dep_pkg_id == package_id) {
continue;
}
if(ecsact::meta::package_name(dep_pkg_id) == import_name) {
// TODO(zaucy): Import support
// ecsact_add_dependency(package_id, dep_pkg_id);
ecsact_add_dependency(package_id, dep_pkg_id);
return {};
}
}
Expand Down
1 change: 1 addition & 0 deletions ecsact/interpret/eval_files.cc
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ std::vector<parse_eval_error> ecsact::eval_files(std::vector<fs::path> files) {
auto source_index = 0;
for(auto& file_state_ref : sorted_file_states) {
auto& file_state = file_state_ref.get();

eval_imports(source_index, file_state, errors);
if(!errors.empty()) {
return errors;
Expand Down
10 changes: 10 additions & 0 deletions parse-resolver-runtime/parse-resolver-runtime.cc
Original file line number Diff line number Diff line change
Expand Up @@ -881,6 +881,16 @@ void ecsact_meta_get_dependencies(
}
}

void ecsact_add_dependency(
ecsact_package_id target,
ecsact_package_id dependency
) {
auto& tgt_pkg_def = package_defs.at(target);
if(package_defs.contains(dependency)) {
tgt_pkg_def.dependencies.push_back(dependency);
}
}

const char* ecsact_meta_decl_full_name(ecsact_decl_id id) {
return full_names.at(id).c_str();
}
Expand Down
19 changes: 19 additions & 0 deletions test/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,22 @@ cc_test(
"@com_google_googletest//:gtest_main",
],
)

cc_test(
name = "multi_pkg",
srcs = ["multi_pkg.cc"],
copts = copts,
data = [
"multi_pkg_a.ecsact",
"multi_pkg_b.ecsact",
"multi_pkg_c.ecsact",
"multi_pkg_main.ecsact",
],
deps = [
":test_lib",
"//:ecsact_interpret",
"@bazel_sundry//bazel_sundry:runfiles",
"@com_google_googletest//:gtest",
"@com_google_googletest//:gtest_main",
],
)
33 changes: 33 additions & 0 deletions test/multi_pkg.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#include "gtest/gtest.h"
#include "ecsact/interpret/eval.h"
#include "ecsact/runtime/meta.hh"

#include "test/test_lib.hh"

TEST(MultiPkgTest, NoErrors) {
auto errs = ecsact_interpret_test_files({
"multi_pkg_main.ecsact",
"multi_pkg_a.ecsact",
"multi_pkg_b.ecsact",
"multi_pkg_c.ecsact",
});
EXPECT_EQ(errs.size(), 0) //
<< "Expected no errors. Instead got: " << errs[0].error_message << "\n";

EXPECT_EQ(ecsact_meta_count_packages(), 4);

auto pkg_ids = ecsact::meta::get_package_ids();
for(auto pkg_id : pkg_ids) {
auto pkg_name = ecsact::meta::package_name(pkg_id);

if(pkg_name == "multi.pkg") {
EXPECT_EQ(ecsact_meta_count_dependencies(pkg_id), 3) //
<< "Expected main package to have 3 dependencies. One for each import";
} else if(pkg_name == "multi.pkg.a") {
} else if(pkg_name == "multi.pkg.b") {
} else if(pkg_name == "multi.pkg.c") {
} else {
EXPECT_TRUE(false) << "No tests for package: " << pkg_name;
}
}
}
4 changes: 4 additions & 0 deletions test/multi_pkg_a.ecsact
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package multi.pkg.a;

component FromA;

3 changes: 3 additions & 0 deletions test/multi_pkg_b.ecsact
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package multi.pkg.b;

component FromB;
4 changes: 4 additions & 0 deletions test/multi_pkg_c.ecsact
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package multi.pkg.c;

component FromC;

15 changes: 15 additions & 0 deletions test/multi_pkg_main.ecsact
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
main package multi.pkg;

import multi.pkg.a;
import multi.pkg.b;
import multi.pkg.c;

component FromMain;

system FullyQualifiedFromMain {
include multi.pkg.FromMain;
include multi.pkg.a.FromA;
include multi.pkg.b.FromB;
include multi.pkg.c.FromC;
}

0 comments on commit da2e08e

Please sign in to comment.