Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
106 changes: 53 additions & 53 deletions src/baseTranspiler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import { IFileImport, IFileExport, TranspilationError, IMethodType, IParameterType } from './types.js';
import { unCamelCase } from "./utils.js";
import { Logger } from "./logger.js";
import { timingSafeEqual } from 'crypto';

Check warning on line 5 in src/baseTranspiler.ts

View workflow job for this annotation

GitHub Actions / build (18.x)

'timingSafeEqual' is defined but never used
class BaseTranspiler {

NUM_LINES_BETWEEN_CLASS_MEMBERS = 1;
Expand Down Expand Up @@ -358,7 +358,7 @@

let method = undefined;

let parentClass = (ts as any).getAllSuperTypeNodes(node.parent)[0];

Check warning on line 361 in src/baseTranspiler.ts

View workflow job for this annotation

GitHub Actions / build (18.x)

Unexpected any. Specify a different type

while (parentClass !== undefined) {
const parentClassType = global.checker.getTypeAtLocation(parentClass);
Expand All @@ -375,13 +375,13 @@
if (ts.isMethodDeclaration(elem)) {

const name = elem.name.getText().trim();
if ((node as any).name.escapedText === name) {

Check warning on line 378 in src/baseTranspiler.ts

View workflow job for this annotation

GitHub Actions / build (18.x)

Unexpected any. Specify a different type
method = elem;
}
}
});

parentClass = (ts as any).getAllSuperTypeNodes(parentClassDecl)[0] ?? undefined;

Check warning on line 384 in src/baseTranspiler.ts

View workflow job for this annotation

GitHub Actions / build (18.x)

Unexpected any. Specify a different type
}


Expand All @@ -394,7 +394,7 @@
return this.DEFAULT_IDENTATION.repeat(parseInt(num));
}

getBlockOpen(identation){

Check warning on line 397 in src/baseTranspiler.ts

View workflow job for this annotation

GitHub Actions / build (18.x)

'identation' is defined but never used
return this.SPACE_BEFORE_BLOCK_OPENING + this.BLOCK_OPENING_TOKEN + "\n";
}

Expand Down Expand Up @@ -459,11 +459,11 @@
return this.getIden(identation) + `${left} instanceof ${right}`;
}

getCustomOperatorIfAny(left, right, operator) {

Check warning on line 462 in src/baseTranspiler.ts

View workflow job for this annotation

GitHub Actions / build (18.x)

'operator' is defined but never used

Check warning on line 462 in src/baseTranspiler.ts

View workflow job for this annotation

GitHub Actions / build (18.x)

'right' is defined but never used

Check warning on line 462 in src/baseTranspiler.ts

View workflow job for this annotation

GitHub Actions / build (18.x)

'left' is defined but never used
return undefined;
}

printCustomBinaryExpressionIfAny(node, identation) {

Check warning on line 466 in src/baseTranspiler.ts

View workflow job for this annotation

GitHub Actions / build (18.x)

'identation' is defined but never used

Check warning on line 466 in src/baseTranspiler.ts

View workflow job for this annotation

GitHub Actions / build (18.x)

'node' is defined but never used
return undefined; // stub to override
}

Expand Down Expand Up @@ -1584,17 +1584,10 @@
return this.printPrefixUnaryExpression(node, identation); // avoid infinite recursion
}

let expression = this.printNode(node, 0);
// wrap falsy/truty expressions if needed
if ( (1+1) || (node.kind !== ts.SyntaxKind.BinaryExpression && node.kind !== ts.SyntaxKind.ParenthesizedExpression)) {

const typeFlags = global.checker.getTypeAtLocation(node).flags;
if ( (1+1) || typeFlags !== ts.TypeFlags.BooleanLiteral && typeFlags !== ts.TypeFlags.Boolean) {
expression = this.printNode(node, 0);
// this.warn(node, node.getText(), "Falsy/Truthy expressions are not supported by this language, so adding the defined wrapper!");
expression = `${this.FALSY_WRAPPER_OPEN}${expression}${this.FALSY_WRAPPER_CLOSE}`;
}
}
// wrap falsy/truthy expressions unconditionally: printing the node once and
// wrapping is equivalent to the previous always-true branches, which printed
// the subtree twice and queried the type checker without using the result
const expression = `${this.FALSY_WRAPPER_OPEN}${this.printNode(node, 0)}${this.FALSY_WRAPPER_CLOSE}`;
return `${this.getIden(identation)}${expression}`; // stub to override
}

Expand Down Expand Up @@ -1839,89 +1832,96 @@
printNode(node, identation = 0): string {

try {
if(ts.isExpressionStatement(node)) {
// dispatch on node.kind directly: every ts.isX predicate used here is a
// plain kind comparison, and a switch avoids running ~45 predicate calls
// for nodes that match late (or not at all) in the former if-else chain
switch (node.kind) {
case ts.SyntaxKind.ExpressionStatement:
return this.printExpressionStatement(node, identation);
} else if(ts.isBlock(node)) {
case ts.SyntaxKind.Block:
return this.printBlock(node, identation);
} else if (ts.isFunctionDeclaration(node) || ts.isFunctionExpression(node) || ts.isArrowFunction(node)){
case ts.SyntaxKind.FunctionDeclaration:
case ts.SyntaxKind.FunctionExpression:
case ts.SyntaxKind.ArrowFunction:
return this.printFunctionDeclaration(node, identation);
} else if (ts.isClassDeclaration(node)) {
case ts.SyntaxKind.ClassDeclaration:
return this.printClass(node, identation);
} else if (ts.isVariableStatement(node)) {
case ts.SyntaxKind.VariableStatement:
return this.printVariableStatement(node, identation);
} else if (ts.isMethodDeclaration(node)) {
case ts.SyntaxKind.MethodDeclaration:
return this.printMethodDeclaration(node, identation);
} else if (ts.isStringLiteral(node)) {
case ts.SyntaxKind.StringLiteral:
return this.printStringLiteral(node);
} else if (ts.isNumericLiteral(node)) {
case ts.SyntaxKind.NumericLiteral:
return this.printNumericLiteral(node);
} else if (ts.isPropertyAccessExpression(node)) {
case ts.SyntaxKind.PropertyAccessExpression:
return this.printPropertyAccessExpression(node, identation);
} else if (ts.isArrayLiteralExpression(node)) {
case ts.SyntaxKind.ArrayLiteralExpression:
return this.printArrayLiteralExpression(node, identation);
} else if (ts.isCallExpression(node)) {
case ts.SyntaxKind.CallExpression:
return this.printCallExpression(node, identation);
} else if (ts.isWhileStatement(node)) {
case ts.SyntaxKind.WhileStatement:
return this.printWhileStatement(node, identation);
} else if (ts.isBinaryExpression(node)) {
case ts.SyntaxKind.BinaryExpression:
return this.printBinaryExpression(node, identation);
} else if (ts.isBreakStatement(node)) {
case ts.SyntaxKind.BreakStatement:
return this.printBreakStatement(node, identation);
} else if (ts.isForStatement(node)) {
case ts.SyntaxKind.ForStatement:
return this.printForStatement(node, identation);
} else if (ts.isPostfixUnaryExpression(node)) {
case ts.SyntaxKind.PostfixUnaryExpression:
return this.printPostFixUnaryExpression(node, identation);
} else if (ts.isVariableDeclarationList(node)) {
case ts.SyntaxKind.VariableDeclarationList:
return this.printVariableDeclarationList(node, identation); // statements are slightly different if inside a for
} else if (ts.isObjectLiteralExpression(node)) {
case ts.SyntaxKind.ObjectLiteralExpression:
return this.printObjectLiteralExpression(node, identation);
} else if (ts.isPropertyAssignment(node)) {
case ts.SyntaxKind.PropertyAssignment:
return this.printPropertyAssignment(node, identation);
} else if (ts.isIdentifier(node)) {
case ts.SyntaxKind.Identifier:
return this.printIdentifier(node);
} else if (ts.isElementAccessExpression(node)) {
case ts.SyntaxKind.ElementAccessExpression:
return this.printElementAccessExpression(node, identation);
} else if (ts.isIfStatement(node)) {
case ts.SyntaxKind.IfStatement:
return this.printIfStatement(node, identation);
} else if (ts.isParenthesizedExpression(node)) {
case ts.SyntaxKind.ParenthesizedExpression:
return this.printParenthesizedExpression(node, identation);
} else if ((ts as any).isBooleanLiteral(node)) {
case ts.SyntaxKind.TrueKeyword:
case ts.SyntaxKind.FalseKeyword:
return this.printBooleanLiteral(node);
} else if (ts.SyntaxKind.ThisKeyword === node.kind) {
case ts.SyntaxKind.ThisKeyword:
return this.printThisKeyword(node, identation);
} else if (ts.SyntaxKind.SuperKeyword === node.kind) {
case ts.SyntaxKind.SuperKeyword:
return this.SUPER_TOKEN;
}else if (ts.isTryStatement(node)){
case ts.SyntaxKind.TryStatement:
return this.printTryStatement(node, identation);
} else if (ts.isPrefixUnaryExpression(node)) {
case ts.SyntaxKind.PrefixUnaryExpression:
return this.printPrefixUnaryExpression(node, identation);
} else if (ts.isThrowStatement(node)) {
case ts.SyntaxKind.ThrowStatement:
return this.printThrowStatement(node, identation);
} else if (ts.isNewExpression(node)) {
case ts.SyntaxKind.NewExpression:
return this.printNewExpression(node, identation);
} else if (ts.isAwaitExpression(node)) {
case ts.SyntaxKind.AwaitExpression:
return this.printAwaitExpression(node, identation);
} else if (ts.isConditionalExpression(node)) {
case ts.SyntaxKind.ConditionalExpression:
return this.printConditionalExpression(node, identation);
} else if (ts.isAsExpression(node)) {
case ts.SyntaxKind.AsExpression:
return this.printAsExpression(node, identation);
} else if (ts.isReturnStatement(node)) {
case ts.SyntaxKind.ReturnStatement:
return this.printReturnStatement(this.wrapImplicitReturnAwait(node), identation);
} else if (ts.isArrayBindingPattern(node)) {
case ts.SyntaxKind.ArrayBindingPattern:
return this.printArrayBindingPattern(node, identation);
} else if (ts.isParameter(node)) {
case ts.SyntaxKind.Parameter:
return this.printParameter(node);
} else if (ts.isConstructorDeclaration(node)) {
case ts.SyntaxKind.Constructor:
return this.printConstructorDeclaration(node, identation);
} else if (ts.isPropertyDeclaration(node)) {
case ts.SyntaxKind.PropertyDeclaration:
return this.printPropertyDeclaration(node, identation);
} else if (ts.isSpreadElement(node)) {
case ts.SyntaxKind.SpreadElement:
return this.printSpreadElement(node, identation);
} else if (ts.SyntaxKind.NullKeyword === node.kind) {
case ts.SyntaxKind.NullKeyword:
return this.printNullKeyword(node, identation);
} else if (ts.isContinueStatement(node)) {
case ts.SyntaxKind.ContinueStatement:
return this.printContinueStatement(node, identation);
} else if (ts.isDeleteExpression(node)) {
case ts.SyntaxKind.DeleteExpression:
return this.printDeleteExpression(node, identation);
}

Expand Down
24 changes: 13 additions & 11 deletions src/csharpTranspiler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -462,19 +462,21 @@ export class CSharpTranspiler extends BaseTranspiler {
return `inOp(${this.printNode(right, 0)}, ${this.printNode(left, 0)})`;
}

const leftText = this.printNode(left, 0);
const rightText = this.printNode(right, 0);

if (op === ts.SyntaxKind.PlusEqualsToken) {
return `${leftText} = add(${leftText}, ${rightText})`;
}

if (op === ts.SyntaxKind.MinusEqualsToken) {
return `${leftText} = subtract(${leftText}, ${rightText})`;
}
// only print the operands when this op is actually handled here; otherwise
// the base printBinaryExpression prints them, and doing it eagerly means
// every unhandled binary expression gets its subtrees printed twice
if (op === ts.SyntaxKind.PlusEqualsToken || op === ts.SyntaxKind.MinusEqualsToken || op in this.binaryExpressionsWrappers) {
const leftText = this.printNode(left, 0);
const rightText = this.printNode(right, 0);

if (op === ts.SyntaxKind.PlusEqualsToken) {
return `${leftText} = add(${leftText}, ${rightText})`;
}

if (op === ts.SyntaxKind.MinusEqualsToken) {
return `${leftText} = subtract(${leftText}, ${rightText})`;
}

if (op in this.binaryExpressionsWrappers) {
const wrapper = this.binaryExpressionsWrappers[op];
const open = wrapper[0];
const close = wrapper[1];
Expand Down
28 changes: 18 additions & 10 deletions src/goTranspiler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,12 @@ export class GoTranspiler extends BaseTranspiler {
if (text in this.StringLiteralReplacements) {
return this.StringLiteralReplacements[text];
}
// skip the replaceAll passes when there is nothing to escape
if (/['"\n]/.test(text)) {
text = text.replaceAll("'", "\\\\" + "'");
text = text.replaceAll("\"", "\\" + "\"");
text = text.replaceAll("\n", "\\n");
}
// Preserve real backslashes
const backslashPlaceholder = "\x00";
text = text.replaceAll("\\", backslashPlaceholder);
Expand Down Expand Up @@ -878,19 +884,21 @@ ${this.getIden(identation)}PanicOnError(${varName})`;
return `InOp(${this.printNode(right, 0)}, ${this.printNode(left, 0)})`;
}

const leftText = this.printNode(left, 0);
const rightText = this.printNode(right, 0);

if (op === ts.SyntaxKind.PlusEqualsToken) {
return `${leftText} = Add(${leftText}, ${rightText})`;
}
// only print the operands when this op is actually handled here; otherwise
// the base printBinaryExpression prints them, and doing it eagerly means
// every unhandled binary expression gets its subtrees printed twice
if (op === ts.SyntaxKind.PlusEqualsToken || op === ts.SyntaxKind.MinusEqualsToken || op in this.binaryExpressionsWrappers) {
const leftText = this.printNode(left, 0);
const rightText = this.printNode(right, 0);

if (op === ts.SyntaxKind.MinusEqualsToken) {
return `${leftText} = Subtract(${leftText}, ${rightText})`;
}
if (op === ts.SyntaxKind.PlusEqualsToken) {
return `${leftText} = Add(${leftText}, ${rightText})`;
}

if (op === ts.SyntaxKind.MinusEqualsToken) {
return `${leftText} = Subtract(${leftText}, ${rightText})`;
}

if (op in this.binaryExpressionsWrappers) {
const wrapper = this.binaryExpressionsWrappers[op];
const open = wrapper[0];
const close = wrapper[1];
Expand Down
76 changes: 42 additions & 34 deletions src/javaTranspiler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -263,28 +263,30 @@ export class JavaTranspiler extends BaseTranspiler {
return this.UNDEFINED_TOKEN;
}

// keep the same class-reference typeof-guarding logic as your original file
const type = (global as any).checker.getTypeAtLocation(node);
const symbol = type?.symbol;
if (symbol !== undefined) {
const decl = symbol?.declarations ?? [];
let isBuiltIn = undefined;
if (decl.length > 0) {
isBuiltIn =
decl[0].getSourceFile().fileName.indexOf("typescript") > -1;
}
// keep the same class-reference typeof-guarding logic as your original file,
// but run the syntactic (parent-position) checks first: they exclude the vast
// majority of identifiers without paying for a type-checker lookup
const isInsideNewExpression =
node?.parent?.kind === ts.SyntaxKind.NewExpression;
const isInsideCatch =
node?.parent?.kind === ts.SyntaxKind.ThrowStatement;
const isLeftSide =
node?.parent?.name === node || node?.parent?.left === node;
const isCallOrPropertyAccess =
node?.parent?.kind === ts.SyntaxKind.PropertyAccessExpression ||
node?.parent?.kind === ts.SyntaxKind.ElementAccessExpression;
if (!isLeftSide && !isCallOrPropertyAccess && !isInsideCatch && !isInsideNewExpression) {
const type = (global as any).checker.getTypeAtLocation(node);
const typeSymbol = type?.symbol;
if (typeSymbol !== undefined) {
const decl = typeSymbol?.declarations ?? [];
let isBuiltIn = undefined;
if (decl.length > 0) {
isBuiltIn =
decl[0].getSourceFile().fileName.indexOf("typescript") > -1;
}

if (isBuiltIn !== undefined && !isBuiltIn) {
const isInsideNewExpression =
node?.parent?.kind === ts.SyntaxKind.NewExpression;
const isInsideCatch =
node?.parent?.kind === ts.SyntaxKind.ThrowStatement;
const isLeftSide =
node?.parent?.name === node || node?.parent?.left === node;
const isCallOrPropertyAccess =
node?.parent?.kind === ts.SyntaxKind.PropertyAccessExpression ||
node?.parent?.kind === ts.SyntaxKind.ElementAccessExpression;
if (!isLeftSide && !isCallOrPropertyAccess && !isInsideCatch && !isInsideNewExpression) {
if (isBuiltIn !== undefined && !isBuiltIn) {
const symbol = (global as any).checker.getSymbolAtLocation(node);
let isClassDeclaration = false;
if (symbol) {
Expand Down Expand Up @@ -509,23 +511,26 @@ export class JavaTranspiler extends BaseTranspiler {
}

getVarMethodIfAny(node) {
// should return the name of the method this node belongs to, if any
// should return the name of the method this node belongs to, if any;
// the raw AST name is enough here — the result is only used as a scoping
// key, and printNode on an identifier consults the type checker
let current = node?.parent;
while (current) {
if (ts.isMethodDeclaration(current) || ts.isFunctionDeclaration(current)) {
return this.printNode(current.name, 0);
return String((current.name as any)?.escapedText ?? '');
}
current = current.parent;
}
return 'outsideAnyMethod';
}

getVarClassIfAny(node) {
// should return the name of the class this node belongs to, if any
// should return the name of the class this node belongs to, if any;
// raw AST name for the same reason as getVarMethodIfAny
let current = node?.parent;
while (current) {
if (ts.isClassDeclaration(current)) {
return this.printNode(current.name, 0);
return String((current.name as any)?.escapedText ?? '');
}
current = current.parent;
}
Expand Down Expand Up @@ -631,18 +636,21 @@ export class JavaTranspiler extends BaseTranspiler {
return `Helpers.inOp(${this.printNode(right, 0)}, ${this.printNode(left, 0)})`;
}

const leftText = this.printNode(left, 0);
const rightText = this.printNode(right, 0);
// only print the operands when this op is actually handled here; otherwise
// the base printBinaryExpression prints them, and doing it eagerly means
// every unhandled binary expression gets its subtrees printed twice
if (op === ts.SyntaxKind.PlusEqualsToken || op === ts.SyntaxKind.MinusEqualsToken || op in this.binaryExpressionsWrappers) {
const leftText = this.printNode(left, 0);
const rightText = this.printNode(right, 0);

if (op === ts.SyntaxKind.PlusEqualsToken) {
return `${leftText} = Helpers.add(${leftText}, ${rightText})`;
}
if (op === ts.SyntaxKind.PlusEqualsToken) {
return `${leftText} = Helpers.add(${leftText}, ${rightText})`;
}

if (op === ts.SyntaxKind.MinusEqualsToken) {
return `${leftText} = Helpers.subtract(${leftText}, ${rightText})`;
}
if (op === ts.SyntaxKind.MinusEqualsToken) {
return `${leftText} = Helpers.subtract(${leftText}, ${rightText})`;
}

if (op in this.binaryExpressionsWrappers) {
const wrapper = this.binaryExpressionsWrappers[op];
const open = wrapper[0];
const close = wrapper[1];
Expand Down
Loading
Loading