Something went wrong. Try again.
Monorepo for Aesthetic.Computer aesthetic.computer
Something went wrong. Try again.
Markdown
KidLisp Malformed Code Protection Plan #
Problem Statement #
When KidLisp code has syntax errors (especially missing closing parentheses), the system crashes with errors like:
❌ Error updating nested embedded layer: TypeError: api.page is not a function
This happens repeatedly and floods the console, making the system unusable.
Root Causes #
- Missing Pre-Validation: Code is parsed and executed without checking for syntax validity first
- Auto-Closing Limitations: While
tokenize()attempts to auto-close parentheses, malformed code can still slip through - No Error Recovery in Embedded Layers: When an embedded layer fails, it continues to retry every frame
- Missing API Safety Checks: The code assumes
api.pageexists without verifying
Solution Architecture #
Phase 1: Pre-Execution Validation (Linting Layer) #
Add a validation step before code execution that checks for:
- Balanced parentheses
- Valid syntax structure
- Safe AST structure
- Recognized function names (optional warning)
class KidLispValidator {
validate(input) {
const errors = [];
const warnings = [];
// 1. Check parenthesis balance
const parenBalance = this.checkParenthesisBalance(input);
if (parenBalance !== 0) {
errors.push({
type: 'UNBALANCED_PARENS',
message: `Missing ${Math.abs(parenBalance)} closing ${parenBalance > 0 ? ')' : '('}`,
severity: 'error'
});
}
// 2. Check for common syntax errors
this.checkSyntaxErrors(input, errors);
// 3. Try to parse and catch tokenization errors
try {
const tokens = tokenize(input);
const ast = readFromTokens([...tokens]);
// 4. Validate AST structure
this.validateAST(ast, errors, warnings);
} catch (e) {
errors.push({
type: 'PARSE_ERROR',
message: e.message,
severity: 'error'
});
}
return {
valid: errors.length === 0,
errors,
warnings
};
}
checkParenthesisBalance(input) {
let balance = 0;
for (const char of input) {
if (char === '(') balance++;
if (char === ')') balance--;
}
return balance;
}
checkSyntaxErrors(input, errors) {
// Check for mismatched quotes
const doubleQuotes = (input.match(/"/g) || []).length;
const singleQuotes = (input.match(/'/g) || []).length;
if (doubleQuotes % 2 !== 0) {
errors.push({
type: 'UNMATCHED_QUOTE',
message: 'Unmatched double quote',
severity: 'error'
});
}
if (singleQuotes % 2 !== 0) {
errors.push({
type: 'UNMATCHED_QUOTE',
message: 'Unmatched single quote',
severity: 'error'
});
}
}
validateAST(ast, errors, warnings) {
// Walk the AST and check for structural issues
// This can be expanded based on common error patterns
}
}
Phase 2: Safe Error Recovery #
Modify the parse() method to catch and handle validation errors:
parse(input) {
const parseStart = this.startTiming('parse');
// Pre-validation step
if (!this.validator) {
this.validator = new KidLispValidator();
}
const validation = this.validator.validate(input);
if (!validation.valid) {
// Store validation errors for debugging
this.lastValidationErrors = validation.errors;
// Log errors to console
console.error('❌ KidLisp Validation Failed:', validation.errors);
// Return a safe empty AST instead of crashing
this.endTiming('parse', parseStart);
return [];
}
// Continue with existing parsing logic...
try {
// ... existing code ...
} catch (error) {
console.error('❌ KidLisp Parse Error:', error);
this.lastParseError = error;
this.endTiming('parse', parseStart);
return [];
}
}
Phase 3: Embedded Layer Safety #
Add safety checks in updateEmbeddedLayer():
async updateEmbeddedLayer(embeddedLayer, api, env) {
let didRender = false;
try {
// Validate that api has required methods
if (!api || typeof api.page !== 'function') {
console.error(`❌ Invalid API object for embedded layer ${embeddedLayer.cacheId}`);
return didRender;
}
// Check if layer has valid parsed code
if (!embeddedLayer.parsedCode || embeddedLayer.parsedCode.length === 0) {
console.warn(`⚠️ Empty parsed code for embedded layer ${embeddedLayer.cacheId}`);
return didRender;
}
// Continue with existing logic...
const originalPage = api.screen;
api.page(embeddedLayer.buffer);
// ... rest of existing code ...
} catch (error) {
console.error(`❌ Error in embedded layer ${embeddedLayer.cacheId}:`, error);
// Mark layer as failed to prevent infinite retry loops
embeddedLayer.failed = true;
embeddedLayer.failureCount = (embeddedLayer.failureCount || 0) + 1;
// Stop retrying after 3 failures
if (embeddedLayer.failureCount >= 3) {
console.warn(`⚠️ Disabling failed embedded layer ${embeddedLayer.cacheId}`);
embeddedLayer.disabled = true;
}
// Always try to restore original page
try {
if (api && typeof api.page === 'function' && api.screen) {
api.page(api.screen);
}
} catch (restoreError) {
console.error("❌ Failed to restore page:", restoreError);
}
}
return didRender;
}
Phase 4: User Feedback #
Add visual feedback for validation errors:
// In the appropriate rendering location
renderValidationErrors(api) {
if (this.lastValidationErrors && this.lastValidationErrors.length > 0) {
const errors = this.lastValidationErrors;
let y = 10;
api.ink('red');
api.write(`Syntax Errors (${errors.length}):`, 10, y);
y += 15;
errors.forEach((error, i) => {
api.ink('yellow');
api.write(`${i + 1}. ${error.message}`, 10, y);
y += 12;
});
}
}
Implementation Steps #
- Create KidLispValidator class (new file:
kidlisp-validator.mjs) - Integrate validation into parse() method
- Add safety checks to updateEmbeddedLayer()
- Add failure tracking to prevent infinite retry
- Add visual error feedback
- Test with known malformed code
Testing Strategy #
Test cases to verify:
- Missing closing parenthesis:
(blue (ink rainbow - Missing opening parenthesis:
blue) ink rainbow) - Unmatched quotes:
(write "hello) - Empty parentheses:
()()() - Deeply nested malformed:
(repeat 10 (repeat 10 (line - Comma-separated with error:
blue, ink rainbow, (line
Expected Outcomes #
- ✅ No more system crashes from malformed code
- ✅ Clear error messages for users
- ✅ Graceful degradation (show previous valid frame)
- ✅ Performance maintained (validation is fast)
- ✅ Better developer experience
Future Enhancements #
- Auto-fix common errors
- Suggest corrections
- Real-time validation in editor
- Syntax highlighting based on validation