Skip to content

Commit

Permalink
[java] Transpile enum with no explicit values to Java enum.
Browse files Browse the repository at this point in the history
Close #81
  • Loading branch information
pfusik committed Aug 17, 2023
1 parent b7ab7fc commit b25821b
Show file tree
Hide file tree
Showing 6 changed files with 236 additions and 23 deletions.
9 changes: 7 additions & 2 deletions GenBase.fu
Original file line number Diff line number Diff line change
Expand Up @@ -1024,7 +1024,7 @@ public abstract class GenBase : FuVisitor
WriteEqualExpr(left, right, parent, GetEqOp(not));
}

void WriteRel!(FuBinaryExpr expr, FuPriority parent, string op)
protected virtual void WriteRel!(FuBinaryExpr expr, FuPriority parent, string op)
{
WriteBinaryExpr(expr, parent > FuPriority.CondAnd, FuPriority.Rel, op, FuPriority.Rel);
}
Expand Down Expand Up @@ -1690,6 +1690,11 @@ public abstract class GenBase : FuVisitor
expr.Accept(this, FuPriority.Argument);
}

protected virtual void WriteSwitchCaseValue!(FuSwitch statement, FuExpr value)
{
WriteCoercedLiteral(statement.Value.Type, value);
}

protected virtual void WriteSwitchCaseBody!(List<FuStatement#> statements)
{
WriteStatements(statements);
Expand All @@ -1699,7 +1704,7 @@ public abstract class GenBase : FuVisitor
{
foreach (FuExpr value in kase.Values) {
Write("case ");
WriteCoercedLiteral(statement.Value.Type, value);
WriteSwitchCaseValue(statement, value);
WriteCharLine(':');
}
this.Indent++;
Expand Down
50 changes: 48 additions & 2 deletions GenJava.fu
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,15 @@ public class GenJava : GenTyped
}
}

static bool IsJavaEnum(FuEnum enu)
{
for (FuSymbol? symbol = enu.First; symbol != null; symbol = symbol.Next) {
if (symbol is FuConst konst && !(konst.Value is FuImplicitEnumValue))
return false;
}
return true;
}

void WriteCollectionType!(string name, FuType elementType)
{
Include("java.util." + name);
Expand Down Expand Up @@ -285,6 +294,7 @@ public class GenJava : GenTyped
case FuEnum enu:
Write(enu.Id == FuId.BoolType
? needClass ? "Boolean" : "boolean"
: IsJavaEnum(enu) ? enu.Name
: needClass ? "Integer" : "int");
break;
case FuClassType klass:
Expand Down Expand Up @@ -458,6 +468,21 @@ public class GenJava : GenTyped
base.WriteCoercedLiteral(type, expr);
}

protected override void WriteRel!(FuBinaryExpr expr, FuPriority parent, string op)
{
if (expr.Left.Type is FuEnum enu && IsJavaEnum(enu)) {
if (parent > FuPriority.CondAnd)
WriteChar('(');
WriteMethodCall(expr.Left, "compareTo", expr.Right);
Write(op);
WriteChar('0');
if (parent > FuPriority.CondAnd)
WriteChar(')');
}
else
base.WriteRel(expr, parent, op);
}

protected override void WriteAnd!(FuBinaryExpr expr, FuPriority parent)
{
if (IsUnsignedByteIndexing(expr.Left)
Expand Down Expand Up @@ -1062,6 +1087,14 @@ public class GenJava : GenTyped
base.WriteSwitchValue(expr);
}

protected override void WriteSwitchCaseValue!(FuSwitch statement, FuExpr value)
{
if (value is FuSymbolReference symbol && symbol.Symbol.Parent is FuEnum enu && IsJavaEnum(enu))
WriteUppercaseWithUnderscores(symbol.Name);
else
base.WriteSwitchCaseValue(statement, value);
}

bool WriteSwitchCaseVar!(FuExpr expr)
{
expr.Accept(this, FuPriority.Argument);
Expand Down Expand Up @@ -1134,10 +1167,23 @@ public class GenJava : GenTyped
WriteNewLine();
WriteDoc(enu.Documentation);
WritePublic(enu);
Write("interface ");
bool javaEnum = IsJavaEnum(enu);
Write(javaEnum ? "enum " : "interface ");
WriteLine(enu.Name);
OpenBlock();
enu.AcceptValues(this);
if (javaEnum) {
for (FuSymbol? symbol = enu.GetFirstValue();;) {
WriteDoc(symbol.Documentation);
WriteUppercaseWithUnderscores(symbol.Name);
symbol = symbol.Next;
if (symbol == null)
break;
WriteCharLine(',');
}
WriteNewLine();
}
else
enu.AcceptValues(this);
CloseBlock();
CloseFile();
}
Expand Down
62 changes: 58 additions & 4 deletions libfut.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7824,6 +7824,11 @@ void GenBase::writeSwitchValue(const FuExpr * expr)
expr->accept(this, FuPriority::argument);
}

void GenBase::writeSwitchCaseValue(const FuSwitch * statement, const FuExpr * value)
{
writeCoercedLiteral(statement->value->type.get(), value);
}

void GenBase::writeSwitchCaseBody(const std::vector<std::shared_ptr<FuStatement>> * statements)
{
writeStatements(statements);
Expand All @@ -7833,7 +7838,7 @@ void GenBase::writeSwitchCase(const FuSwitch * statement, const FuCase * kase)
{
for (const std::shared_ptr<FuExpr> &value : kase->values) {
write("case ");
writeCoercedLiteral(statement->value->type.get(), value.get());
writeSwitchCaseValue(statement, value.get());
writeCharLine(':');
}
this->indent++;
Expand Down Expand Up @@ -16608,6 +16613,16 @@ FuId GenJava::getTypeId(const FuType * type, bool promote) const
}
}

bool GenJava::isJavaEnum(const FuEnum * enu)
{
for (const FuSymbol * symbol = enu->first; symbol != nullptr; symbol = symbol->next) {
const FuConst * konst;
if ((konst = dynamic_cast<const FuConst *>(symbol)) && !dynamic_cast<const FuImplicitEnumValue *>(konst->value.get()))
return false;
}
return true;
}

void GenJava::writeCollectionType(std::string_view name, const FuType * elementType)
{
include("java.util." + std::string(name));
Expand Down Expand Up @@ -16654,7 +16669,7 @@ void GenJava::writeJavaType(const FuType * type, bool promote, bool needClass)
}
}
else if (const FuEnum *enu = dynamic_cast<const FuEnum *>(type))
write(enu->id == FuId::boolType ? needClass ? "Boolean" : "boolean" : needClass ? "Integer" : "int");
write(enu->id == FuId::boolType ? needClass ? "Boolean" : "boolean" : isJavaEnum(enu) ? enu->name : needClass ? "Integer" : "int");
else if (const FuClassType *klass = dynamic_cast<const FuClassType *>(type)) {
switch (klass->class_->id) {
case FuId::stringClass:
Expand Down Expand Up @@ -16830,6 +16845,22 @@ void GenJava::writeCoercedLiteral(const FuType * type, const FuExpr * expr)
GenTyped::writeCoercedLiteral(type, expr);
}

void GenJava::writeRel(const FuBinaryExpr * expr, FuPriority parent, std::string_view op)
{
const FuEnum * enu;
if ((enu = dynamic_cast<const FuEnum *>(expr->left->type.get())) && isJavaEnum(enu)) {
if (parent > FuPriority::condAnd)
writeChar('(');
writeMethodCall(expr->left.get(), "compareTo", expr->right.get());
write(op);
writeChar('0');
if (parent > FuPriority::condAnd)
writeChar(')');
}
else
GenBase::writeRel(expr, parent, op);
}

void GenJava::writeAnd(const FuBinaryExpr * expr, FuPriority parent)
{
const FuLiteralLong * rightLiteral;
Expand Down Expand Up @@ -17433,6 +17464,16 @@ void GenJava::writeSwitchValue(const FuExpr * expr)
GenBase::writeSwitchValue(expr);
}

void GenJava::writeSwitchCaseValue(const FuSwitch * statement, const FuExpr * value)
{
const FuSymbolReference * symbol;
const FuEnum * enu;
if ((symbol = dynamic_cast<const FuSymbolReference *>(value)) && (enu = dynamic_cast<const FuEnum *>(symbol->symbol->parent)) && isJavaEnum(enu))
writeUppercaseWithUnderscores(symbol->name);
else
GenBase::writeSwitchCaseValue(statement, value);
}

bool GenJava::writeSwitchCaseVar(const FuExpr * expr)
{
expr->accept(this, FuPriority::argument);
Expand Down Expand Up @@ -17505,10 +17546,23 @@ void GenJava::writeEnum(const FuEnum * enu)
writeNewLine();
writeDoc(enu->documentation.get());
writePublic(enu);
write("interface ");
bool javaEnum = isJavaEnum(enu);
write(javaEnum ? "enum " : "interface ");
writeLine(enu->name);
openBlock();
enu->acceptValues(this);
if (javaEnum) {
for (const FuSymbol * symbol = enu->getFirstValue();;) {
writeDoc(symbol->documentation.get());
writeUppercaseWithUnderscores(symbol->name);
symbol = symbol->next;
if (symbol == nullptr)
break;
writeCharLine(',');
}
writeNewLine();
}
else
enu->acceptValues(this);
closeBlock();
closeFile();
}
Expand Down
60 changes: 55 additions & 5 deletions libfut.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7364,7 +7364,7 @@ protected virtual void WriteEqual(FuExpr left, FuExpr right, FuPriority parent,
WriteEqualExpr(left, right, parent, GetEqOp(not));
}

void WriteRel(FuBinaryExpr expr, FuPriority parent, string op)
protected virtual void WriteRel(FuBinaryExpr expr, FuPriority parent, string op)
{
WriteBinaryExpr(expr, parent > FuPriority.CondAnd, FuPriority.Rel, op, FuPriority.Rel);
}
Expand Down Expand Up @@ -8026,6 +8026,11 @@ protected virtual void WriteSwitchValue(FuExpr expr)
expr.Accept(this, FuPriority.Argument);
}

protected virtual void WriteSwitchCaseValue(FuSwitch statement, FuExpr value)
{
WriteCoercedLiteral(statement.Value.Type, value);
}

protected virtual void WriteSwitchCaseBody(List<FuStatement> statements)
{
WriteStatements(statements);
Expand All @@ -8035,7 +8040,7 @@ protected virtual void WriteSwitchCase(FuSwitch statement, FuCase kase)
{
foreach (FuExpr value in kase.Values) {
Write("case ");
WriteCoercedLiteral(statement.Value.Type, value);
WriteSwitchCaseValue(statement, value);
WriteCharLine(':');
}
this.Indent++;
Expand Down Expand Up @@ -17302,6 +17307,15 @@ protected override FuId GetTypeId(FuType type, bool promote)
}
}

static bool IsJavaEnum(FuEnum enu)
{
for (FuSymbol symbol = enu.First; symbol != null; symbol = symbol.Next) {
if (symbol is FuConst konst && !(konst.Value is FuImplicitEnumValue))
return false;
}
return true;
}

void WriteCollectionType(string name, FuType elementType)
{
Include("java.util." + name);
Expand Down Expand Up @@ -17349,7 +17363,7 @@ void WriteJavaType(FuType type, bool promote, bool needClass)
}
break;
case FuEnum enu:
Write(enu.Id == FuId.BoolType ? needClass ? "Boolean" : "boolean" : needClass ? "Integer" : "int");
Write(enu.Id == FuId.BoolType ? needClass ? "Boolean" : "boolean" : IsJavaEnum(enu) ? enu.Name : needClass ? "Integer" : "int");
break;
case FuClassType klass:
switch (klass.Class.Id) {
Expand Down Expand Up @@ -17518,6 +17532,21 @@ protected override void WriteCoercedLiteral(FuType type, FuExpr expr)
base.WriteCoercedLiteral(type, expr);
}

protected override void WriteRel(FuBinaryExpr expr, FuPriority parent, string op)
{
if (expr.Left.Type is FuEnum enu && IsJavaEnum(enu)) {
if (parent > FuPriority.CondAnd)
WriteChar('(');
WriteMethodCall(expr.Left, "compareTo", expr.Right);
Write(op);
WriteChar('0');
if (parent > FuPriority.CondAnd)
WriteChar(')');
}
else
base.WriteRel(expr, parent, op);
}

protected override void WriteAnd(FuBinaryExpr expr, FuPriority parent)
{
if (IsUnsignedByteIndexing(expr.Left) && expr.Right is FuLiteralLong rightLiteral) {
Expand Down Expand Up @@ -18107,6 +18136,14 @@ protected override void WriteSwitchValue(FuExpr expr)
base.WriteSwitchValue(expr);
}

protected override void WriteSwitchCaseValue(FuSwitch statement, FuExpr value)
{
if (value is FuSymbolReference symbol && symbol.Symbol.Parent is FuEnum enu && IsJavaEnum(enu))
WriteUppercaseWithUnderscores(symbol.Name);
else
base.WriteSwitchCaseValue(statement, value);
}

bool WriteSwitchCaseVar(FuExpr expr)
{
expr.Accept(this, FuPriority.Argument);
Expand Down Expand Up @@ -18178,10 +18215,23 @@ protected override void WriteEnum(FuEnum enu)
WriteNewLine();
WriteDoc(enu.Documentation);
WritePublic(enu);
Write("interface ");
bool javaEnum = IsJavaEnum(enu);
Write(javaEnum ? "enum " : "interface ");
WriteLine(enu.Name);
OpenBlock();
enu.AcceptValues(this);
if (javaEnum) {
for (FuSymbol symbol = enu.GetFirstValue();;) {
WriteDoc(symbol.Documentation);
WriteUppercaseWithUnderscores(symbol.Name);
symbol = symbol.Next;
if (symbol == null)
break;
WriteCharLine(',');
}
WriteNewLine();
}
else
enu.AcceptValues(this);
CloseBlock();
CloseFile();
}
Expand Down
6 changes: 5 additions & 1 deletion libfut.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1769,6 +1769,7 @@ class GenBase : public FuVisitor
virtual void writeEqualOperand(const FuExpr * expr, const FuExpr * other);
void writeEqualExpr(const FuExpr * left, const FuExpr * right, FuPriority parent, std::string_view op);
virtual void writeEqual(const FuExpr * left, const FuExpr * right, FuPriority parent, bool not_);
virtual void writeRel(const FuBinaryExpr * expr, FuPriority parent, std::string_view op);
virtual void writeAnd(const FuBinaryExpr * expr, FuPriority parent);
virtual void writeAssignRight(const FuBinaryExpr * expr);
virtual void writeAssign(const FuBinaryExpr * expr, FuPriority parent);
Expand Down Expand Up @@ -1807,6 +1808,7 @@ class GenBase : public FuVisitor
void defineVar(const FuExpr * value);
virtual void writeSwitchCaseTypeVar(const FuExpr * value);
virtual void writeSwitchValue(const FuExpr * expr);
virtual void writeSwitchCaseValue(const FuSwitch * statement, const FuExpr * value);
virtual void writeSwitchCaseBody(const std::vector<std::shared_ptr<FuStatement>> * statements);
virtual void writeSwitchCase(const FuSwitch * statement, const FuCase * kase);
void startSwitch(const FuSwitch * statement);
Expand Down Expand Up @@ -1880,7 +1882,6 @@ class GenBase : public FuVisitor
static const FuAggregateInitializer * getAggregateInitializer(const FuNamedValue * def);
void writeAggregateInitField(const FuExpr * obj, const FuExpr * item);
static bool isBitOp(FuPriority parent);
void writeRel(const FuBinaryExpr * expr, FuPriority parent, std::string_view op);
void startIfWhile(const FuExpr * expr);
void writeIf(const FuIf * statement);
};
Expand Down Expand Up @@ -2407,6 +2408,7 @@ class GenJava : public GenTyped
void writeResource(std::string_view name, int length) override;
void writeEqual(const FuExpr * left, const FuExpr * right, FuPriority parent, bool not_) override;
void writeCoercedLiteral(const FuType * type, const FuExpr * expr) override;
void writeRel(const FuBinaryExpr * expr, FuPriority parent, std::string_view op) override;
void writeAnd(const FuBinaryExpr * expr, FuPriority parent) override;
void writeStringLength(const FuExpr * expr) override;
void writeCharAt(const FuBinaryExpr * expr) override;
Expand All @@ -2422,6 +2424,7 @@ class GenJava : public GenTyped
void defineIsVar(const FuBinaryExpr * binary) override;
void writeAssert(const FuAssert * statement) override;
void writeSwitchValue(const FuExpr * expr) override;
void writeSwitchCaseValue(const FuSwitch * statement, const FuExpr * value) override;
void writeSwitchCase(const FuSwitch * statement, const FuCase * kase) override;
void writeEnum(const FuEnum * enu) override;
void writeConst(const FuConst * konst) override;
Expand All @@ -2444,6 +2447,7 @@ class GenJava : public GenTyped
void writeToString(const FuExpr * expr, FuPriority parent);
void writeCamelCaseNotKeyword(std::string_view name);
void writeVisibility(FuVisibility visibility);
static bool isJavaEnum(const FuEnum * enu);
void writeCollectionType(std::string_view name, const FuType * elementType);
void writeDictType(std::string_view name, const FuClassType * dict);
void writeJavaType(const FuType * type, bool promote, bool needClass);
Expand Down
Loading

0 comments on commit b25821b

Please sign in to comment.