namespace icon; include rt, run; // structured runtime transformations of compiler token lists. // token storage follows run.tokens: count, then kind, value and source line. // edits create independent lists; publication recompiles a function only after // delimiter validation. captures match complete balanced token ranges. int icon_error; int icon_eq(word* a, int ai, word* b, int bi, int n) { int i = 0; while (i < n) { if (a[1 + (ai + i) * 3] != b[1 + (bi + i) * 3] || a[2 + (ai + i) * 3] != b[2 + (bi + i) * 3]) return 0; i++; } return 1; } int icon_value(word* q, int i) { if (i < 0 || i >= q[0]) return 0; return q[2 + i * 3]; } int icon_kind(word* q, int i) { if (i < 0 || i >= q[0]) return 0; return q[1 + i * 3]; } int icon_is(word* q, int i, char* s) { int kind = run.T_OP; if (s[0] >= 'a' && s[0] <= 'z') kind = run.T_ID; return icon_kind(q, i) == kind && icon_value(q, i) == run.intern(s); } int icon_open(int v) { return v == run.intern("(") || v == run.intern("[") || v == run.intern("{"); } int icon_close(int v) { return v == run.intern(")") || v == run.intern("]") || v == run.intern("}"); } int icon_pair(int a, int b) { return (a == run.intern("(") && b == run.intern(")")) || (a == run.intern("[") && b == run.intern("]")) || (a == run.intern("{") && b == run.intern("}")); } int icon_declaration(word* q, int start, int binding) { int first = icon_value(q, start), i = start; if (icon_kind(q, start) != run.T_ID || (first != run.intern("let") && first != run.intern("const") && !run.istypename(first))) return 0; while (i < binding) { if (icon_is(q, i, "(") || icon_is(q, i, "=")) return 0; i++; } return binding > start; } // locate a simple declaration at a statement boundary, including nested blocks. // result records [type start, binding position, semicolon, statement start]. int icon_locate_declaration(word* q, int id, word* result) { int start = 0, i, depth, v, binding, comma, type_start; while (start < q[0]) { if (start && !icon_is(q, start - 1, ";") && !icon_is(q, start - 1, "{") && !icon_is(q, start - 1, "}")) { start++; continue; } type_start = start; if (icon_is(q, type_start, "const")) type_start++; if (icon_kind(q, type_start) != run.T_ID || (!icon_is(q, type_start, "let") && !run.istypename(icon_value(q, type_start)))) { start++; continue; } i = type_start; depth = 0; binding = -1; comma = 0; while (i < q[0]) { v = icon_value(q, i); if (!depth && v == id && icon_kind(q, i) == run.T_ID && binding < 0 && icon_declaration(q, type_start, i) && (icon_is(q, i + 1, "=") || icon_is(q, i + 1, ";") || icon_is(q, i + 1, ",") || icon_is(q, i + 1, "("))) binding = i; if (icon_kind(q, i) == run.T_OP) { if (icon_open(v)) depth++; else if (icon_close(v)) { if (!depth) break; depth--; } if (!depth && v == run.intern(",")) comma = 1; if (!depth && v == run.intern(";")) { if (binding >= 0) { if (comma || icon_is(q, binding + 1, "(")) return 0; result[0] = type_start; result[1] = binding; result[2] = i; result[3] = start; return 1; } break; } } i++; } start++; } return 0; } int icon_balanced(word* q, int a, int b) { word* stack = rt.new(b - a + 1); int n = 0, i = a, v, valid = 1; while (i < b) { v = icon_value(q, i); if (icon_kind(q, i) == run.T_OP) { if (icon_open(v)) { stack[n] = v; n++; } else if (icon_close(v)) { if (!n || !icon_pair(stack[n - 1], v)) { valid = 0; break; } n--; } } i++; } if (n) valid = 0; rt.free(stack); return valid; } word* .u icon_slice(word* q, int a, int b) { word* r = rt.new(1 + (b - a) * 3); int i = 0; r[0] = b - a; while (i < (b - a) * 3) { r[1 + i] = q[1 + a * 3 + i]; i++; } return r; } word* .u icon_splice(word* q, int a, int b, word* insert) { int n = q[0] - (b - a) + insert[0], i = 0, j = 0; word* r = rt.new(1 + n * 3); r[0] = n; while (i < a * 3) { r[1 + j] = q[1 + i]; i++; j++; } i = 0; while (i < insert[0] * 3) { r[1 + j] = insert[1 + i]; i++; j++; } i = b * 3; while (i < q[0] * 3) { r[1 + j] = q[1 + i]; i++; j++; } return r; } // capture classes use integer literals, identifiers, expressions, statements // or blocks. a named capture records its exact token range for substitution. int icon_class(int name) { if (name == run.intern("int")) return 1; if (name == run.intern("name")) return 2; if (name == run.intern("expr")) return 3; if (name == run.intern("stmt")) return 4; if (name == run.intern("block")) return 5; return 0; } int icon_pattern(word* q) { int i = 0; if (!q || q[0] <= 0 || !icon_balanced(q, 0, q[0])) return 0; while (i < q[0]) { if (icon_is(q, i, "$")) { if (icon_kind(q, i + 1) != run.T_ID || !icon_class(icon_value(q, i + 1))) return 0; i += 2; if (icon_is(q, i, ":")) { if (icon_kind(q, i + 1) != run.T_ID || icon_class(icon_value(q, i + 1))) return 0; i += 2; } } else i++; } return 1; } int icon_precedence(int name) { if (name == run.intern("||")) return 1; if (name == run.intern("&&")) return 2; if (name == run.intern("|")) return 3; if (name == run.intern("^")) return 4; if (name == run.intern("&")) return 5; if (name == run.intern("==") || name == run.intern("!=")) return 6; if (name == run.intern("<") || name == run.intern("<=") || name == run.intern(">") || name == run.intern(">=")) return 7; if (name == run.intern("<<") || name == run.intern(">>")) return 8; if (name == run.intern("+") || name == run.intern("-")) return 9; if (name == run.intern("*") || name == run.intern("/") || name == run.intern("%")) return 10; return 0; } // recognize expression structure before matching a variable-length capture. // this excludes statement keywords and incomplete operator sequences. int icon_expression(word* q, int start, int end, int minimum) { int i = start, v, kind, priority, next; if (i >= end) return -1; v = icon_value(q, i); kind = icon_kind(q, i); if (kind == run.T_OP && (v == run.intern("!") || v == run.intern("~") || v == run.intern("+") || v == run.intern("-") || v == run.intern("*") || v == run.intern("&"))) { i = icon_expression(q, i + 1, end, 11); if (i < 0) return -1; } else if (icon_is(q, i, "(")) { i = icon_expression(q, i + 1, end, 1); if (i < 0 || !icon_is(q, i, ")")) return -1; i++; } else if (kind == run.T_NUM || kind == run.T_FLT || kind == run.T_STR || kind == run.T_BSTR || kind == run.T_ID) { if (kind == run.T_ID && (v == run.intern("return") || v == run.intern("let") || v == run.intern("if") || v == run.intern("while") || v == run.intern("for") || v == run.intern("else") || v == run.intern("break") || v == run.intern("continue") || v == run.intern("do") || v == run.intern("switch") || v == run.intern("const"))) return -1; i++; } else return -1; while (i < end) { if (icon_is(q, i, "(") || icon_is(q, i, "[")) { v = icon_value(q, i); i++; if (v != run.intern("(") || !icon_is(q, i, ")")) { while (1) { i = icon_expression(q, i, end, 1); if (i < 0) return -1; if (v == run.intern("(") && icon_is(q, i, ",")) { i++; continue; } break; } } if (i >= end || icon_kind(q, i) != run.T_OP || !icon_pair(v, icon_value(q, i))) return -1; i++; continue; } if (icon_is(q, i, ".")) { if (i + 1 >= end || icon_kind(q, i + 1) != run.T_ID) return -1; i += 2; continue; } if (icon_is(q, i, "++") || icon_is(q, i, "--")) { i++; continue; } if (minimum == 1 && icon_is(q, i, "?")) { i = icon_expression(q, i + 1, end, 1); if (i < 0 || !icon_is(q, i, ":")) return -1; i = icon_expression(q, i + 1, end, 1); if (i < 0) return -1; continue; } priority = 0; if (icon_kind(q, i) == run.T_OP) priority = icon_precedence(icon_value(q, i)); if (!priority || priority < minimum) break; next = icon_expression(q, i + 1, end, priority + 1); if (next < 0) return -1; i = next; } return i; } int icon_range(word* q, int a, int b, int kind) { if (a < 0 || a >= b || b > q[0]) return 0; if (kind == 1) return b == a + 1 && icon_kind(q, a) == run.T_NUM; if (kind == 2) return b == a + 1 && icon_kind(q, a) == run.T_ID; if (kind == 3) return icon_expression(q, a, b, 1) == b; if (kind == 5) return icon_is(q, a, "{") && icon_mate(q, a) == b - 1; if (kind == 4) return icon_statement_end(q, a) == b; return icon_expression(q, a, b, 1) == b; } // recursively match a pattern with backtracking at balanced capture boundaries. // captures contain count followed by [name, start, end, class] records. int icon_match(word* q, int at, word* p, int pi, word* caps) { int kind, name, next, end, old, i; if (pi == p[0]) return at + 1; if (at >= q[0]) return 0; if (!icon_is(p, pi, "$")) { if (!icon_eq(q, at, p, pi, 1)) return 0; return icon_match(q, at + 1, p, pi + 1, caps); } if (pi + 1 >= p[0]) return 0; name = icon_value(p, pi + 1); kind = icon_class(name); next = pi + 2; if (!kind) return 0; if (icon_is(p, next, ":")) { name = icon_value(p, next + 1); next += 2; if (!name) return 0; } else name = 0; old = caps[0]; end = at + 1; if (kind == 4) end = icon_statement_end(q, at); if (kind == 5) { if (!icon_is(q, at, "{")) return 0; end = icon_mate(q, at) + 1; } if (end <= at) return 0; while (end <= q[0]) { if (icon_range(q, at, end, kind)) { i = 0; while (i < old) { if (name && caps[1 + i * 4] == name) { if (end - at != caps[3 + i * 4] - caps[2 + i * 4] || !icon_eq(q, at, q, caps[2 + i * 4], end - at)) break; } i++; } if (i == old) { caps[0] = old + 1; caps[1 + old * 4] = name; caps[2 + old * 4] = at; caps[3 + old * 4] = end; caps[4 + old * 4] = kind; i = icon_match(q, end, p, next, caps); if (i) return i; caps[0] = old; } } if (kind != 3) break; end++; } return 0; } int icon_capture(word* caps, int name, int ordinal) { int c = 0, kind = icon_class(name), k = 0; while (c < caps[0]) { if (!kind) { if (caps[1 + c * 4] == name) return c + 1; } else if (caps[4 + c * 4] == kind) { if (k == ordinal) return c + 1; k++; } c++; } return 0; } word* .u icon_expand(word* q, word* replacement, word* caps) { int n = 0, i = 0, j = 0, c, name, kind, k, seen[6], a, b; k = 0; while (k < 6) { seen[k] = 0; k++; } while (i < replacement[0]) { if (icon_is(replacement, i, "$")) { if (icon_kind(replacement, i + 1) != run.T_ID) { icon_error = 3; return 0; } name = icon_value(replacement, i + 1); kind = icon_class(name); c = icon_capture(caps, name, seen[kind]); if (!c) { icon_error = 3; return 0; } c--; n += caps[3 + c * 4] - caps[2 + c * 4]; if (kind) seen[kind]++; i += 2; } else { n++; i++; } } word* r = rt.new(1 + n * 3); i = 0; k = 0; while (k < 6) { seen[k] = 0; k++; } while (i < replacement[0]) { if (icon_is(replacement, i, "$")) { name = icon_value(replacement, i + 1); kind = icon_class(name); c = icon_capture(caps, name, seen[kind]) - 1; if (kind) seen[kind]++; a = caps[2 + c * 4] * 3; b = caps[3 + c * 4] * 3; while (a < b) { r[1 + j] = q[1 + a]; a++; j++; } i += 2; } else { k = 0; while (k < 3) { r[1 + j] = replacement[1 + i * 3 + k]; j++; k++; } i++; } } r[0] = j / 3; if (!icon_balanced(r, 0, r[0])) { rt.free(r); icon_error = 1; return 0; } return r; } // resumable frames retain their own token list and explicit binding maps. // [tokens, position, state, result, error, locals, globals, blocks, steps]. // locate a binding in a frame map by its interned name. int icon_binding(word map, int name) { while (map) { if (map[0] == name) return map; map = map[2]; } return 0; } int icon_read(word binding) { if (binding[3]) return *binding[3]; return binding[1]; } int icon_store(word*.m frame, int column, int name, int value) { word entry = icon_binding(frame[column], name); if (!entry) { word* node = rt.new(4); node[0] = name; node[1] = value; node[2] = frame[column]; node[3] = 0; frame[column] = node; return value; } entry[1] = value; if (entry[3]) *entry[3] = value; return value; } int icon_declare(word*.m frame, int name, int value) { word* node = rt.new(4); node[0] = name; node[1] = value; node[2] = frame[5]; node[3] = 0; frame[5] = node; return value; } int icon_fail(word frame) { frame[2] = 2; frame[4] = 5; icon_error = 5; return 0; } int icon_end(word* q, int start) { int depth = 0, i = start, v; while (i < q[0]) { v = icon_value(q, i); if (icon_kind(q, i) == run.T_OP) { if (icon_open(v)) depth++; else if (icon_close(v)) { if (!depth) return i; depth--; } if (!depth && v == run.intern(";")) return i; } i++; } return i; } int icon_mate(word* q, int start) { int depth = 1, i = start + 1, v; while (i < q[0]) { v = icon_value(q, i); if (icon_kind(q, i) == run.T_OP) { if (icon_open(v)) depth++; else if (icon_close(v)) depth--; if (!depth) return i; } i++; } return -1; } // find one statement boundary; control-flow captures require braced bodies. int icon_statement_end(word* q, int start) { int close, end; if (icon_is(q, start, "{")) { close = icon_mate(q, start); if (close < 0) return -1; return close + 1; } if (icon_is(q, start, "if") || icon_is(q, start, "while")) { if (!icon_is(q, start + 1, "(")) return -1; close = icon_mate(q, start + 1); if (close < 0 || !icon_is(q, close + 1, "{")) return -1; end = icon_mate(q, close + 1); if (end < 0) return -1; end++; if (icon_is(q, start, "if") && icon_is(q, end, "else")) { if (!icon_is(q, end + 1, "{")) return -1; close = icon_mate(q, end + 1); if (close < 0) return -1; return close + 1; } return end; } end = icon_end(q, start); if (!icon_is(q, end, ";")) return -1; return end + 1; } // construct a compiler return body in one allocation, retaining source lines. word* .u icon_eval_tokens(word* q, int start, int end) { int count = end - start; word* expr = rt.new(7 + count * 3); expr[0] = count + 2; expr[1] = run.T_ID; expr[2] = run.intern("return"); expr[3] = 1; if (count) rt.copy_w(expr + 4, q + 1 + start * 3, count * 3); expr[4 + count * 3] = run.T_OP; expr[5 + count * 3] = run.intern(";"); expr[6 + count * 3] = 1; return expr; } // scalar frame substitution cannot preserve lvalue operations or implicit // program-global reads. reject these before compiling or executing a range. int icon_frame_expression(word frame, int start, int end) { word* q = frame[0]; int i = start, s; word binding; if (!icon_range(q, start, end, 3)) return 0; while (i < end) { if (icon_is(q, i, "++") || icon_is(q, i, "--")) return 0; if (icon_kind(q, i) == run.T_ID && !icon_is(q, i - 1, ".")) { binding = icon_binding(frame[5], icon_value(q, i)); if (!binding) binding = icon_binding(frame[6], icon_value(q, i)); if (!binding) { s = run.lookups(icon_value(q, i)); if (s < 0 || (run.skind[s] != run.K_FN && run.skind[s] != run.K_CONST)) return 0; } } i++; } return 1; } int icon_frame_eval(word frame, int start, int end) { word* expr = icon_eval_tokens(frame[0], start, end); int i = 1; word binding; while (i < expr[0] - 1) { if (icon_kind(expr, i) == run.T_ID && !icon_is(expr, i - 1, ".")) { binding = icon_binding(frame[5], icon_value(expr, i)); if (!binding) binding = icon_binding(frame[6], icon_value(expr, i)); if (binding) { expr[1 + i * 3] = run.T_NUM; expr[2 + i * 3] = icon_read(binding); } } i++; } int result = run.eval(expr); rt.free(expr); return result; } int icon_block(word*.m frame, int open, int resume) { int close = icon_mate(frame[0], open); if (close < 0) return icon_fail(frame); word block = rt.new(4); block[0] = close; block[1] = resume; block[2] = frame[7]; block[3] = frame[5]; frame[7] = block; frame[1] = open + 1; return 1; } struct icon { // the last transformation status: 0 success, 1 invalid delimiters, // 2 invalid range or declaration, 3 unresolved replacement capture, // 4 unavailable function metadata, 5 unsupported stepping syntax, // 6 rejected function publication. static int error() { return icon_error; } // check token delimiters without compiling or executing the list. static int validate(word* q) { icon_error = 0; if (!q || q[0] < 0 || !icon_balanced(q, 0, q[0])) { icon_error = 1; return 0; } return 1; } // return an independent token list with [start, end) replaced by insert. static word* .u splice(word* q, int start, int end, word* insert) { icon_error = 0; if (!q || !insert || q[0] < 0 || insert[0] < 0 || start < 0 || end < start || end > q[0]) { icon_error = 2; return 0; } word* r = icon_splice(q, start, end, insert); if (!icon_balanced(r, 0, r[0])) { rt.free(r); icon_error = 1; return 0; } return r; } // replace each nonoverlapping pattern match. inserted tokens are not // searched again. the input and templates remain unchanged. static word* .u rewrite(word* q, word* pattern, word* replacement) { icon_error = 0; if (!q || q[0] < 0 || !replacement || replacement[0] < 0 || !icon_pattern(pattern) || !icon_balanced(q, 0, q[0])) { icon_error = 1; return 0; } word* result = icon_slice(q, 0, q[0]); word* caps = rt.new(1 + pattern[0] * 4); word* insert, next; int at = 0, end; while (at < result[0]) { caps[0] = 0; end = icon_match(result, at, pattern, 0, caps); if (!end) { at++; continue; } insert = icon_expand(result, replacement, caps); if (!insert) { rt.free(result); rt.free(caps); return 0; } next = icon_splice(result, at, end - 1, insert); at += insert[0]; rt.free(insert); rt.free(result); result = next; } rt.free(caps); return result; } // transform retained function tokens and publish the compiled replacement. // references to the original entry continue to use the published version. static int find_replace(word function, word* pattern, word* replacement) { icon_error = 0; if (!replacement || replacement[0] < 0 || !icon_pattern(pattern)) { icon_error = 1; return 0; } word* q = run.function_tokens(function); if (!q) { icon_error = 4; return 0; } word* caps = rt.new(1 + pattern[0] * 4); int i = 0, end, count = 0; while (i < q[0]) { caps[0] = 0; end = icon_match(q, i, pattern, 0, caps); if (end) { count++; i = end - 1; } else i++; } rt.free(caps); if (!count) { rt.free(q); return 0; } word* changed = icon.rewrite(q, pattern, replacement); rt.free(q); if (!changed) return 0; int published = run.replace_function(function, changed); rt.free(changed); if (!published) { icon_error = 6; return 0; } return count; } // remove a complete declaration statement containing the requested name. // declarations containing multiple bindings are rejected to preserve them. static word* .u undeclare(word* q, char* name) { icon_error = 0; int declaration[4]; if (!q || q[0] < 0 || !name || !icon_locate_declaration(q, run.intern(name), declaration)) { icon_error = 2; return 0; } word* empty = rt.new(1); empty[0] = 0; word* result = icon.splice(q, declaration[3], declaration[2] + 1, empty); rt.free(empty); return result; } // change the type of the first simple declaration of name. static word* .u change_type(word* q, char* name, word* type) { icon_error = 0; int declaration[4]; if (!q || q[0] < 0 || !name || !icon_locate_declaration(q, run.intern(name), declaration)) { icon_error = 2; return 0; } return icon.splice(q, declaration[0], declaration[1], type); } // insert a scoped statement block at the given token boundary. static word* .u insert_block(word* q, int at, word* body) { icon_error = 0; if (!q || !body || body[0] < 0 || at < 0 || at > q[0]) { icon_error = 2; return 0; } word* block = rt.new(7 + body[0] * 3); int i = 0; block[0] = body[0] + 2; block[1] = run.T_OP; block[2] = run.intern("{"); block[3] = 1; while (i < body[0] * 3) { block[4 + i] = body[1 + i]; i++; } block[4 + i] = run.T_OP; block[5 + i] = run.intern("}"); block[6 + i] = 1; word* result = icon.splice(q, at, at, block); rt.free(block); return result; } // evaluate a selected expression using the compiler rather than a text // evaluator. the range must contain one complete expression. static int calculate(word* q, int start, int end) { icon_error = 0; if (!q || start < 0 || end > q[0] || !icon_range(q, start, end, 3)) { icon_error = 2; return 0; } word* expr = icon_eval_tokens(q, start, end); int value = run.eval(expr); rt.free(expr); return value; } // start a resumable evaluation with independent tokens and binding storage. // stepping executes statements through the compiler; no native frame is // suspended or inspected. scalar bindings are visible between statements. static word* .u begin(word* q) { if (!icon.validate(q)) { icon_error = 1; return 0; } word* frame = rt.new(9); int i = 0; while (i < 9) { frame[i] = 0; i++; } frame[0] = icon_slice(q, 0, q[0]); return frame; } // create an explicit frame from a function's retained body. argument values // are supplied through set_local before stepping starts. static word* .u begin_function(int function) { word* q = run.function_tokens(function); if (!q) { icon_error = 4; return 0; } word* frame = icon.begin(q); rt.free(q); return frame; } // set an isolated global binding, or update storage explicitly bound to it. static int set_global(word frame, char* name, int value) { icon_error = 0; return icon_store(frame, 6, run.intern(name), value); } // update the innermost local binding, creating a binding when absent. static int set_local(word frame, char* name, int value) { icon_error = 0; return icon_store(frame, 5, run.intern(name), value); } // bind one existing scalar global explicitly. reads observe its current // value, and subsequent frame assignments update its program storage. static int bind_global(word frame, char* name) { int s = run.lookups(name); icon_error = 0; if (s < 0 || run.skind[s] != run.K_GVAR) { icon_error = 2; return 0; } word type = run.stype[s]; if (type && type != run.tint && type != run.tword) { icon_error = 2; return 0; } icon_store(frame, 6, run.intern(name), *run.sval[s]); word binding = icon_binding(frame[6], run.intern(name)); binding[3] = run.sval[s]; return 1; } // read the innermost local binding; a missing binding sets status 2. static int local(word frame, char* name) { icon_error = 0; word b = icon_binding(frame[5], run.intern(name)); if (!b) { icon_error = 2; return 0; } return icon_read(b); } // read an isolated or explicitly connected global binding. static int global(word frame, char* name) { icon_error = 0; word b = icon_binding(frame[6], run.intern(name)); if (!b) { icon_error = 2; return 0; } return icon_read(b); } // frame state: 0 resumable, 1 complete, 2 unsupported statement. static int state(word frame) { return frame[2]; } // the returned value after completion; zero before a return is executed. static int result(word frame) { return frame[3]; } // token index of the next statement or control-flow decision. static int position(word frame) { return frame[1]; } // number of executed statements and control-flow decisions. static int steps(word frame) { return frame[8]; } // number of retained local binding records, including active shadowed records. static int local_count(word frame) { word b = frame[5]; int n = 0; while (b) { n++; b = b[2]; } return n; } // interned name of a local record; zero when index is outside the map. static char* local_name(word frame, int index) { word b = frame[5]; while (b && index > 0) { index--; b = b[2]; } if (!b || index < 0) return 0; return b[0]; } // execute one statement or control-flow decision. returns 1 after progress, // 0 after completion or an unsupported statement. blocks, if and while // require braces; declarations contain one scalar binding. static int step(word frame) { if (!frame || frame[2]) return 0; icon_error = 0; word* q = frame[0]; int at = frame[1], end, name, value, column = 5, v, close, open, alternate; word block, binding; while (frame[7] && at == frame[7][0]) { block = frame[7]; while (frame[5] != block[3]) { binding = frame[5]; frame[5] = binding[2]; rt.free(binding); } at = block[1]; frame[7] = block[2]; rt.free(block); frame[1] = at; } if (at >= q[0]) { frame[2] = 1; return 0; } frame[8]++; if (icon_is(q, at, ";")) { frame[1] = at + 1; return 1; } if (icon_is(q, at, "{")) { close = icon_mate(q, at); return icon_block(frame, at, close + 1); } if (icon_is(q, at, "if") || icon_is(q, at, "while")) { if (!icon_is(q, at + 1, "(")) return icon_fail(frame); close = icon_mate(q, at + 1); open = close + 1; if (close < 0 || !icon_is(q, open, "{")) return icon_fail(frame); end = icon_mate(q, open); if (end < 0) return icon_fail(frame); alternate = end + 1; if (icon_is(q, at, "if") && icon_is(q, alternate, "else")) { if (!icon_is(q, alternate + 1, "{")) return icon_fail(frame); } if (!icon_frame_expression(frame, at + 2, close)) return icon_fail(frame); value = icon_frame_eval(frame, at + 2, close); if (icon_is(q, at, "while")) { if (value) return icon_block(frame, open, at); frame[1] = end + 1; return 1; } if (icon_is(q, alternate, "else")) { close = icon_mate(q, alternate + 1); if (value) return icon_block(frame, open, close + 1); return icon_block(frame, alternate + 1, close + 1); } if (value) return icon_block(frame, open, end + 1); frame[1] = end + 1; return 1; } end = icon_end(q, at); if (end >= q[0] || !icon_is(q, end, ";")) return icon_fail(frame); if (icon_is(q, at, "return")) { frame[3] = 0; if (end > at + 1) { if (!icon_frame_expression(frame, at + 1, end)) return icon_fail(frame); frame[3] = icon_frame_eval(frame, at + 1, end); } frame[1] = end + 1; frame[2] = 1; return 1; } if (icon_is(q, at, "let") || icon_is(q, at, "int") || icon_is(q, at, "word")) { if (icon_kind(q, at + 1) != run.T_ID) return icon_fail(frame); name = icon_value(q, at + 1); value = 0; if (end > at + 2) { if (!icon_is(q, at + 2, "=") || !icon_frame_expression(frame, at + 3, end)) return icon_fail(frame); value = icon_frame_eval(frame, at + 3, end); } icon_declare(frame, name, value); frame[1] = end + 1; return 1; } name = icon_value(q, at); binding = icon_binding(frame[5], name); if (!binding) { binding = icon_binding(frame[6], name); column = 6; } if (binding && icon_kind(q, at) == run.T_ID) { v = icon_value(q, at + 1); if (end == at + 2 && (v == run.intern("++") || v == run.intern("--"))) { value = icon_read(binding) + 1; if (v == run.intern("--")) value = icon_read(binding) - 1; } else { if (v != run.intern("=") && v != run.intern("+=") && v != run.intern("-=") && v != run.intern("*=") && v != run.intern("/=")) return icon_fail(frame); if (!icon_frame_expression(frame, at + 2, end)) return icon_fail(frame); value = icon_frame_eval(frame, at + 2, end); if (v == run.intern("+=")) value = icon_read(binding) + value; if (v == run.intern("-=")) value = icon_read(binding) - value; if (v == run.intern("*=")) value = icon_read(binding) * value; if (v == run.intern("/=")) value = icon_read(binding) / value; } icon_store(frame, column, name, value); frame[1] = end + 1; return 1; } return icon_fail(frame); } // execute at most budget statements. returning 0 leaves the frame resumable; // callers can inspect bindings, edit them, then continue with another budget. static int resume(word frame, int budget) { while (budget > 0 && !frame[2]) { icon.step(frame); budget--; } return frame[2]; } // release a frame and all storage it owns. static int close(.d frame) { word b, next; int column = 5; while (column <= 7) { b = frame[column]; while (b) { next = b[2]; rt.free(b); b = next; } column++; } rt.free(frame[0]); rt.free(frame); return 0; } } // public entry points for the icon namespace. // status of the most recent transformation or binding operation; see docs/ICON.md. int error() { return icon.icon.error(); } // check delimiter structure only; does not compile or execute tokens. int validate(word* q) { return icon.icon.validate(q); } // return a new token list with [start, end) replaced; caller owns the result. word* .u splice(word* q, int start, int end, word* insert) { return icon.icon.splice(q, start, end, insert); } // return a new list with nonoverlapping matches replaced; inputs remain unchanged. word* .u rewrite(word* q, word* pattern, word* replacement) { return icon.icon.rewrite(q, pattern, replacement); } // publish a transformed function body; returns matches, or 0 on no match or failure. int find_replace(word function, word* pattern, word* replacement) { return icon.icon.find_replace(function, pattern, replacement); } // remove the first complete single-binding declaration named name; caller owns the result. word* .u undeclare(word* q, char* name) { return icon.icon.undeclare(q, name); } // replace the type prefix of the first simple declaration named name; caller owns the result. word* .u change_type(word* q, char* name, word* type) { return icon.icon.change_type(q, name, type); } // insert a scoped block containing body at token boundary at; caller owns the result. word* .u insert_block(word* q, int at, word* body) { return icon.icon.insert_block(q, at, body); } // compile and evaluate the expression in [start, end); expression calls retain their effects. int calculate(word* q, int start, int end) { return icon.icon.calculate(q, start, end); } // create a frame with copied tokens and isolated bindings; caller closes the frame. word* .u begin(word* q) { return icon.icon.begin(q); } // create a frame from retained function tokens; set arguments as locals before stepping. word* .u begin_function(int function) { return icon.icon.begin_function(function); } // set an isolated global binding, creating it when absent; returns the stored value. int set_global(word frame, char* name, int value) { return icon.icon.set_global(frame, name, value); } // set the innermost local binding, creating it when absent; returns the stored value. int set_local(word frame, char* name, int value) { return icon.icon.set_local(frame, name, value); } // connect an int or word program global to the frame; later frame writes update it. int bind_global(word frame, char* name) { return icon.icon.bind_global(frame, name); } // read a local binding; missing names return 0 and set error status 2. int local(word frame, char* name) { return icon.icon.local(frame, name); } // read a frame global binding; missing names return 0 and set error status 2. int global(word frame, char* name) { return icon.icon.global(frame, name); } // return frame state: 0 resumable, 1 complete, or 2 unsupported statement. int state(word frame) { return icon.icon.state(frame); } // return the value produced by return, or 0 before a return is executed. int result(word frame) { return icon.icon.result(frame); } // return the token index of the next statement or control-flow decision. int position(word frame) { return icon.icon.position(frame); } // return the number of statements and control-flow decisions executed. int steps(word frame) { return icon.icon.steps(frame); } // count retained local records, including shadowed records in active blocks. int local_count(word frame) { return icon.icon.local_count(frame); } // return the zero-based local record name, or 0 when index is out of range. char* local_name(word frame, int index) { return icon.icon.local_name(frame, index); } // execute scalar declarations and assignments, standalone ++/--, return, blocks, // or braced if/else/while; direct program globals need bind_global first. // unsupported syntax sets error status 5. int step(word frame) { return icon.icon.step(frame); } // execute at most budget steps and return the frame state; frame bindings are scalar int/word values. int resume(word frame, int budget) { return icon.icon.resume(frame, budget); } // release the frame and owned storage; consumes frame and returns 0. int close(.d frame) { return icon.icon.close(d*frame); }