fun isSpace(c) return c == ' ' or c == '\t' or c == '\n'; fun isDigit(c) return unicode(c) <= unicode('9') and unicode(c) >= unicode('0'); fun skip(ctx, test) while not ended(ctx): { if not test(current(ctx)): break; next(ctx); } fun ended(ctx) return ctx.i == count(ctx.str); fun next(ctx) { assert(ctx.i < count(ctx.str)); ctx.i = ctx.i + 1; } fun current(ctx) { assert(ctx.i < count(ctx.str)); return ctx.str[ctx.i]; } fun parse(str) { if str == none: str = ''; ctx = {str: str, i: 0}; skip(ctx, isSpace); if ended(ctx): { print('Source only contains whitespace'); return none; } return parseAny(ctx); } fun parseArray(ctx) { assert(current(ctx) == '['); next(ctx); # Skip '['. skip(ctx, isSpace); if ended(ctx): { error("Source ended inside an array"); return none; } arr = []; if current(ctx) == ']': { next(ctx); return arr; } while true: { child = parseAny(ctx); if child == none: return none; arr[count(arr)] = child; skip(ctx, isSpace); if ended(ctx): { error("Source ended inside an array"); return none; } if current(ctx) == ']': break; if current(ctx) != ',': { error("Bad character inside array"); return none; } next(ctx); # Skip ','. skip(ctx, isSpace); if ended(ctx): { error("Source ended inside an array"); return none; } } next(ctx); return arr; } fun parseObject(ctx) { assert(current(ctx) == '{'); next(ctx); # Skip '{'. skip(ctx, isSpace); if ended(ctx): { error("Source ended inside an object"); return none; } obj = {}; if current(ctx) == '}': { next(ctx); return {}; } while true: { if current(ctx) != '"': { error("Bad character where a string was expected"); return none; } key = parseString(ctx); if key == none: return none; skip(ctx, isSpace); if current(ctx) != ':': { error("Bad character where ':' was expected"); return none; } next(ctx); # Skip ':'. skip(ctx, isSpace); child = parseAny(ctx); if child == none: return none; obj[key] = child; skip(ctx, isSpace); if ended(ctx): { error("Source ended inside an arrays"); return none; } if current(ctx) == '}': break; if current(ctx) != ',': { error("Bad character inside array"); return none; } next(ctx); # Skip ','. skip(ctx, isSpace); if ended(ctx): { error("Source ended inside an array"); return none; } } next(ctx); return obj; } fun parseString(ctx) { next(ctx); # Skip the '"'. buff = ''; while not ended(ctx): { if current(ctx) == '"': break; buff = strcat(buff, current(ctx)); next(ctx); } if ended(ctx): { error("Source ended inside a string"); return none; } next(ctx); # Skip the '"'. return buff; } fun parseNumber(ctx) { assert(isDigit(current(ctx))); # Number (int or float) parsed = 0; while not ended(ctx): { if not isDigit(current(ctx)): break; parsed = parsed * 10 + unicode(current(ctx)) - unicode('0'); next(ctx); } if ended(ctx): return parsed; if current(ctx) == '.': { next(ctx); if ended(ctx): { error("Source string ended unexpectedly after dot"); return none; } if not isDigit(current(ctx)): { error("Got something other than a digit after dot"); return none; } fact = 1; while not ended(ctx): { if not isDigit(current(ctx)): break; fact = fact / 10.0; parsed = parsed + fact * (unicode(current(ctx)) - unicode('0')); next(ctx); } } return parsed; } fun parseAny(ctx) { print('Parsing value\n'); assert(not ended(ctx)); if current(ctx) == '[': return parseArray(ctx); if current(ctx) == '{': return parseObject(ctx); if current(ctx) == '"': return parseString(ctx); if isDigit(current(ctx)): return parseNumber(ctx); error("Not implemented yet"); } #tests = ['', '1', '10', '1.10', '"jeje"', '[]', '[1,2,3]', ' [ ] ', ' [ 1 , 2 , 3 ]', '{}', ' { } ', '{"hoy":4}', ' { "hoy" : 4 } ']; #i = 0; #while i < count(tests): { # r = parse(tests[i]); # if r == none: # print('\nTest ', i, ' failed\n'); # else # print(tests[i], ' -> ', r, '\n'); # i = i + 1; #} file = files.openFile('examples/large-file.json', files.READ); if file == none: error("Failed to open file"); buff = newBuffer(30000000); if buff == none: error("Failed to create buffer"); n = files.read(file, buff); text = bufferToString(sliceBuffer(buff, 0, n)); print(parse(text));