diff options
| -rw-r--r-- | docs/help.txt | 2 | ||||
| -rw-r--r-- | docs/stats.txt | 4 | ||||
| -rw-r--r-- | docs/version.txt | 2 | ||||
| -rw-r--r-- | examples/all-examples.txt | 589 | ||||
| -rwxr-xr-x | fype | bin | 278432 -> 288064 bytes | |||
| -rw-r--r-- | src/build.h | 2 | ||||
| -rw-r--r-- | src/core/functions.c | 961 | ||||
| -rw-r--r-- | tags | 50 |
8 files changed, 873 insertions, 737 deletions
diff --git a/docs/help.txt b/docs/help.txt index 06b1017..f4a8e65 100644 --- a/docs/help.txt +++ b/docs/help.txt @@ -1,4 +1,4 @@ -Fype Superalpha Build 9686 +Fype Superalpha Build 9691 (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 190942c..fdb7486 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 : 8602 +===> Num of C source lines : 8686 ===> Num of Fype source examples : 19 -===> Num of Fype source lines : 822 +===> 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 0087354..e0f6705 100644 --- a/docs/version.txt +++ b/docs/version.txt @@ -1 +1 @@ -Fype Superalpha Build 9686 +Fype Superalpha Build 9691 diff --git a/examples/all-examples.txt b/examples/all-examples.txt index 5349073..0ca0393 100644 --- a/examples/all-examples.txt +++ b/examples/all-examples.txt @@ -493,329 +493,390 @@ assert say integer double string put say neg 12; # Nonsense but working :) #* - * Fype uber-example: exercises every language feature. - * Every assertion must pass for the script to exit cleanly. + * Student Score Report — Fype uber-example + * + * Analyses a class of ten exam scores (0-100) and produces a brief + * statistical summary. Every Fype language feature is exercised in + * service of the analysis; all assertions must pass for the script + * to exit cleanly. *# -# ─── 1. COMMENTS ───────────────────────────────────────────────────────────── +# ─── DATASET ─────────────────────────────────────────────────────────────── +# Ten student exam scores. We will compute sum, average, band counts, etc. +my scores = [72, 45, 89, 91, 55, 78, 63, 100, 48, 82]; +my N = 10; # number of students +my PASS = 60; # minimum score for a pass +my DIST = 80; # minimum score for a distinction -# Single-line comment — ignored completely. +# ─── 1. COMMENTS ─────────────────────────────────────────────────────────── -#* - * Block comment: also ignored. - *# +# Single-line comment — ignored. +#* Block comment — also ignored. *# -# Inline block comment inside an expression: -my commentsok = 1 #* this is ignored *# + 1; -assert 2 == say commentsok; +# Inline block comment inside an expression — the #* *# part is discarded: +my ok = 1 #* invisible *# + 0; +assert 1 == ok; -# ─── 2. VARIABLES AND BASIC ARITHMETIC ─────────────────────────────────────── +# ─── 2. BASIC ARITHMETIC AND VARIABLES ───────────────────────────────────── -# Multiple declarations on one line; bay gets the default value 0 -my x = 10, y = 3, bay; -assert 0 == say bay; -assert 13 == say x + y; -assert 7 == say x - y; -assert 30 == say x * y; -assert 3 == say x / y; # integer division truncates toward zero +# Multiple declarations on one line; band defaults to 0. +my a = 10, b = 3, band; +assert 0 == say band; +assert 13 == say a + b; +assert 7 == say a - b; +assert 30 == say a * b; +assert 3 == say a / b; # integer division truncates toward zero assert 10 == say 2 * (4 + 2) - 2; assert 10 == say (8 / 2) + 2 * 3; -x = x + 1; -assert 11 == say x; - -# ─── 3. NEGATION AND NOT ────────────────────────────────────────────────────── - -assert 5 == say neg neg 5; -assert 0 == say neg neg 0; -assert (neg 1) == (say neg not 0); # not 0 => 1, neg 1 => -1 - -# ─── 4. INCREMENT / DECREMENT ──────────────────────────────────────────────── - -my counter = 5; -incr counter; -assert 6 == say counter; -decr counter; -decr counter; -assert 4 == say counter; - -# ─── 5. TYPE CONVERSION ─────────────────────────────────────────────────────── - -assert 2 == say integer 2.8; # truncates toward zero -assert 1 == say double 1; # 1.0 compared as 1 -assert 14 == say 1 + string 13; # "13" coerced to integer 13 -assert 5 == say "10 bla" / 2; # leading digits extracted - -# ─── 6. STRING ARITHMETIC ──────────────────────────────────────────────────── - -assert 46 == say "12" + "34"; # "12"->12 + "34"->34 = 46 -assert 1231 == say "1234" - "3"; # 1234 - 3 = 1231 -assert 5 == say "10 bla" / 2; - -# ─── 7. COMPARISON OPERATORS ───────────────────────────────────────────────── - -assert 1 == (put 5 > 3); assert 0 == (say 5 > 5); -assert 1 == (put 5 >= 5); assert 0 == (say 4 >= 5); -assert 1 == (put 3 < 5); assert 0 == (say 5 < 5); -assert 1 == (put 3 <= 5); assert 0 == (say 6 <= 5); -assert 1 == (put 5 == 5); assert 0 == (say 4 == 5); -assert 1 == (put 5 != 4); assert 0 == (say 5 != 5); - -# ─── 8. BITWISE OPERATORS ──────────────────────────────────────────────────── - -assert 1 == say (5 and 3); # 0b101 & 0b011 = 0b001 = 1 -assert 7 == say (5 or 2); # 0b101 | 0b010 = 0b111 = 7 -assert 6 == say (5 xor 3); # 0b101 ^ 0b011 = 0b110 = 6 -assert 8 == say (2 :< 2); # 2 << 2 = 8 -assert 2 == say (8 :> 2); # 8 >> 2 = 2 -assert 0 == say (1 and 0); -assert 1 == say (0 or 1); -assert 0 == say (1 xor 1); - -# ─── 9. CONDITIONALS ───────────────────────────────────────────────────────── - -my flag = 0; -if 1 { flag = 1; } -assert 1 == say flag; - -ifnot 0 { flag = 2; } -assert 2 == say flag; - -if 0 { flag = 99; } # must not execute -ifnot 1 { flag = 99; } # must not execute -assert 2 == say flag; - -# ─── 10. WHILE AND UNTIL ───────────────────────────────────────────────────── - -my cnt = 0; -while cnt < 5 { cnt = cnt + 1; } -assert 5 == say cnt; - -cnt = 0; -until cnt >= 4 { cnt = cnt + 1; } -assert 4 == say cnt; - -# ─── 11. LOOP WITH BREAK AND NEXT ──────────────────────────────────────────── +# Assignment is also an expression that returns the new value. +assert 15 == (a = 15); +assert 15 == say a; + +# ─── 3. NEGATION AND NOT ─────────────────────────────────────────────────── + +assert 5 == say neg neg 5; +assert 0 == say neg neg 0; +assert 1 == say not 0; +assert 0 == say not 1; + +# Temporarily penalise the first score by 5, then restore it. +my s0 = scores[0]; # 72 +s0 = s0 - 5; +assert 67 == say s0; +s0 = s0 + 5; +assert 72 == say s0; + +# ─── 4. INCREMENT / DECREMENT ────────────────────────────────────────────── + +# Used as statements: +my tally = 0; +incr tally; incr tally; incr tally; +assert 3 == say tally; +decr tally; +assert 2 == say tally; + +# Used as expressions (return the new value): +my step = 0; +assert 1 == say incr step; +assert 0 == say decr step; + +# ─── 5. TYPE CONVERSION ──────────────────────────────────────────────────── + +assert 7 == say integer 7.9; # truncates toward zero +assert 80 == say double 80; # 80.0 compares equal to 80 +assert 14 == say 1 + string 13; # "13" coerced to integer 13 +assert 5 == say "10 pts" / 2; # leading digits extracted first + +# ─── 6. STRING ARITHMETIC ────────────────────────────────────────────────── + +assert 46 == say "12" + "34"; # "12"->12 + "34"->34 = 46 +assert 1231 == say "1234" - "3"; # 1234 - 3 = 1231 + +# ─── 7. COMPARISON OPERATORS ─────────────────────────────────────────────── + +assert 1 == (put scores[0] > PASS); ln; # 72 > 60 => 1 +assert 0 == (put scores[1] > PASS); ln; # 45 > 60 => 0 +assert 1 == (put scores[3] >= DIST); ln; # 91 >= 80 => 1 +assert 1 == (put PASS != DIST); ln; +assert 0 == (say PASS == DIST); +assert 1 == (put 3 < 5); assert 0 == (say 5 < 5); ln; +assert 1 == (put 5 <= 5); assert 0 == (say 6 <= 5); ln; + +# ─── 8. BITWISE GRADE FLAGS ──────────────────────────────────────────────── +# Encode quality: bit 0 = passed (>=PASS), bit 1 = distinction (>=DIST). + +# Score 91 => passed AND distinction => 0b11 = 3 +my g91 = 0; +if scores[3] >= PASS { g91 = g91 or 1; } +if scores[3] >= DIST { g91 = g91 or 2; } +assert 3 == say g91; + +# Score 45 => failed => 0b00 = 0 +my g45 = 0; +if scores[1] >= PASS { g45 = g45 or 1; } +assert 0 == say g45; + +assert 1 == say (g91 and 1); # extract pass bit from g91 +assert 0 == say (g45 and 1); # extract pass bit from g45 +assert 6 == say (5 xor 3); # 0b101 ^ 0b011 = 0b110 = 6 +assert 4 == say (1 :< 2); # 1 << 2 = 4 +assert 2 == say (8 :> 2); # 8 >> 2 = 2 + +# ─── 9. CONDITIONALS ─────────────────────────────────────────────────────── + +# 91 is a distinction +if scores[3] >= DIST { band = 2; } +assert 2 == say band; + +# 45 is a fail +ifnot scores[1] >= PASS { band = 0; } +assert 0 == say band; + +if 0 { band = 99; } # must not execute +ifnot 1 { band = 99; } # must not execute +assert 0 == say band; + +# ─── 10. WHILE + UNTIL: SUM ALL SCORES ───────────────────────────────────── +# 72+45+89+91+55+78+63+100+48+82 = 723 + +my total = 0, wi = 0; +while wi < N { + total = total + scores[wi]; + incr wi; +} +assert 723 == say total; -my n = 0; -loop { - n = n + 1; - if n == 7 { break; } +my total2 = 0, ui = 0; +until ui >= N { + total2 = total2 + scores[ui]; + incr ui; } -assert 7 == say n; +assert 723 == say total2; + +# ─── 11. LOOP + BREAK + NEXT: COUNT PASSING SCORES ───────────────────────── +# Scores >= 60: 72,89,91,78,63,100,82 => 7 students -# Sum 1..10 skipping multiples of 3: 1+2+4+5+7+8+10 = 37 -my total = 0, step = 0; +my passing = 0, li = 0; loop { - step = step + 1; - if step > 10 { break; } - if step / 3 * 3 == step { next; } # divisible by 3 - total = total + step; + if li >= N { break; } + if scores[li] < PASS { li = li + 1; next; } + incr passing; + incr li; } -assert 37 == say total; +assert 7 == say passing; -# ─── 12. WHILE WITH BREAK AND NEXT ─────────────────────────────────────────── +# ─── 12. WHILE + BREAK + NEXT: COUNT DISTINCTIONS ────────────────────────── +# Scores >= 80: 89,91,100,82 => 4 students -# Sum 1..10 skipping 5, stopping after 8: 1+2+3+4 + 6+7+8 = 31 -my wsum = 0, wi = 0; -while wi < 10 { - wi = wi + 1; - if wi == 5 { next; } - if wi > 8 { break; } - wsum = wsum + wi; +my dists = 0, di = 0; +while di < N { + incr di; + if scores[di - 1] < DIST { next; } + incr dists; } -assert 31 == say wsum; +assert 4 == say dists; -# ─── 13. DO-WHILE / DO-UNTIL ───────────────────────────────────────────────── +# ─── 13. DO-WHILE / DO-UNTIL ─────────────────────────────────────────────── -# Body runs once even though the condition is already false +# Body runs once even though the condition is already false. my dw = 10; do { dw = dw + 1; } while dw < 10; assert 11 == say dw; -my du = 0; -do { du = du + 1; } until du == 5; -assert 5 == say du; - -# ─── 14. PROCEDURES ────────────────────────────────────────────────────────── - -# Procedures share the caller's scope; mutations are visible to the caller -my acc = 0; -proc bump { acc = acc + 10; } -bump; -bump; -assert 20 == say acc; - -# Variables declared inside a procedure leak into the caller's scope -proc initcoords { my cx = 3; my cy = 7; } -initcoords; -assert 3 == say cx; -assert 7 == say cy; - -# ─── 15. FUNCTIONS ─────────────────────────────────────────────────────────── - -# Zero-arg function with explicit return -fun answer() { ret 42; } -assert 42 == say answer(); - -# Single-arg -fun square(m) { ret m * m; } -assert 25 == say square(5); -assert 0 == say square(0); - -# Two-arg -fun add(a, b) { ret a + b; } -assert 9 == say add(4, 5); +# Accumulate scores until the running total exceeds 500 (runs at least once). +# After 8 iterations: 72+45+89+91+55+78+63+100 = 593. +my rsum = 0, ri = 0; +do { + rsum = rsum + scores[ri]; + incr ri; +} while rsum < 500; +assert 593 == say rsum; +assert 8 == say ri; + +# do-until: count down from 3 to 0. +my cd = 3; +do { decr cd; } until cd == 0; +assert 0 == say cd; + +# ─── 14. FUNCTIONS ───────────────────────────────────────────────────────── + +# Sum the first n elements of an array. +fun arr_sum(arr, n) { + my s = 0, i = 0; + while i < n { + s = s + arr[i]; + incr i; + } + ret s; +} +assert 723 == say arr_sum(scores, N); -# Conditional return -fun absval(v) { - if v < 0 { ret neg v; } - ret v; +# Integer average (floor division). +fun avg(arr, n) { + ret arr_sum(arr, n) / n; } -assert 7 == say absval(7); -assert 7 == say absval(neg 7); +assert 72 == say avg(scores, N); -# Iterative function with local variables and decr -fun factorial(num) { - my result = 1; - while num > 1 { - result = result * num; - decr num; - } - ret result; +# Conditional return: grade band (0=fail, 1=pass, 2=distinction). +fun grade_band(score) { + if score >= DIST { ret 2; } + if score >= PASS { ret 1; } + ret 0; } -assert 1 == say factorial(0); -assert 1 == say factorial(1); -assert 120 == say factorial(5); -assert 720 == say factorial(6); - -# Iterative fibonacci using local variables -fun fib(num) { - if num <= 1 { ret num; } - my fa = 0, fb = 1, ftmp = 0, fi = 2; - while fi <= num { - ftmp = fa + fb; - fa = fb; - fb = ftmp; - fi = fi + 1; +assert 2 == say grade_band(91); +assert 1 == say grade_band(72); +assert 0 == say grade_band(45); + +# Multiple return values: minimum and maximum of an array. +fun arr_minmax(arr, n) { + my mn = arr[0], mx = arr[0], i = 1; + while i < n { + if arr[i] < mn { mn = arr[i]; } + if arr[i] > mx { mx = arr[i]; } + incr i; } - ret fb; + ret mn, mx; # prints 45 then 100 } -assert 0 == say fib(0); -assert 1 == say fib(1); -assert 1 == say fib(2); -assert 8 == say fib(6); -assert 55 == say fib(10); - -# Old-style zero-arg function (no parentheses) -fun greet { say "hello from greet"; } -greet; +say arr_minmax(scores, N); -# Multiple return values both land on the caller's stack (printed here) -fun minmax(a, b) { - if a < b { ret a, b; } - ret b, a; +# Nested function: range check (returns 1 if 0 <= score <= 100). +fun valid_score(score) { + fun in_range(v) { + if v >= 0 { if v <= 100 { ret 1; } } + ret 0; + } + ret in_range(score); +} +assert 1 == say valid_score(72); +assert 0 == say valid_score(neg 1); +assert 0 == defined in_range; # nested function gone after the call + +# Old-style zero-arg function (no parentheses). +fun banner { say "=== Student Score Report ==="; } +banner; + +# Self-undefining one-shot function. +fun init_once { say "Initialising report..."; undef init_once; } +init_once; +assert 0 == defined init_once; + +# ─── 15. PROCEDURES ──────────────────────────────────────────────────────── +# Procedures share the caller's scope; mutations are visible to the caller. + +my accum = total; # start from the already-computed sum +proc apply_bonus { accum = accum + 10; } +apply_bonus; apply_bonus; +assert 743 == say accum; # 723 + 20 + +# Variables declared inside a procedure leak into the caller's scope. +proc make_summary { + my summary_pass = passing; + my summary_dist = dists; } -say minmax(3, 7); # prints 3 then 7 +make_summary; +assert 7 == say summary_pass; +assert 4 == say summary_dist; -# ─── 16. SCOPING ───────────────────────────────────────────────────────────── +# ─── 16. SCOPING ─────────────────────────────────────────────────────────── my outer = 100; { - my inner = 200; + my inner = 50; outer = outer + inner; assert 1 == defined inner; + scope; # prints all symbols visible here } -assert 300 == say outer; -assert 0 == defined inner; +assert 150 == say outer; +assert 0 == defined inner; # inner vanished when the block closed -# Variables defined in nested blocks vanish when the block closes +# Deep nesting: mutate a counter from three levels deep. my depth = 0; { - depth = depth + 1; - { - depth = depth + 1; - { depth = depth + 1; } - assert 3 == say depth; - } + incr depth; + { incr depth; { incr depth; } } } assert 3 == say depth; -# ─── 17. SYNONYMS / ALIASES ────────────────────────────────────────────────── +# ─── 17. SYNONYMS / ALIASES ──────────────────────────────────────────────── -my orig = 42; -my alias = \orig; -assert 42 == say alias; # alias starts with orig's value +my best = scores[3]; # 91 +my top = \best; # top is a synonym for best +assert 91 == say top; -orig = 99; -assert 99 == say alias; # alias reflects the change +best = 95; # update through the original name +assert 95 == say top; # synonym reflects the change -assert 2 == syms orig; # two symbols point to the same value -undef orig; -assert 1 == syms alias; -assert 0 == defined orig; -assert 1 == defined alias; -undef alias; +assert 2 == syms best; +undef best; +assert 1 == syms top; +assert 0 == defined best; +assert 1 == defined top; +undef top; -# Procedure synonym -proc grp { say "grp called"; } -my grp2 = \grp; -assert 2 == syms grp; -grp2; # still callable through the alias -undef grp; -grp2; # alias keeps it alive -assert 0 == defined grp; -undef grp2; +# Procedure synonym keeps the procedure alive after the original is undefined. +proc show_band { put "band="; say grade_band(91); } +my show_band2 = \show_band; +assert 2 == syms show_band; +show_band2; +undef show_band; +show_band2; # alias still callable +assert 0 == defined show_band; +undef show_band2; -# ─── 18. DEFINED AND UNDEF ─────────────────────────────────────────────────── +# ─── 18. DEFINED / UNDEF ─────────────────────────────────────────────────── -my tmpvar = 5; -assert 1 == defined tmpvar; +my tmp = 42; +assert 1 == defined tmp; assert 0 == defined nosuchvar; -undef tmpvar; -assert 0 == defined tmpvar; +undef tmp; +assert 0 == defined tmp; # ─── 19. ARRAYS — LITERALS, INDEXING, ASSIGNMENT ──────────────────────────── -my nums = [10, 20, 30, 40, 50]; -assert 5 == say len nums; -assert 10 == say nums[0]; -assert 30 == say nums[2]; -assert 50 == say nums[4]; - -# Expression-based index -my idx = 1; -assert 20 == say nums[idx]; -assert 30 == say nums[idx + 1]; - -# Element assignment -nums[2] = 99; -assert 99 == say nums[2]; - -# ─── 20. ARRAY SLICES ──────────────────────────────────────────────────────── - -# nums is now [10, 20, 99, 40, 50] -my sl = nums[1:4]; # half-open: indices 1, 2, 3 -assert 3 == say len sl; -assert 20 == say sl[0]; -assert 99 == say sl[1]; -assert 40 == say sl[2]; +my extra = [5, 10, 15, 20, 25]; +assert 5 == say len extra; +assert 5 == say extra[0]; +assert 15 == say extra[2]; + +# Element assignment. +extra[2] = 99; +assert 99 == say extra[2]; + +# Expression-based index. +my ei = 1; +assert 10 == say extra[ei]; +assert 99 == say extra[ei + 1]; + +# ─── 20. ARRAY SLICES ────────────────────────────────────────────────────── +# scores is [72, 45, 89, 91, 55, 78, 63, 100, 48, 82] + +# Half-open slice: indices 2, 3, 4 => [89, 91, 55] +my mid = scores[2:5]; +assert 3 == say len mid; +assert 89 == say mid[0]; +assert 55 == say mid[2]; + +# Slice from start (low bound omitted): first three => [72, 45, 89] +my first3 = scores[:3]; +assert 3 == say len first3; +assert 72 == say first3[0]; +assert 89 == say first3[2]; + +# Slice to end (high bound omitted): from index 7 => [100, 48, 82] +my tail = scores[7:]; +assert 3 == say len tail; +assert 100 == say tail[0]; +assert 82 == say tail[2]; + +# Full shallow copy. +my copy = scores[:]; +assert 10 == say len copy; +assert 72 == say copy[0]; +assert 82 == say copy[9]; + +# ─── 21. I/O ─────────────────────────────────────────────────────────────── + +put "Total: "; put total; ln; +put "Average: "; put avg(scores, N); ln; +put "Passing: "; put passing; ln; +put "Distincts: "; say dists; + +# ─── 22. FORK ────────────────────────────────────────────────────────────── +# Child process computes the same sum independently; parent waits. -my head = nums[:2]; # first two elements -assert 2 == say len head; -assert 10 == say head[0]; -assert 20 == say head[1]; +my pid = fork; -my tail = nums[3:]; # from index 3 to end -assert 2 == say len tail; -assert 40 == say tail[0]; -assert 50 == say tail[1]; +if pid { + put "Parent: child pid = "; say pid; +} -my cpy = nums[:]; # full shallow copy -assert 5 == say len cpy; -assert 10 == say cpy[0]; -assert 50 == say cpy[4]; +ifnot pid { + put "Child: score sum = "; say arr_sum(scores, N); + exit 0; +} +# ─── DONE ────────────────────────────────────────────────────────────────── say "All assertions passed."; #* Binary files differdiff --git a/src/build.h b/src/build.h index 161c8f2..ab16e44 100644 --- a/src/build.h +++ b/src/build.h @@ -36,7 +36,7 @@ #ifndef BUILD_H #define BUILD_H -#define BUILDNR 9689 +#define BUILDNR 9696 #define OS_LINUX #endif diff --git a/src/core/functions.c b/src/core/functions.c index af889e2..d4a2b51 100644 --- a/src/core/functions.c +++ b/src/core/functions.c @@ -455,506 +455,533 @@ functions_delete(Functions *p_functions) { /* ─── Operator processing ────────────────────────────────────────────── */ -void -_process(Interpret *p_interpret, Token *p_token_store, Token *p_token_op, - Token *p_token_op2, Token *p_token_next) { +/* Resolve a two-token compound operator into its canonical single TokenType. + * For example, '!' + '=' becomes TT_NEQ, ':' + '<' becomes TT_LSHIFT. + * Returns tt_op unchanged when no compound match is found. */ +static TokenType +_resolve_composite_op(TokenType tt_op, TokenType tt_op2) { + switch (tt_op) { + case TT_NOT: + if (tt_op2 == TT_ASSIGN) return (TT_NEQ); + break; + case TT_ASSIGN: + if (tt_op2 == TT_ASSIGN) return (TT_EQ); + break; + case TT_LT: + if (tt_op2 == TT_ASSIGN) return (TT_LE); + break; + case TT_GT: + if (tt_op2 == TT_ASSIGN) return (TT_GE); + break; + case TT_DDOT: + if (tt_op2 == TT_LT) return (TT_LSHIFT); + if (tt_op2 == TT_GT) return (TT_RSHIFT); + break; + default: + break; + } + return (tt_op); +} - TokenType tt_op = token_get_tt(p_token_op); - TokenType tt_op2 = p_token_op2 == NULL - ? TT_NONE - : token_get_tt(p_token_op2); +/* Perform variable or array-element assignment. + * If p_interpret->p_token_array_lhs is set, writes into that array slot; + * otherwise writes into the named variable in p_interpret->p_token_temp. */ +static void +_op_assign(Interpret *p_interpret, Token *p_token_store) { + /* Array element assignment: arr[i] = val */ + if (p_interpret->p_token_array_lhs != NULL) { + array_set(p_interpret->p_token_array_lhs->p_array, + p_interpret->i_array_lhs_index, + p_token_store); + p_interpret->p_token_array_lhs = NULL; + return; + } -#ifdef DEBUG_FUNCTION_PROCESS - if (p_token_op2 == NULL) - printf("DEBUG::FUNCTION::PROCESS: Operator %s\n", tt_get_name(tt_op)); - else - printf("DEBUG::FUNCTION::PROCESS: Operator %s %s\n", tt_get_name(tt_op), - tt_get_name(tt_op2)); + /* Regular variable assignment */ + Token *p_token_assign = p_interpret->p_token_temp; + TokenType tt_assign = token_get_tt(p_token_assign); - token_print(p_token_next); - printf("\n"); - token_print(p_token_store); - printf("\n"); -#endif /* DEBUG_FUNCTION_PROCESS */ + if (tt_assign != TT_IDENT) { + _FUNCTIONS_ERROR("Can only assign to symbols", p_token_store); + } - if (p_token_op2 != NULL) { - switch (tt_op) { - case TT_NOT: - switch (tt_op2) { - case TT_ASSIGN: - tt_op = TT_NEQ; - break; - default: - break; - } - break; - case TT_ASSIGN: - switch (tt_op2) { - case TT_ASSIGN: - tt_op = TT_EQ; - break; - default: - break; - } - break; - case TT_LT: - switch (tt_op2) { - case TT_ASSIGN: - tt_op = TT_LE; - break; - default: - break; - } - break; - case TT_GT: - switch (tt_op2) { - case TT_ASSIGN: - tt_op = TT_GE; - break; - default: - break; - } - break; - case TT_DDOT: - switch (tt_op2) { - case TT_LT: - tt_op = TT_LSHIFT; - break; - case TT_GT: - tt_op = TT_RSHIFT; - break; - default: - break; - } - break; - default: - break; - } - } else { - switch (tt_op) { - case TT_ASSIGN: - { - /* Array element assignment: arr[i] = val */ - if (p_interpret->p_token_array_lhs != NULL) { - array_set(p_interpret->p_token_array_lhs->p_array, - p_interpret->i_array_lhs_index, - p_token_store); - p_interpret->p_token_array_lhs = NULL; - return; - } + Symbol *p_symbol = scope_get(p_interpret->p_scope, + token_get_val(p_token_assign)); - /* Regular variable assignment */ - Token *p_token_assign = p_interpret->p_token_temp; - TokenType tt_assign = token_get_tt(p_token_assign); + if (p_symbol == NULL) { + _FUNCTIONS_ERROR("No such symbol", p_token_assign); + } - if (tt_assign != TT_IDENT) { - _FUNCTIONS_ERROR("Can only assign to symbols", - p_token_store); - } + symbol_set_val(p_symbol, p_token_store); + symbol_set_sym(p_symbol, SYM_VARIABLE); +} - Symbol *p_symbol = scope_get(p_interpret->p_scope, - token_get_val(p_token_assign)); +/* Addition: store = next + store (integers, doubles, strings, array append) */ +static void +_op_add(Token *p_store, Token *p_next, TokenType tt_highest) { + switch (tt_highest) { + case TT_INTEGER: + token_set_ival(p_store, + token_get_ival(p_next) + token_get_ival(p_store)); + break; + case TT_DOUBLE: + token_set_dval(p_store, + token_get_dval(p_next) + token_get_dval(p_store)); + break; + case TT_STRING: + token_set_ival(p_store, + atoi(token_get_val(p_next)) + + atoi(token_get_val(p_store))); + token_set_tt(p_store, TT_INTEGER); + break; + case TT_ARRAY: + array_append(p_store->p_array, p_next->p_array); + break; + NO_DEFAULT; + } +} - if (p_symbol == NULL) { - _FUNCTIONS_ERROR("No such symbol", - p_token_assign); - } +/* Subtraction: store = next - store */ +static void +_op_sub(Token *p_store, Token *p_next, TokenType tt_highest) { + switch (tt_highest) { + case TT_INTEGER: + token_set_ival(p_store, + token_get_ival(p_next) - token_get_ival(p_store)); + break; + case TT_DOUBLE: + token_set_dval(p_store, + token_get_dval(p_next) - token_get_dval(p_store)); + break; + case TT_STRING: + token_set_ival(p_store, + atoi(token_get_val(p_next)) - + atoi(token_get_val(p_store))); + token_set_tt(p_store, TT_INTEGER); + break; + case TT_ARRAY: + ERROR("TT_ARRAY - TT_ARRAY not yet implemented"); + break; + NO_DEFAULT; + } +} - symbol_set_val(p_symbol, p_token_store); - symbol_set_sym(p_symbol, SYM_VARIABLE); +/* Multiplication: store = next * store */ +static void +_op_mult(Token *p_store, Token *p_next, TokenType tt_highest) { + switch (tt_highest) { + case TT_INTEGER: + token_set_ival(p_store, + token_get_ival(p_next) * token_get_ival(p_store)); + break; + case TT_DOUBLE: + token_set_dval(p_store, + token_get_dval(p_next) * token_get_dval(p_store)); + break; + case TT_STRING: + token_set_ival(p_store, + atoi(token_get_val(p_next)) * + atoi(token_get_val(p_store))); + token_set_tt(p_store, TT_INTEGER); + break; + case TT_ARRAY: + ERROR("TT_ARRAY * TT_ARRAY not yet implemented"); + break; + NO_DEFAULT; + } +} - return; - } +/* Division: store = next / store */ +static void +_op_div(Token *p_store, Token *p_next, TokenType tt_highest) { + switch (tt_highest) { + case TT_INTEGER: + token_set_ival(p_store, + (int) token_get_ival(p_next) / + token_get_ival(p_store)); + break; + case TT_DOUBLE: + token_set_dval(p_store, + token_get_dval(p_next) / token_get_dval(p_store)); + break; + case TT_STRING: + token_set_dval(p_store, + atof(token_get_val(p_next)) / + atof(token_get_val(p_store))); + token_set_tt(p_store, TT_DOUBLE); + break; + case TT_ARRAY: + ERROR("TT_ARRAY / TT_ARRAY not yet implemented"); + break; + NO_DEFAULT; + } +} +/* Equality: store = (next == store) — result is always TT_INTEGER */ +static void +_op_eq(Token *p_store, Token *p_next, TokenType tt_highest) { + switch (tt_highest) { + case TT_INTEGER: + token_set_ival(p_store, + (int) token_get_ival(p_next) == + token_get_ival(p_store)); + break; + case TT_DOUBLE: + token_set_ival(p_store, + token_get_dval(p_next) == token_get_dval(p_store)); + token_set_tt(p_store, TT_INTEGER); + break; + case TT_STRING: + token_set_ival(p_store, + strcmp(token_get_val(p_next), + token_get_val(p_store)) == 0); + token_set_tt(p_store, TT_INTEGER); + break; + case TT_ARRAY: + ERROR("TT_ARRAY eq TT_ARRAY not yet implemented"); break; NO_DEFAULT; - } } +} - p_token_next = token_new_copy(p_token_next); - TokenType tt_highest = convert_to_highest(p_token_store, p_token_next); +/* Inequality: store = (next != store) — result is always TT_INTEGER */ +static void +_op_neq(Token *p_store, Token *p_next, TokenType tt_highest) { + switch (tt_highest) { + case TT_INTEGER: + token_set_ival(p_store, + (int) token_get_ival(p_next) != + token_get_ival(p_store)); + break; + case TT_DOUBLE: + token_set_ival(p_store, + token_get_dval(p_next) != token_get_dval(p_store)); + token_set_tt(p_store, TT_INTEGER); + break; + case TT_STRING: + token_set_ival(p_store, + strcmp(token_get_val(p_next), + token_get_val(p_store)) != 0); + token_set_tt(p_store, TT_INTEGER); + break; + case TT_ARRAY: + ERROR("TT_ARRAY != TT_ARRAY not yet implemented"); + break; + NO_DEFAULT; + } +} -#ifdef DEBUG_FUNCTION_PROCESS - printf("DEBUG::FUNCTION::PROCESS: ===> %s %s %s\n", - tt_get_name(tt_highest), - tt_get_name(tt_op), - tt_get_name(tt_highest)); -#endif /* DEBUG_FUNCTION_PROCESS */ +/* Less-than: store = (next < store) — result is always TT_INTEGER */ +static void +_op_lt(Token *p_store, Token *p_next, TokenType tt_highest) { + switch (tt_highest) { + case TT_INTEGER: + token_set_ival(p_store, + (int) token_get_ival(p_next) < + token_get_ival(p_store)); + break; + case TT_DOUBLE: + token_set_ival(p_store, + token_get_dval(p_next) < token_get_dval(p_store)); + token_set_tt(p_store, TT_INTEGER); + break; + case TT_STRING: + token_set_ival(p_store, + strcmp(token_get_val(p_next), + token_get_val(p_store)) < 0); + token_set_tt(p_store, TT_INTEGER); + break; + case TT_ARRAY: + ERROR("TT_ARRAY < TT_ARRAY not yet implemented"); + break; + NO_DEFAULT; + } +} - switch (tt_op) { - case TT_ADD: - switch (tt_highest) { - case TT_INTEGER: - token_set_ival(p_token_store, - token_get_ival(p_token_next) + - token_get_ival(p_token_store)); - break; - case TT_DOUBLE: - token_set_dval(p_token_store, - token_get_dval(p_token_next) + - token_get_dval(p_token_store)); - break; - case TT_STRING: - token_set_ival(p_token_store, - atoi(token_get_val(p_token_next)) + - atoi(token_get_val(p_token_store))); - token_set_tt(p_token_store, TT_INTEGER); - break; - case TT_ARRAY: - array_append(p_token_store->p_array, - p_token_next->p_array); - break; - NO_DEFAULT; - } +/* Greater-than: store = (next > store) — result is always TT_INTEGER */ +static void +_op_gt(Token *p_store, Token *p_next, TokenType tt_highest) { + switch (tt_highest) { + case TT_INTEGER: + token_set_ival(p_store, + (int) token_get_ival(p_next) > + token_get_ival(p_store)); break; - case TT_SUB: - switch (tt_highest) { - case TT_INTEGER: - token_set_ival(p_token_store, - token_get_ival(p_token_next) - - token_get_ival(p_token_store)); - break; - case TT_DOUBLE: - token_set_dval(p_token_store, - token_get_dval(p_token_next) - - token_get_dval(p_token_store)); - break; - case TT_STRING: - token_set_ival(p_token_store, - atoi(token_get_val(p_token_next)) - - atoi(token_get_val(p_token_store))); - token_set_tt(p_token_store, TT_INTEGER); - break; - case TT_ARRAY: - ERROR("TT_ARRAY - TT_ARRAY not yet implemented"); - break; - NO_DEFAULT; - } + case TT_DOUBLE: + token_set_ival(p_store, + token_get_dval(p_next) > token_get_dval(p_store)); + token_set_tt(p_store, TT_INTEGER); break; - case TT_MULT: - switch (tt_highest) { - case TT_INTEGER: - token_set_ival(p_token_store, - token_get_ival(p_token_next) * - token_get_ival(p_token_store)); - break; - case TT_DOUBLE: - token_set_dval(p_token_store, - token_get_dval(p_token_next) * - token_get_dval(p_token_store)); - break; - case TT_STRING: - token_set_ival(p_token_store, - atoi(token_get_val(p_token_next)) * - atoi(token_get_val(p_token_store))); - token_set_tt(p_token_store, TT_INTEGER); - break; - case TT_ARRAY: - ERROR("TT_ARRAY * TT_ARRAY not yet implemented"); - break; - NO_DEFAULT; - } + case TT_STRING: + token_set_ival(p_store, + strcmp(token_get_val(p_next), + token_get_val(p_store)) > 0); + token_set_tt(p_store, TT_INTEGER); break; - case TT_DIV: - switch (tt_highest) { - case TT_INTEGER: - token_set_ival(p_token_store, - (int) token_get_ival(p_token_next) / - token_get_ival(p_token_store)); - break; - case TT_DOUBLE: - token_set_dval(p_token_store, - token_get_dval(p_token_next) / - token_get_dval(p_token_store)); - break; - case TT_STRING: - token_set_dval(p_token_store, - atof(token_get_val(p_token_next)) / - atof(token_get_val(p_token_store))); - token_set_tt(p_token_store, TT_DOUBLE); - break; - case TT_ARRAY: - ERROR("TT_ARRAY / TT_ARRAY not yet implemented"); - break; - NO_DEFAULT; - } + case TT_ARRAY: + ERROR("TT_ARRAY > TT_ARRAY not yet implemented"); break; - case TT_EQ: - switch (tt_highest) { - case TT_INTEGER: - token_set_ival(p_token_store, - (int) token_get_ival(p_token_next) == - token_get_ival(p_token_store)); - break; - case TT_DOUBLE: - token_set_ival(p_token_store, - token_get_dval(p_token_next) == - token_get_dval(p_token_store)); - token_set_tt(p_token_store, TT_INTEGER); - break; - case TT_STRING: - token_set_ival(p_token_store, - strcmp(token_get_val(p_token_next), - token_get_val(p_token_store)) == 0); - token_set_tt(p_token_store, TT_INTEGER); - break; - case TT_ARRAY: - ERROR("TT_ARRAY eq TT_ARRAY not yet implemented"); - break; - NO_DEFAULT; - } + NO_DEFAULT; + } +} + +/* Less-or-equal: store = (next <= store) — result is always TT_INTEGER */ +static void +_op_le(Token *p_store, Token *p_next, TokenType tt_highest) { + switch (tt_highest) { + case TT_INTEGER: + token_set_ival(p_store, + (int) token_get_ival(p_next) <= + token_get_ival(p_store)); break; - case TT_NEQ: - switch (tt_highest) { - case TT_INTEGER: - token_set_ival(p_token_store, - (int) token_get_ival(p_token_next) != - token_get_ival(p_token_store)); - break; - case TT_DOUBLE: - token_set_ival(p_token_store, - token_get_dval(p_token_next) != - token_get_dval(p_token_store)); - token_set_tt(p_token_store, TT_INTEGER); - break; - case TT_STRING: - token_set_ival(p_token_store, - strcmp(token_get_val(p_token_next), - token_get_val(p_token_store)) != 0); - token_set_tt(p_token_store, TT_INTEGER); - break; - case TT_ARRAY: - ERROR("ARRAY bla yet implemented"); - break; - NO_DEFAULT; - } + case TT_DOUBLE: + token_set_ival(p_store, + token_get_dval(p_next) <= token_get_dval(p_store)); + token_set_tt(p_store, TT_INTEGER); break; - case TT_LE: - switch (tt_highest) { - case TT_INTEGER: - token_set_ival(p_token_store, - (int) token_get_ival(p_token_next) <= - token_get_ival(p_token_store)); - break; - case TT_DOUBLE: - token_set_ival(p_token_store, - token_get_dval(p_token_next) <= - token_get_dval(p_token_store)); - token_set_tt(p_token_store, TT_INTEGER); - break; - case TT_STRING: - token_set_ival(p_token_store, - strcmp(token_get_val(p_token_next), - token_get_val(p_token_store)) <= 0); - token_set_tt(p_token_store, TT_INTEGER); - break; - case TT_ARRAY: - ERROR("ARRAY bla yet implemented"); - break; - NO_DEFAULT; - } + case TT_STRING: + token_set_ival(p_store, + strcmp(token_get_val(p_next), + token_get_val(p_store)) <= 0); + token_set_tt(p_store, TT_INTEGER); break; - case TT_GE: - switch (tt_highest) { - case TT_INTEGER: - token_set_ival(p_token_store, - (int) token_get_ival(p_token_next) >= - token_get_ival(p_token_store)); - break; - case TT_DOUBLE: - token_set_ival(p_token_store, - token_get_dval(p_token_next) >= - token_get_dval(p_token_store)); - token_set_tt(p_token_store, TT_INTEGER); - break; - case TT_STRING: - token_set_ival(p_token_store, - strcmp(token_get_val(p_token_next), - token_get_val(p_token_store)) >= 0); - token_set_tt(p_token_store, TT_INTEGER); - break; - case TT_ARRAY: - ERROR("ARRAY bla yet implemented"); - break; - NO_DEFAULT; - } + case TT_ARRAY: + ERROR("TT_ARRAY <= TT_ARRAY not yet implemented"); break; - case TT_LT: - switch (tt_highest) { - case TT_INTEGER: - token_set_ival(p_token_store, - (int) token_get_ival(p_token_next) < - token_get_ival(p_token_store)); - break; - case TT_DOUBLE: - token_set_ival(p_token_store, - token_get_dval(p_token_next) < - token_get_dval(p_token_store)); - token_set_tt(p_token_store, TT_INTEGER); - break; - case TT_STRING: - token_set_ival(p_token_store, - strcmp(token_get_val(p_token_next), - token_get_val(p_token_store)) < 0); - token_set_tt(p_token_store, TT_INTEGER); - break; - case TT_ARRAY: - ERROR("ARRAY bla yet implemented"); - break; - NO_DEFAULT; - } + NO_DEFAULT; + } +} + +/* Greater-or-equal: store = (next >= store) — result is always TT_INTEGER */ +static void +_op_ge(Token *p_store, Token *p_next, TokenType tt_highest) { + switch (tt_highest) { + case TT_INTEGER: + token_set_ival(p_store, + (int) token_get_ival(p_next) >= + token_get_ival(p_store)); break; - case TT_GT: - switch (tt_highest) { - case TT_INTEGER: - token_set_ival(p_token_store, - (int) token_get_ival(p_token_next) > - token_get_ival(p_token_store)); - break; - case TT_DOUBLE: - token_set_ival(p_token_store, - token_get_dval(p_token_next) > - token_get_dval(p_token_store)); - token_set_tt(p_token_store, TT_INTEGER); - break; - case TT_STRING: - token_set_ival(p_token_store, - strcmp(token_get_val(p_token_next), - token_get_val(p_token_store)) > 0); - token_set_tt(p_token_store, TT_INTEGER); - break; - case TT_ARRAY: - ERROR("ARRAY bla yet implemented"); - break; - NO_DEFAULT; - } + case TT_DOUBLE: + token_set_ival(p_store, + token_get_dval(p_next) >= token_get_dval(p_store)); + token_set_tt(p_store, TT_INTEGER); break; - case TT_AND: - switch (tt_highest) { - case TT_INTEGER: - token_set_ival(p_token_store, - (int) token_get_ival(p_token_next) & - token_get_ival(p_token_store)); - break; - case TT_DOUBLE: - token_set_ival(p_token_store, - (int) token_get_dval(p_token_next) & - (int) token_get_dval(p_token_store)); - token_set_tt(p_token_store, TT_INTEGER); - break; - case TT_STRING: - token_set_ival(p_token_store, - atoi(token_get_val(p_token_next)) & - atoi(token_get_val(p_token_store))); - token_set_tt(p_token_store, TT_INTEGER); - break; - case TT_ARRAY: - ERROR("ARRAY bla yet implemented"); - break; - NO_DEFAULT; - } + case TT_STRING: + token_set_ival(p_store, + strcmp(token_get_val(p_next), + token_get_val(p_store)) >= 0); + token_set_tt(p_store, TT_INTEGER); break; - case TT_OR: - switch (tt_highest) { - case TT_INTEGER: - token_set_ival(p_token_store, - (int) token_get_ival(p_token_next) | - token_get_ival(p_token_store)); - break; - case TT_DOUBLE: - token_set_ival(p_token_store, - (int) token_get_dval(p_token_next) | - (int) token_get_dval(p_token_store)); - token_set_tt(p_token_store, TT_INTEGER); - break; - case TT_STRING: - token_set_ival(p_token_store, - atoi(token_get_val(p_token_next)) | - atoi(token_get_val(p_token_store))); - token_set_tt(p_token_store, TT_INTEGER); - break; - case TT_ARRAY: - ERROR("ARRAY bla yet implemented"); - break; - NO_DEFAULT; - } + case TT_ARRAY: + ERROR("TT_ARRAY >= TT_ARRAY not yet implemented"); break; - case TT_XOR: - switch (tt_highest) { - case TT_INTEGER: - token_set_ival(p_token_store, - (int) token_get_ival(p_token_next) ^ - token_get_ival(p_token_store)); - break; - case TT_DOUBLE: - token_set_ival(p_token_store, - (int) token_get_dval(p_token_next) ^ - (int) token_get_dval(p_token_store)); - token_set_tt(p_token_store, TT_INTEGER); - break; - case TT_STRING: - token_set_ival(p_token_store, - atoi(token_get_val(p_token_next)) ^ - atoi(token_get_val(p_token_store))); - token_set_tt(p_token_store, TT_INTEGER); - break; - case TT_ARRAY: - ERROR("ARRAY bla yet implemented"); - break; - NO_DEFAULT; - } + NO_DEFAULT; + } +} + +/* Bitwise AND: store = next & store — doubles and strings coerced to int */ +static void +_op_and(Token *p_store, Token *p_next, TokenType tt_highest) { + switch (tt_highest) { + case TT_INTEGER: + token_set_ival(p_store, + (int) token_get_ival(p_next) & + token_get_ival(p_store)); break; - case TT_LSHIFT: - switch (tt_highest) { - case TT_INTEGER: - token_set_ival(p_token_store, - (int) token_get_ival(p_token_next) << - token_get_ival(p_token_store)); - break; - case TT_DOUBLE: - token_set_ival(p_token_store, - (int) token_get_dval(p_token_next) << - (int) token_get_dval(p_token_store)); - token_set_tt(p_token_store, TT_INTEGER); - break; - case TT_STRING: - token_set_ival(p_token_store, - atoi(token_get_val(p_token_next)) << - atoi(token_get_val(p_token_store))); - token_set_tt(p_token_store, TT_INTEGER); - break; - case TT_ARRAY: - ERROR("ARRAY bla yet implemented"); - break; - NO_DEFAULT; - } + case TT_DOUBLE: + token_set_ival(p_store, + (int) token_get_dval(p_next) & + (int) token_get_dval(p_store)); + token_set_tt(p_store, TT_INTEGER); break; - case TT_RSHIFT: - switch (tt_highest) { - case TT_INTEGER: - token_set_ival(p_token_store, - (int) token_get_ival(p_token_next) >> - token_get_ival(p_token_store)); - break; - case TT_DOUBLE: - token_set_ival(p_token_store, - (int) token_get_dval(p_token_next) >> - (int) token_get_dval(p_token_store)); - token_set_tt(p_token_store, TT_INTEGER); - break; - case TT_STRING: - token_set_ival(p_token_store, - atoi(token_get_val(p_token_next)) >> - atoi(token_get_val(p_token_store))); - token_set_tt(p_token_store, TT_INTEGER); - break; - case TT_ARRAY: - ERROR("ARRAY bla yet implemented"); - break; - NO_DEFAULT; - } + case TT_STRING: + token_set_ival(p_store, + atoi(token_get_val(p_next)) & + atoi(token_get_val(p_store))); + token_set_tt(p_store, TT_INTEGER); + break; + case TT_ARRAY: + ERROR("TT_ARRAY & TT_ARRAY not yet implemented"); + break; + NO_DEFAULT; + } +} + +/* Bitwise OR: store = next | store — doubles and strings coerced to int */ +static void +_op_or(Token *p_store, Token *p_next, TokenType tt_highest) { + switch (tt_highest) { + case TT_INTEGER: + token_set_ival(p_store, + (int) token_get_ival(p_next) | + token_get_ival(p_store)); + break; + case TT_DOUBLE: + token_set_ival(p_store, + (int) token_get_dval(p_next) | + (int) token_get_dval(p_store)); + token_set_tt(p_store, TT_INTEGER); + break; + case TT_STRING: + token_set_ival(p_store, + atoi(token_get_val(p_next)) | + atoi(token_get_val(p_store))); + token_set_tt(p_store, TT_INTEGER); break; + case TT_ARRAY: + ERROR("TT_ARRAY | TT_ARRAY not yet implemented"); + break; + NO_DEFAULT; + } +} + +/* Bitwise XOR: store = next ^ store — doubles and strings coerced to int */ +static void +_op_xor(Token *p_store, Token *p_next, TokenType tt_highest) { + switch (tt_highest) { + case TT_INTEGER: + token_set_ival(p_store, + (int) token_get_ival(p_next) ^ + token_get_ival(p_store)); + break; + case TT_DOUBLE: + token_set_ival(p_store, + (int) token_get_dval(p_next) ^ + (int) token_get_dval(p_store)); + token_set_tt(p_store, TT_INTEGER); + break; + case TT_STRING: + token_set_ival(p_store, + atoi(token_get_val(p_next)) ^ + atoi(token_get_val(p_store))); + token_set_tt(p_store, TT_INTEGER); + break; + case TT_ARRAY: + ERROR("TT_ARRAY ^ TT_ARRAY not yet implemented"); + break; + NO_DEFAULT; + } +} +/* Left shift: store = next << store — doubles and strings coerced to int */ +static void +_op_lshift(Token *p_store, Token *p_next, TokenType tt_highest) { + switch (tt_highest) { + case TT_INTEGER: + token_set_ival(p_store, + (int) token_get_ival(p_next) << + token_get_ival(p_store)); + break; + case TT_DOUBLE: + token_set_ival(p_store, + (int) token_get_dval(p_next) << + (int) token_get_dval(p_store)); + token_set_tt(p_store, TT_INTEGER); + break; + case TT_STRING: + token_set_ival(p_store, + atoi(token_get_val(p_next)) << + atoi(token_get_val(p_store))); + token_set_tt(p_store, TT_INTEGER); + break; + case TT_ARRAY: + ERROR("TT_ARRAY << TT_ARRAY not yet implemented"); + break; + NO_DEFAULT; + } +} + +/* Right shift: store = next >> store — doubles and strings coerced to int */ +static void +_op_rshift(Token *p_store, Token *p_next, TokenType tt_highest) { + switch (tt_highest) { + case TT_INTEGER: + token_set_ival(p_store, + (int) token_get_ival(p_next) >> + token_get_ival(p_store)); + break; + case TT_DOUBLE: + token_set_ival(p_store, + (int) token_get_dval(p_next) >> + (int) token_get_dval(p_store)); + token_set_tt(p_store, TT_INTEGER); + break; + case TT_STRING: + token_set_ival(p_store, + atoi(token_get_val(p_next)) >> + atoi(token_get_val(p_store))); + token_set_tt(p_store, TT_INTEGER); + break; + case TT_ARRAY: + ERROR("TT_ARRAY >> TT_ARRAY not yet implemented"); + break; + NO_DEFAULT; + } +} + +/* Dispatch to the correct per-operator handler. + * 1. Resolve composite two-token operators (!=, ==, <=, >=, <<, >>). + * 2. Handle assignment early — it does not need type conversion. + * 3. Coerce both operands to their highest shared type. + * 4. Call the matching _op_*() function for the resolved operator. */ +void +_process(Interpret *p_interpret, Token *p_token_store, Token *p_token_op, + Token *p_token_op2, Token *p_token_next) { + + TokenType tt_op = token_get_tt(p_token_op); + TokenType tt_op2 = p_token_op2 == NULL + ? TT_NONE + : token_get_tt(p_token_op2); + +#ifdef DEBUG_FUNCTION_PROCESS + if (p_token_op2 == NULL) + printf("DEBUG::FUNCTION::PROCESS: Operator %s\n", + tt_get_name(tt_op)); + else + printf("DEBUG::FUNCTION::PROCESS: Operator %s %s\n", + tt_get_name(tt_op), tt_get_name(tt_op2)); + + token_print(p_token_next); + printf("\n"); + token_print(p_token_store); + printf("\n"); +#endif /* DEBUG_FUNCTION_PROCESS */ + + /* Resolve two-token operators (!=, ==, <=, >=, <<, >>). + * When p_token_op2 is NULL and operator is TT_ASSIGN, handle assignment + * directly — it does not need type conversion and must not fall through. */ + if (p_token_op2 != NULL) + tt_op = _resolve_composite_op(tt_op, tt_op2); + else if (tt_op == TT_ASSIGN) { + _op_assign(p_interpret, p_token_store); + return; + } + + p_token_next = token_new_copy(p_token_next); + TokenType tt_highest = convert_to_highest(p_token_store, p_token_next); + +#ifdef DEBUG_FUNCTION_PROCESS + printf("DEBUG::FUNCTION::PROCESS: ===> %s %s %s\n", + tt_get_name(tt_highest), tt_get_name(tt_op), + tt_get_name(tt_highest)); +#endif /* DEBUG_FUNCTION_PROCESS */ + + switch (tt_op) { + case TT_ADD: _op_add(p_token_store, p_token_next, tt_highest); break; + case TT_SUB: _op_sub(p_token_store, p_token_next, tt_highest); break; + case TT_MULT: _op_mult(p_token_store, p_token_next, tt_highest); break; + case TT_DIV: _op_div(p_token_store, p_token_next, tt_highest); break; + case TT_EQ: _op_eq(p_token_store, p_token_next, tt_highest); break; + case TT_NEQ: _op_neq(p_token_store, p_token_next, tt_highest); break; + case TT_LT: _op_lt(p_token_store, p_token_next, tt_highest); break; + case TT_GT: _op_gt(p_token_store, p_token_next, tt_highest); break; + case TT_LE: _op_le(p_token_store, p_token_next, tt_highest); break; + case TT_GE: _op_ge(p_token_store, p_token_next, tt_highest); break; + case TT_AND: _op_and(p_token_store, p_token_next, tt_highest); break; + case TT_OR: _op_or(p_token_store, p_token_next, tt_highest); break; + case TT_XOR: _op_xor(p_token_store, p_token_next, tt_highest); break; + case TT_LSHIFT: _op_lshift(p_token_store, p_token_next, tt_highest); break; + case TT_RSHIFT: _op_rshift(p_token_store, p_token_next, tt_highest); break; default: _FUNCTIONS_ERROR("No such function/operator", p_token_op); } @@ -38,6 +38,8 @@ !_TAG_ROLE_DESCRIPTION!C!struct foreigndecl /declared in foreign languages/ ARGV_OSLEN ./src/argv.c /^#define ARGV_OSLEN /;" d file: BINARY ./src/argv.c /^char *BINARY;$/;" v typeref:typename:char * +BuiltinEntry ./src/core/functions.c /^} BuiltinEntry;$/;" t typeref:struct:__anonc43baffb0108 file: +BuiltinFn ./src/core/functions.c /^typedef void (*BuiltinFn)(Interpret *p_interpret,$/;" t typeref:typename:void (*)(Interpret * p_interpret,Stack * p_stack_args,Token * p_token_ident) file: CASE ./src/core/token.c /^#define CASE(/;" d file: CHECK ./src/core/token.c /^#define CHECK(/;" d file: LIST_GARBAGE ./src/core/garbage.c /^List *LIST_GARBAGE = NULL;$/;" v typeref:typename:List * @@ -56,13 +58,40 @@ _NEXT_ORG ./src/core/interpret.c /^#define _NEXT_ORG /;" d file: _NEXT_TT ./src/core/interpret.c /^#define _NEXT_TT /;" d file: _SKIP ./src/core/interpret.c /^#define _SKIP /;" d file: _TOKENENDS ./src/core/scanner.c /^const char _TOKENENDS[] = "}])+-*\/={([<>;:,.!";$/;" v typeref:typename:const char[] +__anonc43baffb0108 ./src/core/functions.c /^typedef struct {$/;" s file: __anoneaa3b3cb0108 ./src/core/garbage.c /^typedef struct {$/;" s file: _add_semicolon_to_list ./src/core/scanner.c /^_add_semicolon_to_list(Scanner *p_scanner) {$/;" f typeref:typename:void _block ./src/core/interpret.c /^_block(Interpret *p_interpret) {$/;" f typeref:typename:int _block_get ./src/core/interpret.c /^_block_get(Interpret *p_interpret, List *p_list_block) {$/;" f typeref:typename:int _block_skip ./src/core/interpret.c /^_block_skip(Interpret *p_interpret) {$/;" f typeref:typename:int +_builtin_assert ./src/core/functions.c /^_builtin_assert(Interpret *p_interpret, Stack *p_stack_args,$/;" f typeref:typename:void file: +_builtin_decr ./src/core/functions.c /^_builtin_decr(Interpret *p_interpret, Stack *p_stack_args,$/;" f typeref:typename:void file: +_builtin_double ./src/core/functions.c /^_builtin_double(Interpret *p_interpret, Stack *p_stack_args,$/;" f typeref:typename:void file: +_builtin_end ./src/core/functions.c /^_builtin_end(Interpret *p_interpret, Stack *p_stack_args,$/;" f typeref:typename:void file: +_builtin_exit ./src/core/functions.c /^_builtin_exit(Interpret *p_interpret, Stack *p_stack_args,$/;" f typeref:typename:void file: +_builtin_fork ./src/core/functions.c /^_builtin_fork(Interpret *p_interpret, Stack *p_stack_args,$/;" f typeref:typename:void file: +_builtin_gc ./src/core/functions.c /^_builtin_gc(Interpret *p_interpret, Stack *p_stack_args,$/;" f typeref:typename:void file: +_builtin_incr ./src/core/functions.c /^_builtin_incr(Interpret *p_interpret, Stack *p_stack_args,$/;" f typeref:typename:void file: +_builtin_ind ./src/core/functions.c /^_builtin_ind(Interpret *p_interpret, Stack *p_stack_args,$/;" f typeref:typename:void file: +_builtin_integer ./src/core/functions.c /^_builtin_integer(Interpret *p_interpret, Stack *p_stack_args,$/;" f typeref:typename:void file: +_builtin_len ./src/core/functions.c /^_builtin_len(Interpret *p_interpret, Stack *p_stack_args,$/;" f typeref:typename:void file: +_builtin_ln ./src/core/functions.c /^_builtin_ln(Interpret *p_interpret, Stack *p_stack_args,$/;" f typeref:typename:void file: +_builtin_neg ./src/core/functions.c /^_builtin_neg(Interpret *p_interpret, Stack *p_stack_args,$/;" f typeref:typename:void file: +_builtin_no ./src/core/functions.c /^_builtin_no(Interpret *p_interpret, Stack *p_stack_args,$/;" f typeref:typename:void file: +_builtin_not ./src/core/functions.c /^_builtin_not(Interpret *p_interpret, Stack *p_stack_args,$/;" f typeref:typename:void file: +_builtin_put ./src/core/functions.c /^_builtin_put(Interpret *p_interpret, Stack *p_stack_args,$/;" f typeref:typename:void file: +_builtin_refs ./src/core/functions.c /^_builtin_refs(Interpret *p_interpret, Stack *p_stack_args,$/;" f typeref:typename:void file: +_builtin_say ./src/core/functions.c /^_builtin_say(Interpret *p_interpret, Stack *p_stack_args,$/;" f typeref:typename:void file: +_builtin_scope ./src/core/functions.c /^_builtin_scope(Interpret *p_interpret, Stack *p_stack_args,$/;" f typeref:typename:void file: +_builtin_string ./src/core/functions.c /^_builtin_string(Interpret *p_interpret, Stack *p_stack_args,$/;" f typeref:typename:void file: +_builtin_yes ./src/core/functions.c /^_builtin_yes(Interpret *p_interpret, Stack *p_stack_args,$/;" f typeref:typename:void file: _compare ./src/core/interpret.c /^_compare(Interpret *p_interpret) {$/;" f typeref:typename:int _control ./src/core/interpret.c /^_control(Interpret *p_interpret) {$/;" f typeref:typename:int +_control_do ./src/core/interpret.c /^_control_do(Interpret *p_interpret) {$/;" f typeref:typename:int file: +_control_if_ifnot ./src/core/interpret.c /^_control_if_ifnot(Interpret *p_interpret) {$/;" f typeref:typename:int file: +_control_loop ./src/core/interpret.c /^_control_loop(Interpret *p_interpret) {$/;" f typeref:typename:int file: +_control_while_until ./src/core/interpret.c /^_control_while_until(Interpret *p_interpret) {$/;" f typeref:typename:int file: +_eval_expr_list ./src/core/interpret.c /^_eval_expr_list(Interpret *p_interpret, List *p_list_expr) {$/;" f typeref:typename:Token * file: _expression ./src/core/interpret.c /^_expression(Interpret *p_interpret) {$/;" f typeref:typename:int _expression_ ./src/core/interpret.c /^_expression_(Interpret *p_interpret) {$/;" f typeref:typename:int _expression_get ./src/core/interpret.c /^_expression_get(Interpret *p_interpret, List *p_list_expression) {$/;" f typeref:typename:int @@ -71,12 +100,29 @@ _indent ./src/data/tree.c /^void _indent(int i_indent) {$/;" f typeref:typename: _list_copy_cb ./src/data/list.c /^_list_copy_cb(void *p_void1, void *p_cpy) {$/;" f typeref:typename:void _next ./src/core/interpret.c /^_next(Interpret *p_interpret) {$/;" f typeref:typename:int _next_tt ./src/core/interpret.c /^_next_tt(Interpret *p_interpret) {$/;" f typeref:typename:TokenType +_op_add ./src/core/functions.c /^_op_add(Token *p_store, Token *p_next, TokenType tt_highest) {$/;" f typeref:typename:void file: +_op_and ./src/core/functions.c /^_op_and(Token *p_store, Token *p_next, TokenType tt_highest) {$/;" f typeref:typename:void file: +_op_assign ./src/core/functions.c /^_op_assign(Interpret *p_interpret, Token *p_token_store) {$/;" f typeref:typename:void file: +_op_div ./src/core/functions.c /^_op_div(Token *p_store, Token *p_next, TokenType tt_highest) {$/;" f typeref:typename:void file: +_op_eq ./src/core/functions.c /^_op_eq(Token *p_store, Token *p_next, TokenType tt_highest) {$/;" f typeref:typename:void file: +_op_ge ./src/core/functions.c /^_op_ge(Token *p_store, Token *p_next, TokenType tt_highest) {$/;" f typeref:typename:void file: +_op_gt ./src/core/functions.c /^_op_gt(Token *p_store, Token *p_next, TokenType tt_highest) {$/;" f typeref:typename:void file: +_op_le ./src/core/functions.c /^_op_le(Token *p_store, Token *p_next, TokenType tt_highest) {$/;" f typeref:typename:void file: +_op_lshift ./src/core/functions.c /^_op_lshift(Token *p_store, Token *p_next, TokenType tt_highest) {$/;" f typeref:typename:void file: +_op_lt ./src/core/functions.c /^_op_lt(Token *p_store, Token *p_next, TokenType tt_highest) {$/;" f typeref:typename:void file: +_op_mult ./src/core/functions.c /^_op_mult(Token *p_store, Token *p_next, TokenType tt_highest) {$/;" f typeref:typename:void file: +_op_neq ./src/core/functions.c /^_op_neq(Token *p_store, Token *p_next, TokenType tt_highest) {$/;" f typeref:typename:void file: +_op_or ./src/core/functions.c /^_op_or(Token *p_store, Token *p_next, TokenType tt_highest) {$/;" f typeref:typename:void file: +_op_rshift ./src/core/functions.c /^_op_rshift(Token *p_store, Token *p_next, TokenType tt_highest) {$/;" f typeref:typename:void file: +_op_sub ./src/core/functions.c /^_op_sub(Token *p_store, Token *p_next, TokenType tt_highest) {$/;" f typeref:typename:void file: +_op_xor ./src/core/functions.c /^_op_xor(Token *p_store, Token *p_next, TokenType tt_highest) {$/;" f typeref:typename:void file: _print_lookahead ./src/core/interpret.c /^_print_lookahead(Interpret *p_interpret) {$/;" f typeref:typename:void _proc_decl ./src/core/interpret.c /^_proc_decl(Interpret *p_interpret) {$/;" f typeref:typename:int _process ./src/core/functions.c /^_process(Interpret *p_interpret, Token *p_token_store, Token *p_token_op,$/;" f typeref:typename:void _product ./src/core/interpret.c /^_product(Interpret *p_interpret) {$/;" f typeref:typename:int _product2 ./src/core/interpret.c /^_product2(Interpret *p_interpret) {$/;" f typeref:typename:int _program ./src/core/interpret.c /^_program(Interpret *p_interpret) {$/;" f typeref:typename:int +_resolve_composite_op ./src/core/functions.c /^_resolve_composite_op(TokenType tt_op, TokenType tt_op2) {$/;" f typeref:typename:TokenType file: _scanner_get_next_char ./src/core/scanner.c /^_scanner_get_next_char(Scanner *p_scanner) {$/;" f typeref:typename:char _scanner_has_next_char ./src/core/scanner.c /^_scanner_has_next_char(Scanner *p_scanner) {$/;" f typeref:typename:_Bool _scope_get_hash ./src/core/scope.c /^_scope_get_hash(Scope *p_scope, char *c_key) {$/;" f typeref:typename:Hash * file: @@ -126,6 +172,7 @@ arrayiterator_delete ./src/data/array.c /^arrayiterator_delete(ArrayIterator *p_ arrayiterator_has_next ./src/data/array.c /^arrayiterator_has_next(ArrayIterator *p_arrayiterator) {$/;" f typeref:typename:_Bool arrayiterator_new ./src/data/array.c /^arrayiterator_new(Array *p_array) {$/;" f typeref:typename:ArrayIterator * arrayiterator_next ./src/data/array.c /^arrayiterator_next(ArrayIterator *p_arrayiterator) {$/;" f typeref:typename:void * +c_name ./src/core/functions.c /^ const char *c_name;$/;" m struct:__anonc43baffb0108 typeref:typename:const char * file: convert_function_arg_types_to_highest ./src/core/convert.c /^convert_function_arg_types_to_highest(Stack *p_stack_args, int i_args) {$/;" f typeref:typename:TokenType convert_to_array ./src/core/convert.c /^convert_to_array(Token *p_token) {$/;" f typeref:typename:void convert_to_double ./src/core/convert.c /^convert_to_double(Token *p_token) {$/;" f typeref:typename:void @@ -161,6 +208,7 @@ datiter_new ./src/data/dat.c /^datiter_new(Dat *p_dat) {$/;" f typeref:typename: datiter_next ./src/data/dat.c /^datiter_next(DatIter *p_iter) {$/;" f typeref:typename:void * datiter_next_t ./src/data/dat.c /^datiter_next_t(DatIter *p_iter, TYPE *p_type) {$/;" f typeref:typename:void * datiter_skip ./src/data/dat.c /^datiter_skip(DatIter *p_iter, unsigned i_num) {$/;" f typeref:typename:void +fn ./src/core/functions.c /^ BuiltinFn fn;$/;" m struct:__anonc43baffb0108 typeref:typename:BuiltinFn file: funcdef_delete ./src/core/symbol.c /^funcdef_delete(FuncDef *p_funcdef) {$/;" f typeref:typename:void funcdef_new ./src/core/symbol.c /^funcdef_new(List *p_body, List *p_params, int i_nparams) {$/;" f typeref:typename:FuncDef * function_delete ./src/core/function.c /^function_delete(Function *p_function) {$/;" f typeref:typename:void @@ -176,6 +224,7 @@ functions_new ./src/core/functions.c /^functions_new() {$/;" f typeref:typename: fype_delete ./src/fype.c /^fype_delete(Fype *p_fype) {$/;" f typeref:typename:void fype_new ./src/fype.c /^fype_new() {$/;" f typeref:typename:Fype * fype_run ./src/fype.c /^fype_run(int i_argc, char **pc_argv) {$/;" f typeref:typename:int +g_builtins ./src/core/functions.c /^static const BuiltinEntry g_builtins[] = {$/;" v typeref:typename:const BuiltinEntry[] file: garbage_add ./src/core/garbage.c /^garbage_add(void *p, GarbageType type) {$/;" f typeref:typename:void garbage_add2 ./src/core/garbage.c /^garbage_add2(void *p,$/;" f typeref:typename:void garbage_add3 ./src/core/garbage.c /^garbage_add3(void *p,$/;" f typeref:typename:void @@ -346,7 +395,6 @@ token_new ./src/core/token.c /^token_new(char *c_val, TokenType tt_cur, int i_li token_new_ ./src/core/token.c /^token_new_(char *c_val, TokenType tt_cur, char *c_filename) {$/;" f typeref:typename:Token * token_new_array ./src/core/token.c /^token_new_array(int i_size) {$/;" f typeref:typename:Token * token_new_copy ./src/core/token.c /^token_new_copy(Token *p_token) {$/;" f typeref:typename:Token * -token_new_double ./src/core/token.c /^token_new_double(double d_val) {$/;" f typeref:typename:Token * token_new_dummy ./src/core/token.c /^token_new_dummy() {$/;" f typeref:typename:Token * token_new_integer ./src/core/token.c /^token_new_integer(int i_val) {$/;" f typeref:typename:Token * token_new_string ./src/core/token.c /^token_new_string(char *c_val) {$/;" f typeref:typename:Token * |
