Skip to content

Instantly share code, notes, and snippets.

@mosheduminer
Last active January 6, 2023 11:42
Show Gist options
  • Save mosheduminer/996a6016642cf0c5577e92428dc75520 to your computer and use it in GitHub Desktop.
Save mosheduminer/996a6016642cf0c5577e92428dc75520 to your computer and use it in GitHub Desktop.
JSON parser for titzer/virgil
type JsonValue {
case Null {
def toString() -> string {
return "null";
}
}
case String(v: string) {
def toString() -> string {
return StringBuilder.new()
.putc('\"')
.puts(v)
.putc('\"')
.extract();
}
}
case Number(v: string) {
def toString() -> string {
return v;
}
def i32() -> Result<i32, string> {
def parsed = Ints.parseDecimal(v, 0);
if (parsed.0 > 0) {
return Result.Ok(parsed.1);
}
return Result.Err("could not parse to int");
}
def i64() -> Result<i64, string> {
def parsed = Longs.parseDecimal(v, 0);
return Result.Ok(parsed);
}
/// TODO: How to parse these? Do we need new methods in the stdlib?
// def f32() -> Result<f32, string> {
// }
// def f64() -> Result<f64, string> {
// }
}
case Bool(v: bool) {
def toString() -> string {
if (v) {
return "true";
}
return "false";
}
}
case Array(array: Array<JsonValue>) {
def toString() -> string {
def buf = StringBuilder.new().putc('[');
for (i < array.length) {
buf.puts(array[i].toString());
if (i != array.length - 1) {
buf.putc(',');
}
}
buf.putc(']');
return buf.extract();
}
}
case Object(object: HashMap<string, JsonValue>) {
def toString() -> string {
def buf = StringBuilder.new().putc('{');
def keys = Lists.toArray(Maps.keyList(object));
for (i < keys.length) {
def key = keys[i];
def value = object[key];
buf.putc('\"').puts(key).putc('\"');
buf.putc(':');
buf.puts(value.toString());
if (i != keys.length - 1) {
buf.putc(',');
}
}
buf.putc('}');
return buf.extract();
}
}
def toString() -> string {
return this.toString();
}
}
type Result<T, U> {
case Ok(value: T);
case Err(error: U);
}
component Json {
def deInt32(json: JsonValue) -> Result<i32, string> {
match (json) {
x: JsonValue.Number => return x.i32();
_ => return Result.Err("Expected to find Number");
}
}
def deInt64(json: JsonValue) -> Result<i64, string> {
match (json) {
x: JsonValue.Number => return x.i64();
_ => return Result.Err("Expected to find Number");
}
}
/// TODO: uncomment once the implementations of the float methods
/// on the Json ADT are completed
// def deFloat32(json: JsonValue) -> Result<f32, string> {
// match (json) {
// x: JsonValue.Number => return x.f32();
// _ => return Result.Err("Expected to find Number");
// }
// }
// def deFloat64(json: JsonValue) -> Result<f64, string> {
// match (json) {
// x: JsonValue.Number => return x.f64();
// _ => return Result.Err("Expected to find Number");
// }
// }
def deBool(json: JsonValue) -> Result<bool, string> {
match (json) {
Bool(v) => {
return Result.Ok(v);
}
_ => return Result.Err("Expected to find Bool");
}
}
def deString(json: JsonValue) -> Result<string, string> {
match (json) {
String(v) => {
return Result.Ok(v);
}
_ => return Result.Err("Expected to find String");
}
}
def deObjectImpl<T>(
propertyAndTransformer: (string, JsonValue -> Result<T, string>),
json: JsonValue
) -> Result<T, string> {
def prop = propertyAndTransformer.0;
def transformer = propertyAndTransformer.1;
match (json) {
Object(object) => {
if (object.has(prop)) {
match (transformer(object[prop])) {
Ok(result) => {
return Result.Ok(result);
}
Err(err) => return Result.Err(err);
}
}
return Result.Err("no such key in object");
}
_ => return Result.Err("Expected to find Object");
}
}
def deObject1Impl<T, A, B>(
fn: (A) -> T,
a: (string, JsonValue -> Result<A, string>),
json: JsonValue
) -> Result<T, string> {
match (json) {
Object(object) => {
match (deObjectImpl(a, json)) {
Ok(resultA) => return Result.Ok(fn(resultA));
Err(err) => return Result.Err(err);
}
}
_ => return Result.Err("Expected to find Object");
}
}
def deObject2Impl<T, A, B>(
fn: (A, B) -> T,
a: (string, JsonValue -> Result<A, string>),
b: (string, JsonValue -> Result<B, string>),
json: JsonValue
) -> Result<T, string> {
match (json) {
Object(object) => {
match (deObjectImpl(a, json)) {
Ok(resultA) => {
match (deObjectImpl(b, json)) {
Ok(resultB) => return Result.Ok(fn(resultA, resultB));
Err(err) => return Result.Err(err);
}
}
Err(err) => return Result.Err(err);
}
}
_ => return Result.Err("Expected to find Object");
}
}
def deObject3Impl<T, A, B, C>(
fn: (A, B, C) -> T,
a: (string, JsonValue -> Result<A, string>),
b: (string, JsonValue -> Result<B, string>),
c: (string, JsonValue -> Result<C, string>),
json: JsonValue
) -> Result<T, string> {
match (json) {
Object(object) => {
match (deObjectImpl(a, json)) {
Ok(resultA) => {
match (deObjectImpl(b, json)) {
Ok(resultB) => {
match (deObjectImpl(c, json)) {
Ok(resultC) => return Result.Ok(fn(resultA, resultB, resultC));
Err(err) => return Result.Err(err);
}
}
Err(err) => return Result.Err(err);
}
}
Err(err) => return Result.Err(err);
}
}
_ => return Result.Err("Expected to find Object");
}
}
def identify<T>(value: T) -> T {
return value;
}
def deArrayImpl<T>(
transformer: JsonValue -> Result<T, string>,
json: JsonValue
) -> Result<Array<T>, string> {
match (json) {
Array(array) => {
def results = Array<T>.new(array.length);
for (i < array.length) {
match (transformer(array[i])) {
Ok(result) => results[i] = result;
Err(err) => return Result.Err(err);
}
}
return Result.Ok(results);
}
_ => return Result.Err("Expected to find Array");
}
}
def deArray<T>(
transformer: JsonValue -> Result<T, string>
) -> JsonValue -> Result<Array<T>, string> {
return deArrayImpl(transformer, _);
}
def deObject1<T, A>(
fn: (A) -> T,
a: (string, JsonValue -> Result<A, string>)
) -> JsonValue -> Result<T, string> {
return deObject1Impl(fn, a, _);
}
def deObject2<T, A, B>(
fn: (A, B) -> T,
a: (string, JsonValue -> Result<A, string>),
b: (string, JsonValue -> Result<B, string>)
) -> JsonValue -> Result<T, string> {
return deObject2Impl(fn, a, b, _);
}
def deObject3<T, A, B, C>(
fn: (A, B, C) -> T,
a: (string, JsonValue -> Result<A, string>),
b: (string, JsonValue -> Result<B, string>),
c: (string, JsonValue -> Result<C, string>)
) -> JsonValue -> Result<T, string> {
return deObject3Impl(fn, a, b, c, _);
}
private def hexParser = PC.choice([
PC.charInRange(48, 57),
PC.charInRange(65, 70),
PC.charInRange(97, 102)
]);
private def characterParser(state: ParserState) -> ParserState {
match (state) {
Result(target, index, result_) => {
if (target.length - index <= 0) {
return PCUtils.parserError(
state,
Strings.format1("got unexpected end of input at index %d", index)
);
}
def character = target[index];
if (character == '\"') {
return PCUtils.parserError(state, "got unexpected \"");
}
if (character == '\\') {
if (target.length - index + 1 <= 0) {
return PCUtils.parserError(
state,
Strings.format1("got unexpected end of input at index %d", index)
);
}
def second = target[index + 1];
if (
second == '\"' ||
second == '\\' ||
second == '/' ||
second == 'b' ||
second == 'f' ||
second == 'n' ||
second == 'r' ||
second == 't') {
return PCUtils.parserState(state, index + 2, ParseResult.Single([character, second]));
} else if (second == 'u') {
def results = Array<ParseResult>.new(5);
results[0] = ParseResult.Single([character, second]);
var nextState = PCUtils.parserState(state, index + 1, results[0]);
for (i < 4) {
nextState = hexParser.parser(nextState);
match (nextState) {
Result(target_, index_, result) => {
results[i + 1] = result;
}
Error => return nextState;
}
}
return PCUtils.parserState(nextState, index, ParseResult.Many(results));
}
}
return PCUtils.parserState(state, index + 1, ParseResult.Single([character]));
}
Error => return state;
}
}
// The `parser` should flatten state.result via `PCUtils.flattenParseResultToString`
// before returning `state`.
private def unicodeParserImpl(parser: Parser, priorState: ParserState) -> ParserState {
def state = parser.parser(priorState);
match (state) {
Result(target, index, result) => {
match (result) {
Single(resultString) => {
//System.puts(resultString);
def errorOffset = Utf8.findError(resultString);
if (errorOffset < 0) {
return state;
}
return PCUtils.parserError(
state,
Strings.format1("invalid unicode codepoint in string at index %d", index + errorOffset)
);
}
_ => {
return state;
}
}
}
Error => return state;
}
}
private def unicodeParser(parser: Parser) -> Parser {
return Parser.new(unicodeParserImpl(parser, _));
}
def whitespaceParser = PC.optional(
PC.many(PC.choice([
PC.str(" "),
PC.str("\r"),
PC.str("\n"),
PC.str("\t")
]))
).map(PCUtils.throwawayParseResult);
def nullParser = PC.str("null");
def boolParser = PC.choice([PC.str("true"), PC.str("false")]);
def stringParser = PC.sequenceOf([
PC.str("\""),
unicodeParser(
PC.many(Parser.new(characterParser))
.map(PCUtils.flattenParseResultToString)
),
PC.str("\"")
]).map(PCUtils.flattenParseResultToString);
def numberParser = PC.sequenceOf([
PC.optional(PC.str("-")),
PC.choice([
// If the first digit is 0, then there
// should be no further digits before the decimal.
PC.str("0"),
PC.digits
]),
PC.optional(
PC.sequenceOf([
PC.str("."),
PC.digits
])
),
PC.optional(
PC.sequenceOf([
PC.choice([PC.str("e"), PC.str("E")]),
PC.choice([PC.str("+"), PC.str("-")]),
PC.digits
])
)
]).map(PCUtils.flattenParseResultToString);
def getObjectParser() -> Parser {
return objectParser;
}
def getArrayParser() -> Parser {
return arrayParser;
}
def valueParser = PC.between(
whitespaceParser,
PC.choice([
stringParser,
numberParser,
boolParser,
nullParser,
PC.lazy(getObjectParser),
PC.lazy(getArrayParser)
]),
whitespaceParser
).map(PCUtils.removeEmptyParseResults);
def objectParser = PC.sequenceOf([
PC.str("{"),
PC.choice([
PC.sepBy1(
PC.str(","),
PC.sequenceOf([
whitespaceParser,
stringParser,
whitespaceParser,
PC.str(":").map(PCUtils.throwawayParseResult),
valueParser
]).map(PCUtils.removeEmptyParseResults)
).map(PCUtils.flattenParseResultsOnce),
whitespaceParser
]),
PC.str("}")
]).map(PCUtils.flattenParseResultsOnce);
def arrayParser = PC.sequenceOf([
PC.str("["),
PC.choice([
PC.sepBy1(PC.str(","), valueParser),
whitespaceParser
]),
PC.str("]")
]).map(PCUtils.flattenParseResultsOnce);
def parseResultArrayToJsonValue(results: Array<ParseResult>) -> JsonValue {
match (results[0]) {
Single(bracket) => {
if (Strings.equal(bracket, "[")) {
def arrayItems = PCUtils.arraySlice(results, 1, results.length - 1);
return JsonValue.Array(Arrays.map(arrayItems, parseValueResultToJsonValue));
} else {
def num = (results.length - 2) / 2;
def keys = Array<string>.new(num);
def values = Array<JsonValue>.new(num);
for (i < num) {
match (results[i * 2 + 1]) {
Single(key) => {
keys[i] = PCUtils.arraySlice(key, 1, key.length - 1);
}
_ => {
System.puts("parseResultArrayToJsonValue: should never reach here - key must be a single value\n");
}
}
values[i] = parseValueResultToJsonValue(results[i * 2 + 2]);
}
def map = Strings.newMap<JsonValue>();
for (i < num) {
map[keys[i]] = values[i];
}
return JsonValue.Object(map);
}
}
_ => {
System.puts("parseResultArrayToJsonValue: should never reach here - opening brace must be a Single value\n");
return JsonValue.Null;
}
}
}
def parseValueResultToJsonValue(result: ParseResult) -> JsonValue {
match(result) {
Single(value) => {
def firstChar = value[0];
if (firstChar == '\"') {
return JsonValue.String(PCUtils.arraySlice(value, 1, value.length - 1));
} else if (firstChar == 't') {
return JsonValue.Bool(true);
} else if (firstChar == 'f') {
return JsonValue.Bool(false);
} else if (firstChar == 'n') {
return JsonValue.Null;
} else {
return JsonValue.Number(value);
}
}
Many(results) => return parseResultArrayToJsonValue(results);
Empty => {
System.puts("parseValueResultToJsonValue: should never reach here\n");
return JsonValue.Null;
}
}
}
def main() {
// def jsonString = "[{\"a\": -193.4e+3, \"b\": [true]}]";
def jsonString = "[{\"a\": -193.4, \"b\": 145}]";
match (valueParser.run(jsonString)) {
Result(target, index, result) => {
def json = parseValueResultToJsonValue(result);
def deserializer = deArray(
deObject2(
JsonObjectDeserializedExample.new,
("a", deInt32),
("b", deInt32)
)
);
def arr = deserializer(json);
match (arr) {
Ok(arr) => {}
Err => System.puts("Uh oh, failed to deserialize\n");
}
System.puts("success:\n");
System.puts(json.toString());
}
Error(target_, index_, result_, error) => {
System.puts("error: ");
System.puts(error);
}
}
System.puts("\n");
}
}
class JsonObjectDeserializedExample {
def a: int;
def b: int;
new(a, b) {}
}
type ParseResult {
case Empty;
case Single(result: string);
case Many(results: Array<ParseResult>);
}
type ParserState {
case Result(target: string, index: int, result: ParseResult);
case Error(target: string, index: int, result: ParseResult, error: string);
}
component PCUtils {
def parserState(state: ParserState, index: int, result: ParseResult) -> ParserState {
match (state) {
Result(target, index_, result_) => return ParserState.Result(target, index, result);
Error(target, index_, result_, error) => return ParserState.Error(target, index, result, error);
}
}
def updateParserResult(state: ParserState, result: ParseResult) -> ParserState {
match (state) {
Result(target, index, result_) => return ParserState.Result(target, index, result);
Error(target, index, result_, error) => return ParserState.Error(target, index, result, error);
}
}
def parserError(state: ParserState, error: string) -> ParserState {
match (state) {
Result(target, index, result) => return ParserState.Error(target, index, result, error);
Error(target, index, result, error_) => return ParserState.Error(target, index, result, error);
}
}
def stringStartsWith(str: string, start: string, start_index: int) -> bool {
if (str.length - start_index < start.length) return false;
for (i < start.length) if (str[i + start_index] != start[i]) return false;
return true;
}
def intMin(first: int, second: int) -> int {
if (second < first) return second;
return first;
}
def arraySlice<T>(str: Array<T>, start_index: int, end_index: int) -> Array<T> {
def length = intMin(end_index - start_index, str.length - start_index);
def dst = Array<T>.new(length);
for (i < dst.length) {
dst[i] = str[i + start_index];
}
return dst;
}
def takeInRange(str: string, lower: int, upper: int, start_index: int) -> string {
var length = 0;
for (i = start_index; i < str.length; i++) {
def character = str[i];
if (character < lower || character > upper) {
break;
}
length += 1;
}
return arraySlice(str, start_index, start_index + length);
}
def takeDigits(str: string, start_index: int) -> string {
return takeInRange(str, 48, 57, start_index);
}
def flattenParseResultToStringImpl(parse_result: ParseResult) -> string {
def state = Vector<string>.new();
var length = 0;
match (parse_result) {
Empty => return "";
Single(result) => {
length += result.length;
state.put(result);
}
Many(results) => {
for (result in results) {
def ret = flattenParseResultToStringImpl(result);
length += ret.length;
state.put(ret);
}
}
}
def ret = Array<byte>.new(length);
var index = 0;
for (fragment in state.extract()) {
Arrays.copyInto(fragment, ret, index);
index += fragment.length;
}
return ret;
}
def flattenParseResultToString(parse_result: ParseResult) -> ParseResult {
def result = flattenParseResultToStringImpl(parse_result);
if (result.length == 0) {
return ParseResult.Empty;
}
return ParseResult.Single(result);
}
def flattenParseResultsOnce(parse_result: ParseResult) -> ParseResult {
match (parse_result) {
Many(results) => {
def ret = Vector<ParseResult>.new();
for (result in results) {
match (result) {
Many(results) => {
for (result in results) {
ret.put(result);
}
}
_ => ret.put(result);
}
}
return ParseResult.Many(ret.extract());
}
_ => return parse_result;
}
}
def throwawayParseResult(parse_result: ParseResult) -> ParseResult {
return ParseResult.Empty;
}
def removeEmptyParseResults(parse_result: ParseResult) -> ParseResult {
match (parse_result) {
Many(results) => {
def ret = Vector<ParseResult>.new();
for (result in results) {
match (result) {
Empty => {}
_ => ret.put(result);
}
}
def r = ParseResult.Many(ret.extract());
return r;
}
_ => return parse_result;
}
}
}
class Parser {
def parser: ParserState -> ParserState;
new(parser) {}
def run(target: string) -> ParserState {
return parser(ParserState.Result(target, 0, ParseResult.Empty));
}
def mapImpl(
parser: ParserState -> ParserState,
fn: ParseResult -> ParseResult,
state: ParserState
) -> ParserState {
def nextState = parser(state);
match (nextState) {
Result(target_, index_, result) => return PCUtils.updateParserResult(nextState, fn(result));
Error => return nextState;
}
}
def map(fn: ParseResult -> ParseResult) -> Parser {
return Parser.new(mapImpl(parser, fn, _));
}
def errorMapImpl(
parser: ParserState -> ParserState,
fn: (string, int) -> string,
state: ParserState
) -> ParserState {
def nextState = parser(state);
match (nextState) {
Result(target_, index_, result) => return nextState;
Error(target_, index, result_, error) => return PCUtils.parserError(nextState, fn(error, index));
}
}
def errorMap(fn: (string, int) -> string) -> Parser {
return Parser.new(errorMapImpl(parser, fn, _));
}
def chainImpl(
parser: ParserState -> ParserState,
fn: ParseResult -> Parser,
state: ParserState
) -> ParserState {
def nextState = parser(state);
match (nextState) {
Result(target_, index_, result) => {
def nextParser = fn(result);
return nextParser.parser(nextState);
}
Error => return nextState;
}
}
def chain(fn: ParseResult -> Parser) -> Parser {
return Parser.new(chainImpl(parser, fn, _));
}
}
component PC {
def strImpl(s: string, state: ParserState) -> ParserState {
match (state) {
Result(target, index, result_) => {
if (target.length - index <= 0) {
return PCUtils.parserError(
state,
Strings.format1("tried to match \"%s\", but got unexpected end of input", s)
);
}
if (PCUtils.stringStartsWith(target, s, index)) {
return PCUtils.parserState(state, index + s.length, ParseResult.Single(s));
} else {
return PCUtils.parserError(
state,
Strings.format2(
"str: Tried to match \"%s\", but got \"%s\"",
s,
PCUtils.arraySlice(target, index, index + 10)
)
);
}
}
Error => return state;
}
}
def str(s: string) -> Parser {
return Parser.new(strImpl(s, _));
}
def charInRangeImpl(lower: int, upper: int, state: ParserState) -> ParserState {
match (state) {
Result(target, index, result_) => {
if (target.length - index <= 0) {
return PCUtils.parserError(
state,
"tried to match char, but got unexpected end of input"
);
}
def character = target[index];
if (character < lower || character > upper) {
return PCUtils.parserError(
state,
Strings.format2("tried to match char but, got character out of bounds of %d-%d", lower, upper)
);
}
return PCUtils.parserState(state, index + 1, ParseResult.Single([character]));
}
Error => return state;
}
}
def charInRange(lower: int, upper: int) -> Parser {
return Parser.new(charInRangeImpl(lower, upper, _));
}
def digitsImpl(state: ParserState) -> ParserState {
match (state) {
Result(target, index, result_) => {
def result = PCUtils.takeDigits(target, index);
if (result.length == 0) {
return PCUtils.parserError(
state,
Strings.format1(
"digits: Tried to match digits, but got \"%s\"",
PCUtils.arraySlice(target, index, index + 10)
)
);
} else {
return PCUtils.parserState(state, index + result.length, ParseResult.Single(result));
}
}
Error => return state;
}
}
def digits = Parser.new(digitsImpl);
def sequenceOfImpl(parsers: Array<Parser>, state: ParserState) -> ParserState {
match (state) {
Result => {
def results = Array<ParseResult>.new(parsers.length);
var nextState = state;
for (i < parsers.length) {
nextState = parsers[i].parser(nextState);
match (nextState) {
Result(target_, index_, result) => results[i] = result;
Error(target, index, result, error) => {
break;
}
}
}
return PCUtils.updateParserResult(nextState, ParseResult.Many(results));
}
Error => return state;
}
}
def sequenceOf(parsers: Array<Parser>) -> Parser {
return Parser.new(sequenceOfImpl(parsers, _));
}
def choiceImpl(parsers: Array<Parser>, state: ParserState) -> ParserState {
match (state) {
Result(target_, index, result_) => {
for (i < parsers.length) {
def nextState = parsers[i].parser(state);
match (nextState) {
Result(target_, index_, result) => {
return PCUtils.updateParserResult(nextState, result);
}
Error => {}
}
}
return PCUtils.parserError(
state,
Strings.format1("choice: Unable to match with any parser at index %d", index)
);
}
Error => return state;
}
}
def choice(parsers: Array<Parser>) -> Parser {
return Parser.new(choiceImpl(parsers, _));
}
def emptyParser(state: ParserState) -> ParserState {
match (state) {
Result => return PCUtils.updateParserResult(state, ParseResult.Empty);
Error => return state;
}
}
def optional(parser: Parser) -> Parser {
return choice([parser, Parser.new(emptyParser)]);
}
def manyImpl(parser: Parser, minimum_results: int, state: ParserState) -> ParserState {
match (state) {
Result(target_, index, result_) => {
def results = Vector<ParseResult>.new();
var nextState = state;
var done = false;
while (!done) {
def testState = parser.parser(nextState);
match (testState) {
Result(target_, index_, result) => {
results.put(result);
nextState = testState;
}
Error => {
done = true;
}
}
}
if (results.length < minimum_results) {
return PCUtils.parserError(
state,
Strings.format2("many%d: Unable to match any parser @ index %d", minimum_results, index));
}
return PCUtils.updateParserResult(nextState, ParseResult.Many(results.extract()));
}
Error => return state;
}
}
def many(parser: Parser) -> Parser {
return Parser.new(manyImpl(parser, 0, _));
}
def many1(parser: Parser) -> Parser {
return Parser.new(manyImpl(parser, 1, _));
}
def sepByImpl(separatorParser: Parser, valueParser: Parser, minimum_results: int, state: ParserState) -> ParserState {
match (state) {
Result(target_, index, result_) => {
def results = Vector<ParseResult>.new();
var nextState = state;
while (true) {
def testState = valueParser.parser(nextState);
match (testState) {
Result(target_, index_, result) => {
results.put(result);
nextState = testState;
def sepState = separatorParser.parser(nextState);
match (sepState) {
Result => nextState = sepState;
Error => break;
}
}
Error => {
break;
}
}
}
if (results.length < minimum_results) {
return PCUtils.parserError(
state,
Strings.format2("sepBy%d: Unable to match any parser @ index %d", minimum_results, index));
}
return PCUtils.updateParserResult(nextState, ParseResult.Many(results.extract()));
}
Error => return state;
}
}
def sepBy(separatorParser: Parser, valueParser: Parser) -> Parser {
return Parser.new(sepByImpl(separatorParser, valueParser, 0, _));
}
def sepBy1(separatorParser: Parser, valueParser: Parser) -> Parser {
return Parser.new(sepByImpl(separatorParser, valueParser, 1, _));
}
def between(leftParser: Parser, contentParser: Parser, rightParser: Parser) -> Parser {
return sequenceOf([leftParser, contentParser, rightParser]).map(takeSecondParseResult);
}
def lazyImpl(parserThunk: void -> Parser, state: ParserState) -> ParserState {
def parser = parserThunk();
return parser.parser(state);
}
def lazy(parserThunk: void -> Parser) -> Parser {
return Parser.new(lazyImpl(parserThunk, _));
}
def takeSecondParseResult(parse_result: ParseResult) -> ParseResult {
match (parse_result) {
Many(results) => return results[1];
_ => return parse_result;
}
}
}
@mosheduminer
Copy link
Author

This just parser to a JSON AST, it doesn't yet have the interface for deserializing to a specific structure.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment