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
7 changes: 2 additions & 5 deletions docs/docs/bindings/java/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,7 @@ public class Example {
String source = "<h1><%= user.name %></h1>";

ParseResult result = Herb.parse(source);

if (result.getValue() != null) {
System.out.println(result.getValue().treeInspect());
}
System.out.println(result.value.inspect());
}
}
```
Expand All @@ -85,7 +82,7 @@ public class LexExample {

LexResult result = Herb.lex(source);

for (Token token : result.getTokens()) {
for (Token token : result.tokens) {
System.out.println(token.inspect());
}
}
Expand Down
24 changes: 11 additions & 13 deletions docs/docs/bindings/java/reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ import org.herb.Token;
String source = "<p>Hello <%= user.name %></p>";
LexResult result = Herb.lex(source);

for (Token token : result.getTokens()) {
for (Token token : result.tokens) {
System.out.println(token.inspect());
}
// Output:
Expand All @@ -51,8 +51,8 @@ The `LexResult` class provides access to the lexed tokens:

```java
public class LexResult {
public List<Token> getTokens();
public String getSource();
public List<Token> tokens;
public String source;
public int getTokenCount();
public boolean isEmpty();
}
Expand All @@ -73,9 +73,7 @@ String source = "<p>Hello <%= user.name %></p>";

ParseResult result = Herb.parse(source);

if (result.getValue() != null) {
System.out.println(result.getValue().treeInspect());
}
System.out.println(result.inspect();
// Output:
// @ DocumentNode (location: (1:0)-(1:29))
// └── children: (1 item)
Expand Down Expand Up @@ -133,12 +131,12 @@ The `ParseResult` class provides access to the parsed AST and any errors:

```java
public class ParseResult {
public Node getValue();
public List<Node> getErrors();
public String getSource();
public Node value;
public List<Node> errors;
public String source;
public boolean hasErrors();
public int getErrorCount();
public boolean isSuccess();
public boolean isSuccessful();
}
```

Expand Down Expand Up @@ -278,7 +276,7 @@ public interface Node {
String getNodeType();
Location getLocation();
List<Node> getErrors();
String treeInspect();
String inspect();
<T> T accept(Visitor<T> visitor);
}
```
Expand All @@ -291,8 +289,8 @@ Parse errors are accessible through the `ParseResult`:
ParseResult result = Herb.parse(source);

if (result.hasErrors()) {
for (Node error : result.getErrors()) {
System.out.println(error.treeInspect());
for (Node error : result.recursiveErrors()) {
System.out.println(error.inspect());
}
}
```
Expand Down
25 changes: 2 additions & 23 deletions java/org/herb/CLI.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,33 +41,12 @@ public static void main(String[] args) {

case "lex":
LexResult lexResult = Herb.lex(source);

if (lexResult.getTokens() != null) {
for (Token token : lexResult.getTokens()) {
System.out.println(token.inspect());
}
}
System.out.print(lexResult.inspect());
break;

case "parse":
ParseResult parseResult = Herb.parse(source);

if (parseResult.getValue() != null) {
System.out.print(parseResult.getValue().treeInspect());
}

if (parseResult.getErrors() != null && !parseResult.getErrors().isEmpty()) {
System.out.println("Errors:");

for (Object error : parseResult.getErrors()) {
if (error instanceof org.herb.ast.Node) {
System.out.println(((org.herb.ast.Node) error).treeInspect());
} else {
System.out.println(" " + error);
}
}
}

System.out.print(parseResult.inspect());
break;

case "ruby":
Expand Down
26 changes: 12 additions & 14 deletions java/org/herb/LexResult.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,14 @@
import java.util.List;

public class LexResult {
private final List<Token> tokens;
private final String source;
public final List<Token> tokens;
public final String source;

public LexResult(List<Token> tokens, String source) {
this.tokens = Collections.unmodifiableList(tokens);
this.source = source;
}

public List<Token> getTokens() {
return tokens;
}

public String getSource() {
return source;
}

public int getTokenCount() {
return tokens.size();
}

public boolean isEmpty() {
return tokens.isEmpty();
}
Expand All @@ -32,4 +20,14 @@ public boolean isEmpty() {
public String toString() {
return String.format("LexResult{tokens=%d, source=%d chars}", tokens.size(), source.length());
}

public String inspect() {
StringBuilder builder = new StringBuilder();

for (Token token : tokens) {
builder.append(token.inspect()).append("\n");
}

return builder.toString();
}
}
46 changes: 33 additions & 13 deletions java/org/herb/ParseResult.java
Original file line number Diff line number Diff line change
@@ -1,46 +1,66 @@
package org.herb;

import org.herb.ast.Node;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class ParseResult {
private final Node value;
public final Node value;
private final List<Node> errors;
private final String source;
public final String source;

public ParseResult(Node value, List<Node> errors, String source) {
this.value = value;
this.errors = Collections.unmodifiableList(errors);
this.source = source;
}

public Node getValue() {
return value;
}
public List<Node> recursiveErrors() {
List<Node> result = new ArrayList<>();

public List<Node> getErrors() {
return errors;
}
result.addAll(errors);

public String getSource() {
return source;
if (value != null) {
result.addAll(value.recursiveErrors());
}

return result;
}

public boolean hasErrors() {
return !errors.isEmpty();
return !recursiveErrors().isEmpty();
}

public int getErrorCount() {
return errors.size();
return recursiveErrors().size();
}

public boolean isSuccess() {
public boolean isSuccessful() {
return errors.isEmpty();
}

@Override
public String toString() {
return String.format("ParseResult{errors=%d, source=%d chars}", errors.size(), source.length());
}

public String inspect() {
StringBuilder builder = new StringBuilder();

if (value != null) {
builder.append(value.inspect());
}

if (hasErrors()) {
builder.append("\n\nErrors:\n");

for (Node error : recursiveErrors()) {
builder.append(error.inspect()).append("\n");
}
}

return builder.toString();
}
}
6 changes: 3 additions & 3 deletions java/org/herb/ast/BaseNode.java
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ protected String inspectErrors(String prefix) {
String nextPrefix = isLast ? " " : "│ ";

if (error != null) {
String tree = error.treeInspect();
String tree = error.inspect();
if (tree.endsWith("\n")) {
tree = tree.substring(0, tree.length() - 1);
}
Expand Down Expand Up @@ -92,7 +92,7 @@ protected String inspectArray(java.util.List<Node> array, String prefix) {
String nextPrefix = isLast ? " " : "│ ";

if (item != null) {
String tree = item.treeInspect();
String tree = item.inspect();

if (tree.endsWith("\n")) {
tree = tree.substring(0, tree.length() - 1);
Expand Down Expand Up @@ -120,7 +120,7 @@ protected String inspectArray(java.util.List<Node> array, String prefix) {
*/
protected String inspectNode(Node node, String prefix) {
if (node == null) return "∅\n";
String tree = node.treeInspect();
String tree = node.inspect();

if (tree.endsWith("\n")) {
tree = tree.substring(0, tree.length() - 1);
Expand Down
21 changes: 15 additions & 6 deletions java/org/herb/ast/ErrorNode.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,24 @@

import org.herb.Location;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
* Simple wrapper for parser errors returned in ParseResult.
* This is a lightweight representation that can be cast to specific error types if needed.
*/
public class ErrorNode extends BaseNode {
private final String errorMessage;
public final String errorMessage;

public ErrorNode(String type, Location location, String errorMessage) {
super(type, location, null);
this.errorMessage = errorMessage;
}

public String getErrorMessage() {
return errorMessage;
}

@Override
public String treeInspect() {
public String inspect() {
StringBuilder output = new StringBuilder();

output.append("@ ").append(type).append(" ");
Expand All @@ -30,6 +30,15 @@ public String treeInspect() {
return output.toString();
}

@Override
public List<Node> recursiveErrors() {
if (errors != null && !errors.isEmpty()) {
return new ArrayList<>(errors);
}

return Collections.emptyList();
}

@Override
public String toString() {
return String.format("ErrorNode{type='%s', message='%s', location=%s}", type, errorMessage, location);
Expand Down
8 changes: 7 additions & 1 deletion java/org/herb/ast/Node.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.herb.ast;

import org.herb.Location;
import java.util.List;

/**
* Base interface for all AST nodes.
Expand Down Expand Up @@ -29,5 +30,10 @@ public interface Node {
/**
* Return a tree-like string representation of this node with all its fields.
*/
String treeInspect();
String inspect();

/**
* Get all errors from this node and recursively from all child nodes.
*/
List<Node> recursiveErrors();
}
6 changes: 3 additions & 3 deletions templates/java/org/herb/ast/Errors.java.erb
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ abstract class HerbError {
return String.format("HerbError{type='%s', message='%s', location=%s}", type, message, location);
}

public abstract String treeInspect();
public abstract String inspect();

protected String indent(String str, int level) {
if (level == 0) return str;
Expand Down Expand Up @@ -90,7 +90,7 @@ class <%= error.name %> extends HerbError {
<%- end -%>
<%- end -%>
@Override
public String treeInspect() {
public String inspect() {
StringBuilder output = new StringBuilder();

output.append("@ <%= error.name %> ");
Expand All @@ -109,7 +109,7 @@ class <%= error.name %> extends HerbError {
output.append("\n");
<%- when Herb::Template::TokenField -%>
output.append("<%= symbol %> <%= field.name %>: ");
output.append(<%= field.name %> != null ? <%= field.name %>.treeInspect() : "∅");
output.append(<%= field.name %> != null ? <%= field.name %>.inspect() : "∅");
output.append("\n");
<%- end -%>
<%- end -%>
Expand Down
Loading
Loading