view modules/json.tp @ 331:61f5b794d939

Breaking change: method call syntax now always uses the syntactic receiver as the actual receiver. This makes its behavior different from function call syntax, but solves some problems with methods being shadowed by local variables and the like.
author Michael Pavone <pavone@retrodev.com>
date Sat, 28 Mar 2015 14:21:04 -0700
parents eef8a5cea812
children 3d36d69aab7f
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
	period <- "." byte: 0
	tab <- "	" 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
		ignore <- false
		while: { at < l } do: {
			b <- str byte: at
			if: b = neg {
				minus <- true
			} else: {
				if: b = period {
					ignore <- true
				} else: {
					if: b >= zero && b <= nine {
						if: (not: ignore) {
							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
		}

		encode <- :value {
			jsonEncoder encode: value
		}

		main <- {
			o <- #{
				foo <- "bar"
				baz <- ["fizz" "buzz" "buzzzz"]
				qux <- ((dict hash) set: "fo" "shizzle") set: "my" "nizzle"
				arr <- #["pirate" "booty"]
				numbers <- [1 2 3 42 (0-1337) 3.14159]
				booleans <- [
					true
					false
				]
			}
			print: (encode: o) . "\n"
			0
		}
	}
}