Skip to content

Commit

Permalink
Add more granular tests for ObjectNodeProcessor
Browse files Browse the repository at this point in the history
  • Loading branch information
Sheikah45 committed Jun 11, 2024
1 parent 6816fd9 commit ce37c48
Show file tree
Hide file tree
Showing 40 changed files with 2,646 additions and 1,405 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
import io.github.sheikah45.fx2j.parser.element.ScriptSource;
import io.github.sheikah45.fx2j.parser.element.StaticPropertyElement;
import io.github.sheikah45.fx2j.parser.element.ValueElement;
import io.github.sheikah45.fx2j.parser.property.Expression;
import io.github.sheikah45.fx2j.parser.property.BindExpression;
import io.github.sheikah45.fx2j.parser.property.Handler;
import io.github.sheikah45.fx2j.parser.property.Value;
import io.github.sheikah45.fx2j.parser.utils.StringUtils;
Expand Down Expand Up @@ -55,6 +55,9 @@

public class FxmlParser {

private static final Value.Empty EMPTY_VALUE = new Value.Empty();
private static final ElementContent<?, ?> EMPTY_CONTENT = new ElementContent<>(List.of(), List.of(), EMPTY_VALUE);

public static FxmlComponents readFxml(Path filePath) {
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newDefaultInstance();
try {
Expand All @@ -74,12 +77,17 @@ public static FxmlComponents readFxml(Path filePath) {
private static ElementContent<?, ?> createContent(Element element) {
List<FxmlAttribute> fxmlAttributes = createFxmlAttributes(element);
List<FxmlElement> fxmlElements = createFxmlElements(element);
return new ElementContent<>(fxmlAttributes, fxmlElements, retrieveInnerValue(element));
Value innerValue = retrieveInnerValue(element);
if (fxmlAttributes.isEmpty() && fxmlElements.isEmpty() && innerValue instanceof Value.Empty) {
return EMPTY_CONTENT;
}

return new ElementContent<>(fxmlAttributes, fxmlElements, innerValue);
}

private static Value retrieveInnerValue(Element element) {
String innerText = retrieveInnerText(element);
return innerText.isBlank() ? new Value.Empty() : createPropertyValue(innerText);
return innerText.isBlank() ? EMPTY_VALUE : createPropertyValue(innerText);
}

private static String retrieveInnerText(Element element) {
Expand Down Expand Up @@ -133,40 +141,18 @@ private static FxmlElement createFxmlElement(Element element) {
case String tag -> {
int separatorIndex = tag.lastIndexOf(".");
if (Character.isLowerCase(tag.charAt(separatorIndex + 1))) {
ElementContent<?, ?> content = createContent(element);
List<AssignableElement> assignableElements = content.elements().stream().map(fxmlElement -> {
if (!(fxmlElement instanceof AssignableElement assignable)) {
throw new ParseException(
"A property element cannot contain unassignable values");
}

return assignable;
}).toList();
List<AssignableAttribute> assignableAttributes = content.attributes()
.stream()
.map(fxmlAttribute -> {
if (!(fxmlAttribute instanceof AssignableAttribute assignable)) {
throw new ParseException(
"A property attribute cannot contain unassignable values");
}

return assignable;
})
.toList();
ElementContent<AssignableAttribute, AssignableElement> newContent = createAssignableContent(
element);

if (separatorIndex == -1) {
yield new InstancePropertyElement(tag,
new ElementContent<>(assignableAttributes, assignableElements,
content.value()));
yield new InstancePropertyElement(tag, newContent);
} else {
if (!content.attributes().isEmpty()) {
if (!newContent.attributes().isEmpty()) {
throw new ParseException("static property elements cannot have attributes");
}

yield new StaticPropertyElement(tag.substring(0, separatorIndex),
tag.substring(separatorIndex + 1),
new ElementContent<>(assignableAttributes, assignableElements,
content.value()));
tag.substring(separatorIndex + 1), newContent);
}
} else {
yield createInstanceElement(element);
Expand All @@ -175,6 +161,32 @@ yield new StaticPropertyElement(tag.substring(0, separatorIndex),
};
}

@SuppressWarnings("unchecked")
private static ElementContent<AssignableAttribute, AssignableElement> createAssignableContent(Element element) {
ElementContent<?, ?> content = createContent(element);
if (EMPTY_CONTENT.equals(content)) {
return (ElementContent<AssignableAttribute, AssignableElement>) content;
}

List<AssignableElement> assignableElements = content.elements().stream().map(fxmlElement -> {
if (!(fxmlElement instanceof AssignableElement assignable)) {
throw new ParseException("A property element cannot contain unassignable values");
}

return assignable;
}).toList();

List<AssignableAttribute> assignableAttributes = content.attributes().stream().map(fxmlAttribute -> {
if (!(fxmlAttribute instanceof AssignableAttribute assignable)) {
throw new ParseException("A property attribute cannot contain unassignable values");
}

return assignable;
}).toList();

return new ElementContent<>(assignableAttributes, assignableElements, content.value());
}

private static ClassInstanceElement createInstanceElement(Element element) {
String className = element.getTagName();
String factory = removeAndGetValueIfPresent(element, "fx:factory").orElse(null);
Expand Down Expand Up @@ -243,7 +255,8 @@ private static ScriptElement createScriptElement(Element element) {
scriptSource = new ScriptSource.Inline(retrieveInnerText(element), charset);
} else {
if (!content.attributes().isEmpty() ||
!content.elements().isEmpty() || !(content.value() instanceof Value.Empty)) {
!content.elements().isEmpty() ||
!(content.value() instanceof Value.Empty)) {
throw new ParseException(
"fx:script with reference source cannot have any elements, attributes other than charset and source, or an inner value");
}
Expand Down Expand Up @@ -306,7 +319,7 @@ private static Value createPropertyValue(String value) {
case String val when val.startsWith("@") -> new Value.Location(Path.of(val.substring(1)));
case String val when val.startsWith("%") -> new Value.Resource(val.substring(1));
case String val when val.startsWith("${") && val.endsWith("}") ->
Expression.parse(val.substring(2, val.length() - 1));
BindExpression.parse(val.substring(2, val.length() - 1));
case String val when val.startsWith("$") -> new Value.Reference(val.substring(1));
case String val when val.startsWith("\\") -> new Value.Literal(val.substring(1));
case String val -> new Value.Literal(val);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,122 +1,122 @@
package io.github.sheikah45.fx2j.parser.antlr;

import io.github.sheikah45.fx2j.parser.property.Expression;
import io.github.sheikah45.fx2j.parser.property.BindExpression;
import org.antlr.v4.runtime.tree.AbstractParseTreeVisitor;

public class BindExpressionVisitorImpl extends AbstractParseTreeVisitor<Expression>
implements BindExpressionVisitor<Expression> {
public class BindExpressionVisitorImpl extends AbstractParseTreeVisitor<BindExpression>
implements BindExpressionVisitor<BindExpression> {
@Override
public Expression visitFractionLiteral(BindExpressionParser.FractionLiteralContext ctx) {
return new Expression.Fraction(Double.parseDouble(ctx.getText()));
public BindExpression visitFractionLiteral(BindExpressionParser.FractionLiteralContext ctx) {
return new BindExpression.Fraction(Double.parseDouble(ctx.getText()));
}

@Override
public Expression visitCollectionAccess(BindExpressionParser.CollectionAccessContext ctx) {
return new Expression.CollectionAccess(visit(ctx.collection), visit(ctx.accessor));
public BindExpression visitCollectionAccess(BindExpressionParser.CollectionAccessContext ctx) {
return new BindExpression.CollectionAccess(visit(ctx.collection), visit(ctx.accessor));
}

@Override
public Expression visitNullLiteral(BindExpressionParser.NullLiteralContext ctx) {
return new Expression.Null();
public BindExpression visitNullLiteral(BindExpressionParser.NullLiteralContext ctx) {
return new BindExpression.Null();
}

@Override
public Expression visitInvert(BindExpressionParser.InvertContext ctx) {
return new Expression.Invert(visit(ctx.base));
public BindExpression visitInvert(BindExpressionParser.InvertContext ctx) {
return new BindExpression.Invert(visit(ctx.base));
}

@Override
public Expression visitComparative(BindExpressionParser.ComparativeContext ctx) {
Expression left = visit(ctx.left);
Expression right = visit(ctx.right);
public BindExpression visitComparative(BindExpressionParser.ComparativeContext ctx) {
BindExpression left = visit(ctx.left);
BindExpression right = visit(ctx.right);
return switch (ctx.operator.getText()) {
case "==" -> new Expression.Equal(left, right);
case "!=" -> new Expression.NotEqual(left, right);
case ">=" -> new Expression.GreaterThanEqual(left, right);
case ">" -> new Expression.GreaterThan(left, right);
case "<=" -> new Expression.LessThanEqual(left, right);
case "<" -> new Expression.LessThan(left, right);
case "==" -> new BindExpression.Equal(left, right);
case "!=" -> new BindExpression.NotEqual(left, right);
case ">=" -> new BindExpression.GreaterThanEqual(left, right);
case ">" -> new BindExpression.GreaterThan(left, right);
case "<=" -> new BindExpression.LessThanEqual(left, right);
case "<" -> new BindExpression.LessThan(left, right);
case String operator -> throw new IllegalArgumentException("Unknown operator: %s".formatted(operator));
};
}

@Override
public Expression visitMultiplicative(BindExpressionParser.MultiplicativeContext ctx) {
Expression left = visit(ctx.left);
Expression right = visit(ctx.right);
public BindExpression visitMultiplicative(BindExpressionParser.MultiplicativeContext ctx) {
BindExpression left = visit(ctx.left);
BindExpression right = visit(ctx.right);
return switch (ctx.operator.getText()) {
case "*" -> new Expression.Multiply(left, right);
case "/" -> new Expression.Divide(left, right);
case "%" -> new Expression.Modulo(left, right);
case "*" -> new BindExpression.Multiply(left, right);
case "/" -> new BindExpression.Divide(left, right);
case "%" -> new BindExpression.Modulo(left, right);
case String operator -> throw new IllegalArgumentException("Unknown operator: %s".formatted(operator));
};
}

@Override
public Expression visitLogical(BindExpressionParser.LogicalContext ctx) {
Expression left = visit(ctx.left);
Expression right = visit(ctx.right);
public BindExpression visitLogical(BindExpressionParser.LogicalContext ctx) {
BindExpression left = visit(ctx.left);
BindExpression right = visit(ctx.right);
return switch (ctx.operator.getText()) {
case "&&" -> new Expression.And(left, right);
case "||" -> new Expression.Or(left, right);
case "&&" -> new BindExpression.And(left, right);
case "||" -> new BindExpression.Or(left, right);
case String operator -> throw new IllegalArgumentException("Unknown operator: %s".formatted(operator));
};
}

@Override
public Expression visitEnclosed(BindExpressionParser.EnclosedContext ctx) {
public BindExpression visitEnclosed(BindExpressionParser.EnclosedContext ctx) {
return visit(ctx.inside);
}

@Override
public Expression visitAdditive(BindExpressionParser.AdditiveContext ctx) {
Expression left = visit(ctx.left);
Expression right = visit(ctx.right);
public BindExpression visitAdditive(BindExpressionParser.AdditiveContext ctx) {
BindExpression left = visit(ctx.left);
BindExpression right = visit(ctx.right);
return switch (ctx.operator.getText()) {
case "+" -> new Expression.Add(left, right);
case "-" -> new Expression.Subtract(left, right);
case "+" -> new BindExpression.Add(left, right);
case "-" -> new BindExpression.Subtract(left, right);
case String operator -> throw new IllegalArgumentException("Unknown operator: %s".formatted(operator));
};
}

@Override
public Expression visitStringLiteral(BindExpressionParser.StringLiteralContext ctx) {
public BindExpression visitStringLiteral(BindExpressionParser.StringLiteralContext ctx) {
String text = ctx.getText();
return new Expression.String(text.substring(1, text.length() - 1));
return new BindExpression.String(text.substring(1, text.length() - 1));
}

@Override
public Expression visitNegate(BindExpressionParser.NegateContext ctx) {
return new Expression.Negate(visit(ctx.base));
public BindExpression visitNegate(BindExpressionParser.NegateContext ctx) {
return new BindExpression.Negate(visit(ctx.base));
}

@Override
public Expression visitVariable(BindExpressionParser.VariableContext ctx) {
return new Expression.Variable(ctx.getText());
public BindExpression visitVariable(BindExpressionParser.VariableContext ctx) {
return new BindExpression.Variable(ctx.getText());
}

@Override
public Expression visitWholeLiteral(BindExpressionParser.WholeLiteralContext ctx) {
return new Expression.Whole(Long.parseLong(ctx.getText()));
public BindExpression visitWholeLiteral(BindExpressionParser.WholeLiteralContext ctx) {
return new BindExpression.Whole(Long.parseLong(ctx.getText()));
}

@Override
public Expression visitPropertyRead(BindExpressionParser.PropertyReadContext ctx) {
return new Expression.PropertyRead(visit(ctx.base), ctx.property.getText());
public BindExpression visitPropertyRead(BindExpressionParser.PropertyReadContext ctx) {
return new BindExpression.PropertyRead(visit(ctx.base), ctx.property.getText());
}

@Override
public Expression visitBooleanLiteral(BindExpressionParser.BooleanLiteralContext ctx) {
public BindExpression visitBooleanLiteral(BindExpressionParser.BooleanLiteralContext ctx) {
return switch (ctx.getText()) {
case "true" -> new Expression.Boolean(true);
case "false" -> new Expression.Boolean(false);
case "true" -> new BindExpression.Boolean(true);
case "false" -> new BindExpression.Boolean(false);
case String val -> throw new IllegalArgumentException("Unknown boolean: %s".formatted(val));
};
}

@Override
public Expression visitMethodCall(BindExpressionParser.MethodCallContext ctx) {
return new Expression.MethodCall(visit(ctx.base), ctx.method.getText(),
ctx.args.stream().map(this::visit).toList());
public BindExpression visitMethodCall(BindExpressionParser.MethodCallContext ctx) {
return new BindExpression.MethodCall(visit(ctx.base), ctx.method.getText(),
ctx.args.stream().map(this::visit).toList());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,6 @@ public record IncludeElement(Path source, Path resources, Charset charset, Eleme
public IncludeElement {
Objects.requireNonNull(source, "source cannot be null");
Objects.requireNonNull(content, "content cannot be null");
Objects.requireNonNull(charset, "charset cannot be null");
}
}
Loading

0 comments on commit ce37c48

Please sign in to comment.