171 lines
6.2 KiB
C++
171 lines
6.2 KiB
C++
#define GEN_TIME
|
|
#define GEN_DEFINE_LIBRARY_CODE_CONSTANTS
|
|
#define GEN_ENFORCE_STRONG_CODE_TYPES
|
|
#include "gen.cpp"
|
|
|
|
using namespace gen;
|
|
|
|
global int g_failures = 0;
|
|
|
|
internal void expect(int condition, Str label) {
|
|
if (condition == false) { log_fmt("FAIL %S\n", label); ++g_failures; }
|
|
}
|
|
|
|
internal Str body_text(CodeBody body) {
|
|
return strbuilder_to_str(code_to_strbuilder(cast(Code, body)));
|
|
}
|
|
|
|
internal b32 body_has_variable(CodeBody body, Str name) { for (Code member : body) {
|
|
if (member->Type == CT_Variable && member->Name.is_equal(name)) return true;
|
|
if ((member->Type == CT_Struct || member->Type == CT_Union) && member->Body.ast != nullptr) {
|
|
if (body_has_variable(cast(CodeBody, member->Body), name))
|
|
return true;
|
|
}
|
|
} return false; }
|
|
|
|
internal Str bad_at(Str good) {
|
|
StrBuilder built = strbuilder_make_reserve(_ctx->Allocator_Temp, good.Len + 2);
|
|
strbuilder_append_str(& built, good);
|
|
strbuilder_append_str(& built, txt("\n@"));
|
|
return strbuilder_to_str(built);
|
|
}
|
|
|
|
internal void expect_context_good(Context* ctx, Str label) {
|
|
Str def = txt("struct Context\n{\n\tContext* parent;\n};\n\nContext* make_context();\n");
|
|
CodeBody body = parse_global_body(def);
|
|
Code found = InvalidCode;
|
|
for (Code code : body) if (code->Type == CT_Struct && code->Name.is_equal(txt("Context")))
|
|
found = code;
|
|
expect(found.ast != nullptr, label); if (found.ast != nullptr) {
|
|
Code member = InvalidCode;
|
|
for (Code code : cast(CodeBody, found->Body)) {
|
|
if (code->Type == CT_Variable && code->Name.is_equal(txt("parent")))
|
|
member = code;
|
|
}
|
|
expect(member.ast != nullptr, label);
|
|
}
|
|
expect(ctx->parse_info.messages == nullptr, label);
|
|
expect(ctx->parse_info.lexed.messages == nullptr, label);
|
|
}
|
|
|
|
internal void expect_context_bad(Str label) {
|
|
Context ctx = {}; init(& ctx);
|
|
Str good = txt("struct Context\n{\n\tContext* parent;\n};\n\nContext* make_context();\n");
|
|
CodeBody body = parse_global_body(bad_at(good));
|
|
Str text = body_text(body);
|
|
expect(str_contains(text, txt("Context")), label);
|
|
expect(str_contains(text, txt("parent")), label);
|
|
expect(ctx.parse_info.lexed.messages != nullptr, label);
|
|
if (ctx.parse_info.lexed.messages != nullptr) expect(str_contains(ctx.parse_info.lexed.messages->content, txt("Failed to lex token")), label);
|
|
expect_context_good(&ctx, txt("context-reuse"));
|
|
deinit(& ctx);
|
|
}
|
|
|
|
internal Str vec_def() {
|
|
Str type = txt("Vec2f");
|
|
Str unit_type = txt("f32");
|
|
return token_fmt("type", type, "unit_type", unit_type, stringize(
|
|
struct <type>
|
|
{
|
|
union {
|
|
struct {
|
|
<unit_type> x;
|
|
<unit_type> y;
|
|
};
|
|
<unit_type> Basis[2];
|
|
};
|
|
};
|
|
));
|
|
}
|
|
|
|
internal void expect_vec_good(Context* ctx, Str label) {
|
|
Str def = vec_def();
|
|
expect(str_contains(def, txt("struct Vec2f")), txt("vec-def-struct"));
|
|
expect(str_contains(def, txt("union")), txt("vec-def-union"));
|
|
expect(str_contains(def, txt("f32 x;")), txt("vec-def-x"));
|
|
expect(str_contains(def, txt("f32 y;")), txt("vec-def-y"));
|
|
expect(str_contains(def, txt("f32 Basis[2]")), txt("vec-def-Basis"));
|
|
CodeBody body = parse_global_body(def);
|
|
expect(body_has_variable(body, txt("x")), txt("vec-ast-x"));
|
|
expect(body_has_variable(body, txt("y")), txt("vec-ast-y"));
|
|
Str text = body_text(body);
|
|
expect(str_contains(text, txt("Vec2f")), txt("vec-name"));
|
|
expect(str_contains(text, txt("x")), txt("vec-x"));
|
|
expect(str_contains(text, txt("y")), txt("vec-y"));
|
|
expect(ctx->parse_info.messages == nullptr, txt("vec-parser-messages"));
|
|
expect(ctx->parse_info.lexed.messages == nullptr, txt("vec-lexer-messages"));
|
|
}
|
|
|
|
internal void expect_vec_bad(Str label) {
|
|
Context ctx = {}; init(& ctx);
|
|
CodeBody body = parse_global_body(bad_at(vec_def()));
|
|
Str text = body_text(body);
|
|
expect(str_contains(text, txt("Vec2f")), label);
|
|
expect(ctx.parse_info.lexed.messages != nullptr, label);
|
|
if (ctx.parse_info.lexed.messages != nullptr) expect(str_contains(ctx.parse_info.lexed.messages->content, txt("Failed to lex token")), label);
|
|
expect_vec_good(& ctx, txt("vec-reuse"));
|
|
deinit(& ctx);
|
|
}
|
|
|
|
internal Str unreal_def() { return txt("UCLASS()\nclass UGasaFixture\n{\n\tUPROPERTY()\n\tint Health;\n};\n"); }
|
|
|
|
internal void expect_unreal_good(Context* ctx, Str label) {
|
|
CodeBody body = parse_global_body(unreal_def());
|
|
Code found = InvalidCode;
|
|
for (Code code : body) if (code->Type == CT_Class && code->Name.is_equal(txt("UGasaFixture")))
|
|
found = code;
|
|
expect(found.ast != nullptr, label); if (found.ast != nullptr) {
|
|
b32 saw_prop = false;
|
|
b32 saw_health = false;
|
|
for (Code member : cast(CodeBody, found->Body)) {
|
|
if ( member->Type == CT_Untyped && member->Name.starts_with(txt("UPROPERTY"))) saw_prop = true;
|
|
if (saw_prop && member->Type == CT_Variable && member->Name.is_equal(txt("Health"))) saw_health = true;
|
|
}
|
|
expect(saw_prop, label);
|
|
expect(saw_health, label);
|
|
}
|
|
expect(ctx->parse_info.messages == nullptr, label);
|
|
expect(ctx->parse_info.lexed.messages == nullptr, label);
|
|
}
|
|
|
|
internal void expect_unreal_bad(Str label) {
|
|
Context ctx = {}; init(& ctx);
|
|
register_macros(args(
|
|
(Macro { txt("UCLASS"), MT_Statement, MF_Functional }),
|
|
(Macro { txt("UPROPERTY"), MT_Statement, MF_Functional })
|
|
));
|
|
CodeBody body = parse_global_body(bad_at(unreal_def()));
|
|
Str text = body_text(body);
|
|
expect(str_contains(text, txt("UGasaFixture")), label);
|
|
expect(ctx.parse_info.lexed.messages != nullptr, label);
|
|
if (ctx.parse_info.lexed.messages != nullptr) expect(str_contains(ctx.parse_info.lexed.messages->content, txt("Failed to lex token")), label);
|
|
expect_unreal_good(&ctx, txt("unreal-reuse"));
|
|
deinit(& ctx);
|
|
}
|
|
|
|
int main()
|
|
{
|
|
Context ctx = {}; init(& ctx);
|
|
expect_context_good(&ctx, txt("context"));
|
|
deinit(& ctx);
|
|
expect_context_bad(txt("context-at"));
|
|
|
|
init(& ctx);
|
|
expect_vec_good(& ctx, txt("vec"));
|
|
deinit(& ctx);
|
|
expect_vec_bad(txt("vec-at"));
|
|
|
|
init(& ctx);
|
|
register_macros(args(
|
|
(Macro { txt("UCLASS"), MT_Statement, MF_Functional }),
|
|
(Macro { txt("UPROPERTY"), MT_Statement, MF_Functional })
|
|
));
|
|
expect_unreal_good(& ctx, txt("unreal"));
|
|
deinit(& ctx);
|
|
expect_unreal_bad(txt("unreal-at"));
|
|
|
|
if (g_failures != 0) { log_fmt("dogfood parse fixtures failed: %d\n", g_failures); return 1; }
|
|
log_fmt("dogfood parse fixtures passed\n");
|
|
return 0;
|
|
}
|