load.ha (3396B)
1 use bufio; 2 use io; 3 use strings; 4 use types; 5 6 // Options for [[load]]. 7 export type load_option = nestlimit; 8 9 // The maximum number of nested objects or arrays that can be entered before 10 // erroring out. 11 export type nestlimit = uint; 12 13 // Parses a JSON value from the given [[io::handle]], returning the value or an 14 // error. The return value is allocated on the heap; use [[finish]] to free it 15 // up when you're done using it. 16 // 17 // By default, this function assumes non-antagonistic inputs, and does not limit 18 // recursion depth or memory usage. You may want to set a custom [[nestlimit]], 19 // or incorporate an [[io::limitreader]] or similar. Alternatively, you can use 20 // the JSON lexer ([[lex]]) directly if dealing with potentially malicious 21 // inputs. 22 export fn load(src: io::handle, opts: load_option...) (value | error) = { 23 let limit = types::UINT_MAX; 24 for (let i = 0z; i < len(opts); i += 1) { 25 limit = opts[i]: nestlimit: uint; 26 }; 27 const lex = newlexer(src); 28 defer close(&lex); 29 return _load(&lex, 0, limit); 30 }; 31 32 // Parses a JSON value from the given string, returning the value or an error. 33 // The return value is allocated on the heap; use [[finish]] to free it up when 34 // you're done using it. 35 // 36 // See the documentation for [[load]] for information on dealing with 37 // potentially malicious inputs. 38 export fn loadstr(input: str, opts: load_option...) (value | error) = { 39 let src = bufio::fixed(strings::toutf8(input), io::mode::READ); 40 return load(&src, opts...); 41 }; 42 43 fn _load(lexer: *lexer, level: uint, limit: uint) (value | error) = { 44 const tok = mustscan(lexer)?; 45 match (tok) { 46 case _null => 47 return _null; 48 case let b: bool => 49 return b; 50 case let f: f64 => 51 return f; 52 case let s: str => 53 return strings::dup(s); 54 case arraystart => 55 if (level == limit) { 56 return limitreached; 57 }; 58 return _load_array(lexer, level + 1, limit); 59 case objstart => 60 if (level == limit) { 61 return limitreached; 62 }; 63 return _load_obj(lexer, level + 1, limit); 64 case (arrayend | objend | colon | comma) => 65 return lexer.loc: invalid; 66 }; 67 }; 68 69 fn _load_array(lexer: *lexer, level: uint, limit: uint) (value | error) = { 70 let array: []value = []; 71 let tok = mustscan(lexer)?; 72 match (tok) { 73 case arrayend => 74 return array; 75 case => 76 unlex(lexer, tok); 77 }; 78 79 for (true) { 80 append(array, _load(lexer, level, limit)?); 81 82 tok = mustscan(lexer)?; 83 match (tok) { 84 case comma => void; 85 case arrayend => break; 86 case => 87 return lexer.loc: invalid; 88 }; 89 }; 90 return array; 91 }; 92 93 fn _load_obj(lexer: *lexer, level: uint, limit: uint) (value | error) = { 94 let obj = newobject(); 95 let tok = mustscan(lexer)?; 96 match (tok) { 97 case objend => 98 return obj; 99 case => 100 unlex(lexer, tok); 101 }; 102 103 for (true) { 104 let tok = mustscan(lexer)?; 105 const key = match (tok) { 106 case let s: str => 107 yield strings::dup(s); 108 case => 109 return lexer.loc: invalid; 110 }; 111 defer free(key); 112 113 tok = mustscan(lexer)?; 114 if (!(tok is colon)) { 115 return lexer.loc: invalid; 116 }; 117 118 const val = _load(lexer, level, limit)?; 119 defer finish(val); 120 set(&obj, key, val); 121 122 tok = mustscan(lexer)?; 123 match (tok) { 124 case comma => void; 125 case objend => break; 126 case => 127 return lexer.loc: invalid; 128 }; 129 }; 130 131 return obj; 132 }; 133 134 fn mustscan(lexer: *lexer) (token | error) = { 135 match (lex(lexer)?) { 136 case io::EOF => 137 lexer.loc.1 += 1; 138 return lexer.loc: invalid; 139 case let tok: token => 140 return tok; 141 }; 142 };