Merge branch 'worktree-api-urls' into macros
This commit is contained in:
@@ -14,7 +14,7 @@
|
||||
// =========================================================================
|
||||
|
||||
var NIL = Object.freeze({ _nil: true, toString: function() { return "nil"; } });
|
||||
var SX_VERSION = "2026-03-13T05:11:12Z";
|
||||
var SX_VERSION = "2026-03-13T11:02:33Z";
|
||||
|
||||
function isNil(x) { return x === NIL || x === null || x === undefined; }
|
||||
function isSxTruthy(x) { return x !== false && !isNil(x); }
|
||||
@@ -410,6 +410,7 @@
|
||||
PRIMITIVES["ends-with?"] = function(s, p) { var str = String(s); return str.indexOf(p, str.length - p.length) !== -1; };
|
||||
PRIMITIVES["slice"] = function(c, a, b) { if (!c || typeof c.slice !== "function") { console.error("[sx-debug] slice called on non-sliceable:", typeof c, c, "a=", a, "b=", b, new Error().stack); return []; } return b !== undefined ? c.slice(a, b) : c.slice(a); };
|
||||
PRIMITIVES["substring"] = function(s, a, b) { return String(s).substring(a, b); };
|
||||
PRIMITIVES["char-from-code"] = function(n) { return String.fromCharCode(n); };
|
||||
PRIMITIVES["string-length"] = function(s) { return String(s).length; };
|
||||
PRIMITIVES["string-contains?"] = function(s, sub) { return String(s).indexOf(String(sub)) !== -1; };
|
||||
PRIMITIVES["concat"] = function() {
|
||||
@@ -774,6 +775,7 @@
|
||||
return s.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/\n/g, "\\n").replace(/\t/g, "\\t");
|
||||
}
|
||||
function sxExprSource(e) { return typeof e === "string" ? e : String(e); }
|
||||
var charFromCode = PRIMITIVES["char-from-code"];
|
||||
|
||||
|
||||
// === Transpiled from eval ===
|
||||
@@ -1382,6 +1384,7 @@ if (isSxTruthy(sxOr((ch == " "), (ch == "\t"), (ch == "\n"), (ch == "\r")))) { p
|
||||
continue; } else if (isSxTruthy((ch == ";"))) { pos = (pos + 1);
|
||||
skipComment();
|
||||
continue; } else { return NIL; } } } else { return NIL; } } };
|
||||
var hexDigitValue = function(ch) { return indexOf_("0123456789abcdef", lower(ch)); };
|
||||
var readString = function() { pos = (pos + 1);
|
||||
return (function() {
|
||||
var buf = "";
|
||||
@@ -1389,9 +1392,19 @@ return (function() {
|
||||
if (isSxTruthy((ch == "\""))) { pos = (pos + 1);
|
||||
return NIL; } else if (isSxTruthy((ch == "\\"))) { pos = (pos + 1);
|
||||
{ var esc = nth(source, pos);
|
||||
buf = (String(buf) + String((isSxTruthy((esc == "n")) ? "\n" : (isSxTruthy((esc == "t")) ? "\t" : (isSxTruthy((esc == "r")) ? "\r" : esc)))));
|
||||
if (isSxTruthy((esc == "u"))) { pos = (pos + 1);
|
||||
{ var d0 = hexDigitValue(nth(source, pos));
|
||||
var _ = (pos = (pos + 1));
|
||||
var d1 = hexDigitValue(nth(source, pos));
|
||||
var _ = (pos = (pos + 1));
|
||||
var d2 = hexDigitValue(nth(source, pos));
|
||||
var _ = (pos = (pos + 1));
|
||||
var d3 = hexDigitValue(nth(source, pos));
|
||||
var _ = (pos = (pos + 1));
|
||||
buf = (String(buf) + String(charFromCode(((((d0 * 4096) + (d1 * 256)) + (d2 * 16)) + d3))));
|
||||
continue; } } else { buf = (String(buf) + String((isSxTruthy((esc == "n")) ? "\n" : (isSxTruthy((esc == "t")) ? "\t" : (isSxTruthy((esc == "r")) ? "\r" : esc)))));
|
||||
pos = (pos + 1);
|
||||
continue; } } else { buf = (String(buf) + String(ch));
|
||||
continue; } } } else { buf = (String(buf) + String(ch));
|
||||
pos = (pos + 1);
|
||||
continue; } } } } };
|
||||
readStrLoop();
|
||||
|
||||
@@ -106,6 +106,14 @@ def _unescape_string(s: str) -> str:
|
||||
while i < len(s):
|
||||
if s[i] == "\\" and i + 1 < len(s):
|
||||
nxt = s[i + 1]
|
||||
if nxt == "u" and i + 5 < len(s):
|
||||
hex_str = s[i + 2:i + 6]
|
||||
try:
|
||||
out.append(chr(int(hex_str, 16)))
|
||||
i += 6
|
||||
continue
|
||||
except ValueError:
|
||||
pass # fall through to default handling
|
||||
out.append(_ESCAPE_MAP.get(nxt, nxt))
|
||||
i += 2
|
||||
else:
|
||||
|
||||
@@ -1259,11 +1259,21 @@
|
||||
|
||||
(define js-emit-infix
|
||||
(fn ((op :as string) (args :as list))
|
||||
(let ((js-op (js-op-symbol op)))
|
||||
(if (and (= (len args) 1) (= op "-"))
|
||||
(str "(-" (js-expr (first args)) ")")
|
||||
(str "(" (js-expr (first args))
|
||||
" " js-op " " (js-expr (nth args 1)) ")")))))
|
||||
(let ((js-op (js-op-symbol op))
|
||||
(n (len args)))
|
||||
(cond
|
||||
(and (= n 1) (= op "-"))
|
||||
(str "(-" (js-expr (first args)) ")")
|
||||
(= n 2)
|
||||
(str "(" (js-expr (first args))
|
||||
" " js-op " " (js-expr (nth args 1)) ")")
|
||||
;; Variadic: left-fold (a op b op c op d ...)
|
||||
:else
|
||||
(let ((result (js-expr (first args))))
|
||||
(for-each (fn (arg)
|
||||
(set! result (str "(" result " " js-op " " (js-expr arg) ")")))
|
||||
(rest args))
|
||||
result)))))
|
||||
|
||||
|
||||
;; --------------------------------------------------------------------------
|
||||
|
||||
@@ -80,6 +80,9 @@
|
||||
|
||||
;; -- Atom readers --
|
||||
|
||||
(define hex-digit-value :effects []
|
||||
(fn (ch) (index-of "0123456789abcdef" (lower ch))))
|
||||
|
||||
(define read-string :effects []
|
||||
(fn ()
|
||||
(set! pos (inc pos)) ;; skip opening "
|
||||
@@ -95,14 +98,29 @@
|
||||
(= ch "\\")
|
||||
(do (set! pos (inc pos))
|
||||
(let ((esc (nth source pos)))
|
||||
(set! buf (str buf
|
||||
(cond
|
||||
(= esc "n") "\n"
|
||||
(= esc "t") "\t"
|
||||
(= esc "r") "\r"
|
||||
:else esc)))
|
||||
(set! pos (inc pos))
|
||||
(read-str-loop)))
|
||||
(if (= esc "u")
|
||||
;; Unicode escape: \uXXXX → char
|
||||
(do (set! pos (inc pos))
|
||||
(let ((d0 (hex-digit-value (nth source pos)))
|
||||
(_ (set! pos (inc pos)))
|
||||
(d1 (hex-digit-value (nth source pos)))
|
||||
(_ (set! pos (inc pos)))
|
||||
(d2 (hex-digit-value (nth source pos)))
|
||||
(_ (set! pos (inc pos)))
|
||||
(d3 (hex-digit-value (nth source pos)))
|
||||
(_ (set! pos (inc pos))))
|
||||
(set! buf (str buf (char-from-code
|
||||
(+ (* d0 4096) (* d1 256) (* d2 16) d3))))
|
||||
(read-str-loop)))
|
||||
;; Standard escapes: \n \t \r or literal
|
||||
(do (set! buf (str buf
|
||||
(cond
|
||||
(= esc "n") "\n"
|
||||
(= esc "t") "\t"
|
||||
(= esc "r") "\r"
|
||||
:else esc)))
|
||||
(set! pos (inc pos))
|
||||
(read-str-loop)))))
|
||||
:else
|
||||
(do (set! buf (str buf ch))
|
||||
(set! pos (inc pos))
|
||||
|
||||
@@ -983,6 +983,7 @@ PRIMITIVES_JS_MODULES: dict[str, str] = {
|
||||
PRIMITIVES["ends-with?"] = function(s, p) { var str = String(s); return str.indexOf(p, str.length - p.length) !== -1; };
|
||||
PRIMITIVES["slice"] = function(c, a, b) { if (!c || typeof c.slice !== "function") { console.error("[sx-debug] slice called on non-sliceable:", typeof c, c, "a=", a, "b=", b, new Error().stack); return []; } return b !== undefined ? c.slice(a, b) : c.slice(a); };
|
||||
PRIMITIVES["substring"] = function(s, a, b) { return String(s).substring(a, b); };
|
||||
PRIMITIVES["char-from-code"] = function(n) { return String.fromCharCode(n); };
|
||||
PRIMITIVES["string-length"] = function(s) { return String(s).length; };
|
||||
PRIMITIVES["string-contains?"] = function(s, sub) { return String(s).indexOf(String(sub)) !== -1; };
|
||||
PRIMITIVES["concat"] = function() {
|
||||
@@ -1600,6 +1601,7 @@ PLATFORM_PARSER_JS = r"""
|
||||
return s.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/\n/g, "\\n").replace(/\t/g, "\\t");
|
||||
}
|
||||
function sxExprSource(e) { return typeof e === "string" ? e : String(e); }
|
||||
var charFromCode = PRIMITIVES["char-from-code"];
|
||||
"""
|
||||
|
||||
|
||||
|
||||
@@ -881,6 +881,7 @@ PRIMITIVES["zero?"] = lambda n: n == 0
|
||||
"core.strings": '''
|
||||
# core.strings
|
||||
PRIMITIVES["str"] = sx_str
|
||||
PRIMITIVES["char-from-code"] = lambda n: chr(_b_int(n))
|
||||
PRIMITIVES["upper"] = lambda s: str(s).upper()
|
||||
PRIMITIVES["lower"] = lambda s: str(s).lower()
|
||||
PRIMITIVES["trim"] = lambda s: str(s).strip()
|
||||
|
||||
@@ -323,6 +323,11 @@
|
||||
:returns "number"
|
||||
:doc "Length of string in characters.")
|
||||
|
||||
(define-primitive "char-from-code"
|
||||
:params ((n :as number))
|
||||
:returns "string"
|
||||
:doc "Convert Unicode code point to single-character string.")
|
||||
|
||||
(define-primitive "substring"
|
||||
:params ((s :as string) (start :as number) (end :as number))
|
||||
:returns "string"
|
||||
|
||||
@@ -830,11 +830,21 @@
|
||||
|
||||
(define py-emit-infix
|
||||
(fn ((op :as string) (args :as list) (cell-vars :as list))
|
||||
(let ((py-op (py-op-symbol op)))
|
||||
(if (and (= (len args) 1) (= op "-"))
|
||||
(str "(-" (py-expr-with-cells (first args) cell-vars) ")")
|
||||
(str "(" (py-expr-with-cells (first args) cell-vars)
|
||||
" " py-op " " (py-expr-with-cells (nth args 1) cell-vars) ")")))))
|
||||
(let ((py-op (py-op-symbol op))
|
||||
(n (len args)))
|
||||
(cond
|
||||
(and (= n 1) (= op "-"))
|
||||
(str "(-" (py-expr-with-cells (first args) cell-vars) ")")
|
||||
(= n 2)
|
||||
(str "(" (py-expr-with-cells (first args) cell-vars)
|
||||
" " py-op " " (py-expr-with-cells (nth args 1) cell-vars) ")")
|
||||
;; Variadic: left-fold (a op b op c op d ...)
|
||||
:else
|
||||
(let ((result (py-expr-with-cells (first args) cell-vars)))
|
||||
(for-each (fn (arg)
|
||||
(set! result (str "(" result " " py-op " " (py-expr-with-cells arg cell-vars) ")")))
|
||||
(rest args))
|
||||
result)))))
|
||||
|
||||
|
||||
;; --------------------------------------------------------------------------
|
||||
|
||||
@@ -851,6 +851,7 @@ PRIMITIVES["zero?"] = lambda n: n == 0
|
||||
|
||||
# core.strings
|
||||
PRIMITIVES["str"] = sx_str
|
||||
PRIMITIVES["char-from-code"] = lambda n: chr(_b_int(n))
|
||||
PRIMITIVES["upper"] = lambda s: str(s).upper()
|
||||
PRIMITIVES["lower"] = lambda s: str(s).lower()
|
||||
PRIMITIVES["trim"] = lambda s: str(s).strip()
|
||||
|
||||
@@ -940,6 +940,18 @@ def _load_types(env):
|
||||
# types.sx uses component-has-children (no ?), test runner has component-has-children?
|
||||
if "component-has-children" not in env:
|
||||
env["component-has-children"] = lambda c: getattr(c, 'has_children', False)
|
||||
# types.sx uses map-dict for record type resolution
|
||||
if "map-dict" not in env:
|
||||
from shared.sx.types import Lambda as _Lambda
|
||||
def _map_dict(fn, d):
|
||||
result = {}
|
||||
for k, v in d.items():
|
||||
if isinstance(fn, _Lambda):
|
||||
result[k] = _trampoline(_eval([fn, k, v], env))
|
||||
else:
|
||||
result[k] = fn(k, v)
|
||||
return result
|
||||
env["map-dict"] = _map_dict
|
||||
|
||||
# Try bootstrapped types first, fall back to eval
|
||||
try:
|
||||
|
||||
Reference in New Issue
Block a user