diff options
| author | Bruce Hill <bruce@bruce-hill.com> | 2025-04-06 20:07:09 -0400 |
|---|---|---|
| committer | Bruce Hill <bruce@bruce-hill.com> | 2025-04-06 20:07:09 -0400 |
| commit | 6cf980ea713906621d28baf847ce7dbdd0d003f9 (patch) | |
| tree | 7cb0fb5f55213d4a6594e1999ef37ea2b2c85ede | |
| parent | 1d2e55f53dfab5153dbfd0c03f28cd9daedb3b77 (diff) | |
Add `continue` and `break` as aliases for `skip`/`stop`, also improve
keyword detection using a binary search
| -rw-r--r-- | examples/learnxiny.tm | 4 | ||||
| -rw-r--r-- | src/compile.c | 4 | ||||
| -rw-r--r-- | src/parse.c | 33 |
3 files changed, 28 insertions, 13 deletions
diff --git a/examples/learnxiny.tm b/examples/learnxiny.tm index 31d768eb..b8eaa77e 100644 --- a/examples/learnxiny.tm +++ b/examples/learnxiny.tm @@ -86,11 +86,12 @@ func main() >> [x*10 for x in my_numbers if x != 20] = [100, 300] - # Loop control flow uses "skip" and "stop" + # Loop control flow uses "skip"/"continue" and "stop"/"break" for x in my_numbers for y in my_numbers if x == y skip + continue # This is the same as `skip` # For readability, you can also use postfix conditionals: skip if x == y @@ -99,6 +100,7 @@ func main() # Skip or stop can specify a loop variable if you want to # affect an enclosing loop: stop x + break x # This is the same as `stop x` # Tables are efficient hash maps table := {"one"=1, "two"=2} diff --git a/src/compile.c b/src/compile.c index 0b7f19f5..aaf41166 100644 --- a/src/compile.c +++ b/src/compile.c @@ -1338,7 +1338,7 @@ static CORD _compile_statement(env_t *env, ast_t *ast) } } if (env->loop_ctx) - code_err(ast, "This 'skip' is not inside any loop"); + code_err(ast, "This is not inside any loop"); else if (target) code_err(ast, "No loop target named '", target, "' was found"); else @@ -1367,7 +1367,7 @@ static CORD _compile_statement(env_t *env, ast_t *ast) } } if (env->loop_ctx) - code_err(ast, "This 'stop' is not inside any loop"); + code_err(ast, "This is not inside any loop"); else if (target) code_err(ast, "No loop target named '", target, "' was found"); else diff --git a/src/parse.c b/src/parse.c index c76266ee..3b8f55bf 100644 --- a/src/parse.c +++ b/src/parse.c @@ -61,10 +61,10 @@ int op_tightness[] = { }; static const char *keywords[] = { - "yes", "xor", "while", "when", "use", "unless", "then", "struct", "stop", "skip", "return", - "or", "not", "none", "no", "mod1", "mod", "pass", "lang", "inline", "in", "if", - "func", "for", "extern", "extend", "enum", "else", "do", "deserialize", "defer", "and", - "_min_", "_max_", NULL, + "_max_", "_min_", "and", "break", "continue", "defer", "deserialize", "do", "else", "enum", + "extend", "extern", "for", "func", "if", "in", "inline", "lang", "mod", "mod1", "no", "none", + "not", "or", "pass", "return", "skip", "skip", "stop", "struct", "then", "unless", "use", "when", + "while", "xor", "yes", }; enum {NORMAL_FUNCTION=0, EXTERN_FUNCTION=1}; @@ -379,13 +379,26 @@ const char *get_word(const char **inout) { return GC_strndup(word, (size_t)((const char*)pos - word)); } +static CONSTFUNC bool is_keyword(const char *word) { + int64_t lo = 0, hi = sizeof(keywords)/sizeof(keywords[0])-1; + while (lo <= hi) { + int64_t mid = (lo + hi) / 2; + int32_t cmp = strcmp(word, keywords[mid]); + if (cmp == 0) + return true; + else if (cmp > 0) + lo = mid + 1; + else if (cmp < 0) + hi = mid - 1; + } + return false; +} + const char *get_id(const char **inout) { const char *pos = *inout; const char *word = get_word(&pos); - if (!word) return word; - for (int i = 0; keywords[i]; i++) - if (strcmp(word, keywords[i]) == 0) - return NULL; + if (!word || is_keyword(word)) + return NULL; *inout = pos; return word; } @@ -1346,7 +1359,7 @@ PARSER(parse_defer) { PARSER(parse_skip) { const char *start = pos; - if (!match_word(&pos, "skip")) return NULL; + if (!match_word(&pos, "continue") && !match_word(&pos, "skip")) return NULL; const char *target; if (match_word(&pos, "for")) target = "for"; else if (match_word(&pos, "while")) target = "while"; @@ -1358,7 +1371,7 @@ PARSER(parse_skip) { PARSER(parse_stop) { const char *start = pos; - if (!match_word(&pos, "stop")) return NULL; + if (!match_word(&pos, "stop") && !match_word(&pos, "break")) return NULL; const char *target; if (match_word(&pos, "for")) target = "for"; else if (match_word(&pos, "while")) target = "while"; |
