All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
us.bpsm.edn.parser.ParserImpl Maven / Gradle / Ivy
// (c) 2012 B Smith-Mannschott -- Distributed under the Eclipse Public License
package us.bpsm.edn.parser;
import static us.bpsm.edn.TaggedValue.newTaggedValue;
import static us.bpsm.edn.parser.Token.END_LIST;
import static us.bpsm.edn.parser.Token.END_MAP_OR_SET;
import static us.bpsm.edn.parser.Token.END_VECTOR;
import us.bpsm.edn.*;
class ParserImpl implements Parser {
private static final Object DISCARDED_VALUE = new Object() {
@Override
public String toString() { return "##discarded value##"; }
};
private Config cfg;
private Scanner scanner;
ParserImpl(Config cfg, Scanner scanner) {
this.scanner = scanner;
this.cfg = cfg;
}
public Object nextValue(Parseable pbr) {
Object value = nextValue(pbr, false);
if (value instanceof Token && value != END_OF_INPUT) {
throw new EdnSyntaxException("Unexpected "+ value);
}
return value;
}
private Object nextValue(Parseable pbr, boolean discard) {
Object curr = scanner.nextToken(pbr);
if (curr instanceof Token) {
switch ((Token) curr) {
case BEGIN_LIST:
return parseIntoCollection(cfg.getListFactory(),
END_LIST, pbr, discard);
case BEGIN_VECTOR:
return parseIntoCollection(cfg.getVectorFactory(),
END_VECTOR, pbr, discard);
case BEGIN_SET:
return parseIntoCollection(cfg.getSetFactory(),
END_MAP_OR_SET, pbr, discard);
case BEGIN_MAP:
return parseIntoCollection(cfg.getMapFactory(),
END_MAP_OR_SET, pbr, discard);
case DEFAULT_NAMESPACE_FOLLOWS: {
final String ns = parseNamespaceName(pbr, discard);
Object t = scanner.nextToken(pbr);
if (t != Token.BEGIN_MAP) {
throw new EdnSyntaxException(
"Expected #:" + ns + " to be followed by a map.");
}
return parseIntoCollection(new NamespacedMapFactory(ns),
END_MAP_OR_SET, pbr, discard);
}
case DISCARD:
nextValue(pbr, true);
return nextValue(pbr, discard);
case NIL:
return null;
case END_OF_INPUT:
case END_LIST:
case END_MAP_OR_SET:
case END_VECTOR:
return curr;
default:
throw new EdnSyntaxException("Unrecognized Token: " + curr);
}
} else if (curr instanceof Tag) {
return nextValue((Tag)curr, pbr, discard);
} else {
return curr;
}
}
private String parseNamespaceName(Parseable pbr, boolean discard) {
final Object nsObj = nextValue(pbr, discard);
if (!(nsObj instanceof Symbol)) {
throw new EdnSyntaxException(
"Expected symbol following #:, but found: " + nsObj);
}
final Symbol nsSym = (Symbol) nsObj;
if (nsSym.getPrefix().length() > 0) {
throw new EdnSyntaxException(
"Expected symbol following #: to be namespaceless, " +
"but found: " + nsSym);
}
return nsSym.getName();
}
private Object nextValue(Tag t, Parseable pbr, boolean discard) {
Object v = nextValue(pbr, discard);
if (discard) {
// It doesn't matter what we return here, as it will be discarded.
return DISCARDED_VALUE;
}
TagHandler x = cfg.getTagHandler(t);
return x != null ? x.transform(t, v) : newTaggedValue(t, v);
}
private Object parseIntoCollection(CollectionBuilder.Factory f, Token end,
Parseable pbr, boolean discard) {
CollectionBuilder b = !discard ? f.builder() : null;
for (Object o = nextValue(pbr, discard);
o != end;
o = nextValue(pbr, discard)) {
if (o instanceof Token) {
throw new EdnSyntaxException("Expected " + end +
", but found " + o);
}
if (!discard) {
b.add(o);
}
}
return !discard ? b.build() : null;
}
private class NamespacedMapFactory implements CollectionBuilder.Factory {
private final String defaultNs;
public NamespacedMapFactory(String defaultNs) {
this.defaultNs = defaultNs;
}
@Override
public CollectionBuilder builder() {
return new NamespacedMapBuilder();
}
private class NamespacedMapBuilder implements CollectionBuilder {
private final CollectionBuilder cfgBuilder =
cfg.getMapFactory().builder();
boolean key = true;
@Override
public void add(Object o) {
if (key) {
o = maybeApplyDefaultNamespace(o);
}
key = !key;
cfgBuilder.add(o);
}
@Override
public Object build() {
return cfgBuilder.build();
}
private Object maybeApplyDefaultNamespace(final Object o) {
if (!(o instanceof Symbol || o instanceof Keyword)) {
return o;
}
final Named named = (Named) o;
final String prefix = named.getPrefix();
final String ns;
if ("".equals(prefix)) {
ns = defaultNs;
} else if ("_".equals(prefix)) {
ns = "";
} else {
return o;
}
final String name = named.getName();
if (o instanceof Symbol) {
return Symbol.newSymbol(ns, name);
} else {
assert o instanceof Keyword;
return Keyword.newKeyword(ns, name);
}
}
}
}
}