diff --git a/README.md b/README.md index 23c617b..ba557f7 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,7 @@ Single Heaer Meta Programming Header Library for C. The same header for both cod - Only parses `typedef struct { ... } type_name;` - Will generate colliding definitions in case of types with the same name +- Parsing expects more or less correct code, if you forget a semi it will generating bad code ## Quick start diff --git a/cmeta.h b/cmeta.h index 8a8489f..c654a5a 100644 --- a/cmeta.h +++ b/cmeta.h @@ -15,6 +15,15 @@ typedef struct { } Struct_Info; // AUTO GENERATED CODE // +Struct_Info foo_struct_info = { // cmeta.h:478 + .name = "Foo_Struct", // cmeta.h:479 + .fields_count = 3, // cmeta.h:480 + .fields = (Field_Info[3]) { // cmeta.h:481 + { .type = "int ", .name = "int_field" }, // cmeta.h:483 + { .type = "char* ", .name = "char_star_field" }, // cmeta.h:483 + { .type = "const char* ", .name = "const_char_star_field" }, // cmeta.h:483 + }, // cmeta.h:485 +}; // cmeta.h:486 // AUTO GENERATED CODE // #ifdef CMETA_COMPTIME @@ -229,7 +238,6 @@ char* sv_to_string(String_View sv) { typedef enum { TOKEN_IDENT, - TOKEN_DQUOTE, TOKEN_OPAREN, TOKEN_CPAREN, TOKEN_OCURLY, @@ -242,9 +250,9 @@ typedef enum { } Token_Kind; const char* token_kind_to_str(Token_Kind token) { + static_assert(__token_kind_count == 9, "Update the token_kind_to_str table"); switch (token) { case TOKEN_IDENT: return "identifier"; - case TOKEN_DQUOTE: return "\""; case TOKEN_OPAREN: return "("; case TOKEN_CPAREN: return ")"; case TOKEN_OCURLY: return "{"; @@ -255,7 +263,6 @@ const char* token_kind_to_str(Token_Kind token) { case TOKEN_EOF: return "EOF"; default: assert(false && "Unreachable"); } - static_assert(__token_kind_count == 10, "Update the token_kind_to_str table"); } typedef struct { @@ -299,15 +306,25 @@ bool lexer_next(Lexer* lexer, Token* token) { return true; } + static_assert(__token_kind_count == 9, "Update lexer_next"); switch (lexer->text.data[0]) { - // TODO: while in string, keep calling next - case '"': *token = lexer_make_token(lexer, TOKEN_DQUOTE, 1); return true; - case '*': *token = lexer_make_token(lexer, TOKEN_STAR, 1); return true; - case '(': *token = lexer_make_token(lexer, TOKEN_OPAREN, 1); return true; - case ')': *token = lexer_make_token(lexer, TOKEN_CPAREN, 1); return true; - case '{': *token = lexer_make_token(lexer, TOKEN_OCURLY, 1); return true; - case '}': *token = lexer_make_token(lexer, TOKEN_CCURLY, 1); return true; - case ';': *token = lexer_make_token(lexer, TOKEN_SEMI, 1); return true; + // we don't want to parse type definitions in strings + case '"': { + do { + String_View ch = sv_shift(&lexer->text, 1); + if (sv_eq_cstr(ch, "\\")) sv_shift(&lexer->text, 1); + } + while (lexer->text.len > 0 && lexer->text.data[0] != '"'); + sv_shift(&lexer->text, 1); + + return lexer_next(lexer, token); + } + case '*': *token = lexer_make_token(lexer, TOKEN_STAR, 1); return true; + case '(': *token = lexer_make_token(lexer, TOKEN_OPAREN, 1); return true; + case ')': *token = lexer_make_token(lexer, TOKEN_CPAREN, 1); return true; + case '{': *token = lexer_make_token(lexer, TOKEN_OCURLY, 1); return true; + case '}': *token = lexer_make_token(lexer, TOKEN_CCURLY, 1); return true; + case ';': *token = lexer_make_token(lexer, TOKEN_SEMI, 1); return true; default: { if (is_valid_ident_char_at(lexer->text, 0)) { size_t end = 0; diff --git a/example/01_simple_struct/cmeta.h b/example/01_simple_struct/cmeta.h index 3171166..c654a5a 100644 --- a/example/01_simple_struct/cmeta.h +++ b/example/01_simple_struct/cmeta.h @@ -15,15 +15,15 @@ typedef struct { } Struct_Info; // AUTO GENERATED CODE // -Struct_Info foo_struct_info = { // cmeta.h:470 - .name = "Foo_Struct", // cmeta.h:471 - .fields_count = 3, // cmeta.h:472 - .fields = (Field_Info[3]) { // cmeta.h:473 - { .type = "int ", .name = "int_field" }, // cmeta.h:475 - { .type = "char* ", .name = "char_star_field" }, // cmeta.h:475 - { .type = "const char* ", .name = "const_char_star_field" }, // cmeta.h:475 - }, // cmeta.h:477 -}; // cmeta.h:478 +Struct_Info foo_struct_info = { // cmeta.h:478 + .name = "Foo_Struct", // cmeta.h:479 + .fields_count = 3, // cmeta.h:480 + .fields = (Field_Info[3]) { // cmeta.h:481 + { .type = "int ", .name = "int_field" }, // cmeta.h:483 + { .type = "char* ", .name = "char_star_field" }, // cmeta.h:483 + { .type = "const char* ", .name = "const_char_star_field" }, // cmeta.h:483 + }, // cmeta.h:485 +}; // cmeta.h:486 // AUTO GENERATED CODE // #ifdef CMETA_COMPTIME @@ -238,7 +238,6 @@ char* sv_to_string(String_View sv) { typedef enum { TOKEN_IDENT, - TOKEN_DQUOTE, TOKEN_OPAREN, TOKEN_CPAREN, TOKEN_OCURLY, @@ -251,9 +250,9 @@ typedef enum { } Token_Kind; const char* token_kind_to_str(Token_Kind token) { + static_assert(__token_kind_count == 9, "Update the token_kind_to_str table"); switch (token) { case TOKEN_IDENT: return "identifier"; - case TOKEN_DQUOTE: return "\""; case TOKEN_OPAREN: return "("; case TOKEN_CPAREN: return ")"; case TOKEN_OCURLY: return "{"; @@ -264,7 +263,6 @@ const char* token_kind_to_str(Token_Kind token) { case TOKEN_EOF: return "EOF"; default: assert(false && "Unreachable"); } - static_assert(__token_kind_count == 10, "Update the token_kind_to_str table"); } typedef struct { @@ -308,15 +306,25 @@ bool lexer_next(Lexer* lexer, Token* token) { return true; } + static_assert(__token_kind_count == 9, "Update lexer_next"); switch (lexer->text.data[0]) { - // TODO: while in string, keep calling next - case '"': *token = lexer_make_token(lexer, TOKEN_DQUOTE, 1); return true; - case '*': *token = lexer_make_token(lexer, TOKEN_STAR, 1); return true; - case '(': *token = lexer_make_token(lexer, TOKEN_OPAREN, 1); return true; - case ')': *token = lexer_make_token(lexer, TOKEN_CPAREN, 1); return true; - case '{': *token = lexer_make_token(lexer, TOKEN_OCURLY, 1); return true; - case '}': *token = lexer_make_token(lexer, TOKEN_CCURLY, 1); return true; - case ';': *token = lexer_make_token(lexer, TOKEN_SEMI, 1); return true; + // we don't want to parse type definitions in strings + case '"': { + do { + String_View ch = sv_shift(&lexer->text, 1); + if (sv_eq_cstr(ch, "\\")) sv_shift(&lexer->text, 1); + } + while (lexer->text.len > 0 && lexer->text.data[0] != '"'); + sv_shift(&lexer->text, 1); + + return lexer_next(lexer, token); + } + case '*': *token = lexer_make_token(lexer, TOKEN_STAR, 1); return true; + case '(': *token = lexer_make_token(lexer, TOKEN_OPAREN, 1); return true; + case ')': *token = lexer_make_token(lexer, TOKEN_CPAREN, 1); return true; + case '{': *token = lexer_make_token(lexer, TOKEN_OCURLY, 1); return true; + case '}': *token = lexer_make_token(lexer, TOKEN_CCURLY, 1); return true; + case ';': *token = lexer_make_token(lexer, TOKEN_SEMI, 1); return true; default: { if (is_valid_ident_char_at(lexer->text, 0)) { size_t end = 0;