package com.googlecode.totallylazy.json;
import com.googlecode.totallylazy.Characters;
import com.googlecode.totallylazy.Maps;
import com.googlecode.totallylazy.Pair;
import com.googlecode.totallylazy.predicates.Predicate;
import com.googlecode.totallylazy.Sequence;
import com.googlecode.totallylazy.parser.Parser;
import com.googlecode.totallylazy.parser.Parsers;
import java.math.BigDecimal;
import java.util.List;
import java.util.concurrent.Callable;
import static com.googlecode.totallylazy.Characters.among;
import static com.googlecode.totallylazy.Characters.hexDigit;
import static com.googlecode.totallylazy.predicates.Predicates.is;
import static com.googlecode.totallylazy.Sequences.cons;
import static com.googlecode.totallylazy.Sequences.repeat;
import static com.googlecode.totallylazy.parser.Parsers.characters;
import static com.googlecode.totallylazy.parser.Parsers.isChar;
import static com.googlecode.totallylazy.parser.Parsers.string;
import static com.googlecode.totallylazy.parser.Parsers.ws;
import static com.googlecode.totallylazy.parser.Parsers.wsChar;
@SuppressWarnings("unchecked")
public interface Grammar {
Parser<Void> NULL = string("null").ignore();
Parser<Boolean> BOOLEAN = string("true").or(string("false")).map(Boolean::valueOf);
Parser<String> ESCAPED_CHARACTER = isChar('\\').next(
string(Characters.among("\"\\/bfnrt")).or(string(cons(is('u'), repeat(hexDigit).take(4)))).
map(Strings.functions.unescape));
Predicate<Character> UNICODE_CHARACTER = Characters.notAmong("\"\\");
Parser<String> STRING = characters(UNICODE_CHARACTER).
or(ESCAPED_CHARACTER).many().map(Parsers.toString).between(isChar('"'), isChar('"'));
Parser<Number> NUMBER = Parsers.characters(Characters.digit.or(among(".eE-+"))).map(chars -> new BigDecimal(chars.toString()));
Parser<Object> VALUE = Parsers.lazy(new Callable<Parser<Object>>() {
@Override
public Parser<Object> call() throws Exception {return ws(Parsers.or(OBJECT, ARRAY, STRING, NUMBER, BOOLEAN, NULL));}
});
Parser<Pair<String, Object>> PAIR = Parsers.tuple(STRING, wsChar(':'), VALUE).map(triple -> Pair.pair(triple.first(), triple.third()));
Parser<?> SEPARATOR = wsChar(',');
Parser<List<Object>> ARRAY = VALUE.sepBy(SEPARATOR).between(wsChar('['), wsChar(']'));
Parser<java.util.Map<String, Object>> OBJECT = Parsers.between(wsChar('{'), PAIR.sepBy(SEPARATOR), wsChar('}')).map(Maps::map);
Parser<Sequence<Pair<String, Object>>> PAIRS = wsChar('{').next(PAIR.sequence());
Parser<Sequence<Object>> SEQUENCE = wsChar('[').next(VALUE.seqBy(SEPARATOR));
}