Compiler: dict destructuring in let, paren-aware library stripping — 31/31 sxbc
compile-let now handles dict destructuring patterns:
(let {:key1 var1 :key2 var2} source body). This unblocked core-signals.sx
(deref uses dict destructuring) which was the sole bytecode skip.
Rewrote stripLibraryWrapper from line-based to paren-aware extraction.
The old regex missed (define-library on its own line (no trailing space),
silently passing the full wrapper to the compiler.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -126,36 +126,102 @@ for (const file of FILES) {
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
function stripLibraryWrapper(source) {
|
||||
// Line-based stripping: unwrap (define-library ... (begin BODY)), keep (import ...).
|
||||
const lines = source.split('\n');
|
||||
const result = [];
|
||||
let skip = false; // inside header region (define-library, export)
|
||||
// Paren-aware stripping: find (begin ...) inside (define-library ...), extract body.
|
||||
// Keep top-level (import ...) forms outside the define-library.
|
||||
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
const line = lines[i];
|
||||
const trimmed = line.trim();
|
||||
// Find (define-library at the start
|
||||
const dlMatch = source.match(/^[\s\S]*?\(define-library\b/);
|
||||
if (!dlMatch) return source; // no define-library, return as-is
|
||||
|
||||
// Skip (define-library ...) header lines until (begin
|
||||
if (trimmed.startsWith('(define-library ')) { skip = true; continue; }
|
||||
if (skip && trimmed.startsWith('(export')) { continue; }
|
||||
if (skip && trimmed.match(/^\(begin/)) { skip = false; continue; }
|
||||
if (skip) continue;
|
||||
// Find the (begin that opens the body — skip past (export ...) using paren counting
|
||||
const afterDL = dlMatch[0].length;
|
||||
let pos = afterDL;
|
||||
let foundBegin = -1;
|
||||
|
||||
// Skip closing )) of define-library — line is just ) or )) optionally with comments
|
||||
if (trimmed.match(/^\)+(\s*;.*)?$/)) {
|
||||
// Check if this is the end-of-define-library closer (only `)` chars + optional comment)
|
||||
// vs a regular body closer like ` )` inside a nested form
|
||||
// Only skip if at column 0 (not indented = top-level closer)
|
||||
if (line.match(/^\)/)) continue;
|
||||
while (pos < source.length) {
|
||||
// Skip whitespace and comments
|
||||
while (pos < source.length && /[\s]/.test(source[pos])) pos++;
|
||||
if (pos >= source.length) break;
|
||||
if (source[pos] === ';') { // skip comment line
|
||||
while (pos < source.length && source[pos] !== '\n') pos++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Skip standalone comments that are just structural markers
|
||||
if (trimmed.match(/^;;\s*(end define-library|Re-export)/)) continue;
|
||||
// Check for (begin
|
||||
if (source.startsWith('(begin', pos)) {
|
||||
foundBegin = pos;
|
||||
break;
|
||||
}
|
||||
|
||||
result.push(line);
|
||||
// Skip balanced sexp (the library name and export list)
|
||||
if (source[pos] === '(') {
|
||||
let depth = 1;
|
||||
pos++;
|
||||
while (pos < source.length && depth > 0) {
|
||||
if (source[pos] === '(') depth++;
|
||||
else if (source[pos] === ')') depth--;
|
||||
else if (source[pos] === '"') { // skip strings
|
||||
pos++;
|
||||
while (pos < source.length && source[pos] !== '"') {
|
||||
if (source[pos] === '\\') pos++;
|
||||
pos++;
|
||||
}
|
||||
} else if (source[pos] === ';') { // skip comments
|
||||
while (pos < source.length && source[pos] !== '\n') pos++;
|
||||
continue;
|
||||
}
|
||||
pos++;
|
||||
}
|
||||
} else {
|
||||
// Skip atom
|
||||
while (pos < source.length && !/[\s()]/.test(source[pos])) pos++;
|
||||
}
|
||||
}
|
||||
|
||||
return result.join('\n');
|
||||
if (foundBegin === -1) return source; // no (begin found
|
||||
|
||||
// Find the body inside (begin ...) — skip "(begin" + optional whitespace
|
||||
let bodyStart = foundBegin + 6; // len("(begin") = 6
|
||||
// Skip optional newline/whitespace after (begin
|
||||
while (bodyStart < source.length && /[\s]/.test(source[bodyStart])) bodyStart++;
|
||||
|
||||
// Find matching close of (begin ...) using paren counting from foundBegin
|
||||
pos = foundBegin + 1; // after opening (
|
||||
let depth = 1;
|
||||
while (pos < source.length && depth > 0) {
|
||||
if (source[pos] === '(') depth++;
|
||||
else if (source[pos] === ')') depth--;
|
||||
else if (source[pos] === '"') {
|
||||
pos++;
|
||||
while (pos < source.length && source[pos] !== '"') {
|
||||
if (source[pos] === '\\') pos++;
|
||||
pos++;
|
||||
}
|
||||
} else if (source[pos] === ';') {
|
||||
while (pos < source.length && source[pos] !== '\n') pos++;
|
||||
continue;
|
||||
}
|
||||
if (depth > 0) pos++;
|
||||
}
|
||||
const beginClose = pos; // position of closing ) for (begin ...)
|
||||
|
||||
// Extract body (everything between (begin and its closing paren)
|
||||
const body = source.slice(bodyStart, beginClose);
|
||||
|
||||
// Find any (import ...) forms AFTER the define-library
|
||||
// The define-library's closing paren is right after begin's
|
||||
let dlClose = beginClose + 1;
|
||||
while (dlClose < source.length && source[dlClose] !== ')') {
|
||||
if (source[dlClose] === ';') {
|
||||
while (dlClose < source.length && source[dlClose] !== '\n') dlClose++;
|
||||
}
|
||||
dlClose++;
|
||||
}
|
||||
dlClose++; // past the closing )
|
||||
|
||||
const afterDLForm = source.slice(dlClose);
|
||||
|
||||
return body + '\n' + afterDLForm;
|
||||
}
|
||||
|
||||
// Compile each module (stripped of define-library/import wrappers)
|
||||
|
||||
Reference in New Issue
Block a user