view modules/json.tp @ 166:e7642715d575

Handle newlines and carriage returns in JSON decoder
author Mike Pavone <pavone@retrodev.com>
date Sun, 11 Aug 2013 02:31:33 -0700
parents fe816637fcc4
children 5a6a55592c45
line wrap: on
line source

{
	startArr <- "[" byte: 0
	endArr <- "]" byte: 0
	startObj <- "{" byte: 0
	endObj <- "}" byte: 0
	quote <- "\"" byte: 0
	esc <- "\\" byte: 0
	zero <- "0" byte: 0
	nine <- "9" byte: 0
	neg <- "-" byte: 0
	space <- " " byte: 0
	comma <- "," byte: 0
	tab <- "\t" byte: 0
	nl <- "\n" byte: 0
	cr <- "\r" byte: 0
	colon <- ":" byte: 0
	t <- "t" byte: 0
	f <- "f" byte: 0

	parseNumAt <- :str :at :recvResult {
		num <- 0
		l <- str length
		minus <- false
		aft <- -1
		while: { at < l } do: {
			b <- str byte: at
			if: b = neg {
				minus <- true
			} else: {
				if: b >= zero && b <= nine {
					num <- num * 10 + (str byte: at) - zero
				} else: {
					aft <- at
					at <- l
				}
			}
			at <- at + 1
		}
		if: aft < 0 {
			aft <- at
		}
		if: minus {
			num <- 0 - num
		}
		#{
			value <- num
			after <- aft
		}
	}

	parseStrAt <- :src :at :recvResult {
		//TODO: Deal with escaped characters
		end <- src find: "\"" startingAt: at + 1 else: { src length }
		#{
			value <- src from: (at + 1) withLength: (end - at - 1)
			after <- end + 1
		}
	}

	_decode:at <- :text :cur {
		ret <- false
		b <- text byte: cur
		if: b = neg || b >= zero && b <= nine {
			text parseNumAt: cur
		} else: {
			if: b = quote {
				text parseStrAt: cur
			} else: {
				if: b = startArr {
					len <- text length
					val <- #[]
					cur <- cur + 1
					aft <- -1
					while: { cur < len } do: {
						b <- text byte: cur
						if: b = endArr {
							aft <- cur + 1
							cur <- len
						} else: {
							if: b = comma || b = space || b = tab || b = nl || b = cr {
								cur <- cur + 1
							} else: {
								el <- _decode: text at: cur
								cur <- el after
								val append: (el value)
							}
						}
					}
					#{
						value <- val
						after <- aft
					}
				} else: {
					if: b = startObj {
						len <- text length
						val <- dict linear
						cur <- cur + 1
						aft <- -1
						expectKey <- true
						key <- ""
						while: { cur < len } do: {
							b <- text byte: cur
							if: b = comma || b = space || b = tab || b = colon || b = nl || b = cr {
								cur <- cur + 1
							} else: {
								if: expectKey {
									if: b = endObj {
										aft <- cur + 1
										cur <- len
									} else: {
										kd <- _decode: text at: cur
										key <- kd value
										cur <- kd after
										expectKey <- false
									}
								} else: {
									el <- _decode: text at: cur
									val set: key (el value)
									cur <- el after
									expectKey <- true
								}
							}
						}
						#{
							after <- aft
							value <- val
						}
					} else: {
						if: b = t && (text from: cur withLength: 4) = "true" {
							#{
								value <- true
								after <- cur + 4
							}
						} else: {
							if: b = f && (text from: cur withLength: 5) = "false" {
								#{
									value <- false
									after <- cur + 5
								}
							} else: {
								#{
									value <- "foobar"
									after <- (text length)
								}
							}
						}

					}
				}
			}
		}
	}
	#{
		decode <- :text {
			(_decode: text at: 0) value
		}
	}
}