updates
ober
07cd8c8783b8aacc2824bbcaea1970ccf8d6f569
--- a/data/anti-patterns.sexp +++ b/data/anti-patterns.sexp @@ -5183,6 +5183,28 @@ "jerboa_balanced_insert")) (("advice" . + "Run jerboa_check_balance on the user-facing .ss file first. If the file is already unbalanced, use jerboa_repair_balance dry-run or restore the broken edit and redo the change with jerboa_balanced_insert/jerboa_balanced_replace around complete forms. Verify with make build before investigating generated build/src artifacts.") + ("avoid" + . + "Do not keep hand-editing close parens or debug generated build/src copies as the source of truth.") + ("id" + . + "manual-paren-repair-loop-after-generated-jerboa-edit") + ("kinds" "edit" "debug" "verification") + ("pattern" + . + "A model repeatedly hand-counts parentheses, edits partial closing-paren fragments, or probes build/src generated files after a Jerboa source edit fails balance or EOF syntax checks.") + ("severity" . "high") + ("tags" "jerboa" "scheme" "balance" "balanced-replace" + "repair-loop" "generated-source") + ("title" + . + "Manual paren repair loop after generated Jerboa edit") + ("tools" "jerboa_check_balance" "jerboa_repair_balance" + "jerboa_balanced_insert" "jerboa_balanced_replace" + "jerboa_verify")) + (("advice" + . "Either delete the wrapper and let member code call the top-level helper, or give the wrapper a distinct Kotlin name. After regeneration, grep generated Kotlin for `private fun foo(...): ... { return foo(...) }` and run an emulator launch/logcat check.") ("avoid" . @@ -5191,7 +5213,7 @@ ("kinds" "android" "debug-error" "test") ("pattern" . - "private fun ([A-Za-z0-9_]+)\([^)]*\).*return \1\(") + "private fun ([A-Za-z0-9_]+)\\([^)]*\\).*return \\1\\(") ("severity" . "high") ("tags" "typed-kotlin" "android" "kotlin-name" "stack-overflow" "generator") --- a/data/cookbooks.sexp +++ b/data/cookbooks.sexp @@ -7140,25 +7140,31 @@ "Recover when a .ss file becomes unbalanced (dropped/extra paren)")) (("code" . - "# tools/build_android_embedded_rules.sh -JERBOA_WPO_SCHEME="${JERBOA_WPO_SCHEME:-$JERBOA_VENDOR/build/chez/$(uname -m | sed 's/arm64/tarm64osx/;s/x86_64/ta6osx/')/bin/$(uname -m | sed 's/arm64/tarm64osx/;s/x86_64/ta6osx/')/scheme}" - -JERBUILD_BINARY_OBJ_DIR="$JERBUILD_OBJ_DIR" \ -JERBUILD_BINARY_KEEP_OBJ_DIR=1 \ -JERBOA_WPO_SCHEME="$JERBOA_WPO_SCHEME" \ -"$JERBOA_BIN" jerbuild binary \ - --libdirs "$ANDROID_RULES_BUILD_DIR/lib" \ - --cc "$TARGET_CC -shared -fPIC" \ - --csv-dir "$CSV_DIR" \ - --xpatch "$XPATCH" \ - --os-libs "-llog -lm -ldl" \ - --main-c "$ANDROID_APP/src/main/jni/originaltactics_rules_jni.c" \ - "$ROOT/sfb/android-service-main.ss" \ - "$OUTPUT_SO" - -# jerbuild.ss subprocess selection -# If JERBOA_WPO_SCHEME is set, run: $JERBOA_WPO_SCHEME --script cross-wpo-compile.ss -# Otherwise fall back to the packaged jerboa runtime.") ("id" . "android-cross-wpo-use-host-scheme") ("imports") + "(def (send-json-line output obj)\n (display (json-object->string obj) output)\n (newline output)\n (flush-output-port output))\n\n(def (fd->input-output-ports fd c-dup)\n (let* ((fd2 (c-dup fd))\n (inp (open-fd-input-port fd (buffer-mode block) (native-transcoder)))\n (out (open-fd-output-port fd2 (buffer-mode block) (native-transcoder))))\n (values inp out)))") ("id" . "mcp-jsonrpc-explicit-port-writes") + ("imports" "(chezscheme)" "(jerboa prelude clean)") + ("notes" + . + "Do not use `(displayln value output)` when `displayln` is a variadic stdout helper; it can print the port object instead of writing to that port. When creating separate input/output ports for one fd, duplicate the fd first so closing both ports does not double-close the same descriptor.") + ("tags" "mcp" "json-rpc" "display" "newline" "socket" + "open-fd-output-port") + ("title" + . + "Write newline-delimited JSON-RPC to an explicit port")) + (("code" + . + "(def (json-key key)\n (if (symbol? key) (symbol->string key) key))\n\n(def (json-alist? value)\n (and (pair? value)\n (pair? (car value))\n (or (symbol? (caar value)) (string? (caar value)))))\n\n(def (json-safe value)\n (cond\n ((json-alist? value)\n (let* ((ht (make-hash-table)))\n (for-each\n (lambda (p)\n (hash-put! ht (json-key (car p)) (json-safe (cdr p))))\n value)\n ht))\n ((list? value) (map json-safe value))\n (else value)))\n\n(def (json-rpc-response result id)\n (json-object->string\n (json-safe\n (list (cons 'jsonrpc \"2.0\")\n (cons 'result result)\n (cons 'id id)))))") ("id" . "json-rpc-alist-to-hash-response") + ("imports" "(jerboa prelude)") + ("notes" + . + "Jerboa JSON parsing returns hash tables, but local code often builds alists. `json-object->string` may reject pair objects such as `(jsonrpc . \"2.0\")`; convert alists recursively and turn symbol keys into strings before encoding. The `json-alist?` guard avoids treating arrays of objects as one object.") + ("tags" "json" "json-rpc" "alist" "hash-table" + "json-object-string" "symbol-keys") + ("title" + . + "Convert alist JSON-RPC responses to hash tables before encoding")) + (("code" + . + "# tools/build_android_embedded_rules.sh\nJERBOA_WPO_SCHEME=\"${JERBOA_WPO_SCHEME:-$JERBOA_VENDOR/build/chez/$(uname -m | sed 's/arm64/tarm64osx/;s/x86_64/ta6osx/')/bin/$(uname -m | sed 's/arm64/tarm64osx/;s/x86_64/ta6osx/')/scheme}\"\n\nJERBUILD_BINARY_OBJ_DIR=\"$JERBUILD_OBJ_DIR\" \\\nJERBUILD_BINARY_KEEP_OBJ_DIR=1 \\\nJERBOA_WPO_SCHEME=\"$JERBOA_WPO_SCHEME\" \\\n\"$JERBOA_BIN\" jerbuild binary \\\n --libdirs \"$ANDROID_RULES_BUILD_DIR/lib\" \\\n --cc \"$TARGET_CC -shared -fPIC\" \\\n --csv-dir \"$CSV_DIR\" \\\n --xpatch \"$XPATCH\" \\\n --os-libs \"-llog -lm -ldl\" \\\n --main-c \"$ANDROID_APP/src/main/jni/originaltactics_rules_jni.c\" \\\n \"$ROOT/sfb/android-service-main.ss\" \\\n \"$OUTPUT_SO\"\n\n# jerbuild.ss subprocess selection\n# If JERBOA_WPO_SCHEME is set, run: $JERBOA_WPO_SCHEME --script cross-wpo-compile.ss\n# Otherwise fall back to the packaged jerboa runtime.") ("id" . "android-cross-wpo-use-host-scheme") ("imports") ("notes" . "When Android cross-WPO fails with `Exception in lookup_c_entry: invalid index 51`, reproduce with a one-line .ss file. If raw host Chez Scheme can run the generated cross-wpo helper but `dist/jerboa runtime` cannot, teach jerbuild to honor `JERBOA_WPO_SCHEME` for isolated WPO helpers and rebuild `vendor/jerboa/dist/jerboa` so the packaged multicall binary sees the source change.") --- a/data/error-fixes.sexp +++ b/data/error-fixes.sexp @@ -2946,11 +2946,21 @@ ("type" . "compile")) (("code_example" . - "JERBOA_WPO_SCHEME="$PWD/vendor/jerboa/build/chez/tarm64osx/bin/tarm64osx/scheme" \ -vendor/jerboa/dist/jerboa jerbuild binary \ - --csv-dir vendor/jerboa/.chez-cross-tarm64le/lib/csv10.4.0-pre-release.4/tarm64le \ - --xpatch vendor/jerboa/build/chez/xc-tarm64le/s/xpatch \ - entry.ss output.so") + ";; Before\n(json-object->string (list (cons 'jsonrpc \"2.0\") (cons 'id 1)))\n\n;; After\n(let ((ht (make-hash-table)))\n (hash-put! ht \"jsonrpc\" \"2.0\")\n (hash-put! ht \"id\" 1)\n (json-object->string ht))") + ("explanation" + . + "Jerboa's JSON writer expects JSON objects as hash tables; an alist pair such as `(jsonrpc . \"2.0\")` is not a JSON value by itself and serialization fails.") + ("fix" + . + "Do not pass raw alists or pairs with symbol keys directly to `json-object->string`. Convert response objects to hash tables with string keys first, recursively preserving arrays as lists.") + ("id" . "write-json-cannot-serialize-pair") + ("pattern" + . + "Exception in write-json: cannot serialize with irritant \\([^)]* \\. [^)]*\\)") + ("type" . "runtime")) + (("code_example" + . + "JERBOA_WPO_SCHEME=\"$PWD/vendor/jerboa/build/chez/tarm64osx/bin/tarm64osx/scheme\" \\\nvendor/jerboa/dist/jerboa jerbuild binary \\\n --csv-dir vendor/jerboa/.chez-cross-tarm64le/lib/csv10.4.0-pre-release.4/tarm64le \\\n --xpatch vendor/jerboa/build/chez/xc-tarm64le/s/xpatch \\\n entry.ss output.so") ("explanation" . "A packaged Jerboa multicall runtime can fail when loading a Chez xpatch and running Android cross-WPO helpers. The same generated helper may succeed under the raw host Chez Scheme binary.") @@ -2964,12 +2974,7 @@ vendor/jerboa/dist/jerboa jerbuild binary \ ("type" . "cross-build")) (("code_example" . - ";; Bad inside MainActivity typed template: -(def (truncateForLogLocal (text : String) (limit : Int32)) : String - (modifiers private) (kotlin-name truncateForLog) - (truncateForLog text limit)) - -;; Fix: delete this wrapper and call the top-level truncateForLog directly.") + ";; Bad inside MainActivity typed template:\n(def (truncateForLogLocal (text : String) (limit : Int32)) : String\n (modifiers private) (kotlin-name truncateForLog)\n (truncateForLog text limit))\n\n;; Fix: delete this wrapper and call the top-level truncateForLog directly.") ("explanation" . "A Typed Android template emitted a private member with `(kotlin-name helper)` whose body calls `helper` with the same arity. Kotlin resolves the call to the member instead of the top-level helper, causing infinite recursion.") @@ -2979,5 +2984,19 @@ vendor/jerboa/dist/jerboa jerbuild binary \ ("id" . "typed-kotlin-helper-wrapper-stack-overflow") ("pattern" . - "java\.lang\.StackOverflowError:.*MainActivity\.(truncateForLog|autoEventDelayMillis|hudActionLabel|seekingSortBucket|shortDefenseKind|isInterestingEvent)") - ("type" . "android-runtime"))) + "java\\.lang\\.StackOverflowError:.*MainActivity\\.(truncateForLog|autoEventDelayMillis|hudActionLabel|seekingSortBucket|shortDefenseKind|isInterestingEvent)") + ("type" . "android-runtime")) + (("code_example" + . + "(if (nullable-null? truth)\n (begin)\n (begin\n (mainServerPageApplyTruth session (nullable-get truth))\n (mainServerPagePrune session)\n (begin)))") + ("explanation" + . + "Typed Android/Jerboa if branches must have the same result type. A branch that ends with a helper returning Int32, such as a prune/count function, mismatches an empty (begin) Unit branch even when the enclosing function returns Unit.") + ("fix" + . + "When using an if for side effects in typed Android code, make both branches return Unit. If the non-empty branch calls an Int32-returning helper for its side effect, add a final (begin) after that call so the branch result is Unit.") + ("id" . "typed-branch-type-mismatch-unit-int-return") + ("pattern" + . + "Exception in typed-modules->kotlin-files: typed modules have check errors with irritant (((com sfb ssdreview) branch-type-mismatch))") + ("type" . "typecheck"))) --- a/lib/jerboa/prelude/clean.ss +++ b/lib/jerboa/prelude/clean.ss @@ -27,6 +27,8 @@ ;; ---- Runtime (no make-hash-table, hash-table?, 1+, 1-, iota) ---- ~ bind-method! call-method + make-rwlock rwlock? rwlock-read-lock! rwlock-read-unlock! rwlock-write-lock! rwlock-write-unlock! with-read-lock with-write-lock + make-thread thread-start! thread-join! make-hash-table-eq hash-ref hash-get hash-put! hash-update! hash-remove! hash-key? hash->list hash->plist hash-for-each hash-map hash-fold @@ -76,6 +78,7 @@ zip ;; ---- std/misc/alist ---- + alist agetq agetv aget asetq! asetv! aset! pgetq pgetv pget @@ -117,11 +120,13 @@ register-struct-type! *struct-types* struct-predicate struct-field-ref struct-field-set! struct-type-info) + (only (std concur util) make-rwlock rwlock? rwlock-read-lock! rwlock-read-unlock! rwlock-write-lock! rwlock-write-unlock! with-read-lock with-write-lock) + (only (std misc thread) make-thread thread-start! thread-join!) (only (jerboa ffi) c-lambda define-c-lambda begin-ffi c-declare) (only (std sort) stable-sort stable-sort!) (only (std format) eprintf) (only (std error) Error ContractViolation) - (only (std sugar) chain chain-and assert!) + (only (std sugar) chain chain-and assert! alist) (only (std text json) read-json write-json json-object->string string->json-object) (only (std os path) path-expand path-normalize path-directory path-strip-directory path-strip-extension path-join)