python2ib
Version:
Convert Python code to IB Pseudocode format
328 lines • 10.2 kB
JavaScript
/**
* Main emitter for converting IR to IB Pseudocode text
*/
import { IndentManager, IndentUtils } from '../utils/indent.js';
/** Main emitter class for IR to IB Pseudocode conversion */
export class IBPseudocodeEmitter {
indentManager;
config;
output = [];
constructor(config) {
this.config = config;
this.indentManager = new IndentManager(config.indentStyle, config.indentSize);
}
/** Main emit method */
emit(ir) {
this.output = [];
this.emitNode(ir);
let result = this.output.join('\n');
// Apply post-processing
if (this.config.normalizeIndentation) {
result = IndentUtils.normalize(result, this.config.indentStyle, this.config.indentSize);
}
// Ensure proper line endings
result = result.replace(/\r\n/g, '\n').replace(/\r/g, '\n');
// Remove trailing newlines for single statements
result = result.replace(/\n+$/, '');
return result;
}
/** Emit a single IR node */
emitNode(node) {
switch (node.kind) {
case 'program':
this.emitProgram(node);
break;
case 'assign':
this.emitAssign(node);
break;
case 'output':
this.emitOutput(node);
break;
case 'input':
this.emitInput(node);
break;
case 'if':
this.emitIf(node);
break;
case 'endif':
this.emitEndif(node);
break;
case 'elseif':
this.emitElseif(node);
break;
case 'else':
this.emitElse(node);
break;
case 'while':
this.emitWhile(node);
break;
case 'until':
this.emitUntil(node);
break;
case 'endwhile':
this.emitEndwhile(node);
break;
case 'for':
this.emitFor(node);
break;
case 'next':
this.emitNext(node);
break;
case 'function':
this.emitFunction(node);
break;
case 'endfunction':
this.emitEndfunction(node);
break;
case 'procedure':
this.emitProcedure(node);
break;
case 'endprocedure':
this.emitEndprocedure(node);
break;
case 'return':
this.emitReturn(node);
break;
case 'comment':
this.emitComment(node);
break;
case 'expression':
this.emitExpression(node);
break;
case 'block':
this.emitBlock(node);
break;
case 'sequence':
this.emitSequence(node);
break;
default:
this.emitUnsupported(node);
break;
}
}
/** Emit block */
emitBlock(node) {
for (const child of node.children) {
this.emitNode(child);
}
}
/** Emit sequence */
emitSequence(node) {
for (const child of node.children) {
this.emitNode(child);
}
}
/** Emit program (root) */
emitProgram(node) {
for (const child of node.children) {
this.emitNode(child);
}
}
/** Emit assignment */
emitAssign(node) {
const line = this.indentManager.current + node.text;
this.output.push(line);
}
/** Emit output statement */
emitOutput(node) {
const line = this.indentManager.current + node.text;
this.output.push(line);
}
/** Emit input statement */
emitInput(node) {
const line = this.indentManager.current + node.text;
this.output.push(line);
}
/** Emit if statement */
emitIf(node) {
const line = this.indentManager.current + node.text;
this.output.push(line);
// Increase indent for body
this.indentManager.increase();
// Emit children
for (const child of node.children) {
this.emitNode(child);
}
}
/** Emit endif */
emitEndif(node) {
// Decrease indent before emitting ENDIF
this.indentManager.decrease();
const line = this.indentManager.current + node.text;
this.output.push(line);
}
/** Emit elseif */
emitElseif(node) {
// Temporarily decrease indent for ELSEIF
this.indentManager.decrease();
const line = this.indentManager.current + node.text;
this.output.push(line);
this.indentManager.increase();
// Emit children
for (const child of node.children) {
this.emitNode(child);
}
}
/** Emit else */
emitElse(node) {
// Temporarily decrease indent for ELSE
this.indentManager.decrease();
const line = this.indentManager.current + node.text;
this.output.push(line);
this.indentManager.increase();
// Emit children
for (const child of node.children) {
this.emitNode(child);
}
}
/** Emit while loop */
emitWhile(node) {
const line = this.indentManager.current + node.text;
this.output.push(line);
// Increase indent for body
this.indentManager.increase();
// Emit children
for (const child of node.children) {
this.emitNode(child);
}
}
/** Emit until loop */
emitUntil(node) {
const line = this.indentManager.current + node.text;
this.output.push(line);
// Increase indent for body
this.indentManager.increase();
// Emit children
for (const child of node.children) {
this.emitNode(child);
}
}
/** Emit endwhile */
emitEndwhile(node) {
// Decrease indent before emitting ENDWHILE
this.indentManager.decrease();
const line = this.indentManager.current + node.text;
this.output.push(line);
}
/** Emit for loop */
emitFor(node) {
const line = this.indentManager.current + node.text;
this.output.push(line);
// Increase indent for body
this.indentManager.increase();
// Emit children
for (const child of node.children) {
this.emitNode(child);
}
}
/** Emit next (end of for loop) */
emitNext(node) {
// Decrease indent before emitting NEXT
this.indentManager.decrease();
const line = this.indentManager.current + node.text;
this.output.push(line);
}
/** Emit function definition */
emitFunction(node) {
const line = this.indentManager.current + node.text;
this.output.push(line);
// Increase indent for body
this.indentManager.increase();
// Emit children
for (const child of node.children) {
this.emitNode(child);
}
}
/** Emit endfunction */
emitEndfunction(node) {
// Decrease indent before emitting ENDFUNCTION
this.indentManager.decrease();
const line = this.indentManager.current + node.text;
this.output.push(line);
}
/** Emit procedure definition */
emitProcedure(node) {
const line = this.indentManager.current + node.text;
this.output.push(line);
// Increase indent for body
this.indentManager.increase();
// Emit children
for (const child of node.children) {
this.emitNode(child);
}
}
/** Emit endprocedure */
emitEndprocedure(node) {
// Decrease indent before emitting ENDPROCEDURE
this.indentManager.decrease();
const line = this.indentManager.current + node.text;
this.output.push(line);
}
/** Emit return statement */
emitReturn(node) {
const line = this.indentManager.current + node.text;
this.output.push(line);
}
/** Emit comment */
emitComment(node) {
const line = this.indentManager.current + node.text;
this.output.push(line);
}
/** Emit expression */
emitExpression(node) {
const line = this.indentManager.current + node.text;
this.output.push(line);
}
/** Emit unsupported node */
emitUnsupported(node) {
const unsupportedComment = `// UNSUPPORTED: ${node.kind} - ${node.text}`;
const line = this.indentManager.current + unsupportedComment;
this.output.push(line);
}
/** Get current indentation level */
getCurrentIndentLevel() {
return this.indentManager.getLevel();
}
/** Reset emitter state */
reset() {
this.output = [];
this.indentManager.reset();
}
}
/** Convenience function for emitting IR to IB Pseudocode */
export function emitIBPseudocode(ir, config) {
const emitter = new IBPseudocodeEmitter(config);
return emitter.emit(ir);
}
/** Convenience function with default config */
export function emitIBPseudocodeDefault(ir) {
const defaultConfig = {
format: 'plain',
indentStyle: 'spaces',
indentSize: 4,
includeLineNumbers: false,
includeOriginalCode: false,
validateSyntax: true,
preserveEmptyLines: true,
variableMapping: {},
functionMapping: {},
strictMode: false,
normalizeIndentation: false,
preserveComments: true,
customOperators: {},
customKeywords: {},
outputOptions: {
includeLineNumbers: false,
includeComments: true,
wrapInCodeBlock: false
},
conversionRules: {
forceExplicitTypes: false,
convertFStrings: true,
expandCompoundAssignments: true,
simplifyExpressions: false
}
};
return emitIBPseudocode(ir, defaultConfig);
}
//# sourceMappingURL=index.js.map