Skip to content

Instantly share code, notes, and snippets.

@eridal
Last active August 9, 2023 13:26
Show Gist options
  • Star 8 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save eridal/a850a8a665a255b74d2c to your computer and use it in GitHub Desktop.
Save eridal/a850a8a665a255b74d2c to your computer and use it in GitHub Desktop.
Java to PHP Compilation
<?php
namespace j2p;
use japa\parser\JavaParser;
use japa\parser\ParseException;
use japa\parser\ast\CompilationUnit;
use japa\parser\ast\ImportDeclaration;
use japa\parser\ast\PackageDeclaration;
use japa\parser\ast\body\BodyDeclaration;
use japa\parser\ast\body\ClassOrInterfaceDeclaration;
use japa\parser\ast\body\FieldDeclaration;
use japa\parser\ast\body\InitializerDeclaration;
use japa\parser\ast\body\MethodDeclaration;
use japa\parser\ast\body\Parameter;
use japa\parser\ast\body\TypeDeclaration;
use japa\parser\ast\body\VariableDeclarator;
use japa\parser\ast\body\VariableDeclaratorId;
use japa\parser\ast\expr\AssignExpr;
use japa\parser\ast\expr\BinaryExpr;
use japa\parser\ast\expr\BooleanLiteralExpr;
use japa\parser\ast\expr\ClassExpr;
use japa\parser\ast\expr\ConditionalExpr;
use japa\parser\ast\expr\DoubleLiteralExpr;
use japa\parser\ast\expr\Expression;
use japa\parser\ast\expr\FieldAccessExpr;
use japa\parser\ast\expr\InstanceOfExpr;
use japa\parser\ast\expr\IntegerLiteralExpr;
use japa\parser\ast\expr\LiteralExpr;
use japa\parser\ast\expr\LongLiteralExpr;
use japa\parser\ast\expr\MethodCallExpr;
use japa\parser\ast\expr\NameExpr;
use japa\parser\ast\expr\NullLiteralExpr;
use japa\parser\ast\expr\ObjectCreationExpr;
use japa\parser\ast\expr\QualifiedNameExpr;
use japa\parser\ast\expr\StringLiteralExpr;
use japa\parser\ast\expr\VariableDeclarationExpr;
use japa\parser\ast\stmt\BlockStmt;
use japa\parser\ast\stmt\CatchClause;
use japa\parser\ast\stmt\ContinueStmt;
use japa\parser\ast\stmt\ExpressionStmt;
use japa\parser\ast\stmt\ForeachStmt;
use japa\parser\ast\stmt\IfStmt;
use japa\parser\ast\stmt\ReturnStmt;
use japa\parser\ast\stmt\Statement;
use japa\parser\ast\stmt\SwitchEntryStmt;
use japa\parser\ast\stmt\SwitchStmt;
use japa\parser\ast\stmt\ThrowStmt;
use japa\parser\ast\stmt\TryStmt;
use japa\parser\ast\type\ClassOrInterfaceType;
use japa\parser\ast\type\PrimitiveType;
use japa\parser\ast\type\ReferenceType;
use japa\parser\ast\type\Type;
use java\io\File;
use java\io\IOException;
use java\util\Arrays;
use java\util\HashMap;
use java\util\List_;
use java\util\Map;
class Compiler {
function main($paths) {
foreach ($paths as $path) {
try {
$this->file($path);
}
catch (Exception $e) {
$System->err->println($e->getMessage());
}
}
}
function file($path) {
$file = new File($path);
$unit = $JavaParser->parse($file);
$System->out->println('<?php\n');
$System->out->println($this->stmt_namespace($unit->getPackage()));
$System->out->println('');
foreach ($unit->getImports() as $i) {
$System->out->println($this->stmt_use($i));
}
foreach ($unit->getTypes() as $type) {
$System->out->println('');
$System->out->println($this->stmt_type($type));
}
}
function stmt_namespace(PackageDeclaration $pkg) {
return $String->format('namespace %s;', $this->expr_name($pkg->getName()));
}
function stmt_use(ImportDeclaration $import_) {
return $String->format('use %s;', $this->expr_name($import_->getName()));
}
function stmt_type(TypeDeclaration $type) {
if ($type instanceof ClassOrInterfaceDeclaration) {
return $this->decl_class($expr);
}
else {
throw $this->missing('php_type');
}
}
function decl_class(ClassOrInterfaceDeclaration $type) {
$sb = new StringBuilder();
$extends_ = $type->getExtends();
$implements_ = $type->getImplements();
$sb->append($type->isInterface() ? 'interface' : 'class');
$sb->append(' ');
$sb->append($type->getName());
if (null != $extends_) {
$sb->append(' extends ');
$sb->append($this->decl_class_list($extends_));
}
if (null != $implements_) {
$sb->append(' implements ');
$sb->append($this->decl_class_list($implements_));
}
$sb->append(' {\n');
foreach ($type->getMembers() as $member) {
$sb->append('\n');
$sb->append($this->tab($this->decl_member($member)));
}
$sb->append('\n}');
return $sb->toString();
}
function decl_class_list(List_ $list) {
$sb = new StringBuilder();
$first = true;
foreach ($list as $type) {
if ($first) {
$first = false;
}
else {
$sb->append(', ');
}
$sb->append($type->getName());
}
return $sb->toString();
}
function decl_member(BodyDeclaration $member) {
if ($member instanceof MethodDeclaration) {
return $this->decl_method($expr);
}
if ($member instanceof FieldDeclaration) {
return $this->decl_field($expr);
}
if ($member instanceof InitializerDeclaration) {
return $this->decl_initializer($expr);
}
throw $this->missing('decl_member', $member);
}
function decl_method(MethodDeclaration $method) {
$sb = new StringBuilder();
$body = $method->getBody();
if (null == $body) {
$sb->append('abstract ');
}
$sb->append('function ');
$sb->append($this->keyword($method->getName()));
$sb->append('(');
$params = $method->getParameters();
if (null != $params) {
$sb->append($this->decl_param_list($params));
}
$sb->append(')');
if (null == $body) {
$sb->append(';');
}
else {
$sb->append(' ');
$sb->append($this->stmt_block($body));
}
return $sb->toString();
}
function decl_field(FieldDeclaration $field) {
return '/* decl_field */';
}
function decl_initializer(InitializerDeclaration $init) {
return '/* decl_initializer */';
}
function decl_param_list(List_ $params) {
$sb = new StringBuilder();
$first = true;
foreach ($params as $p) {
if ($first) {
$first = false;
}
else {
$sb->append(', ');
}
$sb->append($this->decl_param($p));
}
return $sb->toString();
}
function decl_param(Parameter $param) {
$sb = new StringBuilder();
$type;
$type = $this->type($param->getType());
if (null != $type) {
$sb->append($type);
$sb->append(' ');
}
if ($param->isVarArgs()) {
$sb->append('...');
}
$sb->append($this->var_($param->getId()));
return $sb->toString();
}
function decl_var(VariableDeclarator $var) {
$sb = new StringBuilder();
$init = $var->getInit();
$sb->append($this->var_($var->getId()));
if (null != $init) {
$sb->append(' = ');
$sb->append($this->expr($var->getInit()));
}
return $sb->toString();
}
function decl_vars(List_ $vars) {
$sb = new StringBuilder();
$first = true;
foreach ($vars as $v) {
if ($first) {
$first = false;
}
else {
$sb->append(', ');
}
$sb->append($this->decl_var($v));
}
return $sb->toString();
}
function stmt_list(List_ $list) {
$sb = new StringBuilder();
foreach ($list as $s) {
$sb->append($this->stmt($s));
$sb->append('\n');
}
return $sb->toString();
}
function stmt(Statement $stmt) {
if ($stmt instanceof IfStmt) {
return $this->stmt_if($expr);
}
if ($stmt instanceof ForeachStmt) {
return $this->stmt_foreach($expr);
}
if ($stmt instanceof SwitchStmt) {
return $this->stmt_switch($expr);
}
if ($stmt instanceof TryStmt) {
return $this->stmt_try($expr);
}
if ($stmt instanceof ReturnStmt) {
return $this->stmt_return($expr);
}
if ($stmt instanceof ContinueStmt) {
return $this->stmt_continue($expr);
}
if ($stmt instanceof ThrowStmt) {
return $this->stmt_throw($expr);
}
if ($stmt instanceof BlockStmt) {
return $this->stmt_block($expr);
}
if ($stmt instanceof ExpressionStmt) {
return $this->stmt_expr($expr);
}
throw $this->missing('stmt', $stmt);
}
function stmt_if(IfStmt $if_) {
$sb = new StringBuilder();
$sb->append('if (');
$sb->append($this->expr($if_->getCondition()));
$sb->append(') ');
$sb->append($this->stmt_block($if_->getThenStmt()));
$else_ = $if_->getElseStmt();
if (null != $else_) {
$sb->append('\nelse');
if ($else_ instanceof IfStmt) {
$sb->append($this->stmt_if($expr));
}
else {
$sb->append(' ');
$sb->append($this->stmt_block($else_));
}
}
return $sb->toString();
}
function stmt_foreach(ForeachStmt $forEach) {
$sb = new StringBuilder();
$sb->append('foreach (');
$sb->append($this->expr($forEach->getIterable()));
$sb->append(' as ');
$sb->append($this->decl_vars($forEach->getVariable()->getVars()));
$sb->append(') ');
$sb->append($this->stmt_block($forEach->getBody()));
return $sb->toString();
}
function stmt_switch(SwitchStmt $switch_) {
$sb = new StringBuilder();
$sb->append('switch (');
$sb->append($this->expr($switch_->getSelector()));
$sb->append('){\n');
foreach ($switch_->getEntries() as $case_) {
$sb->append($this->stmt_switch_case($case_));
}
$sb->append('}');
return $sb->toString();
}
function stmt_switch_case(SwitchEntryStmt $case_) {
$sb = new StringBuilder();
$label = $case_->getLabel();
$list = $case_->getStmts();
if (null == $label) {
$sb->append('default:');
}
else {
$sb->append('case ');
$sb->append($this->expr($label));
$sb->append(':');
}
$sb->append('\n');
if (null != $list) {
$sb->append($this->tab($this->stmt_list($list)));
}
return $sb->toString();
}
function stmt_try(TryStmt $try_) {
$sb = new StringBuilder();
$sb->append('try ');
$sb->append($this->stmt_block($try_->getTryBlock()));
$catchs = $try_->getCatchs();
if (null != $catchs) {
foreach ($catchs as $catch_) {
$sb->append('\ncatch (');
$sb->append($this->decl_param($catch_->getExcept()));
$sb->append(') ');
$sb->append($this->stmt_block($catch_->getCatchBlock()));
}
}
$finally_ = $try_->getFinallyBlock();
if (null != $finally_) {
$sb->append('\nfinally ');
$sb->append($this->stmt_block($finally_));
}
return $sb->toString();
}
function stmt_return(ReturnStmt $return_) {
return $String->format('return %s;', $this->expr($return_->getExpr()));
}
function stmt_continue(ContinueStmt $continue_) {
$id = $continue_->getId();
if (null != $id) {
return $String->format('continue %s;', $id);
}
else {
return 'continue;';
}
}
function stmt_throw(ThrowStmt $throw_) {
return $String->format('throw %s;', $this->expr($throw_->getExpr()));
}
function stmt_expr(ExpressionStmt $exprStmt) {
$expression = $exprStmt->getExpression();
if ($expression instanceof VariableDeclarationExpr) {
return $this->stmt_expr_vars($expr);
}
else {
return $this->stmt_expr_expr($expression);
}
}
function stmt_expr_vars(VariableDeclarationExpr $vars) {
$sb = new StringBuilder();
foreach ($vars->getVars() as $var) {
$sb->append($this->decl_var($var));
$sb->append(';');
}
return $sb->toString();
}
function stmt_expr_expr(Expression $expr) {
$sb = new StringBuilder();
if (null != $expr) {
$sb->append($this->expr($expr));
}
$sb->append(';');
return $sb->toString();
}
function stmt_block(Statement $stmt) {
if ($stmt instanceof BlockStmt) {
return $this->stmt_block($expr);
}
else {
return $this->stmt_block(new BlockStmt($Arrays->asList($stmt)));
}
}
function stmt_block(BlockStmt $block) {
$sb = new StringBuilder();
$list = $block->getStmts();
$sb->append('{\n');
if (null != $list) {
$sb->append($this->tab($this->stmt_list($list)));
}
$sb->append('}');
return $sb->toString();
}
function expr_list(List_ $list) {
$sb = new StringBuilder();
$first = true;
foreach ($list as $e) {
if ($first) {
$first = false;
}
else {
$sb->append(', ');
}
$sb->append($this->expr($e));
}
return $sb->toString();
}
function expr(Expression $expr) {
if ($expr instanceof LiteralExpr) {
return $this->expr_literal($expr);
}
if ($expr instanceof NameExpr) {
return $this->expr_var($expr);
}
if ($expr instanceof AssignExpr) {
return $this->expr_assign($expr);
}
if ($expr instanceof BinaryExpr) {
return $this->expr_binary($expr);
}
if ($expr instanceof ConditionalExpr) {
return $this->expr_conditional($expr);
}
if ($expr instanceof ObjectCreationExpr) {
return $this->expr_new($expr);
}
if ($expr instanceof InstanceOfExpr) {
return $this->expr_instanceOf($expr);
}
if ($expr instanceof ClassExpr) {
return $this->expr_class($expr);
}
if ($expr instanceof MethodCallExpr) {
return $this->expr_method($expr);
}
if ($expr instanceof FieldAccessExpr) {
return $this->expr_field_access($expr);
}
return '$expr';
}
function expr_var(NameExpr $name) {
return $this->var_($name->getName());
}
function expr_literal(LiteralExpr $lit) {
if ($lit instanceof NullLiteralExpr) {
return 'null';
}
if ($lit instanceof BooleanLiteralExpr) {
$bool_ = $expr;
return $bool_->getValue() ? 'true' : 'false';
}
$value = $expr->getValue();
if ($lit instanceof DoubleLiteralExpr || $lit instanceof IntegerLiteralExpr || $lit instanceof LongLiteralExpr) {
return $value;
}
return $String->format('\'%s\'', $value->replace('\'', '\\\''));
}
function expr_name(NameExpr $expr) {
if ($expr instanceof QualifiedNameExpr) {
$qualif = $expr->getQualifier();
$pkg = $qualif->toString()->replace('.', '\\');
return $String->format('%s\\%s', $pkg, $this->name($expr->getName()));
}
else {
return $this->keyword($expr->getName());
}
}
function expr_assign(AssignExpr $expr) {
$sb = new StringBuilder();
$sb->append($this->expr($expr->getTarget()));
$sb->append(' ');
$sb->append($ASSIGN->get($expr->getOperator()));
$sb->append(' ');
$sb->append($this->expr($expr->getValue()));
return $sb->toString();
}
/* decl_field */
/* decl_initializer */
function expr_binary(BinaryExpr $expr) {
$sb = new StringBuilder();
$left = $expr->getLeft();
$right = $expr->getRight();
$sb->append($this->expr($left));
$sb->append(' ');
$sb->append($BINARY->get($expr->getOperator()));
$sb->append(' ');
$sb->append($this->expr($right));
return $sb->toString();
}
/* decl_field */
/* decl_initializer */
function expr_conditional(ConditionalExpr $expr) {
$sb = new StringBuilder();
$sb->append($this->expr($expr->getCondition()));
$sb->append(' ? ');
$sb->append($this->expr($expr->getThenExpr()));
$sb->append(' : ');
$sb->append($this->expr($expr->getElseExpr()));
return $sb->toString();
}
function expr_new(ObjectCreationExpr $expr) {
$sb = new StringBuilder();
$args = $expr->getArgs();
$sb->append('new ');
$sb->append($this->type($expr->getType()));
$sb->append('(');
if (null != $args) {
$sb->append($this->expr_list($args));
}
$sb->append(')');
return $sb->toString();
}
function expr_instanceOf(InstanceOfExpr $expr) {
$sb = new StringBuilder();
$sb->append($this->expr($expr->getExpr()));
$sb->append(' instanceof ');
$sb->append($this->type($expr->getType()));
return $sb->toString();
}
function expr_class(ClassExpr $expr) {
throw $this->missing('expr_class', $expr);
}
function expr_method(MethodCallExpr $expr) {
$sb = new StringBuilder();
$args = $expr->getArgs();
$sb->append($this->scope($expr->getScope()));
$sb->append('->');
$sb->append($this->keyword($expr->getName()));
$sb->append('(');
if (null != $args) {
$sb->append($this->expr_list($args));
}
$sb->append(')');
return $sb->toString();
}
function expr_field_access(FieldAccessExpr $expr) {
$sb = new StringBuilder();
$sb->append($this->scope($expr->getScope()));
$sb->append('->');
$sb->append($this->keyword($expr->getField()));
return $sb->toString();
}
function scope(Expression $scope) {
if (null == $scope) {
return '$this';
}
else {
return $this->expr($scope);
}
}
function type(Type $type) {
if ($type instanceof PrimitiveType) {
return null;
}
if ($type instanceof ReferenceType) {
return $this->type($expr->getType());
}
if ($type instanceof ClassOrInterfaceType) {
$name = $expr->getName();
return $this->name($name);
}
throw $this->missing('type', $type);
}
function keyword($name) {
switch ($name->toLowerCase()){
case 'list':
case 'var':
case 'array':
return $String->format('%s_', $name);
default:
return $name;
}
}
function name($name) {
switch ($name){
case 'String':
case 'Object':
return null;
default:
return $this->keyword($name);
}
}
function var_(VariableDeclaratorId $var) {
return $this->var_($var->getName());
}
function var_($name) {
return $String->format('$%s', $name);
}
function tab($value) {
$tabs = $value->replaceAll('\n', '\n ');
return $String->format(' %s\n', $tabs->trim());
}
function missing($method) {
throw new RuntimeException($String->format('missing impl %s', $method));
}
function missing($method, $value) {
throw new RuntimeException($String->format('missing impl %s for %s', $method, $value->getClass()));
}
}
package j2p;
import japa.parser.JavaParser;
import japa.parser.ParseException;
import japa.parser.ast.CompilationUnit;
import japa.parser.ast.ImportDeclaration;
import japa.parser.ast.PackageDeclaration;
import japa.parser.ast.body.BodyDeclaration;
import japa.parser.ast.body.ClassOrInterfaceDeclaration;
import japa.parser.ast.body.FieldDeclaration;
import japa.parser.ast.body.InitializerDeclaration;
import japa.parser.ast.body.MethodDeclaration;
import japa.parser.ast.body.Parameter;
import japa.parser.ast.body.TypeDeclaration;
import japa.parser.ast.body.VariableDeclarator;
import japa.parser.ast.body.VariableDeclaratorId;
import japa.parser.ast.expr.AssignExpr;
import japa.parser.ast.expr.BinaryExpr;
import japa.parser.ast.expr.BooleanLiteralExpr;
import japa.parser.ast.expr.ClassExpr;
import japa.parser.ast.expr.ConditionalExpr;
import japa.parser.ast.expr.DoubleLiteralExpr;
import japa.parser.ast.expr.Expression;
import japa.parser.ast.expr.FieldAccessExpr;
import japa.parser.ast.expr.InstanceOfExpr;
import japa.parser.ast.expr.IntegerLiteralExpr;
import japa.parser.ast.expr.LiteralExpr;
import japa.parser.ast.expr.LongLiteralExpr;
import japa.parser.ast.expr.MethodCallExpr;
import japa.parser.ast.expr.NameExpr;
import japa.parser.ast.expr.NullLiteralExpr;
import japa.parser.ast.expr.ObjectCreationExpr;
import japa.parser.ast.expr.QualifiedNameExpr;
import japa.parser.ast.expr.StringLiteralExpr;
import japa.parser.ast.expr.VariableDeclarationExpr;
import japa.parser.ast.stmt.BlockStmt;
import japa.parser.ast.stmt.CatchClause;
import japa.parser.ast.stmt.ContinueStmt;
import japa.parser.ast.stmt.ExpressionStmt;
import japa.parser.ast.stmt.ForeachStmt;
import japa.parser.ast.stmt.IfStmt;
import japa.parser.ast.stmt.ReturnStmt;
import japa.parser.ast.stmt.Statement;
import japa.parser.ast.stmt.SwitchEntryStmt;
import japa.parser.ast.stmt.SwitchStmt;
import japa.parser.ast.stmt.ThrowStmt;
import japa.parser.ast.stmt.TryStmt;
import japa.parser.ast.type.ClassOrInterfaceType;
import japa.parser.ast.type.PrimitiveType;
import japa.parser.ast.type.ReferenceType;
import japa.parser.ast.type.Type;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author eridal
*/
public class Compiler {
public static void main(String paths[]) {
for (String path : paths) {
try {
file(path);
} catch (Exception e) {
System.err.println(e.getMessage());
}
}
}
static void file(String path) throws ParseException, IOException {
final File file = new File(path);
final CompilationUnit unit = JavaParser.parse(file);
System.out.println("<?php\n");
System.out.println(stmt_namespace(unit.getPackage()));
System.out.println("");
for (ImportDeclaration i : unit.getImports()) {
System.out.println(stmt_use(i));
}
for (TypeDeclaration type : unit.getTypes()) {
System.out.println("");
System.out.println(stmt_type(type));
}
}
static String stmt_namespace(PackageDeclaration pkg) {
return String.format("namespace %s;", expr_name(pkg.getName()));
}
static String stmt_use(ImportDeclaration import_) {
return String.format("use %s;", expr_name(import_.getName()));
}
static String stmt_type(TypeDeclaration type) {
if (type instanceof ClassOrInterfaceDeclaration) {
return decl_class((ClassOrInterfaceDeclaration) type);
} else {
throw missing("php_type");
}
}
static String decl_class(ClassOrInterfaceDeclaration type) {
final StringBuilder sb = new StringBuilder();
final List<ClassOrInterfaceType> extends_ = type.getExtends();
final List<ClassOrInterfaceType> implements_ = type.getImplements();
sb.append(type.isInterface() ? "interface" : "class");
sb.append(' ');
sb.append(type.getName());
if (null != extends_) {
sb.append(" extends ");
sb.append(decl_class_list(extends_));
}
if (null != implements_) {
sb.append(" implements ");
sb.append(decl_class_list(implements_));
}
sb.append(" {\n");
for (BodyDeclaration member : type.getMembers()) {
sb.append("\n");
sb.append(tab(decl_member(member)));
}
sb.append("\n}");
return sb.toString();
}
static String decl_class_list(List<ClassOrInterfaceType> list) {
final StringBuilder sb = new StringBuilder();
boolean first = true;
for (ClassOrInterfaceType type : list) {
if (first) {
first = false;
} else {
sb.append(", ");
}
sb.append(type.getName());
}
return sb.toString();
}
static String decl_member(BodyDeclaration member) {
if (member instanceof MethodDeclaration) {
return decl_method((MethodDeclaration) member);
}
if (member instanceof FieldDeclaration) {
return decl_field((FieldDeclaration) member);
}
if (member instanceof InitializerDeclaration) {
return decl_initializer((InitializerDeclaration) member);
}
throw missing("decl_member", member);
}
static String decl_method(MethodDeclaration method) {
final StringBuilder sb = new StringBuilder();
final BlockStmt body = method.getBody();
if (null == body) {
sb.append("abstract ");
}
sb.append("function ");
sb.append(keyword(method.getName()));
sb.append('(');
final List<Parameter> params = method.getParameters();
if (null != params) {
sb.append(decl_param_list(params));
}
sb.append(')');
if (null == body) {
sb.append(";");
} else {
sb.append(' ');
sb.append(stmt_block(body));
}
return sb.toString();
}
static String decl_field(FieldDeclaration field) {
// FIXME
return "/* decl_field */";
}
static String decl_initializer(InitializerDeclaration init) {
// FIXME
return "/* decl_initializer */";
}
static String decl_param_list(List<Parameter> params) {
final StringBuilder sb = new StringBuilder();
boolean first = true;
for (Parameter p : params) {
if (first) {
first = false;
} else {
sb.append(", ");
}
sb.append(decl_param(p));
}
return sb.toString();
}
static String decl_param(Parameter param) {
final StringBuilder sb = new StringBuilder();
final String type;
type = type(param.getType());
if (null != type) {
sb.append(type);
sb.append(' ');
}
if (param.isVarArgs()) {
sb.append("...");
}
sb.append(var(param.getId()));
return sb.toString();
}
static String decl_var(VariableDeclarator var) {
final StringBuilder sb = new StringBuilder();
final Expression init = var.getInit();
sb.append(var(var.getId()));
if (null != init) {
sb.append(" = ");
sb.append(expr(var.getInit()));
}
return sb.toString();
}
static String decl_vars(List<VariableDeclarator> vars) {
final StringBuilder sb = new StringBuilder();
boolean first = true;
for (VariableDeclarator v : vars) {
if (first) {
first = false;
} else {
sb.append(", ");
}
sb.append(decl_var(v));
}
return sb.toString();
}
static String stmt_list(List<Statement> list) {
final StringBuilder sb = new StringBuilder();
for (Statement s : list) {
sb.append(stmt(s));
sb.append('\n');
}
return sb.toString();
}
static String stmt(Statement stmt) {
if (stmt instanceof IfStmt) {
return stmt_if((IfStmt) stmt);
}
if (stmt instanceof ForeachStmt) {
return stmt_foreach((ForeachStmt) stmt);
}
if (stmt instanceof SwitchStmt) {
return stmt_switch((SwitchStmt) stmt);
}
if (stmt instanceof TryStmt) {
return stmt_try((TryStmt) stmt);
}
if (stmt instanceof ReturnStmt) {
return stmt_return((ReturnStmt) stmt);
}
if (stmt instanceof ContinueStmt) {
return stmt_continue((ContinueStmt) stmt);
}
if (stmt instanceof ThrowStmt) {
return stmt_throw((ThrowStmt) stmt);
}
if (stmt instanceof BlockStmt) {
return stmt_block((BlockStmt) stmt);
}
if (stmt instanceof ExpressionStmt) {
return stmt_expr((ExpressionStmt) stmt);
}
throw missing("stmt", stmt);
}
static String stmt_if(IfStmt if_) {
final StringBuilder sb = new StringBuilder();
sb.append("if (");
sb.append(expr(if_.getCondition()));
sb.append(") ");
sb.append(stmt_block(if_.getThenStmt()));
final Statement else_ = if_.getElseStmt();
if (null != else_) {
sb.append("\nelse");
if (else_ instanceof IfStmt) {
sb.append(stmt_if((IfStmt) else_));
}
else {
sb.append(' ');
sb.append(stmt_block(else_));
}
}
return sb.toString();
}
static String stmt_foreach(ForeachStmt forEach) {
final StringBuilder sb = new StringBuilder();
sb.append("foreach (");
sb.append(expr(forEach.getIterable()));
sb.append(" as ");
sb.append(decl_vars(forEach.getVariable().getVars()));
sb.append(") ");
sb.append(stmt_block(forEach.getBody()));
return sb.toString();
}
static String stmt_switch(SwitchStmt switch_) {
final StringBuilder sb = new StringBuilder();
sb.append("switch (");
sb.append(expr(switch_.getSelector()));
sb.append("){\n");
for (SwitchEntryStmt case_ : switch_.getEntries()) {
sb.append(stmt_switch_case(case_));
}
sb.append("}");
return sb.toString();
}
static String stmt_switch_case(SwitchEntryStmt case_) {
final StringBuilder sb = new StringBuilder();
final Expression label = case_.getLabel();
final List<Statement> list = case_.getStmts();
if (null == label) {
sb.append("default:");
} else {
sb.append("case ");
sb.append(expr(label));
sb.append(":");
}
sb.append('\n');
if (null != list) {
sb.append(tab(stmt_list(list)));
}
return sb.toString();
}
static String stmt_try(TryStmt try_) {
final StringBuilder sb = new StringBuilder();
sb.append("try ");
sb.append(stmt_block(try_.getTryBlock()));
final List<CatchClause> catchs = try_.getCatchs();
if (null != catchs) {
for (CatchClause catch_ : catchs) {
sb.append("\ncatch (");
sb.append(decl_param(catch_.getExcept()));
sb.append(") ");
sb.append(stmt_block(catch_.getCatchBlock()));
}
}
final BlockStmt finally_ = try_.getFinallyBlock();
if (null != finally_) {
sb.append("\nfinally ");
sb.append(stmt_block(finally_));
}
return sb.toString();
}
static String stmt_return(ReturnStmt return_) {
return String.format("return %s;", expr(return_.getExpr()));
}
static String stmt_continue(ContinueStmt continue_) {
final String id = continue_.getId();
if (null != id) {
return String.format("continue %s;", id);
} else {
return "continue;";
}
}
static String stmt_throw(ThrowStmt throw_) {
return String.format("throw %s;", expr(throw_.getExpr()));
}
static String stmt_expr(ExpressionStmt exprStmt) {
final Expression expression = exprStmt.getExpression();
if (expression instanceof VariableDeclarationExpr) {
return stmt_expr_vars((VariableDeclarationExpr) expression);
} else {
return stmt_expr_expr(expression);
}
}
static String stmt_expr_vars(VariableDeclarationExpr vars) {
final StringBuilder sb = new StringBuilder();
for (VariableDeclarator var : vars.getVars()) {
sb.append(decl_var(var));
sb.append(";");
}
return sb.toString();
}
static String stmt_expr_expr(Expression expr) {
final StringBuilder sb = new StringBuilder();
if (null != expr) {
sb.append(expr(expr));
}
sb.append(';');
return sb.toString();
}
static String stmt_block(Statement stmt) {
if (stmt instanceof BlockStmt) {
return stmt_block((BlockStmt) stmt);
} else {
return stmt_block(new BlockStmt(Arrays.asList(stmt)));
}
}
static String stmt_block(BlockStmt block) {
final StringBuilder sb = new StringBuilder();
List<Statement> list = block.getStmts();
sb.append("{\n");
if (null != list) {
sb.append(tab(stmt_list(list)));
}
sb.append("}");
return sb.toString();
}
static String expr_list(List<Expression> list) {
final StringBuilder sb = new StringBuilder();
boolean first = true;
for (Expression e : list) {
if (first) {
first = false;
} else {
sb.append(", ");
}
sb.append(expr(e));
}
return sb.toString();
}
static String expr(Expression expr) {
if (expr instanceof LiteralExpr) {
return expr_literal((LiteralExpr) expr);
}
if (expr instanceof NameExpr) {
return expr_var((NameExpr) expr);
}
if (expr instanceof AssignExpr) {
return expr_assign((AssignExpr) expr);
}
if (expr instanceof BinaryExpr) {
return expr_binary((BinaryExpr) expr);
}
if (expr instanceof ConditionalExpr) {
return expr_conditional((ConditionalExpr) expr);
}
if (expr instanceof ObjectCreationExpr) {
return expr_new((ObjectCreationExpr) expr);
}
if (expr instanceof InstanceOfExpr) {
return expr_instanceOf((InstanceOfExpr) expr);
}
if (expr instanceof ClassExpr) {
return expr_class((ClassExpr) expr);
}
if (expr instanceof MethodCallExpr) {
return expr_method((MethodCallExpr) expr);
}
if (expr instanceof FieldAccessExpr) {
return expr_field_access((FieldAccessExpr) expr);
}
return "$expr";
}
static String expr_var(NameExpr name) {
return var(name.getName());
}
static String expr_literal(LiteralExpr lit) {
if (lit instanceof NullLiteralExpr) {
return "null";
}
if (lit instanceof BooleanLiteralExpr) {
BooleanLiteralExpr bool_ = (BooleanLiteralExpr) lit;
return bool_.getValue() ? "true" : "false";
}
final String value = ((StringLiteralExpr) lit).getValue();
if (lit instanceof DoubleLiteralExpr ||
lit instanceof IntegerLiteralExpr ||
lit instanceof LongLiteralExpr) {
return value;
}
return String.format("'%s'", value.replace("'", "\\'"));
}
static String expr_name(NameExpr expr) {
if (expr instanceof QualifiedNameExpr) {
final NameExpr qualif = ((QualifiedNameExpr) expr).getQualifier();
final String pkg = qualif.toString().replace('.', '\\');
return String.format("%s\\%s", pkg, name(expr.getName()));
} else {
return keyword(expr.getName());
}
}
static String expr_assign(AssignExpr expr) {
final StringBuilder sb = new StringBuilder();
sb.append(expr(expr.getTarget()));
sb.append(' ');
sb.append(ASSIGN.get(expr.getOperator()));
sb.append(' ');
sb.append(expr(expr.getValue()));
return sb.toString();
}
static Map<AssignExpr.Operator, String> ASSIGN = new HashMap<AssignExpr.Operator, String>();
static {
ASSIGN.put(AssignExpr.Operator.assign , "=");
ASSIGN.put(AssignExpr.Operator.plus , "+=");
ASSIGN.put(AssignExpr.Operator.minus , "-=");
ASSIGN.put(AssignExpr.Operator.star , "*=");
ASSIGN.put(AssignExpr.Operator.slash , "/=");
ASSIGN.put(AssignExpr.Operator.and , "&=");
ASSIGN.put(AssignExpr.Operator.or , "|=");
ASSIGN.put(AssignExpr.Operator.xor , "^=");
ASSIGN.put(AssignExpr.Operator.rem , "%=");
ASSIGN.put(AssignExpr.Operator.lShift , "<<=");
ASSIGN.put(AssignExpr.Operator.rSignedShift , ">>=");
ASSIGN.put(AssignExpr.Operator.rUnsignedShift , ">>>=");
}
static String expr_binary(BinaryExpr expr) {
final StringBuilder sb = new StringBuilder();
final Expression left = expr.getLeft();
final Expression right = expr.getRight();
sb.append(expr(left));
sb.append(' ');
sb.append(BINARY.get(expr.getOperator()));
sb.append(' ');
sb.append(expr(right));
return sb.toString();
}
static Map<BinaryExpr.Operator, String> BINARY = new HashMap<BinaryExpr.Operator, String>();
static {
BINARY.put(BinaryExpr.Operator.or , "||");
BINARY.put(BinaryExpr.Operator.and , "&&");
BINARY.put(BinaryExpr.Operator.binOr , "|");
BINARY.put(BinaryExpr.Operator.binAnd , "&");
BINARY.put(BinaryExpr.Operator.xor , "^");
BINARY.put(BinaryExpr.Operator.equals , "==");
BINARY.put(BinaryExpr.Operator.notEquals , "!=");
BINARY.put(BinaryExpr.Operator.less , "<");
BINARY.put(BinaryExpr.Operator.greater , ">");
BINARY.put(BinaryExpr.Operator.lessEquals , "<=");
BINARY.put(BinaryExpr.Operator.greaterEquals , ">=");
BINARY.put(BinaryExpr.Operator.lShift , "<<");
BINARY.put(BinaryExpr.Operator.rSignedShift , ">>");
BINARY.put(BinaryExpr.Operator.rUnsignedShift , ">>>");
BINARY.put(BinaryExpr.Operator.plus , "+");
BINARY.put(BinaryExpr.Operator.minus , "-");
BINARY.put(BinaryExpr.Operator.times , "*");
BINARY.put(BinaryExpr.Operator.divide , "/");
BINARY.put(BinaryExpr.Operator.remainder , "/");
}
static String expr_conditional(ConditionalExpr expr) {
final StringBuilder sb = new StringBuilder();
sb.append(expr(expr.getCondition()));
sb.append(" ? ");
sb.append(expr(expr.getThenExpr()));
sb.append(" : ");
sb.append(expr(expr.getElseExpr()));
return sb.toString();
}
static String expr_new(ObjectCreationExpr expr) {
final StringBuilder sb = new StringBuilder();
final List<Expression >args = expr.getArgs();
sb.append("new ");
sb.append(type(expr.getType()));
sb.append('(');
if (null != args) {
sb.append(expr_list(args));
}
sb.append(')');
return sb.toString();
}
static String expr_instanceOf(InstanceOfExpr expr) {
final StringBuilder sb = new StringBuilder();
sb.append(expr(expr.getExpr()));
sb.append(" instanceof ");
sb.append(type(expr.getType()));
return sb.toString();
}
static String expr_class(ClassExpr expr) {
throw missing("expr_class", expr);
}
static String expr_method(MethodCallExpr expr) {
final StringBuilder sb = new StringBuilder();
final List<Expression> args = expr.getArgs();
sb.append(scope(expr.getScope()));
sb.append("->");
sb.append(keyword(expr.getName()));
sb.append('(');
if (null != args) {
sb.append(expr_list(args));
}
sb.append(')');
return sb.toString();
}
static String expr_field_access(FieldAccessExpr expr) {
final StringBuilder sb = new StringBuilder();
sb.append(scope(expr.getScope()));
sb.append("->");
sb.append(keyword(expr.getField()));
return sb.toString();
}
static String scope(Expression scope) {
if (null == scope) {
return "$this";
} else {
return expr(scope);
}
}
static String type(Type type) {
if (type instanceof PrimitiveType) {
return null;
}
if (type instanceof ReferenceType) {
return type(((ReferenceType) type).getType());
}
if (type instanceof ClassOrInterfaceType) {
String name = ((ClassOrInterfaceType) type).getName();
return name(name);
}
throw missing("type", type);
}
static String keyword(String name) {
switch(name.toLowerCase()) {
case "list":
case "var":
case "array":
return String.format("%s_", name);
default:
return name;
}
}
static String name(String name) {
switch(name) {
case "String":
case "Object":
return null;
default:
return keyword(name);
}
}
static String var(VariableDeclaratorId var) {
return var(var.getName());
}
static String var(String name) {
return String.format("$%s", name);
}
static String tab(String value) {
final String tabs = value.replaceAll("\n", "\n ");
return String.format(" %s\n", tabs.trim());
}
private static RuntimeException missing(String method) {
throw new RuntimeException(String.format("missing impl %s", method));
}
private static RuntimeException missing(String method, Object value) {
throw new RuntimeException(String.format("missing impl %s for %s", method, value.getClass()));
}
}
@saleemkce
Copy link

@eridal, great work, it looks great. Keep it up.

@pchr-srf
Copy link

pchr-srf commented Mar 9, 2022

I'm a little scared

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment