# line.ludic - a request: one line of stdin, cut into words. A word is a JSON value (a string, an # object or a list, read whole) or a run of anything but spaces (a name, a number) # the next line without its end (a \r before it is dropped too), or null at the end of the input @alloc_ok("a request read: the studio's input, never a frame") function pv_read_line(b: PvOut) -> string { b.n = 0 var c = read_char() if c < 0 { return null } while c >= 0 and c != 10 { if c != 13 { pv_byte(b, c) } c = read_char() } var s: pointer = null unsafe { s = bytes(b.n + 1) for i in 0 .. b.n { s[i] = b.p[i] } s[b.n] = 0 } return s } @alloc_ok("a request's words: one list kept, each word a slice of the line") function pv_words(s: string, out: []string) -> void { List.clear(out) let n = len(s) var i = 0 while i < n { while i < n and (s[i] == 32 or s[i] == 9) { i += 1 } if i >= n { break } var j = i let c = s[i] if c == 34 or c == 123 or c == 91 { j = pv_json_end(s, i) } else { while j < n and s[j] != 32 and s[j] != 9 { j += 1 } } push(out, s[i..j]) i = j } } # where the JSON value starting at i ends: its closing quote or bracket, strings and escapes skipped function pv_json_end(s: string, i: int) -> int { let n = len(s) var depth = 0 var ins = false var j = i while j < n { let c = s[j] if ins { if c == 92 { j += 1 } else if c == 34 { ins = false if depth == 0 { return j + 1 } } } else if c == 34 { ins = true } else if c == 123 or c == 91 { depth += 1 } else if c == 125 or c == 93 { depth -= 1 if depth == 0 { return j + 1 } } j += 1 } return n } # a word as text: a JSON string unquoted, anything else as it stands @alloc_ok("a request's word read") function pv_text(w: string) -> string { if len(w) > 0 and w[0] == 34 { return Value.as_str(Json.parse(w)) } return w } # a word as a number (0 when it is not one) @alloc_ok("a request's word read") function pv_float(w: string) -> float { if len(w) == 0 { return 0.0 } let c = w[0] if not ((c >= 48 and c <= 57) or c == 45 or c == 46) { return 0.0 } return Value.as_float(Json.parse(w)) } function pv_int_of(w: string) -> int { return int(pv_float(w)) } # a word as a JSON value (a bare word is a string) @alloc_ok("a request's word read") function pv_val(w: string) -> Val { if len(w) == 0 { return Value.null() } let c = w[0] if c == 34 or c == 123 or c == 91 or (c >= 48 and c <= 57) or c == 45 { return Json.parse(w) } if w == "true" { return Value.bool(1) } if w == "false" { return Value.bool(0) } if w == "null" { return Value.null() } return Value.str(w) } # whether s holds p at `at`, compared where it stands function pv_sat(s: string, at: int, p: string) -> bool { if at + len(p) > len(s) { return false } for i in 0 .. len(p) { if s[at + i] != p[i] { return false } } return true }