Skip to content

Commit

Permalink
JSON and config refactoring
Browse files Browse the repository at this point in the history
  • Loading branch information
lavajuno committed Apr 3, 2024
1 parent 121c0e9 commit cdeb883
Show file tree
Hide file tree
Showing 16 changed files with 390 additions and 350 deletions.
102 changes: 34 additions & 68 deletions src/main/java/org/lavajuno/lucidjson/JsonArray.java
Original file line number Diff line number Diff line change
@@ -1,103 +1,71 @@
package org.lavajuno.lucidjson;

import org.lavajuno.lucidjson.util.Index;
import org.lavajuno.lucidjson.error.JsonParseException;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.text.ParseException;
import java.util.List;
import java.util.Scanner;
import java.util.Vector;
import java.util.ArrayList;

/**
* Represents a JSON array.
* Provides functionality for accessing and modifying its values.
*/
@SuppressWarnings("unused")
public class JsonArray extends JsonEntity {
private final Vector<JsonEntity> values;
private final ArrayList<JsonEntity> values;

/**
* Constructs an empty JsonArray.
*/
public JsonArray() { values = new Vector<>(); }
public JsonArray() { values = new ArrayList<>(); }

/**
* Constructs a JsonArray from the given vector of elements.
* @param values Values to initialize array with
*/
public JsonArray(Vector<JsonEntity> values) { this.values = values; }
public JsonArray(ArrayList<JsonEntity> values) { this.values = values; }

/**
* Constructs a JsonArray by parsing the input.
* @param text JSON to parse
* @param i Index of next character to parse
* @throws ParseException If an error is encountered while parsing the input
* @throws JsonParseException If an error is encountered while parsing the input
*/
protected JsonArray(String text, Index i) throws ParseException {
protected JsonArray(String text, Index i) throws JsonParseException {
values = parseValues(text, i);
}

/**
* Deserializes a JSON array from a String.
* @param text Input string
* @return Deserialized JSON array
* @throws ParseException if parsing fails;
* @throws JsonParseException if parsing fails;
*/
public static JsonArray from(String text) throws ParseException {
String line = text.replace("\n", "");
public static JsonArray from(String text) throws JsonParseException {
Index i = new Index(0);
return new JsonArray(line, i);
}

/**
* Deserializes a JSON array from a list of lines (Strings).
* @param lines Input lines
* @return Deserialized JSON array
* @throws ParseException If parsing fails
*/
public static JsonArray from(List<String> lines) throws ParseException {
StringBuilder sb = new StringBuilder();
for(String i : lines) { sb.append(i); }
return from(sb.toString());
}

/**
* Deserializes a JSON array from a file.
* @param file_path Path to the input file
* @return Deserialized JSON array
* @throws FileNotFoundException If the file could not be read
* @throws ParseException If parsing fails
*/
public static JsonArray fromFile(String file_path) throws FileNotFoundException, ParseException {
Scanner file = new Scanner(new FileInputStream(file_path));
StringBuilder lines = new StringBuilder();
while(file.hasNextLine()) { lines.append(file.nextLine()); }
file.close();
return from(lines.toString());
return new JsonArray(text, i);
}

/**
* @param text JSON to parse
* @param i Index of next character to parse
* @return Vector created from the input
* @throws ParseException If an error is encountered while parsing the input
* @throws JsonParseException If an error is encountered while parsing the input
*/
private static Vector<JsonEntity> parseValues(String text, Index i) throws ParseException {
Vector<JsonEntity> values = new Vector<>();
private static ArrayList<JsonEntity> parseValues(String text, Index i) throws JsonParseException {
ArrayList<JsonEntity> values = new ArrayList<>();
skipSpace(text, i);
if(text.charAt(i.pos) != '[') {
throwParseError(text, i.pos, "Parsing array, expected a '['.");
throw new JsonParseException(text, i.pos, "Parsing array, expected a '['.");
}
i.pos++;
if(i.pos >= text.length()) {
// Handle end of input after opening {
throwParseError(text, i.pos, "Parsing array, reached end of input.");
throw new JsonParseException(text, i.pos, "Parsing array, reached end of input.");
}
if(text.charAt(i.pos) == ']') {
// Handle empty arrays
i.pos++;
return new Vector<>();
return new ArrayList<>();
}
skipSpace(text, i);
// Parse this JsonArray's values
Expand All @@ -109,7 +77,7 @@ private static Vector<JsonEntity> parseValues(String text, Index i) throws Parse
break;
}
if(text.charAt(i.pos) != ',') {
throwParseError(text , i.pos, "Parsing array, expected a ','.");
throw new JsonParseException(text , i.pos, "Parsing array, expected a ','.");
}
i.pos++;
}
Expand All @@ -119,21 +87,21 @@ private static Vector<JsonEntity> parseValues(String text, Index i) throws Parse

/**
* @param index Index of the target JsonEntity
* @return JsonEntity at the given index (null if it does not exist)
* @return JsonEntity at the given index
* @throws IndexOutOfBoundsException If the index is larger than the size of the array
*/
public JsonEntity get(int index) {
try {
return values.get(index);
} catch(ArrayIndexOutOfBoundsException e) {
return null;
}
public JsonEntity get(int index) throws IndexOutOfBoundsException {
return values.get(index);
}

/**
* @param index Index of the target JsonEntity
* @param value New value for the target JsonEntity
* @throws IndexOutOfBoundsException If the index is larger than the size of the array
*/
public void set(int index, JsonEntity value) { values.set(index, value); }
public void set(int index, JsonEntity value) throws IndexOutOfBoundsException {
values.set(index, value);
}

/**
* @param value JsonEntity to be added to this JsonArray
Expand All @@ -142,8 +110,11 @@ public JsonEntity get(int index) {

/**
* @param index Index of the JsonEntity to remove
* @throws IndexOutOfBoundsException If the index is larger than the size of the array
*/
public void remove(int index) { values.remove(index); }
public void remove(int index) throws IndexOutOfBoundsException {
values.remove(index);
}

/**
* Clears this JsonArray
Expand All @@ -158,21 +129,16 @@ public JsonEntity get(int index) {
/**
* @return This JsonArray's elements
*/
public Vector<JsonEntity> getValues() { return values; }
public ArrayList<JsonEntity> values() { return values; }

/**
* Serializes this JsonArray to a String, with indentation and newlines.
* @param indent Indent of this JsonEntity (0)
* @return Returns this JsonEntity as a string.
*/
@Override
protected String toString(int indent) {
protected String toJsonString(int indent) {
StringBuilder sb = new StringBuilder();
String pad_elem = " ".repeat(indent + 4);
String pad_close = " ".repeat(indent);
sb.append("[\n");
for(int i = 0; i < values.size(); i++) {
sb.append(pad_elem).append(values.get(i).toString(indent + 4));
sb.append(pad_elem).append(values.get(i).toJsonString(indent + 4));
if(i < values.size() - 1) { sb.append(","); }
sb.append("\n");
}
Expand All @@ -181,11 +147,11 @@ protected String toString(int indent) {
}

@Override
public String toString() {
public String toJsonString() {
StringBuilder sb = new StringBuilder();
sb.append("[");
for(int i = 0; i < values.size() - 1; i++) {
sb.append(values.get(i)).append(",\n");
sb.append(values.get(i).toJsonString()).append(",\n");
}
if(!values.isEmpty()) {
sb.append(values.get(values.size() - 1));
Expand Down
63 changes: 27 additions & 36 deletions src/main/java/org/lavajuno/lucidjson/JsonEntity.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import org.lavajuno.lucidjson.util.Index;
import org.lavajuno.lucidjson.util.Pair;
import java.text.ParseException;
import org.lavajuno.lucidjson.error.JsonParseException;

/**
* Abstract representation of a single JSON entity.
Expand All @@ -11,31 +11,15 @@
*/
@SuppressWarnings("unused")
public abstract class JsonEntity {
/**
* Prints a parse error to stderr, then throws a ParseException
* @param text The input currently being parsed
* @param pos Index of the character that caused error
* @param explanation Why the parse error happened
*/
protected static void throwParseError(String text, int pos, String explanation)
throws ParseException {
System.err.println("JSON - Parse error at index " + pos + " of input:");
System.err.print(text.substring(pos, Math.min(pos + 12, text.length())));
System.err.println("...");
System.err.println("^");
System.err.println(explanation + "\n"); /* extra newline */
throw new ParseException(explanation, pos);
}

/**
* Constructs a single JsonEntity by parsing the input.
* @param text Text to parse
* @param i Index of next character to parse
* @return JsonEntity created from the input.
* @throws ParseException If the input does not match any type of entity
* @throws JsonParseException If the input does not match any type of entity
*/
protected static JsonEntity parseEntity(String text, Index i) throws ParseException {
while(text.charAt(i.pos) == ' ' || text.charAt(i.pos) == '\t') { i.pos++; }
protected static JsonEntity parseEntity(String text, Index i) throws JsonParseException {
skipSpace(text, i);
return switch(text.charAt(i.pos)) {
case '{' -> new JsonObject(text, i);
case '[' -> new JsonArray(text, i);
Expand All @@ -50,49 +34,56 @@ protected static JsonEntity parseEntity(String text, Index i) throws ParseExcept
* @param text Text to parse
* @param i Index of next character to parse
* @return Key-value pair created from the input.
* @throws ParseException If the input does not match a pair containing a String and JsonEntity
* @throws JsonParseException If the input does not match a pair containing a String and JsonEntity
*/
protected static Pair<String, JsonEntity> parsePair(String text, Index i) throws ParseException {
while(text.charAt(i.pos) == ' ' || text.charAt(i.pos) == '\t') { i.pos++; }
String key = (new JsonString(text, i)).getValue();
protected static Pair<String, JsonEntity> parsePair(String text, Index i) throws JsonParseException {
skipSpace(text, i);
String key = (new JsonString(text, i)).value();
skipSpace(text, i);
if(text.charAt(i.pos) != ':') {
throwParseError(text, i.pos, "Parsing pair, expected a ':'.");
throw new JsonParseException(text, i.pos, "Parsing pair, expected a ':'.");
}
i.pos++;
JsonEntity value = parseEntity(text, i);
return new Pair<>(key, value);
}

/**
* @param c Character to check
* @return True if the character is whitespace (space, tab, or newline)
*/
protected static boolean isWhitespace(char c) {
return c == ' ' || c == '\t' || c == '\n' || c == '\r';
}

/**
* Advances the index past any whitespace
* @param text Text to scan
* @param i Index of next character to parse
*/
protected static void skipSpace(String text, Index i) {
while(text.charAt(i.pos) == ' ' || text.charAt(i.pos) == '\t') { i.pos++; }
while(isWhitespace(text.charAt(i.pos))) { i.pos++; }
}

/**
* Serializes this JsonEntity to a String with newlines and indentation.
* Serializes this JsonEntity to a JSON string with newlines and indentation.
* @param indent Indent of this JsonEntity
* @return This JsonEntity as a String
*/
protected abstract String toString(int indent);
protected abstract String toJsonString(int indent);

/**
* Serializes this JsonEntity to a String with optional formatting.
* @param pretty Whether to use newlines and indents in the output
* Serializes this JsonEntity to a JSON string.
* @param pretty false to minify, true to use newlines and indents
* @return This JsonEntity as a String
*/
public String toString(boolean pretty) {
return pretty ? this.toString(0) : this.toString();
public String toJsonString(boolean pretty) {
return pretty ? this.toJsonString(0) : this.toJsonString();
}

/**
* Serializes this JsonEntity to a String without any formatting.
* @return This JsonEntity as a String
* Serializes this JsonEntity to a minified JSON string.
* @return This JsonEntity as a JSON string
*/
@Override
public abstract String toString();
public abstract String toJsonString();
}
13 changes: 6 additions & 7 deletions src/main/java/org/lavajuno/lucidjson/JsonLiteral.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
package org.lavajuno.lucidjson;

import org.lavajuno.lucidjson.util.Index;

import java.text.ParseException;
import org.lavajuno.lucidjson.error.JsonParseException;

/**
* Represents a JSON literal value (true/false/null).
Expand All @@ -28,7 +27,7 @@ public class JsonLiteral extends JsonEntity {
* @param i Index of next character to parse
* @param text JSON to parse
*/
protected JsonLiteral(String text, Index i) throws ParseException {
protected JsonLiteral(String text, Index i) throws JsonParseException {
if(text.startsWith("true", i.pos)) {
i.pos += 4;
value = true;
Expand All @@ -39,7 +38,7 @@ protected JsonLiteral(String text, Index i) throws ParseException {
i.pos += 4;
value = null;
} else {
throwParseError(text, i.pos, "Parsing literal, unknown value");
throw new JsonParseException(text, i.pos, "Parsing literal, unknown value");
}
}

Expand All @@ -53,14 +52,14 @@ protected JsonLiteral(String text, Index i) throws ParseException {
* Gets the value of this JsonLiteral.
* @return Value of this JsonLiteral (true/false/null)
*/
public Boolean getValue() { return value; }
public Boolean value() { return value; }

@Override
public String toString() {
public String toJsonString() {
if(value == null) { return "null"; }
return value ? "true" : "false";
}

@Override
protected String toString(int indent) { return this.toString(); }
protected String toJsonString(int indent) { return this.toJsonString(); }
}
Loading

0 comments on commit cdeb883

Please sign in to comment.