|
@@ -1471,7 +1471,7 @@ loop:
|
|
|
return params;
|
|
|
}
|
|
|
|
|
|
-// MARK: - UnitTest -
|
|
|
+// MARK: - Macro -
|
|
|
|
|
|
typedef enum {
|
|
|
UNITTEST_NONE,
|
|
@@ -1483,7 +1483,7 @@ typedef enum {
|
|
|
UNITTEST_NOTE
|
|
|
} unittest_t;
|
|
|
|
|
|
-static unittest_t parse_unittest_identifier(const char *identifier) {
|
|
|
+static unittest_t parse_unittest_identifier (const char *identifier) {
|
|
|
if (string_cmp(identifier, "name") == 0) return UNITTEST_NAME;
|
|
|
if (string_cmp(identifier, "note") == 0) return UNITTEST_NOTE;
|
|
|
if (string_cmp(identifier, "error") == 0) return UNITTEST_ERROR;
|
|
@@ -1494,9 +1494,9 @@ static unittest_t parse_unittest_identifier(const char *identifier) {
|
|
|
return UNITTEST_NONE;
|
|
|
}
|
|
|
|
|
|
-static gnode_t *parse_unittest_declaration(gravity_parser_t *parser) {
|
|
|
+static gnode_t *parse_unittest_macro (gravity_parser_t *parser) {
|
|
|
+ DEBUG_PARSER("parse_unittest_macro");
|
|
|
DECLARE_LEXER;
|
|
|
- DEBUG_PARSER("parse_unittest_declaration");
|
|
|
|
|
|
// @unittest {
|
|
|
// name: "Unit test name";
|
|
@@ -1659,6 +1659,65 @@ handle_error:
|
|
|
return NULL;
|
|
|
}
|
|
|
|
|
|
+static gnode_t *parse_include_macro (gravity_parser_t *parser) {
|
|
|
+ DEBUG_PARSER("parse_include_macro");
|
|
|
+ DECLARE_LEXER;
|
|
|
+
|
|
|
+ // process filename (can be an identifier or a literal string)
|
|
|
+ // only literals are supported in this version
|
|
|
+ gtoken_t type;
|
|
|
+ gtoken_s token;
|
|
|
+ const char *module_name;
|
|
|
+ gravity_lexer_t *newlexer;
|
|
|
+
|
|
|
+loop:
|
|
|
+ newlexer = NULL;
|
|
|
+ type = gravity_lexer_next(lexer);
|
|
|
+ token = gravity_lexer_token(lexer);
|
|
|
+
|
|
|
+ // check if it is a string token
|
|
|
+ if (type != TOK_STRING) {
|
|
|
+ REPORT_ERROR(token, "Expected file name but found %s.", token_name(type));
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ // check pre-requisites
|
|
|
+ if ((!parser->delegate) || (!parser->delegate->loadfile_callback)) {
|
|
|
+ REPORT_ERROR(gravity_lexer_token(lexer), "%s", "Unable to load file because no loadfile callback registered in delegate.");
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ // parse string
|
|
|
+ module_name = cstring_from_token(parser, token);
|
|
|
+ size_t size = 0;
|
|
|
+ uint32_t fileid = 0;
|
|
|
+
|
|
|
+ // module_name is a filename and it is used by lexer to store filename into tokens
|
|
|
+ // tokens are then stored inside AST nodes in order to locate errors into source code
|
|
|
+ // AST can live a lot longer than both lexer and parser so we need a way to persistent
|
|
|
+ // store these chuncks of memory
|
|
|
+ const char *source = parser->delegate->loadfile_callback(module_name, &size, &fileid, parser->delegate->xdata);
|
|
|
+ if (source) newlexer = gravity_lexer_create(source, size, fileid, false);
|
|
|
+
|
|
|
+ if (newlexer) {
|
|
|
+ // push new lexer into lexer stack
|
|
|
+ marray_push(gravity_lexer_t*, *parser->lexer, newlexer);
|
|
|
+ } else {
|
|
|
+ REPORT_ERROR(token, "Unable to load file %s.", module_name);
|
|
|
+ }
|
|
|
+
|
|
|
+ // check for optional comma
|
|
|
+ if (gravity_lexer_peek(lexer) == TOK_OP_COMMA) {
|
|
|
+ gravity_lexer_next(lexer); // consume TOK_OP_COMMA
|
|
|
+ goto loop;
|
|
|
+ }
|
|
|
+
|
|
|
+ // parse semicolon
|
|
|
+ parse_semicolon(parser);
|
|
|
+
|
|
|
+ return NULL;
|
|
|
+}
|
|
|
+
|
|
|
// MARK: - Statements -
|
|
|
|
|
|
static gnode_t *parse_label_statement (gravity_parser_t *parser) {
|
|
@@ -1899,70 +1958,20 @@ static gnode_t *parse_declaration_statement (gravity_parser_t *parser) {
|
|
|
}
|
|
|
|
|
|
static gnode_t *parse_import_statement (gravity_parser_t *parser) {
|
|
|
+ #pragma unused(parser)
|
|
|
DEBUG_PARSER("parse_import_statement");
|
|
|
|
|
|
- DECLARE_LEXER;
|
|
|
-
|
|
|
- // parse import keyword
|
|
|
- gravity_lexer_next(lexer);
|
|
|
-
|
|
|
- // process filename (can be an identifier or a literal string)
|
|
|
- // identifier to import modules ?
|
|
|
- // only literals are supported in this version
|
|
|
- gtoken_t type;
|
|
|
- gtoken_s token;
|
|
|
- const char *module_name;
|
|
|
- gravity_lexer_t *newlexer;
|
|
|
-
|
|
|
-loop:
|
|
|
- newlexer = NULL;
|
|
|
- type = gravity_lexer_next(lexer);
|
|
|
- token = gravity_lexer_token(lexer);
|
|
|
-
|
|
|
- // check if it is a string token
|
|
|
- if (type != TOK_STRING) {
|
|
|
- REPORT_ERROR(token, "Expected file name but found %s.", token_name(type));
|
|
|
- return NULL;
|
|
|
- }
|
|
|
-
|
|
|
- // check pre-requisites
|
|
|
- if ((!parser->delegate) || (!parser->delegate->loadfile_callback)) {
|
|
|
- REPORT_ERROR(gravity_lexer_token(lexer), "%s", "Unable to load file because no loadfile callback registered in delegate.");
|
|
|
- return NULL;
|
|
|
- }
|
|
|
-
|
|
|
- // parse string
|
|
|
- module_name = cstring_from_token(parser, token);
|
|
|
- size_t size = 0;
|
|
|
- uint32_t fileid = 0;
|
|
|
-
|
|
|
- // module_name is a filename and it is used by lexer to store filename into tokens
|
|
|
- // tokens are then stored inside AST nodes in order to locate errors into source code
|
|
|
- // AST can live a lot longer than both lexer and parser so we need a way to persistent
|
|
|
- // store these chuncks of memory
|
|
|
- const char *source = parser->delegate->loadfile_callback(module_name, &size, &fileid, parser->delegate->xdata);
|
|
|
- if (source) newlexer = gravity_lexer_create(source, size, fileid, false);
|
|
|
-
|
|
|
- if (newlexer) {
|
|
|
- // push new lexer into lexer stack
|
|
|
- marray_push(gravity_lexer_t*, *parser->lexer, newlexer);
|
|
|
- } else {
|
|
|
- REPORT_ERROR(token, "Unable to load file %s.", module_name);
|
|
|
- }
|
|
|
-
|
|
|
- // check for optional comma
|
|
|
- if (gravity_lexer_peek(lexer) == TOK_OP_COMMA) {
|
|
|
- gravity_lexer_next(lexer); // consume TOK_OP_COMMA
|
|
|
- goto loop;
|
|
|
- }
|
|
|
-
|
|
|
- // parse semicolon
|
|
|
- parse_semicolon(parser);
|
|
|
-
|
|
|
+ // import is a syntactic sugar for System.import
|
|
|
return NULL;
|
|
|
}
|
|
|
|
|
|
static gnode_t *parse_macro_statement (gravity_parser_t *parser) {
|
|
|
+ typedef enum {
|
|
|
+ MACRO_UNKNOWN = 0,
|
|
|
+ MACRO_UNITEST = 1,
|
|
|
+ MACRO_INCLUDE = 2
|
|
|
+ } builtin_macro;
|
|
|
+
|
|
|
DEBUG_PARSER("parse_macro_statement");
|
|
|
DECLARE_LEXER;
|
|
|
|
|
@@ -1986,12 +1995,23 @@ static gnode_t *parse_macro_statement (gravity_parser_t *parser) {
|
|
|
const char *macroid = parse_identifier(parser);
|
|
|
if (macroid == NULL) goto handle_error;
|
|
|
|
|
|
- // check #unittest macro
|
|
|
- bool is_unittest = (string_cmp(macroid, "unittest") == 0);
|
|
|
+ // check macro
|
|
|
+ builtin_macro macro_type = MACRO_UNKNOWN;
|
|
|
+ if (string_cmp(macroid, "unittest") == 0) macro_type = MACRO_UNITEST;
|
|
|
+ else if (string_cmp(macroid, "include") == 0) macro_type = MACRO_INCLUDE;
|
|
|
mem_free(macroid);
|
|
|
|
|
|
- if (is_unittest) {
|
|
|
- return parse_unittest_declaration(parser);
|
|
|
+ switch (macro_type) {
|
|
|
+ case MACRO_UNITEST:
|
|
|
+ return parse_unittest_macro(parser);
|
|
|
+ break;
|
|
|
+
|
|
|
+ case MACRO_INCLUDE:
|
|
|
+ return parse_include_macro(parser);
|
|
|
+ break;
|
|
|
+
|
|
|
+ case MACRO_UNKNOWN:
|
|
|
+ break;
|
|
|
}
|
|
|
|
|
|
handle_error:
|