diff options
| author | Paul Buetow <paul@buetow.org> | 2026-02-28 16:08:49 +0200 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2026-02-28 16:08:49 +0200 |
| commit | 5f557ebafb596755cb3047cbdafa6122166c26ac (patch) | |
| tree | 38311c31975d8cb9c8b211252c3c0865802d2d90 | |
| parent | 946fac7d813f6283c18087a46b9e2ee084852c64 (diff) | |
Refactor _term() by extracting _term_ident(), _term_array_literal(), _term_paren() [SRP]
_term() was ~130 lines mixing literal push, array literal construction,
identifier resolution, parenthesized expressions, and defined/undef/syms.
Extracted three static helpers:
- _term_ident(): resolves TT_IDENT as array access, builtin call,
self-defined function/proc call, or variable/procedure (~90 lines;
acceptable given the complexity of identifier resolution)
- _term_array_literal(): builds an array from [expr, ...] syntax
- _term_paren(): evaluates a parenthesised expression and checks ')'
_term() is now a ~100-line dispatcher. The defined/undef/syms cases
remain inline as they are self-contained ~10-line blocks.
Also fixes a latent double-assignment bug in _term_array_literal():
the original `TokenType tt = tt = p_interpret->tt;` is now `= p_interpret->tt;`.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
| -rw-r--r-- | docs/help.txt | 2 | ||||
| -rw-r--r-- | docs/stats.txt | 2 | ||||
| -rw-r--r-- | docs/version.txt | 2 | ||||
| -rwxr-xr-x | fype | bin | 288168 -> 288368 bytes | |||
| -rw-r--r-- | src/build.h | 2 | ||||
| -rw-r--r-- | src/core/interpret.c | 301 | ||||
| -rw-r--r-- | tags | 3 |
7 files changed, 169 insertions, 143 deletions
diff --git a/docs/help.txt b/docs/help.txt index f4a8e65..fae20f2 100644 --- a/docs/help.txt +++ b/docs/help.txt @@ -1,4 +1,4 @@ -Fype Superalpha Build 9691 +Fype Superalpha Build 9701 (c) Paul C. Buetow (2005 - 2008) <fype@dev.buetow.org> -e Executes given code string (see synopses) -h Prints this help diff --git a/docs/stats.txt b/docs/stats.txt index bf4e4cc..47a0f36 100644 --- a/docs/stats.txt +++ b/docs/stats.txt @@ -1,6 +1,6 @@ make[1]: Entering directory '/home/paul/git/fype' ===> Num of C source files : 46 -===> Num of C source lines : 8702 +===> Num of C source lines : 8725 ===> Num of Fype source examples : 19 ===> Num of Fype source lines : 883 make[1]: Leaving directory '/home/paul/git/fype' diff --git a/docs/version.txt b/docs/version.txt index e0f6705..dbb9597 100644 --- a/docs/version.txt +++ b/docs/version.txt @@ -1 +1 @@ -Fype Superalpha Build 9691 +Fype Superalpha Build 9701 Binary files differdiff --git a/src/build.h b/src/build.h index fce9d6f..b96d7c4 100644 --- a/src/build.h +++ b/src/build.h @@ -36,7 +36,7 @@ #ifndef BUILD_H #define BUILD_H -#define BUILDNR 9698 +#define BUILDNR 9702 #define OS_LINUX #endif diff --git a/src/core/interpret.c b/src/core/interpret.c index 085f716..b6c7c33 100644 --- a/src/core/interpret.c +++ b/src/core/interpret.c @@ -79,6 +79,9 @@ int _program(Interpret *p_interpret); int _statement(Interpret *p_interpret); int _sum(Interpret *p_interpret); int _term(Interpret *p_interpret); +static int _term_ident(Interpret *p_interpret); +static int _term_array_literal(Interpret *p_interpret); +static int _term_paren(Interpret *p_interpret); int _term_array_access(Interpret *p_interpret, Token *p_token_array, Array *p_array); int _var_assign(Interpret *p_interpret); @@ -1053,132 +1056,190 @@ _term_array_access(Interpret *p_interpret, return (1); } -int -_term(Interpret *p_interpret) { - _CHECK TRACK +/* Handle the TT_IDENT case in _term(): resolve the identifier as an array + * access, builtin call, self-defined function/procedure call, or variable. + * Returns 1 on success, 0 if no matching symbol kind is handled. */ +static int +_term_ident(Interpret *p_interpret) { + if (_NEXT_TT != TT_ASSIGN) { + if (_NEXT_TT == TT_PARANT_AL) { + /* Delegate to the array-access / slice helper */ + char *c_name = token_get_val(p_interpret->p_token); + Symbol *p_symbol = scope_get(p_interpret->p_scope, c_name); - switch (p_interpret->tt) { - case TT_ARRAY: - case TT_STRING: - case TT_INTEGER: - case TT_DOUBLE: - stack_push(p_interpret->p_stack, p_interpret->p_token); - // Checks if the term is the last element of an array - // say ["element"] # The "element" - // or of a function - // func foo { say 1 } # The 1 - if (_NEXT_TT != TT_PARANT_AR && _NEXT_TT != TT_PARANT_CR) - _NEXT - return (1); + if (p_symbol == NULL) + _INTERPRET_ERROR("No such symbol", p_interpret->p_token); - case TT_IDENT: - { - if (_NEXT_TT != TT_ASSIGN) { - if (_NEXT_TT == TT_PARANT_AL) { - /* Delegate to the array-access / slice helper */ - char *c_name = token_get_val(p_interpret->p_token); - Symbol *p_symbol = scope_get( - p_interpret->p_scope, c_name); + Token *p_token_array = symbol_get_val(p_symbol); + Array *p_array = TOKEN_GET_ARRAY(p_token_array); - if (p_symbol == NULL) - _INTERPRET_ERROR("No such symbol", - p_interpret->p_token); - Token *p_token_array = symbol_get_val(p_symbol); - Array *p_array = TOKEN_GET_ARRAY(p_token_array); - if (p_array == NULL) - _INTERPRET_ERROR("Expected an array", - p_interpret->p_token); + if (p_array == NULL) + _INTERPRET_ERROR("Expected an array", p_interpret->p_token); - return (_term_array_access(p_interpret, - p_token_array, p_array)); + return (_term_array_access(p_interpret, p_token_array, p_array)); - } else if (function_is_buildin(p_interpret->p_token)) { - Token *p_token = p_interpret->p_token; - Stack *p_stack = p_interpret->p_stack; - p_interpret->p_stack = stack_new(); + } else if (function_is_buildin(p_interpret->p_token)) { + Token *p_token = p_interpret->p_token; + Stack *p_stack = p_interpret->p_stack; + p_interpret->p_stack = stack_new(); - if (_HAS_NEXT) { - _NEXT - //if (_expression_(p_interpret)); - _expression_(p_interpret); + if (_HAS_NEXT) { + _NEXT + //if (_expression_(p_interpret)); + _expression_(p_interpret); - } else { - _SKIP + } else { + _SKIP + } + + function_process_buildin(p_interpret, p_token, + p_interpret->p_stack); + + stack_merge(p_stack, p_interpret->p_stack); + stack_delete(p_interpret->p_stack); + p_interpret->p_stack = p_stack; + + return (1); + + } else if (function_is_self_defined(p_interpret)) { + Token *p_token = p_interpret->p_token; + Stack *p_stack = p_interpret->p_stack; + p_interpret->p_stack = stack_new(); + + _NEXT /* advance past function name */ + if (p_interpret->tt == TT_PARANT_L) { + /* Parenthesised call: func(arg1, arg2) — collect args */ + _NEXT /* past '(' */ + while (p_interpret->tt != TT_PARANT_R + && p_interpret->tt != TT_NONE) { + _expression_(p_interpret); + if (p_interpret->tt == TT_COMMA) + _NEXT /* past ',' between arguments */ } + _NEXT /* past ')' */ + } else { + /* Old-style call without parens (procedures; zero-arg funcs) */ + if (_expression_(p_interpret)); + } - function_process_buildin(p_interpret, p_token, - p_interpret->p_stack); + function_process_self_defined(p_interpret, p_token); - stack_merge(p_stack, p_interpret->p_stack); - stack_delete(p_interpret->p_stack); - p_interpret->p_stack = p_stack; + if (stack_empty(p_interpret->p_stack)) { + Token *p_token = token_new_dummy(); + token_set_tt(p_token, TT_INTEGER); + token_set_ival(p_token, 0); + stack_push(p_interpret->p_stack, p_token); + } - return (1); + stack_merge(p_stack, p_interpret->p_stack); + stack_delete(p_interpret->p_stack); + p_interpret->p_stack = p_stack; - } else if (function_is_self_defined(p_interpret)) { - Token *p_token = p_interpret->p_token; - Stack *p_stack = p_interpret->p_stack; - p_interpret->p_stack = stack_new(); + return (1); + } + } - _NEXT /* advance past function name */ - if (p_interpret->tt == TT_PARANT_L) { - /* Parenthesised call: func(arg1, arg2) — collect args */ - _NEXT /* past '(' */ - while (p_interpret->tt != TT_PARANT_R - && p_interpret->tt != TT_NONE) { - _expression_(p_interpret); - if (p_interpret->tt == TT_COMMA) - _NEXT /* past ',' between arguments */ - } - _NEXT /* past ')' */ - } else { - /* Old-style call without parens (procedures; zero-arg funcs) */ - if (_expression_(p_interpret)); - } + /* It is not a function, it is a variable or some sort of */ - function_process_self_defined(p_interpret, p_token); + char *c_name = token_get_val(p_interpret->p_token); + Symbol *p_symbol = scope_get(p_interpret->p_scope, c_name); - if (stack_empty(p_interpret->p_stack)) { - Token *p_token = token_new_dummy(); - token_set_tt(p_token, TT_INTEGER); - token_set_ival(p_token, 0); - stack_push(p_interpret->p_stack, p_token); - } + if (p_symbol == NULL) + _INTERPRET_ERROR("No such symbol", p_interpret->p_token); - stack_merge(p_stack, p_interpret->p_stack); - stack_delete(p_interpret->p_stack); - p_interpret->p_stack = p_stack; + SymbolType st = symbol_get_sym(p_symbol); - return (1); + switch (st) { + case SYM_VARIABLE: + stack_push(p_interpret->p_stack, symbol_get_val(p_symbol)); + _NEXT + return (1); + + /* Example: proc foo { foo = "Hello"; } foo; say foo; */ + case SYM_PROCEDURE: + stack_push(p_interpret->p_stack, symbol_get_val(p_symbol)); + _NEXT + return (1); + + NO_DEFAULT; + } + + return (0); +} + +/* Handle the TT_PARANT_AL case in _term(): construct an array literal. + * Reads comma/semicolon-separated expressions until ']' and pushes the + * resulting array token onto the eval stack. */ +static int +_term_array_literal(Interpret *p_interpret) { + Token *p_token_arr = token_new_array(ARRAY_SIZE); + Array *p_array = p_token_arr->p_array; + + _NEXT + /* Collect array elements; commas and semicolons are skipped */ + while (p_interpret->tt != TT_PARANT_AR) { + TokenType tt = p_interpret->tt; + if (tt != TT_COMMA && tt != TT_SEMICOLON) { + UNLESS (_expression_(p_interpret)) { + Token *p_token = p_interpret->p_token; + _INTERPRET_ERROR("Expected expression", p_token); } + + array_unshift(p_array, stack_pop(p_interpret->p_stack)); } - /* It is not a function, it is a variable or some sort of */ + _NEXT + } - char *c_name = token_get_val(p_interpret->p_token); - Symbol *p_symbol = scope_get(p_interpret->p_scope, c_name); + stack_push(p_interpret->p_stack, p_token_arr); + _NEXT + return (1); +} - if (p_symbol == NULL) - _INTERPRET_ERROR("No such symbol", p_interpret->p_token); +/* Handle the TT_PARANT_L case in _term(): evaluate a parenthesised + * expression and verify the closing ')'. */ +static int +_term_paren(Interpret *p_interpret) { + Token *p_token = p_interpret->p_token; + _NEXT - SymbolType st = symbol_get_sym(p_symbol); + if (_expression_(p_interpret)) { + if (p_interpret->tt != TT_PARANT_R) + _INTERPRET_ERROR("Expected ')'", p_token); - switch (st) { - case SYM_VARIABLE: - stack_push(p_interpret->p_stack, symbol_get_val(p_symbol)); - _NEXT - return (1); + } else { + _INTERPRET_ERROR("Expected expression", p_token); + } - /* Example: proc foo { foo = "Hello"; } foo; say foo; */ - case SYM_PROCEDURE: - stack_push(p_interpret->p_stack, symbol_get_val(p_symbol)); + _NEXT + return (1); +} + +/* Evaluate a single atomic expression term and push its value onto the eval + * stack. Dispatches to per-case helpers for the complex TT_IDENT, + * TT_PARANT_AL, and TT_PARANT_L cases. + * Returns 1 on match, 2 on token-stream exhaustion, 0 on no match. */ +int +_term(Interpret *p_interpret) { + _CHECK TRACK + + switch (p_interpret->tt) { + case TT_ARRAY: + case TT_STRING: + case TT_INTEGER: + case TT_DOUBLE: + stack_push(p_interpret->p_stack, p_interpret->p_token); + // Checks if the term is the last element of an array + // say ["element"] # The "element" + // or of a function + // func foo { say 1 } # The 1 + if (_NEXT_TT != TT_PARANT_AR && _NEXT_TT != TT_PARANT_CR) _NEXT return (1); - NO_DEFAULT; - } - } - break; + case TT_IDENT: + return (_term_ident(p_interpret)); + case TT_DEFINED: { _NEXT @@ -1210,7 +1271,7 @@ _term(Interpret *p_interpret) { Token *p_token = NULL; Symbol *p_symbol = NULL; - if ((p_symbol = scope_remove(p_interpret->p_scope, c_name))) { + if ((p_symbol = scope_remove(p_interpret->p_scope, c_name))) { symbol_delete(p_symbol); p_token = token_new_integer(1); @@ -1237,7 +1298,6 @@ _term(Interpret *p_interpret) { if (p_symbol == NULL) _INTERPRET_ERROR("No such symbol", p_interpret->p_token); - Token *p_token_num_refs = token_new_integer(p_symbol->i_refs); stack_push(p_interpret->p_stack, p_token_num_refs); @@ -1247,47 +1307,10 @@ _term(Interpret *p_interpret) { break; case TT_PARANT_AL: - { - Token *p_token_arr = token_new_array(ARRAY_SIZE); - Array *p_array = p_token_arr->p_array; - - _NEXT - // Get the array elements - while (p_interpret->tt != TT_PARANT_AR) { - TokenType tt = tt = p_interpret->tt; - if (tt != TT_COMMA && tt != TT_SEMICOLON) { - UNLESS (_expression_(p_interpret)) { - Token *p_token = p_interpret->p_token; - _INTERPRET_ERROR("Expected expression", p_token); - } - - array_unshift(p_array, stack_pop(p_interpret->p_stack)); - } - - _NEXT - } - - stack_push(p_interpret->p_stack, p_token_arr); - _NEXT - return (1); - } - break; + return (_term_array_literal(p_interpret)); case TT_PARANT_L: - { - Token *p_token = p_interpret->p_token; - _NEXT - - if (_expression_(p_interpret)) { - if (p_interpret->tt != TT_PARANT_R) - _INTERPRET_ERROR("Expected ')'", p_token); - - } else { - _INTERPRET_ERROR("Expected expression", p_token); - } - } - _NEXT - return (1); + return (_term_paren(p_interpret)); default: break; @@ -131,6 +131,9 @@ _statement ./src/core/interpret.c /^_statement(Interpret *p_interpret) {$/;" f t _sum ./src/core/interpret.c /^_sum(Interpret *p_interpret) {$/;" f typeref:typename:int _term ./src/core/interpret.c /^_term(Interpret *p_interpret) {$/;" f typeref:typename:int _term_array_access ./src/core/interpret.c /^_term_array_access(Interpret *p_interpret,$/;" f typeref:typename:int +_term_array_literal ./src/core/interpret.c /^_term_array_literal(Interpret *p_interpret) {$/;" f typeref:typename:int file: +_term_ident ./src/core/interpret.c /^_term_ident(Interpret *p_interpret) {$/;" f typeref:typename:int file: +_term_paren ./src/core/interpret.c /^_term_paren(Interpret *p_interpret) {$/;" f typeref:typename:int file: _tree_print ./src/data/tree.c /^_tree_print(TreeNode *p_treenode, int i_indent) {$/;" f typeref:typename:void _tree_print_cb ./src/data/tree.c /^_tree_print_cb(void *p_void, void *p_indent) {$/;" f typeref:typename:void _tree_print_cb2 ./src/data/tree.c /^_tree_print_cb2(void *p_void, void *p_indent) {$/;" f typeref:typename:void |
