added Wcfg file parser and CLI
This commit is contained in:
@@ -2,12 +2,18 @@ plugins {
|
||||
id 'antlr'
|
||||
}
|
||||
|
||||
configurations {
|
||||
api {
|
||||
exclude group: 'org.antlr', module: 'antlr4'
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation catalog.jwo
|
||||
implementation rootProject
|
||||
implementation catalog.antlr.runtime
|
||||
|
||||
antlr catalog.antlr
|
||||
antlr catalog.antlr.runtime
|
||||
}
|
||||
|
||||
generateGrammarSource {
|
||||
|
@@ -1,15 +1,19 @@
|
||||
grammar WCFG;
|
||||
|
||||
wcfg
|
||||
: assignment*
|
||||
: assignment* export?
|
||||
;
|
||||
|
||||
export
|
||||
: 'export' value ';'
|
||||
;
|
||||
|
||||
assignment
|
||||
: IDENTIFIER ':=' (expression | value) ';'
|
||||
: IDENTIFIER ':=' value ';'
|
||||
;
|
||||
|
||||
expression
|
||||
: value ('<<' value)+
|
||||
: (obj | IDENTIFIER) ('<<' (obj | IDENTIFIER))+
|
||||
;
|
||||
|
||||
obj
|
||||
@@ -18,7 +22,7 @@ obj
|
||||
;
|
||||
|
||||
pair
|
||||
: STRING ':' (expression | value)
|
||||
: STRING ':' value
|
||||
;
|
||||
|
||||
array
|
||||
@@ -34,6 +38,7 @@ value
|
||||
| IDENTIFIER
|
||||
| obj
|
||||
| array
|
||||
| expression
|
||||
;
|
||||
|
||||
BOOLEAN
|
||||
|
@@ -1,6 +1,6 @@
|
||||
module net.woggioni.wson.wcfg {
|
||||
requires static lombok;
|
||||
requires static org.antlr.antlr4.runtime;
|
||||
requires org.antlr.antlr4.runtime;
|
||||
|
||||
requires net.woggioni.jwo;
|
||||
requires net.woggioni.wson;
|
||||
|
@@ -1,6 +1,7 @@
|
||||
package net.woggioni.wson.wcfg;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import net.woggioni.jwo.LazyValue;
|
||||
import net.woggioni.wson.traversal.ValueIdentity;
|
||||
import net.woggioni.wson.value.ObjectValue;
|
||||
import net.woggioni.wson.xface.Value;
|
||||
@@ -11,53 +12,55 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import static net.woggioni.jwo.JWO.dynamicCast;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class CompositeObjectValue implements ObjectValue {
|
||||
|
||||
private final List<ObjectValue> elements;
|
||||
private final List<? extends Value> elements;
|
||||
|
||||
private ObjectValue wrapped;
|
||||
private LazyValue<ObjectValue> wrapped;
|
||||
|
||||
public CompositeObjectValue(List<ObjectValue> elements, Value.Configuration cfg) {
|
||||
public CompositeObjectValue(List<? extends Value> elements, Value.Configuration cfg) {
|
||||
this.elements = elements;
|
||||
wrapped = ObjectValue.newInstance(cfg);
|
||||
List<ValueIdentity> identities = new ArrayList<>();
|
||||
for (ObjectValue element : elements) {
|
||||
CompositeObjectValue compositeObjectValue;
|
||||
if ((compositeObjectValue = dynamicCast(element, CompositeObjectValue.class)) != null) {
|
||||
boolean differenceFound = false;
|
||||
for (int i = 0; i < compositeObjectValue.elements.size(); i++) {
|
||||
ObjectValue objectValue = compositeObjectValue.elements.get(i);
|
||||
if (!differenceFound && (i >= identities.size() || !Objects.equals(
|
||||
identities.get(i),
|
||||
new ValueIdentity(compositeObjectValue.elements.get(i))))) {
|
||||
differenceFound = true;
|
||||
}
|
||||
if (differenceFound) {
|
||||
merge(wrapped, objectValue);
|
||||
identities.add(new ValueIdentity(objectValue));
|
||||
this.wrapped = LazyValue.of(() -> {
|
||||
ObjectValue result = ObjectValue.newInstance(cfg);
|
||||
List<ValueIdentity> identities = new ArrayList<>();
|
||||
for (Value element : elements) {
|
||||
if (element instanceof CompositeObjectValue compositeObjectValue) {
|
||||
boolean differenceFound = false;
|
||||
for (int i = 0; i < compositeObjectValue.elements.size(); i++) {
|
||||
ObjectValue objectValue = (ObjectValue) compositeObjectValue.elements.get(i);
|
||||
if (!differenceFound && (i >= identities.size() || !Objects.equals(
|
||||
identities.get(i),
|
||||
new ValueIdentity(compositeObjectValue.elements.get(i))))) {
|
||||
differenceFound = true;
|
||||
}
|
||||
if (differenceFound) {
|
||||
merge(result, objectValue);
|
||||
identities.add(new ValueIdentity(objectValue));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
merge(result, (ObjectValue) element);
|
||||
identities.add(new ValueIdentity(element));
|
||||
}
|
||||
} else {
|
||||
merge(wrapped, element);
|
||||
identities.add(new ValueIdentity(element));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}, LazyValue.ThreadSafetyMode.NONE);
|
||||
}
|
||||
|
||||
private static void merge(ObjectValue v1, ObjectValue v2) {
|
||||
for (Map.Entry<String, Value> entry : v2) {
|
||||
Value putResult = v1.getOrPut(entry.getKey(), entry.getValue());
|
||||
if (putResult != entry.getValue()) {
|
||||
if (putResult.type() == Value.Type.OBJECT && entry.getValue().type() == Value.Type.OBJECT) {
|
||||
String key = entry.getKey();
|
||||
Value value2put = entry.getValue();
|
||||
Value putResult = v1.getOrPut(key, value2put);
|
||||
if (putResult != value2put) {
|
||||
if (putResult.type() == Value.Type.OBJECT && value2put.type() == Value.Type.OBJECT) {
|
||||
ObjectValue ov = ObjectValue.newInstance();
|
||||
merge(ov, (ObjectValue) putResult);
|
||||
merge(ov, (ObjectValue) entry.getValue());
|
||||
v1.put(entry.getKey(), ov);
|
||||
merge(ov, (ObjectValue) value2put);
|
||||
v1.put(key, ov);
|
||||
} else {
|
||||
v1.put(entry.getKey(), entry.getValue());
|
||||
v1.put(key, value2put);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -65,27 +68,27 @@ public class CompositeObjectValue implements ObjectValue {
|
||||
|
||||
@Override
|
||||
public Iterator<Map.Entry<String, Value>> iterator() {
|
||||
return wrapped.iterator();
|
||||
return wrapped.get().iterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Value get(String key) {
|
||||
return wrapped.get(key);
|
||||
return wrapped.get().get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Value getOrDefault(String key, Value defaultValue) {
|
||||
return wrapped.getOrDefault(key, defaultValue);
|
||||
return wrapped.get().getOrDefault(key, defaultValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean has(String key) {
|
||||
return wrapped.has(key);
|
||||
return wrapped.get().has(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return wrapped.size();
|
||||
return wrapped.get().size();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
18
wcfg/src/main/java/net/woggioni/wson/wcfg/ErrorHandler.java
Normal file
18
wcfg/src/main/java/net/woggioni/wson/wcfg/ErrorHandler.java
Normal file
@@ -0,0 +1,18 @@
|
||||
package net.woggioni.wson.wcfg;
|
||||
|
||||
import org.antlr.v4.runtime.BaseErrorListener;
|
||||
import org.antlr.v4.runtime.RecognitionException;
|
||||
import org.antlr.v4.runtime.Recognizer;
|
||||
|
||||
class ErrorHandler extends BaseErrorListener {
|
||||
@Override
|
||||
public void syntaxError(Recognizer<?, ?> recognizer,
|
||||
Object offendingSymbol,
|
||||
int line, int charPositionInLine,
|
||||
String msg,
|
||||
RecognitionException e) {
|
||||
throw new SyntaxError(msg, line, charPositionInLine);
|
||||
}
|
||||
|
||||
|
||||
}
|
@@ -1,6 +1,9 @@
|
||||
package net.woggioni.wson.wcfg;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import net.woggioni.jwo.JWO;
|
||||
import net.woggioni.wson.value.ArrayValue;
|
||||
import net.woggioni.wson.value.BooleanValue;
|
||||
import net.woggioni.wson.value.FloatValue;
|
||||
@@ -10,27 +13,45 @@ import net.woggioni.wson.value.ObjectValue;
|
||||
import net.woggioni.wson.value.StringValue;
|
||||
import net.woggioni.wson.xface.Value;
|
||||
import org.antlr.v4.runtime.ParserRuleContext;
|
||||
import org.antlr.v4.runtime.Token;
|
||||
import org.antlr.v4.runtime.misc.Interval;
|
||||
import org.antlr.v4.runtime.tree.ErrorNode;
|
||||
import org.antlr.v4.runtime.tree.TerminalNode;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static net.woggioni.jwo.JWO.dynamicCast;
|
||||
import static net.woggioni.jwo.JWO.newThrowable;
|
||||
import static net.woggioni.jwo.JWO.tail;
|
||||
|
||||
class ListenerImpl implements WCFGListener {
|
||||
|
||||
private final Value.Configuration cfg;
|
||||
|
||||
@Getter
|
||||
private final Value result;
|
||||
private Value result;
|
||||
|
||||
private final List<ValueHolder> holders = new ArrayList<>();
|
||||
private final Map<String, ValueHolder> unresolvedReferences = new TreeMap<>();
|
||||
|
||||
private interface StackLevel {
|
||||
Value getValue();
|
||||
}
|
||||
|
||||
@RequiredArgsConstructor
|
||||
private static class ExportStackLevel implements StackLevel {
|
||||
|
||||
@Setter
|
||||
private Value value;
|
||||
|
||||
@Override
|
||||
public Value getValue() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
private static class ArrayStackLevel implements StackLevel {
|
||||
private final ArrayValue value = new ArrayValue();
|
||||
|
||||
@@ -57,7 +78,7 @@ class ListenerImpl implements WCFGListener {
|
||||
private static class ExpressionStackLevel implements StackLevel {
|
||||
private final Value.Configuration cfg;
|
||||
private ObjectValue value = null;
|
||||
public List<ObjectValue> elements = new ArrayList<>();
|
||||
public List<Value> elements = new ArrayList<>();
|
||||
|
||||
public ExpressionStackLevel(Value.Configuration cfg) {
|
||||
this.cfg = cfg;
|
||||
@@ -65,8 +86,19 @@ class ListenerImpl implements WCFGListener {
|
||||
|
||||
@Override
|
||||
public Value getValue() {
|
||||
if(value == null) {
|
||||
value = new CompositeObjectValue(elements, cfg);
|
||||
if (value == null) {
|
||||
List<ObjectValue> objects = elements.stream()
|
||||
.map(it -> {
|
||||
if (it instanceof ObjectValue ov)
|
||||
return ov;
|
||||
else if (it instanceof ValueHolder vh) {
|
||||
return (ObjectValue) vh.getDelegate();
|
||||
} else {
|
||||
throw newThrowable(RuntimeException.class, "");
|
||||
}
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
value = new CompositeObjectValue(objects, cfg);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
@@ -75,26 +107,37 @@ class ListenerImpl implements WCFGListener {
|
||||
private final List<StackLevel> stack = new ArrayList<>();
|
||||
|
||||
private void add2Last(Value value) {
|
||||
StackLevel last = stack.get(stack.size() - 1);
|
||||
StackLevel last = tail(stack);
|
||||
if (last instanceof ArrayStackLevel asl) {
|
||||
asl.value.add(value);
|
||||
if(value instanceof ValueHolder holder) {
|
||||
if (value instanceof ValueHolder holder) {
|
||||
Value arrayValue = asl.getValue();
|
||||
int index = arrayValue.size() - 1;
|
||||
holder.addDeleter(() -> arrayValue.set(index, holder.getDelegate()));
|
||||
}
|
||||
} else if (last instanceof ObjectStackLevel osl) {
|
||||
String key = osl.currentKey;
|
||||
osl.currentKey = null;
|
||||
osl.value.put(key, value);
|
||||
if(value instanceof ValueHolder holder) {
|
||||
Value objectValue = osl.getValue();
|
||||
holder.addDeleter(() -> objectValue.put(key, holder.getDelegate()));
|
||||
Value objectValue = osl.getValue();
|
||||
objectValue.put(key, value);
|
||||
if (value instanceof ValueHolder holder) {
|
||||
holder.addDeleter(() -> {
|
||||
objectValue.put(key, holder.getDelegate());
|
||||
});
|
||||
}
|
||||
} else if(last instanceof ExpressionStackLevel esl) {
|
||||
esl.elements.add((ObjectValue) value);
|
||||
} else if (last instanceof ExpressionStackLevel esl) {
|
||||
List<Value> values = esl.elements;
|
||||
int index = values.size();
|
||||
values.add(value);
|
||||
if (value instanceof ValueHolder holder) {
|
||||
holder.addDeleter(() -> {
|
||||
values.set(index, holder.getDelegate());
|
||||
});
|
||||
}
|
||||
} else if (last instanceof ExportStackLevel esl) {
|
||||
esl.setValue(value);
|
||||
}
|
||||
}
|
||||
|
||||
private static String unquote(String quoted) {
|
||||
return quoted.substring(1, quoted.length() - 1);
|
||||
}
|
||||
@@ -121,6 +164,17 @@ class ListenerImpl implements WCFGListener {
|
||||
@Override
|
||||
public void exitWcfg(WCFGParser.WcfgContext ctx) {
|
||||
stack.clear();
|
||||
for (ValueHolder holder : unresolvedReferences.values()) {
|
||||
if (holder.getDelegate() == null) {
|
||||
TerminalNode node = holder.getNode();
|
||||
throw new ParseError(
|
||||
"Undeclared identifier '" + node.getText() + "'",
|
||||
node.getSymbol().getLine(),
|
||||
node.getSymbol().getCharPositionInLine() + 1
|
||||
);
|
||||
}
|
||||
holder.replace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -128,15 +182,15 @@ class ListenerImpl implements WCFGListener {
|
||||
ObjectStackLevel osl = (ObjectStackLevel) stack.get(0);
|
||||
String key = ctx.IDENTIFIER().getText();
|
||||
osl.currentKey = key;
|
||||
ValueHolder holder = new ValueHolder();
|
||||
holders.add(holder);
|
||||
holder.addDeleter(() -> result.put(key, holder.getDelegate()));
|
||||
result.put(key, holder);
|
||||
ValueHolder holder = unresolvedReferences.computeIfAbsent(key, it -> new ValueHolder(ctx.IDENTIFIER()));
|
||||
// holder.addDeleter(() -> holder.setDelegate(result.get(key)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exitAssignment(WCFGParser.AssignmentContext ctx) {
|
||||
ObjectStackLevel osl = (ObjectStackLevel) stack.get(0);
|
||||
String key = osl.currentKey;
|
||||
unresolvedReferences.get(key).setDelegate(osl.getValue().get(key));
|
||||
osl.currentKey = null;
|
||||
}
|
||||
|
||||
@@ -144,6 +198,16 @@ class ListenerImpl implements WCFGListener {
|
||||
public void enterExpression(WCFGParser.ExpressionContext ctx) {
|
||||
ExpressionStackLevel esl = new ExpressionStackLevel(cfg);
|
||||
stack.add(esl);
|
||||
for(TerminalNode node : ctx.IDENTIFIER()) {
|
||||
String key = node.getSymbol().getText();
|
||||
ValueHolder holder = unresolvedReferences
|
||||
.computeIfAbsent(key, k -> new ValueHolder(node));
|
||||
int index = esl.elements.size();
|
||||
esl.elements.add(holder);
|
||||
holder.addDeleter(() -> {
|
||||
esl.elements.set(index, holder.getDelegate());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -200,16 +264,25 @@ class ListenerImpl implements WCFGListener {
|
||||
} else {
|
||||
add2Last(new FloatValue(Double.parseDouble(text)));
|
||||
}
|
||||
} else if(ctx.IDENTIFIER() != null) {
|
||||
} else if (ctx.IDENTIFIER() != null) {
|
||||
String name = ctx.IDENTIFIER().getText();
|
||||
Value referredValue = result.getOrDefault(name, null);
|
||||
if(referredValue == null) {
|
||||
throw new ParseError(
|
||||
"Undeclared identifier '" + name + "'",
|
||||
ctx.start.getLine(),
|
||||
ctx.start.getCharPositionInLine() + 1
|
||||
);
|
||||
}
|
||||
ValueHolder referredValue = unresolvedReferences.computeIfAbsent(name,
|
||||
it -> new ValueHolder(ctx.IDENTIFIER())
|
||||
);
|
||||
// referredValue.addError(() -> new ParseError(
|
||||
// "Undeclared identifier '" + name + "'",
|
||||
// ctx.start.getLine(),
|
||||
// ctx.start.getCharPositionInLine() + 1
|
||||
// )
|
||||
// );
|
||||
// Value referredValue = result.getOrDefault(name, null);
|
||||
// if(referredValue == null) {
|
||||
// throw new ParseError(
|
||||
// "Undeclared identifier '" + name + "'",
|
||||
// ctx.start.getLine(),
|
||||
// ctx.start.getCharPositionInLine() + 1
|
||||
// );
|
||||
// }
|
||||
add2Last(referredValue);
|
||||
}
|
||||
}
|
||||
@@ -238,9 +311,19 @@ class ListenerImpl implements WCFGListener {
|
||||
|
||||
}
|
||||
|
||||
public void replaceHolders() {
|
||||
for(ValueHolder holder : holders) {
|
||||
holder.replace();
|
||||
@Override
|
||||
public void enterExport(WCFGParser.ExportContext ctx) {
|
||||
ExportStackLevel esl = new ExportStackLevel();
|
||||
stack.add(esl);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exitExport(WCFGParser.ExportContext ctx) {
|
||||
result = pop().getValue();
|
||||
if (result instanceof ValueHolder holder) {
|
||||
holder.addDeleter(() -> {
|
||||
result = holder.getDelegate();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
15
wcfg/src/main/java/net/woggioni/wson/wcfg/SyntaxError.java
Normal file
15
wcfg/src/main/java/net/woggioni/wson/wcfg/SyntaxError.java
Normal file
@@ -0,0 +1,15 @@
|
||||
package net.woggioni.wson.wcfg;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public class SyntaxError extends RuntimeException {
|
||||
public SyntaxError(String message, int line, int column) {
|
||||
super(message + String.format(" at %d:%d", line, column));
|
||||
}
|
||||
@Override
|
||||
public String getMessage() {
|
||||
return super.getMessage();
|
||||
}
|
||||
}
|
@@ -1,23 +1,32 @@
|
||||
package net.woggioni.wson.wcfg;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import lombok.SneakyThrows;
|
||||
import net.woggioni.wson.xface.Value;
|
||||
import org.antlr.v4.runtime.Token;
|
||||
import org.antlr.v4.runtime.tree.TerminalNode;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
class ValueHolder implements Value {
|
||||
private List<Runnable> deleters = new ArrayList<>();
|
||||
|
||||
@Getter
|
||||
private final TerminalNode node;
|
||||
private List<Runnable> deleters = new ArrayList<>();
|
||||
public void addDeleter(Runnable runnable) {
|
||||
deleters.add(runnable);
|
||||
}
|
||||
|
||||
@Setter
|
||||
@Getter
|
||||
private Value delegate = Value.Null;
|
||||
private Value delegate = null;
|
||||
|
||||
@Override
|
||||
public Type type() {
|
||||
return delegate.type();
|
||||
|
@@ -18,12 +18,14 @@ public class WConfig {
|
||||
private final Value value;
|
||||
|
||||
@SneakyThrows
|
||||
public WConfig(Reader reader, Value.Configuration cfg) {
|
||||
private WConfig(Reader reader, Value.Configuration cfg) {
|
||||
this.cfg = cfg;
|
||||
CodePointCharStream inputStream = CharStreams.fromReader(reader);
|
||||
WCFGLexer lexer = new WCFGLexer(inputStream);
|
||||
CommonTokenStream commonTokenStream = new CommonTokenStream(lexer);
|
||||
WCFGParser parser = new WCFGParser(commonTokenStream);
|
||||
parser.removeErrorListeners();
|
||||
parser.addErrorListener(new ErrorHandler());
|
||||
ListenerImpl listener = new ListenerImpl(cfg);
|
||||
ParseTreeWalker walker = new ParseTreeWalker();
|
||||
walker.walk(listener, parser.wcfg());
|
||||
@@ -44,4 +46,8 @@ public class WConfig {
|
||||
public Value whole() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public static WConfig parse(Reader reader, Value.Configuration cfg) {
|
||||
return new WConfig(reader, cfg);
|
||||
}
|
||||
}
|
||||
|
@@ -2,6 +2,7 @@ package net.woggioni.wson.wcfg;
|
||||
|
||||
import lombok.SneakyThrows;
|
||||
import net.woggioni.wson.serialization.json.JSONDumper;
|
||||
import net.woggioni.wson.value.ObjectValue;
|
||||
import net.woggioni.wson.xface.Value;
|
||||
import org.antlr.v4.runtime.CharStreams;
|
||||
import org.antlr.v4.runtime.CodePointCharStream;
|
||||
@@ -23,24 +24,21 @@ public class ParseTest {
|
||||
@SneakyThrows
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = {
|
||||
// "build.wcfg",
|
||||
// "test.wcfg",
|
||||
// "recursive.wcfg",
|
||||
"build.wcfg",
|
||||
"test.wcfg",
|
||||
"recursive.wcfg",
|
||||
"recursive2.wcfg",
|
||||
"recursive3.wcfg",
|
||||
})
|
||||
public void test(String resource) {
|
||||
Value.Configuration cfg = Value.Configuration.builder()
|
||||
.objectValueImplementation(ObjectValue.Implementation.HashMap)
|
||||
.serializeReferences(true)
|
||||
.build();
|
||||
try(Reader reader = new InputStreamReader(getClass().getClassLoader().getResourceAsStream(resource))) {
|
||||
CodePointCharStream inputStream = CharStreams.fromReader(reader);
|
||||
WCFGLexer lexer = new WCFGLexer(inputStream);
|
||||
CommonTokenStream commonTokenStream = new CommonTokenStream(lexer);
|
||||
WCFGParser parser = new WCFGParser(commonTokenStream);
|
||||
Value.Configuration cfg = Value.Configuration.builder().serializeReferences(true).build();
|
||||
ListenerImpl listener = new ListenerImpl(cfg);
|
||||
ParseTreeWalker walker = new ParseTreeWalker();
|
||||
walker.walk(listener, parser.wcfg());
|
||||
listener.replaceHolders();
|
||||
Value result = listener.getResult();
|
||||
new JSONDumper(cfg).dump(result, System.out);
|
||||
WConfig wcfg = WConfig.parse(reader, cfg);
|
||||
new JSONDumper(cfg).dump(wcfg.whole(), System.out);
|
||||
System.out.println();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,8 +47,8 @@ public class ParseTest {
|
||||
public void test2() {
|
||||
Value.Configuration cfg = Value.Configuration.builder().serializeReferences(true).build();
|
||||
try (Reader reader = new InputStreamReader(getClass().getResourceAsStream("/build.wcfg"))) {
|
||||
WConfig wConfig = new WConfig(reader, cfg);
|
||||
Value result = wConfig.get("release", "dev");
|
||||
WConfig wcfg = WConfig.parse(reader, cfg);
|
||||
Value result = wcfg.get("release", "dev");
|
||||
try (OutputStream os = new BufferedOutputStream(new FileOutputStream("/tmp/build.json"))) {
|
||||
new JSONDumper(cfg).dump(result, os);
|
||||
}
|
||||
|
5
wcfg/src/test/resources/recursive3.wcfg
Normal file
5
wcfg/src/test/resources/recursive3.wcfg
Normal file
@@ -0,0 +1,5 @@
|
||||
value := [1, 2, value2, null, false];
|
||||
|
||||
value2 := [3, 4, value, null, true, value3];
|
||||
|
||||
value3 := {"key" : "Some string" };
|
@@ -20,4 +20,6 @@ foobar := {
|
||||
} << {
|
||||
"enabled" : true
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
export default << foobar;
|
Reference in New Issue
Block a user