Fix SQLiteWAL: Map literals, nested bracket access, and/or, comments
- Added and/or -> &&/|| rewrite
- Strip // comments before TS processing
- Fix [a..b] range syntax to array literal
- Fix nested Map bracket access (rewrite inner expressions)
- Fix Map assignment index expression rewriting
- Convert {k: v} Map literals to new Map([[k, v]])
- SQLiteWAL: 19 errors -> 0 errors
Progress: 11 specs at 0 errors
This commit is contained in:
parent
7f417d37e0
commit
832feb47b3
1 changed files with 46 additions and 6 deletions
|
|
@ -333,9 +333,12 @@ function emitAction(action: ActionNode, stateVarNames: Set<string>, mapVarNames:
|
|||
case 'assign': {
|
||||
const target = cleanName(stmt.target);
|
||||
const expr = rewriteExpr(stmt.expr, stateVarNames, mapVarNames, localNames, stateEnumName, knownStateValues);
|
||||
const mapBracketMatch = target.match(/^(\w+)\[([^\]]+)\]$/);
|
||||
// Handle Map bracket assignment: mapVar[index] := value -> this.mapVar.set(index, value)
|
||||
// Support nested brackets by finding the outermost [ ] pair
|
||||
const mapBracketMatch = target.match(/^(\w+)\[([\s\S]+)\]$/);
|
||||
if (mapBracketMatch && mapVarNames.has(mapBracketMatch[1])) {
|
||||
bodyParts.push(` this.${mapBracketMatch[1]}.set(${mapBracketMatch[2]}, ${expr});`);
|
||||
const indexExpr = rewriteExpr(mapBracketMatch[2], stateVarNames, mapVarNames, localNames, stateEnumName, knownStateValues);
|
||||
bodyParts.push(` this.${mapBracketMatch[1]}.set(${indexExpr}, ${expr});`);
|
||||
} else {
|
||||
bodyParts.push(` this.${target} = ${expr};`);
|
||||
}
|
||||
|
|
@ -416,13 +419,19 @@ function rewriteExpr(expr: string, stateVarNames: Set<string>, mapVarNames: Set<
|
|||
});
|
||||
|
||||
// Step 3b: Replace identifiers that are state variables but not local params
|
||||
// Track if previous token was 'this.' to avoid double-prefixing
|
||||
const tokens = ts.split(/([\s\(\)\[\]{}+\-*/=<>!&|.,;:'"`]+)/);
|
||||
let prevWasThisDot = false;
|
||||
const result = tokens.map(tok => {
|
||||
if (/^[a-zA-Z_]\w*\.\w+$/.test(tok)) return tok; // already has dot (enum ref)
|
||||
if (/^(true|false|null|undefined|\d+|\w+\.\w+)$/.test(tok)) return tok;
|
||||
if (tok === 'this') { prevWasThisDot = true; return tok; }
|
||||
if (tok === '.') { prevWasThisDot = true; return tok; }
|
||||
if (prevWasThisDot) { prevWasThisDot = false; return tok; } // skip if preceded by this.
|
||||
if (/^[a-zA-Z_]\w*$/.test(tok) && shouldPrefix(tok)) {
|
||||
return `this.${tok}`;
|
||||
}
|
||||
prevWasThisDot = false;
|
||||
return tok;
|
||||
}).join('')
|
||||
// Undo this. prefix on identifiers after bracket access
|
||||
|
|
@ -478,6 +487,28 @@ function rewriteExpr(expr: string, stateVarNames: Set<string>, mapVarNames: Set<
|
|||
// "not isOn" -> "!this.isOn" (will be prefixed by step 3)
|
||||
ts = ts.replace(/\bnot\s+/g, '!');
|
||||
|
||||
// 5d2: and -> &&, or -> || (logical operators)
|
||||
ts = ts.replace(/\band\b/g, '&&').replace(/\bor\b/g, '||');
|
||||
|
||||
// 5d3: Strip SpeckDL comments (// ...) before TS processing
|
||||
ts = ts.replace(/\/\/.*$/gm, '');
|
||||
|
||||
// 5d4: [a..b] range syntax -> array literal [a, a+1, ..., b]
|
||||
ts = ts.replace(/\[(\d+)\.\.(\d+)\]/g, (match, a, b) => {
|
||||
const start = parseInt(a);
|
||||
const end = parseInt(b);
|
||||
const values = [];
|
||||
for (let i = start; i <= end; i++) values.push(i);
|
||||
return `[${values.join(', ')}]`;
|
||||
});
|
||||
|
||||
// 5d5: Map literals {k: v} for Map type assignments
|
||||
// If target is a Map var, convert {k: v} to new Map([[k, v]])
|
||||
ts = ts.replace(/\{(\d+):\s*([^}]+)\}/g, (match, k, v) => {
|
||||
// Only convert if it looks like a Map literal (single key:value pair with number key)
|
||||
return `new Map([[${k}, ${v}]])`;
|
||||
});
|
||||
|
||||
// 5e: Clean up trailing empty comparisons (===) — expression has no RHS after old() removal
|
||||
// "accounts[t.from].debits_posted ===" -> "accounts[t.from].debits_posted === accounts[t.from].debits_posted"
|
||||
ts = ts.replace(/(\S+)\s*===\s*$/g, '$1 === $1');
|
||||
|
|
@ -491,10 +522,17 @@ function rewriteExpr(expr: string, stateVarNames: Set<string>, mapVarNames: Set<
|
|||
for (const mapVar of mapVarNames) {
|
||||
// Match: mapVar[expr] where mapVar is a known Map state variable
|
||||
// Handle both bare mapVar[...] and this.mapVar[...]
|
||||
// The inner expr needs rewriting for this-prefixing
|
||||
const barePattern = new RegExp('\\b(' + mapVar + ')\\[([^\\]]+)\\]', 'g');
|
||||
ts = ts.replace(barePattern, '$1.get($2)!');
|
||||
ts = ts.replace(barePattern, (match, varName, innerExpr) => {
|
||||
const rewrittenInner = rewriteExpr(innerExpr, stateVarNames, mapVarNames, localNames, stateEnumName, knownStateValues);
|
||||
return `${varName}.get(${rewrittenInner})!`;
|
||||
});
|
||||
const thisPattern = new RegExp('\\b(this\\.' + mapVar + ')\\[([^\\]]+)\\]', 'g');
|
||||
ts = ts.replace(thisPattern, '$1.get($2)!');
|
||||
ts = ts.replace(thisPattern, (match, varName, innerExpr) => {
|
||||
const rewrittenInner = rewriteExpr(innerExpr, stateVarNames, mapVarNames, localNames, stateEnumName, knownStateValues);
|
||||
return `${varName}.get(${rewrittenInner})!`;
|
||||
});
|
||||
}
|
||||
// 5h: .size() -> .size (Set/Map size property, not a method in JS)
|
||||
ts = ts.replace(/\.size\(\)/g, '.size');
|
||||
|
|
@ -571,13 +609,15 @@ function tsType(t: any, speckName: string = '', enumMap?: Map<string, string[]>)
|
|||
}
|
||||
if (t.type === 'ident') {
|
||||
const rawName = cleanName(t.name); // strip trailing comma
|
||||
// Map known identifier types to concrete TS types BEFORE checking enum
|
||||
if (rawName === 'Integer') return 'number';
|
||||
if (rawName === 'Boolean') return 'boolean';
|
||||
if (rawName === 'Nat') return 'number';
|
||||
// Check if this ident maps to a known enum interface
|
||||
if (enumMap && enumMap.has(rawName)) {
|
||||
return `${speckName}${rawName}`;
|
||||
}
|
||||
// Map known identifier types to concrete TS types
|
||||
if (rawName === 'IssueState') return 'IssueWorkflowState';
|
||||
if (rawName === 'Nat') return 'number';
|
||||
// Opaque interfaces become 'any' for now
|
||||
if (rawName === 'AST' || rawName === 'ArtifactMap') return 'any';
|
||||
return rawName;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue