more modules updated

This commit is contained in:
Araq 2014-08-28 01:54:36 +02:00
commit e12f9518cc
3 changed files with 62 additions and 62 deletions

View file

@ -82,7 +82,7 @@ type
stateEof, stateStart, stateObject, stateArray, stateExpectArrayComma, stateEof, stateStart, stateObject, stateArray, stateExpectArrayComma,
stateExpectObjectComma, stateExpectColon, stateExpectValue stateExpectObjectComma, stateExpectColon, stateExpectValue
JsonParser* = object of TBaseLexer ## the parser object. JsonParser* = object of BaseLexer ## the parser object.
a: string a: string
tok: TTokKind tok: TTokKind
kind: JsonEventKind kind: JsonEventKind
@ -119,7 +119,7 @@ const
"{", "}", "[", "]", ":", "," "{", "}", "[", "]", ":", ","
] ]
proc open*(my: var JsonParser, input: PStream, filename: string) = proc open*(my: var JsonParser, input: Stream, filename: string) =
## initializes the parser with an input stream. `Filename` is only used ## initializes the parser with an input stream. `Filename` is only used
## for nice error messages. ## for nice error messages.
lexbase.open(my, input) lexbase.open(my, input)
@ -224,7 +224,7 @@ proc parseString(my: var JsonParser): TTokKind =
if handleHexChar(buf[pos], r): inc(pos) if handleHexChar(buf[pos], r): inc(pos)
if handleHexChar(buf[pos], r): inc(pos) if handleHexChar(buf[pos], r): inc(pos)
if handleHexChar(buf[pos], r): inc(pos) if handleHexChar(buf[pos], r): inc(pos)
add(my.a, toUTF8(TRune(r))) add(my.a, toUTF8(Rune(r)))
else: else:
# don't bother with the error # don't bother with the error
add(my.a, buf[pos]) add(my.a, buf[pos])
@ -402,7 +402,7 @@ proc next*(my: var JsonParser) =
case tk case tk
of tkString, tkInt, tkFloat, tkTrue, tkFalse, tkNull: of tkString, tkInt, tkFloat, tkTrue, tkFalse, tkNull:
my.state[i] = stateEof # expect EOF next! my.state[i] = stateEof # expect EOF next!
my.kind = TJsonEventKind(ord(tk)) my.kind = JsonEventKind(ord(tk))
of tkBracketLe: of tkBracketLe:
my.state.add(stateArray) # we expect any my.state.add(stateArray) # we expect any
my.kind = jsonArrayStart my.kind = jsonArrayStart
@ -418,7 +418,7 @@ proc next*(my: var JsonParser) =
case tk case tk
of tkString, tkInt, tkFloat, tkTrue, tkFalse, tkNull: of tkString, tkInt, tkFloat, tkTrue, tkFalse, tkNull:
my.state.add(stateExpectColon) my.state.add(stateExpectColon)
my.kind = TJsonEventKind(ord(tk)) my.kind = JsonEventKind(ord(tk))
of tkBracketLe: of tkBracketLe:
my.state.add(stateExpectColon) my.state.add(stateExpectColon)
my.state.add(stateArray) my.state.add(stateArray)
@ -437,7 +437,7 @@ proc next*(my: var JsonParser) =
case tk case tk
of tkString, tkInt, tkFloat, tkTrue, tkFalse, tkNull: of tkString, tkInt, tkFloat, tkTrue, tkFalse, tkNull:
my.state.add(stateExpectArrayComma) # expect value next! my.state.add(stateExpectArrayComma) # expect value next!
my.kind = TJsonEventKind(ord(tk)) my.kind = JsonEventKind(ord(tk))
of tkBracketLe: of tkBracketLe:
my.state.add(stateExpectArrayComma) my.state.add(stateExpectArrayComma)
my.state.add(stateArray) my.state.add(stateArray)
@ -488,7 +488,7 @@ proc next*(my: var JsonParser) =
case tk case tk
of tkString, tkInt, tkFloat, tkTrue, tkFalse, tkNull: of tkString, tkInt, tkFloat, tkTrue, tkFalse, tkNull:
my.state[i] = stateExpectObjectComma my.state[i] = stateExpectObjectComma
my.kind = TJsonEventKind(ord(tk)) my.kind = JsonEventKind(ord(tk))
of tkBracketLe: of tkBracketLe:
my.state[i] = stateExpectObjectComma my.state[i] = stateExpectObjectComma
my.state.add(stateArray) my.state.add(stateArray)
@ -505,7 +505,7 @@ proc next*(my: var JsonParser) =
# ------------- higher level interface --------------------------------------- # ------------- higher level interface ---------------------------------------
type type
TJsonNodeKind* = enum ## possible JSON node types JsonNodeKind* = enum ## possible JSON node types
JNull, JNull,
JBool, JBool,
JInt, JInt,
@ -514,9 +514,9 @@ type
JObject, JObject,
JArray JArray
PJsonNode* = ref TJsonNode ## JSON node JsonNode* = ref JsonNodeObj ## JSON node
TJsonNode* {.final, pure, acyclic.} = object JsonNodeObj* {.acyclic.} = object
case kind*: TJsonNodeKind case kind*: JsonNodeKind
of JString: of JString:
str*: string str*: string
of JInt: of JInt:
@ -528,104 +528,104 @@ type
of JNull: of JNull:
nil nil
of JObject: of JObject:
fields*: seq[tuple[key: string, val: PJsonNode]] fields*: seq[tuple[key: string, val: JsonNode]]
of JArray: of JArray:
elems*: seq[PJsonNode] elems*: seq[JsonNode]
JsonParsingError* = object of ValueError ## is raised for a JSON error JsonParsingError* = object of ValueError ## is raised for a JSON error
{.deprecated: [EJsonParsingError: JsonParsingError, TJsonNode: JsonNodeObj, {.deprecated: [EJsonParsingError: JsonParsingError, TJsonNode: JsonNodeObj,
PJsonNode: JsonNode, TJsonNodeKind: JsonNodeKind].} PJsonNode: JsonNode, TJsonNodeKind: JsonNodeKind].}
proc raiseParseErr*(p: TJsonParser, msg: string) {.noinline, noreturn.} = proc raiseParseErr*(p: JsonParser, msg: string) {.noinline, noreturn.} =
## raises an `EJsonParsingError` exception. ## raises an `EJsonParsingError` exception.
raise newException(EJsonParsingError, errorMsgExpected(p, msg)) raise newException(JsonParsingError, errorMsgExpected(p, msg))
proc newJString*(s: string): PJsonNode = proc newJString*(s: string): JsonNode =
## Creates a new `JString PJsonNode`. ## Creates a new `JString PJsonNode`.
new(result) new(result)
result.kind = JString result.kind = JString
result.str = s result.str = s
proc newJStringMove(s: string): PJsonNode = proc newJStringMove(s: string): JsonNode =
new(result) new(result)
result.kind = JString result.kind = JString
shallowCopy(result.str, s) shallowCopy(result.str, s)
proc newJInt*(n: BiggestInt): PJsonNode = proc newJInt*(n: BiggestInt): JsonNode =
## Creates a new `JInt PJsonNode`. ## Creates a new `JInt PJsonNode`.
new(result) new(result)
result.kind = JInt result.kind = JInt
result.num = n result.num = n
proc newJFloat*(n: float): PJsonNode = proc newJFloat*(n: float): JsonNode =
## Creates a new `JFloat PJsonNode`. ## Creates a new `JFloat PJsonNode`.
new(result) new(result)
result.kind = JFloat result.kind = JFloat
result.fnum = n result.fnum = n
proc newJBool*(b: bool): PJsonNode = proc newJBool*(b: bool): JsonNode =
## Creates a new `JBool PJsonNode`. ## Creates a new `JBool PJsonNode`.
new(result) new(result)
result.kind = JBool result.kind = JBool
result.bval = b result.bval = b
proc newJNull*(): PJsonNode = proc newJNull*(): JsonNode =
## Creates a new `JNull PJsonNode`. ## Creates a new `JNull PJsonNode`.
new(result) new(result)
proc newJObject*(): PJsonNode = proc newJObject*(): JsonNode =
## Creates a new `JObject PJsonNode` ## Creates a new `JObject PJsonNode`
new(result) new(result)
result.kind = JObject result.kind = JObject
result.fields = @[] result.fields = @[]
proc newJArray*(): PJsonNode = proc newJArray*(): JsonNode =
## Creates a new `JArray PJsonNode` ## Creates a new `JArray PJsonNode`
new(result) new(result)
result.kind = JArray result.kind = JArray
result.elems = @[] result.elems = @[]
proc `%`*(s: string): PJsonNode = proc `%`*(s: string): JsonNode =
## Generic constructor for JSON data. Creates a new `JString PJsonNode`. ## Generic constructor for JSON data. Creates a new `JString PJsonNode`.
new(result) new(result)
result.kind = JString result.kind = JString
result.str = s result.str = s
proc `%`*(n: BiggestInt): PJsonNode = proc `%`*(n: BiggestInt): JsonNode =
## Generic constructor for JSON data. Creates a new `JInt PJsonNode`. ## Generic constructor for JSON data. Creates a new `JInt PJsonNode`.
new(result) new(result)
result.kind = JInt result.kind = JInt
result.num = n result.num = n
proc `%`*(n: float): PJsonNode = proc `%`*(n: float): JsonNode =
## Generic constructor for JSON data. Creates a new `JFloat PJsonNode`. ## Generic constructor for JSON data. Creates a new `JFloat PJsonNode`.
new(result) new(result)
result.kind = JFloat result.kind = JFloat
result.fnum = n result.fnum = n
proc `%`*(b: bool): PJsonNode = proc `%`*(b: bool): JsonNode =
## Generic constructor for JSON data. Creates a new `JBool PJsonNode`. ## Generic constructor for JSON data. Creates a new `JBool PJsonNode`.
new(result) new(result)
result.kind = JBool result.kind = JBool
result.bval = b result.bval = b
proc `%`*(keyVals: openArray[tuple[key: string, val: PJsonNode]]): PJsonNode = proc `%`*(keyVals: openArray[tuple[key: string, val: JsonNode]]): JsonNode =
## Generic constructor for JSON data. Creates a new `JObject PJsonNode` ## Generic constructor for JSON data. Creates a new `JObject PJsonNode`
new(result) new(result)
result.kind = JObject result.kind = JObject
newSeq(result.fields, keyVals.len) newSeq(result.fields, keyVals.len)
for i, p in pairs(keyVals): result.fields[i] = p for i, p in pairs(keyVals): result.fields[i] = p
proc `%`*(elements: openArray[PJsonNode]): PJsonNode = proc `%`*(elements: openArray[JsonNode]): JsonNode =
## Generic constructor for JSON data. Creates a new `JArray PJsonNode` ## Generic constructor for JSON data. Creates a new `JArray PJsonNode`
new(result) new(result)
result.kind = JArray result.kind = JArray
newSeq(result.elems, elements.len) newSeq(result.elems, elements.len)
for i, p in pairs(elements): result.elems[i] = p for i, p in pairs(elements): result.elems[i] = p
proc `==`* (a,b: PJsonNode): bool = proc `==`* (a,b: JsonNode): bool =
## Check two nodes for equality ## Check two nodes for equality
if a.isNil: if a.isNil:
if b.isNil: return true if b.isNil: return true
@ -649,7 +649,7 @@ proc `==`* (a,b: PJsonNode): bool =
of JObject: of JObject:
a.fields == b.fields a.fields == b.fields
proc hash* (n:PJsonNode): THash = proc hash* (n:JsonNode): THash =
## Compute the hash for a JSON node ## Compute the hash for a JSON node
case n.kind case n.kind
of JArray: of JArray:
@ -667,7 +667,7 @@ proc hash* (n:PJsonNode): THash =
of JNull: of JNull:
result = hash(0) result = hash(0)
proc len*(n: PJsonNode): int = proc len*(n: JsonNode): int =
## If `n` is a `JArray`, it returns the number of elements. ## If `n` is a `JArray`, it returns the number of elements.
## If `n` is a `JObject`, it returns the number of pairs. ## If `n` is a `JObject`, it returns the number of pairs.
## Else it returns 0. ## Else it returns 0.
@ -676,7 +676,7 @@ proc len*(n: PJsonNode): int =
of JObject: result = n.fields.len of JObject: result = n.fields.len
else: discard else: discard
proc `[]`*(node: PJsonNode, name: string): PJsonNode = proc `[]`*(node: JsonNode, name: string): JsonNode =
## Gets a field from a `JObject`, which must not be nil. ## Gets a field from a `JObject`, which must not be nil.
## If the value at `name` does not exist, returns nil ## If the value at `name` does not exist, returns nil
assert(not isNil(node)) assert(not isNil(node))
@ -686,35 +686,35 @@ proc `[]`*(node: PJsonNode, name: string): PJsonNode =
return item return item
return nil return nil
proc `[]`*(node: PJsonNode, index: int): PJsonNode = proc `[]`*(node: JsonNode, index: int): JsonNode =
## Gets the node at `index` in an Array. Result is undefined if `index` ## Gets the node at `index` in an Array. Result is undefined if `index`
## is out of bounds ## is out of bounds
assert(not isNil(node)) assert(not isNil(node))
assert(node.kind == JArray) assert(node.kind == JArray)
return node.elems[index] return node.elems[index]
proc hasKey*(node: PJsonNode, key: string): bool = proc hasKey*(node: JsonNode, key: string): bool =
## Checks if `key` exists in `node`. ## Checks if `key` exists in `node`.
assert(node.kind == JObject) assert(node.kind == JObject)
for k, item in items(node.fields): for k, item in items(node.fields):
if k == key: return true if k == key: return true
proc existsKey*(node: PJsonNode, key: string): bool {.deprecated.} = node.hasKey(key) proc existsKey*(node: JsonNode, key: string): bool {.deprecated.} = node.hasKey(key)
## Deprecated for `hasKey` ## Deprecated for `hasKey`
proc add*(father, child: PJsonNode) = proc add*(father, child: JsonNode) =
## Adds `child` to a JArray node `father`. ## Adds `child` to a JArray node `father`.
assert father.kind == JArray assert father.kind == JArray
father.elems.add(child) father.elems.add(child)
proc add*(obj: PJsonNode, key: string, val: PJsonNode) = proc add*(obj: JsonNode, key: string, val: JsonNode) =
## Adds ``(key, val)`` pair to the JObject node `obj`. For speed ## Adds ``(key, val)`` pair to the JObject node `obj`. For speed
## reasons no check for duplicate keys is performed! ## reasons no check for duplicate keys is performed!
## But ``[]=`` performs the check. ## But ``[]=`` performs the check.
assert obj.kind == JObject assert obj.kind == JObject
obj.fields.add((key, val)) obj.fields.add((key, val))
proc `[]=`*(obj: PJsonNode, key: string, val: PJsonNode) = proc `[]=`*(obj: JsonNode, key: string, val: JsonNode) =
## Sets a field from a `JObject`. Performs a check for duplicate keys. ## Sets a field from a `JObject`. Performs a check for duplicate keys.
assert(obj.kind == JObject) assert(obj.kind == JObject)
for i in 0..obj.fields.len-1: for i in 0..obj.fields.len-1:
@ -723,14 +723,14 @@ proc `[]=`*(obj: PJsonNode, key: string, val: PJsonNode) =
return return
obj.fields.add((key, val)) obj.fields.add((key, val))
proc `{}`*(node: PJsonNode, key: string): PJsonNode = proc `{}`*(node: JsonNode, key: string): JsonNode =
## Transverses the node and gets the given value. If any of the ## Transverses the node and gets the given value. If any of the
## names does not exist, returns nil ## names does not exist, returns nil
result = node result = node
if isNil(node): return nil if isNil(node): return nil
result = result[key] result = result[key]
proc `{}=`*(node: PJsonNode, names: varargs[string], value: PJsonNode) = proc `{}=`*(node: JsonNode, names: varargs[string], value: JsonNode) =
## Transverses the node and tries to set the value at the given location ## Transverses the node and tries to set the value at the given location
## to `value` If any of the names are missing, they are added ## to `value` If any of the names are missing, they are added
var node = node var node = node
@ -740,7 +740,7 @@ proc `{}=`*(node: PJsonNode, names: varargs[string], value: PJsonNode) =
node = node[names[i]] node = node[names[i]]
node[names[names.len-1]] = value node[names[names.len-1]] = value
proc delete*(obj: PJsonNode, key: string) = proc delete*(obj: JsonNode, key: string) =
## Deletes ``obj[key]`` preserving the order of the other (key, value)-pairs. ## Deletes ``obj[key]`` preserving the order of the other (key, value)-pairs.
assert(obj.kind == JObject) assert(obj.kind == JObject)
for i in 0..obj.fields.len-1: for i in 0..obj.fields.len-1:
@ -749,7 +749,7 @@ proc delete*(obj: PJsonNode, key: string) =
return return
raise newException(IndexError, "key not in object") raise newException(IndexError, "key not in object")
proc copy*(p: PJsonNode): PJsonNode = proc copy*(p: JsonNode): JsonNode =
## Performs a deep copy of `a`. ## Performs a deep copy of `a`.
case p.kind case p.kind
of JString: of JString:
@ -800,7 +800,7 @@ proc escapeJson*(s: string): string =
result.add(toHex(r, 4)) result.add(toHex(r, 4))
result.add("\"") result.add("\"")
proc toPretty(result: var string, node: PJsonNode, indent = 2, ml = true, proc toPretty(result: var string, node: JsonNode, indent = 2, ml = true,
lstArr = false, currIndent = 0) = lstArr = false, currIndent = 0) =
case node.kind case node.kind
of JObject: of JObject:
@ -855,34 +855,34 @@ proc toPretty(result: var string, node: PJsonNode, indent = 2, ml = true,
if lstArr: result.indent(currIndent) if lstArr: result.indent(currIndent)
result.add("null") result.add("null")
proc pretty*(node: PJsonNode, indent = 2): string = proc pretty*(node: JsonNode, indent = 2): string =
## Converts `node` to its JSON Representation, with indentation and ## Converts `node` to its JSON Representation, with indentation and
## on multiple lines. ## on multiple lines.
result = "" result = ""
toPretty(result, node, indent) toPretty(result, node, indent)
proc `$`*(node: PJsonNode): string = proc `$`*(node: JsonNode): string =
## Converts `node` to its JSON Representation on one line. ## Converts `node` to its JSON Representation on one line.
result = "" result = ""
toPretty(result, node, 1, false) toPretty(result, node, 1, false)
iterator items*(node: PJsonNode): PJsonNode = iterator items*(node: JsonNode): JsonNode =
## Iterator for the items of `node`. `node` has to be a JArray. ## Iterator for the items of `node`. `node` has to be a JArray.
assert node.kind == JArray assert node.kind == JArray
for i in items(node.elems): for i in items(node.elems):
yield i yield i
iterator pairs*(node: PJsonNode): tuple[key: string, val: PJsonNode] = iterator pairs*(node: JsonNode): tuple[key: string, val: JsonNode] =
## Iterator for the child elements of `node`. `node` has to be a JObject. ## Iterator for the child elements of `node`. `node` has to be a JObject.
assert node.kind == JObject assert node.kind == JObject
for key, val in items(node.fields): for key, val in items(node.fields):
yield (key, val) yield (key, val)
proc eat(p: var TJsonParser, tok: TTokKind) = proc eat(p: var JsonParser, tok: TTokKind) =
if p.tok == tok: discard getTok(p) if p.tok == tok: discard getTok(p)
else: raiseParseErr(p, tokToStr[tok]) else: raiseParseErr(p, tokToStr[tok])
proc parseJson(p: var TJsonParser): PJsonNode = proc parseJson(p: var JsonParser): JsonNode =
## Parses JSON from a JSON Parser `p`. ## Parses JSON from a JSON Parser `p`.
case p.tok case p.tok
of tkString: of tkString:
@ -931,20 +931,20 @@ proc parseJson(p: var TJsonParser): PJsonNode =
raiseParseErr(p, "{") raiseParseErr(p, "{")
when not defined(js): when not defined(js):
proc parseJson*(s: PStream, filename: string): PJsonNode = proc parseJson*(s: Stream, filename: string): JsonNode =
## Parses from a stream `s` into a `PJsonNode`. `filename` is only needed ## Parses from a stream `s` into a `PJsonNode`. `filename` is only needed
## for nice error messages. ## for nice error messages.
var p: TJsonParser var p: JsonParser
p.open(s, filename) p.open(s, filename)
discard getTok(p) # read first token discard getTok(p) # read first token
result = p.parseJson() result = p.parseJson()
p.close() p.close()
proc parseJson*(buffer: string): PJsonNode = proc parseJson*(buffer: string): JsonNode =
## Parses JSON from `buffer`. ## Parses JSON from `buffer`.
result = parseJson(newStringStream(buffer), "input") result = parseJson(newStringStream(buffer), "input")
proc parseFile*(filename: string): PJsonNode = proc parseFile*(filename: string): JsonNode =
## Parses `file` into a `PJsonNode`. ## Parses `file` into a `PJsonNode`.
var stream = newFileStream(filename, fmRead) var stream = newFileStream(filename, fmRead)
if stream == nil: if stream == nil:
@ -1062,8 +1062,8 @@ when isMainModule:
echo(pretty(parsed2)) echo(pretty(parsed2))
try: try:
echo(parsed["key2"][12123]) echo(parsed["key2"][12123])
raise newException(EInvalidValue, "That line was expected to fail") raise newException(ValueError, "That line was expected to fail")
except EInvalidIndex: echo() except IndexError: echo()
let testJson = parseJson"""{ "a": [1, 2, 3, 4], "b": "asd" }""" let testJson = parseJson"""{ "a": [1, 2, 3, 4], "b": "asd" }"""
# nil passthrough # nil passthrough
@ -1075,12 +1075,12 @@ when isMainModule:
try: try:
let a = testJson["a"][9] let a = testJson["a"][9]
assert(false, "EInvalidIndex not thrown") assert(false, "EInvalidIndex not thrown")
except EInvalidIndex: except IndexError:
discard discard
try: try:
let a = testJson["a"][-1] let a = testJson["a"][-1]
assert(false, "EInvalidIndex not thrown") assert(false, "EInvalidIndex not thrown")
except EInvalidIndex: except IndexError:
discard discard
try: try:
assert(testJson["a"][0].num == 1, "Index doesn't correspond to its value") assert(testJson["a"][0].num == 1, "Index doesn't correspond to its value")

View file

@ -216,7 +216,7 @@ when not defined(windows):
gFG = 0 gFG = 0
gBG = 0 gBG = 0
proc setStyle*(style: set[TStyle]) = proc setStyle*(style: set[Style]) =
## sets the terminal style ## sets the terminal style
when defined(windows): when defined(windows):
var a = 0'i16 var a = 0'i16
@ -229,7 +229,7 @@ proc setStyle*(style: set[TStyle]) =
for s in items(style): for s in items(style):
stdout.write("\e[" & $ord(s) & 'm') stdout.write("\e[" & $ord(s) & 'm')
proc writeStyled*(txt: string, style: set[TStyle] = {styleBright}) = proc writeStyled*(txt: string, style: set[Style] = {styleBright}) =
## writes the text `txt` in a given `style`. ## writes the text `txt` in a given `style`.
when defined(windows): when defined(windows):
var old = getAttributes() var old = getAttributes()

View file

@ -58,7 +58,7 @@ template suite*(name: expr, body: stmt): stmt {.immediate, dirty.} =
proc testDone(name: string, s: TestStatus) = proc testDone(name: string, s: TestStatus) =
if s == FAILED: if s == FAILED:
program_result += 1 programResult += 1
if OutputLevel != PRINT_NONE and (OutputLevel == PRINT_ALL or s == FAILED): if OutputLevel != PRINT_NONE and (OutputLevel == PRINT_ALL or s == FAILED):
template rawPrint() = echo("[", $s, "] ", name, "\n") template rawPrint() = echo("[", $s, "] ", name, "\n")
@ -105,7 +105,7 @@ template fail* =
when declared(TestStatusIMPL): when declared(TestStatusIMPL):
TestStatusIMPL = FAILED TestStatusIMPL = FAILED
else: else:
program_result += 1 programResult += 1
checkpoints = @[] checkpoints = @[]