... | ... | @@ -145,44 +145,36 @@ after any value or Comma. |
|
|
Assume we have two bit streams for tokens: `valueToken` (explained above) and `anyToken`, a bit stream marking the end position of any legal or illegal token. Assume also that `LBrace`, `RBrace`, `DQuote`, `Colon` and `Comma` are streams marking the position of JSON `{`, `}`, `"`, `:` and `,` tokens respectively.
|
|
|
|
|
|
```
|
|
|
str = valueToken & DQuote
|
|
|
valueTokenMinusStr = valueToken ^ str
|
|
|
|
|
|
atDepth = bnc.EQ(ND, d)
|
|
|
nested = bnc.UGT(ND, d)
|
|
|
objStart = atDepth & LBrace
|
|
|
objEnd = ScanThru(objStart, nested | (atDepth & ~ (RBrak | RBrace)))
|
|
|
objAtEnd = objEnd & RBrak
|
|
|
objSpan = ExclusiveSpan(objStart, objEnd)
|
|
|
// Now validate that every value or nested item is followed
|
|
|
// either by a comma or a the end RBrace.
|
|
|
afterNested = Advance(nested & objSpan, 1) & atDepth
|
|
|
//
|
|
|
// process all values that are not strings
|
|
|
afterTokenMinusStr = Advance(atDepth & valueTokenMinusStr & objSpan, 1)
|
|
|
tokenNextMinusStr = ScanThru(afterNested | afterTokenMinusStr, whitespace)
|
|
|
errAfterValueMinusStr = tokenNextMinusStr &~(Comma | RBrace)
|
|
|
//
|
|
|
// process strings as both key and value
|
|
|
strAtDepth = atDepth & str
|
|
|
afterTokenStr = Advance(strAtDepth & objSpan, 1)
|
|
|
tokenNextStr = ScanThru(afterNested | afterTokenStr, whitespace)
|
|
|
errAfterValueStr = tokenNextStr &~(Comma | RBrace | Colon)
|
|
|
//
|
|
|
// join errors
|
|
|
errAfterValue = errAfterValueMinusStr | errAfterValueStr
|
|
|
//
|
|
|
// Every Colon must be followed by a value
|
|
|
advColon = Advance(Colon & atDepth & objSpan, 1)
|
|
|
errAfterColon = ScanTo(advColon, anyToken) & ~ (nested | (valueToken & atDepth))
|
|
|
//
|
|
|
// Every Comma must be followed by a key string
|
|
|
advComma = Advance(Comma & atDepth & objSpan, 1)
|
|
|
errAfterComma = ScanTo(advComma, anyToken) & ~ strAtDepth
|
|
|
//
|
|
|
// After the LBrace we must have either a value or an RBrace.
|
|
|
scanObjStartAnyToken = ScanTo(Advance(objStart, 1), anyToken)
|
|
|
errAfterLBrace = scanObjStartAnyToken & ~ (nested | valueToken | RBrace)
|
|
|
str = valueToken & DQuote
|
|
|
zeroND = bnc.EQ(ND, 0)
|
|
|
|
|
|
// process strings as both key and value
|
|
|
validStr = str & ~zeroND
|
|
|
afterTokenStr = Advance(validStr, 1)
|
|
|
tokenNextStr = ScanThru(afterTokenStr, whitespace)
|
|
|
errAfterValueStr = tokenNextStr & ~(Comma | Colon | RBrace | RBrak | zeroND)
|
|
|
|
|
|
// Every Colon must be followed by a value
|
|
|
validBeginValues = (valueToken | LBrak | LBrace) & ~zeroND
|
|
|
advColon = Advance(Colon, 1)
|
|
|
errAfterColon = ScanTo(advColon, anyToken) & ~validBeginValues)
|
|
|
|
|
|
for d in 1...MaxDepth
|
|
|
atDepth = bnc.EQ(ND, d)
|
|
|
nested = bnc.UGT(ND, d)
|
|
|
objStart = atDepth & LBrace
|
|
|
objEnd = ScanThru(objStart, nested | (atDepth & ~ (RBrak | RBrace)))
|
|
|
objAtEnd = objEnd & RBrak
|
|
|
objSpan = ExclusiveSpan(objStart, objEnd)
|
|
|
//
|
|
|
// Every Comma must be followed by a key string
|
|
|
strAtDepth = str & atDepth
|
|
|
advComma = Advance(Comma & atDepth & objSpan, 1)
|
|
|
errAfterComma = ScanTo(advComma, anyToken) & ~ strAtDepth
|
|
|
//
|
|
|
// After the LBrace we must have either a value or an RBrace.
|
|
|
scanObjStartAnyToken = ScanTo(Advance(objStart, 1), anyToken)
|
|
|
errAfterLBrace = scanObjStartAnyToken & ~ (nested | valueToken | RBrace)
|
|
|
```
|
|
|
|
|
|
# CFG Kernel (_note: this doc isn't ready_)
|
... | ... | |