[backport] run nimpretty on parsers
This commit is contained in:
parent
6c994b2498
commit
b17ed2ca9c
11 changed files with 207 additions and 193 deletions
|
|
@ -52,7 +52,7 @@
|
||||||
import strutils, streams, parsexml, xmltree, unicode, strtabs
|
import strutils, streams, parsexml, xmltree, unicode, strtabs
|
||||||
|
|
||||||
type
|
type
|
||||||
HtmlTag* = enum ## list of all supported HTML tags; order will always be
|
HtmlTag* = enum ## list of all supported HTML tags; order will always be
|
||||||
## alphabetically
|
## alphabetically
|
||||||
tagUnknown, ## unknown HTML element
|
tagUnknown, ## unknown HTML element
|
||||||
tagA, ## the HTML ``a`` element
|
tagA, ## the HTML ``a`` element
|
||||||
|
|
@ -1945,7 +1945,8 @@ proc untilElementEnd(x: var XmlParser, result: XmlNode,
|
||||||
adderr(expected(x, result))
|
adderr(expected(x, result))
|
||||||
# this seems to do better match error corrections in browsers:
|
# this seems to do better match error corrections in browsers:
|
||||||
while x.kind in {xmlElementEnd, xmlWhitespace}:
|
while x.kind in {xmlElementEnd, xmlWhitespace}:
|
||||||
if x.kind == xmlElementEnd and cmpIgnoreCase(x.elemName, result.tag) == 0:
|
if x.kind == xmlElementEnd and cmpIgnoreCase(x.elemName,
|
||||||
|
result.tag) == 0:
|
||||||
break
|
break
|
||||||
next(x)
|
next(x)
|
||||||
next(x)
|
next(x)
|
||||||
|
|
|
||||||
|
|
@ -406,7 +406,7 @@ macro `%*`*(x: untyped): untyped =
|
||||||
## `%` for every element.
|
## `%` for every element.
|
||||||
result = toJson(x)
|
result = toJson(x)
|
||||||
|
|
||||||
proc `==`* (a, b: JsonNode): 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
|
||||||
|
|
@ -428,13 +428,13 @@ proc `==`* (a, b: JsonNode): bool =
|
||||||
of JArray:
|
of JArray:
|
||||||
result = a.elems == b.elems
|
result = a.elems == b.elems
|
||||||
of JObject:
|
of JObject:
|
||||||
# we cannot use OrderedTable's equality here as
|
# we cannot use OrderedTable's equality here as
|
||||||
# the order does not matter for equality here.
|
# the order does not matter for equality here.
|
||||||
if a.fields.len != b.fields.len: return false
|
if a.fields.len != b.fields.len: return false
|
||||||
for key, val in a.fields:
|
for key, val in a.fields:
|
||||||
if not b.fields.hasKey(key): return false
|
if not b.fields.hasKey(key): return false
|
||||||
if b.fields[key] != val: return false
|
if b.fields[key] != val: return false
|
||||||
result = true
|
result = true
|
||||||
|
|
||||||
proc hash*(n: OrderedTable[string, JsonNode]): Hash {.noSideEffect.}
|
proc hash*(n: OrderedTable[string, JsonNode]): Hash {.noSideEffect.}
|
||||||
|
|
||||||
|
|
@ -502,7 +502,8 @@ proc contains*(node: JsonNode, val: JsonNode): bool =
|
||||||
assert(node.kind == JArray)
|
assert(node.kind == JArray)
|
||||||
find(node.elems, val) >= 0
|
find(node.elems, val) >= 0
|
||||||
|
|
||||||
proc existsKey*(node: JsonNode, key: string): bool {.deprecated: "use 'hasKey' instead".} =
|
proc existsKey*(node: JsonNode, key: string): bool {.
|
||||||
|
deprecated: "use 'hasKey' instead".} =
|
||||||
node.hasKey(key)
|
node.hasKey(key)
|
||||||
|
|
||||||
proc `{}`*(node: JsonNode, keys: varargs[string]): JsonNode =
|
proc `{}`*(node: JsonNode, keys: varargs[string]): JsonNode =
|
||||||
|
|
@ -538,7 +539,8 @@ proc getOrDefault*(node: JsonNode, key: string): JsonNode =
|
||||||
if not isNil(node) and node.kind == JObject:
|
if not isNil(node) and node.kind == JObject:
|
||||||
result = node.fields.getOrDefault(key)
|
result = node.fields.getOrDefault(key)
|
||||||
|
|
||||||
template simpleGetOrDefault*{`{}`(node, [key])}(node: JsonNode, key: string): JsonNode = node.getOrDefault(key)
|
template simpleGetOrDefault*{`{}`(node, [key])}(node: JsonNode,
|
||||||
|
key: string): JsonNode = node.getOrDefault(key)
|
||||||
|
|
||||||
proc `{}=`*(node: JsonNode, keys: varargs[string], value: JsonNode) =
|
proc `{}=`*(node: JsonNode, keys: varargs[string], value: JsonNode) =
|
||||||
## Traverses the node and tries to set the value at the given location
|
## Traverses the node and tries to set the value at the given location
|
||||||
|
|
@ -691,7 +693,7 @@ proc pretty*(node: JsonNode, indent = 2): string =
|
||||||
## Similar to prettyprint in Python.
|
## Similar to prettyprint in Python.
|
||||||
runnableExamples:
|
runnableExamples:
|
||||||
let j = %* {"name": "Isaac", "books": ["Robot Dreams"],
|
let j = %* {"name": "Isaac", "books": ["Robot Dreams"],
|
||||||
"details": {"age":35, "pi":3.1415}}
|
"details": {"age": 35, "pi": 3.1415}}
|
||||||
doAssert pretty(j) == """
|
doAssert pretty(j) == """
|
||||||
{
|
{
|
||||||
"name": "Isaac",
|
"name": "Isaac",
|
||||||
|
|
@ -721,14 +723,14 @@ proc toUgly*(result: var string, node: JsonNode) =
|
||||||
result.add "["
|
result.add "["
|
||||||
for child in node.elems:
|
for child in node.elems:
|
||||||
if comma: result.add ","
|
if comma: result.add ","
|
||||||
else: comma = true
|
else: comma = true
|
||||||
result.toUgly child
|
result.toUgly child
|
||||||
result.add "]"
|
result.add "]"
|
||||||
of JObject:
|
of JObject:
|
||||||
result.add "{"
|
result.add "{"
|
||||||
for key, value in pairs(node.fields):
|
for key, value in pairs(node.fields):
|
||||||
if comma: result.add ","
|
if comma: result.add ","
|
||||||
else: comma = true
|
else: comma = true
|
||||||
key.escapeJson(result)
|
key.escapeJson(result)
|
||||||
result.add ":"
|
result.add ":"
|
||||||
result.toUgly value
|
result.toUgly value
|
||||||
|
|
@ -1331,7 +1333,8 @@ proc createConstructor(typeSym, jsonNode: NimNode): NimNode =
|
||||||
(
|
(
|
||||||
var map = `tableInit`[`tableKeyType`, `tableValueType`]();
|
var map = `tableInit`[`tableKeyType`, `tableValueType`]();
|
||||||
verifyJsonKind(`jsonNode`, {JObject}, astToStr(`jsonNode`));
|
verifyJsonKind(`jsonNode`, {JObject}, astToStr(`jsonNode`));
|
||||||
for `forLoopKey` in keys(`jsonNode`.fields): map[`forLoopKey`] = `constructorNode`;
|
for `forLoopKey` in keys(`jsonNode`.fields): map[
|
||||||
|
`forLoopKey`] = `constructorNode`;
|
||||||
map
|
map
|
||||||
)
|
)
|
||||||
of "ref":
|
of "ref":
|
||||||
|
|
@ -1374,7 +1377,8 @@ proc createConstructor(typeSym, jsonNode: NimNode): NimNode =
|
||||||
(
|
(
|
||||||
var list: `typeSym`;
|
var list: `typeSym`;
|
||||||
verifyJsonKind(`jsonNode`, {JArray}, astToStr(`jsonNode`));
|
verifyJsonKind(`jsonNode`, {JArray}, astToStr(`jsonNode`));
|
||||||
for `forLoopI` in 0 ..< `jsonNode`.len: list[`forLoopI`] =`constructorNode`;
|
for `forLoopI` in 0 ..< `jsonNode`.len: list[
|
||||||
|
`forLoopI`] = `constructorNode`;
|
||||||
list
|
list
|
||||||
)
|
)
|
||||||
of "tuple":
|
of "tuple":
|
||||||
|
|
@ -1640,11 +1644,11 @@ when isMainModule:
|
||||||
except:
|
except:
|
||||||
doAssert(false, "IndexError thrown for valid index")
|
doAssert(false, "IndexError thrown for valid index")
|
||||||
|
|
||||||
doAssert(testJson{"b"}.getStr()=="asd", "Couldn't fetch a singly nested key with {}")
|
doAssert(testJson{"b"}.getStr() == "asd", "Couldn't fetch a singly nested key with {}")
|
||||||
doAssert(isNil(testJson{"nonexistent"}), "Non-existent keys should return nil")
|
doAssert(isNil(testJson{"nonexistent"}), "Non-existent keys should return nil")
|
||||||
doAssert(isNil(testJson{"a", "b"}), "Indexing through a list should return nil")
|
doAssert(isNil(testJson{"a", "b"}), "Indexing through a list should return nil")
|
||||||
doAssert(isNil(testJson{"a", "b"}), "Indexing through a list should return nil")
|
doAssert(isNil(testJson{"a", "b"}), "Indexing through a list should return nil")
|
||||||
doAssert(testJson{"a"}==parseJson"[1, 2, 3, 4]", "Didn't return a non-JObject when there was one to be found")
|
doAssert(testJson{"a"} == parseJson"[1, 2, 3, 4]", "Didn't return a non-JObject when there was one to be found")
|
||||||
doAssert(isNil(parseJson("[1, 2, 3]"){"foo"}), "Indexing directly into a list should return nil")
|
doAssert(isNil(parseJson("[1, 2, 3]"){"foo"}), "Indexing directly into a list should return nil")
|
||||||
|
|
||||||
# Generator:
|
# Generator:
|
||||||
|
|
@ -1669,10 +1673,10 @@ when isMainModule:
|
||||||
const hisAge = 31
|
const hisAge = 31
|
||||||
|
|
||||||
var j3 = %*
|
var j3 = %*
|
||||||
[ { "name": "John"
|
[ {"name": "John"
|
||||||
, "age": herAge
|
, "age": herAge
|
||||||
}
|
}
|
||||||
, { "name": "Susan"
|
, {"name": "Susan"
|
||||||
, "age": hisAge
|
, "age": hisAge
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
@ -1708,7 +1712,8 @@ when isMainModule:
|
||||||
except IndexError: doAssert(true)
|
except IndexError: doAssert(true)
|
||||||
|
|
||||||
var parsed2 = parseFile("tests/testdata/jsontest2.json")
|
var parsed2 = parseFile("tests/testdata/jsontest2.json")
|
||||||
doAssert(parsed2{"repository", "description"}.str=="IRC Library for Haskell", "Couldn't fetch via multiply nested key using {}")
|
doAssert(parsed2{"repository", "description"}.str ==
|
||||||
|
"IRC Library for Haskell", "Couldn't fetch via multiply nested key using {}")
|
||||||
|
|
||||||
doAssert escapeJsonUnquoted("\10Foo🎃barÄ") == "\\nFoo🎃barÄ"
|
doAssert escapeJsonUnquoted("\10Foo🎃barÄ") == "\\nFoo🎃barÄ"
|
||||||
doAssert escapeJsonUnquoted("\0\7\20") == "\\u0000\\u0007\\u0014" # for #7887
|
doAssert escapeJsonUnquoted("\0\7\20") == "\\u0000\\u0007\\u0014" # for #7887
|
||||||
|
|
@ -1752,15 +1757,15 @@ when isMainModule:
|
||||||
# Generate constructors for range[T] types
|
# Generate constructors for range[T] types
|
||||||
block:
|
block:
|
||||||
type
|
type
|
||||||
Q1 = range[0'u8 .. 50'u8]
|
Q1 = range[0'u8 .. 50'u8]
|
||||||
Q2 = range[0'u16 .. 50'u16]
|
Q2 = range[0'u16 .. 50'u16]
|
||||||
Q3 = range[0'u32 .. 50'u32]
|
Q3 = range[0'u32 .. 50'u32]
|
||||||
Q4 = range[0'i8 .. 50'i8]
|
Q4 = range[0'i8 .. 50'i8]
|
||||||
Q5 = range[0'i16 .. 50'i16]
|
Q5 = range[0'i16 .. 50'i16]
|
||||||
Q6 = range[0'i32 .. 50'i32]
|
Q6 = range[0'i32 .. 50'i32]
|
||||||
Q7 = range[0'f32 .. 50'f32]
|
Q7 = range[0'f32 .. 50'f32]
|
||||||
Q8 = range[0'f64 .. 50'f64]
|
Q8 = range[0'f64 .. 50'f64]
|
||||||
Q9 = range[0 .. 50]
|
Q9 = range[0 .. 50]
|
||||||
|
|
||||||
X = object
|
X = object
|
||||||
m1: Q1
|
m1: Q1
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ import
|
||||||
strutils, streams
|
strutils, streams
|
||||||
|
|
||||||
const
|
const
|
||||||
EndOfFile* = '\0' ## end of file marker
|
EndOfFile* = '\0' ## end of file marker
|
||||||
NewLines* = {'\c', '\L'}
|
NewLines* = {'\c', '\L'}
|
||||||
|
|
||||||
# Buffer handling:
|
# Buffer handling:
|
||||||
|
|
@ -27,13 +27,13 @@ const
|
||||||
type
|
type
|
||||||
BaseLexer* = object of RootObj ## the base lexer. Inherit your lexer from
|
BaseLexer* = object of RootObj ## the base lexer. Inherit your lexer from
|
||||||
## this object.
|
## this object.
|
||||||
bufpos*: int ## the current position within the buffer
|
bufpos*: int ## the current position within the buffer
|
||||||
buf*: string ## the buffer itself
|
buf*: string ## the buffer itself
|
||||||
input: Stream ## the input stream
|
input: Stream ## the input stream
|
||||||
lineNumber*: int ## the current line number
|
lineNumber*: int ## the current line number
|
||||||
sentinel: int
|
sentinel: int
|
||||||
lineStart: int # index of last line start in buffer
|
lineStart: int # index of last line start in buffer
|
||||||
offsetBase*: int # use ``offsetBase + bufpos`` to get the offset
|
offsetBase*: int # use ``offsetBase + bufpos`` to get the offset
|
||||||
refillChars: set[char]
|
refillChars: set[char]
|
||||||
|
|
||||||
proc close*(L: var BaseLexer) =
|
proc close*(L: var BaseLexer) =
|
||||||
|
|
@ -65,11 +65,11 @@ proc fillBuffer(L: var BaseLexer) =
|
||||||
charsRead = L.input.readDataStr(L.buf, toCopy ..< toCopy + L.sentinel + 1)
|
charsRead = L.input.readDataStr(L.buf, toCopy ..< toCopy + L.sentinel + 1)
|
||||||
s = toCopy + charsRead
|
s = toCopy + charsRead
|
||||||
if charsRead < L.sentinel + 1:
|
if charsRead < L.sentinel + 1:
|
||||||
L.buf[s] = EndOfFile # set end marker
|
L.buf[s] = EndOfFile # set end marker
|
||||||
L.sentinel = s
|
L.sentinel = s
|
||||||
else:
|
else:
|
||||||
# compute sentinel:
|
# compute sentinel:
|
||||||
dec(s) # BUGFIX (valgrind)
|
dec(s) # BUGFIX (valgrind)
|
||||||
while true:
|
while true:
|
||||||
assert(s < L.buf.len)
|
assert(s < L.buf.len)
|
||||||
while s >= 0 and L.buf[s] notin L.refillChars: dec(s)
|
while s >= 0 and L.buf[s] notin L.refillChars: dec(s)
|
||||||
|
|
@ -92,7 +92,7 @@ proc fillBuffer(L: var BaseLexer) =
|
||||||
proc fillBaseLexer(L: var BaseLexer, pos: int): int =
|
proc fillBaseLexer(L: var BaseLexer, pos: int): int =
|
||||||
assert(pos <= L.sentinel)
|
assert(pos <= L.sentinel)
|
||||||
if pos < L.sentinel:
|
if pos < L.sentinel:
|
||||||
result = pos + 1 # nothing to do
|
result = pos + 1 # nothing to do
|
||||||
else:
|
else:
|
||||||
fillBuffer(L)
|
fillBuffer(L)
|
||||||
L.offsetBase += pos
|
L.offsetBase += pos
|
||||||
|
|
@ -142,7 +142,7 @@ proc open*(L: var BaseLexer, input: Stream, bufLen: int = 8192;
|
||||||
L.buf = newString(bufLen)
|
L.buf = newString(bufLen)
|
||||||
L.sentinel = bufLen - 1
|
L.sentinel = bufLen - 1
|
||||||
L.lineStart = 0
|
L.lineStart = 0
|
||||||
L.lineNumber = 1 # lines start at 1
|
L.lineNumber = 1 # lines start at 1
|
||||||
fillBuffer(L)
|
fillBuffer(L)
|
||||||
skipUtf8Bom(L)
|
skipUtf8Bom(L)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -115,34 +115,34 @@ include "system/inclrtl"
|
||||||
|
|
||||||
type
|
type
|
||||||
CfgEventKind* = enum ## enumeration of all events that may occur when parsing
|
CfgEventKind* = enum ## enumeration of all events that may occur when parsing
|
||||||
cfgEof, ## end of file reached
|
cfgEof, ## end of file reached
|
||||||
cfgSectionStart, ## a ``[section]`` has been parsed
|
cfgSectionStart, ## a ``[section]`` has been parsed
|
||||||
cfgKeyValuePair, ## a ``key=value`` pair has been detected
|
cfgKeyValuePair, ## a ``key=value`` pair has been detected
|
||||||
cfgOption, ## a ``--key=value`` command line option
|
cfgOption, ## a ``--key=value`` command line option
|
||||||
cfgError ## an error occurred during parsing
|
cfgError ## an error occurred during parsing
|
||||||
|
|
||||||
CfgEvent* = object of RootObj ## describes a parsing event
|
CfgEvent* = object of RootObj ## describes a parsing event
|
||||||
case kind*: CfgEventKind ## the kind of the event
|
case kind*: CfgEventKind ## the kind of the event
|
||||||
of cfgEof: nil
|
of cfgEof: nil
|
||||||
of cfgSectionStart:
|
of cfgSectionStart:
|
||||||
section*: string ## `section` contains the name of the
|
section*: string ## `section` contains the name of the
|
||||||
## parsed section start (syntax: ``[section]``)
|
## parsed section start (syntax: ``[section]``)
|
||||||
of cfgKeyValuePair, cfgOption:
|
of cfgKeyValuePair, cfgOption:
|
||||||
key*, value*: string ## contains the (key, value) pair if an option
|
key*, value*: string ## contains the (key, value) pair if an option
|
||||||
## of the form ``--key: value`` or an ordinary
|
## of the form ``--key: value`` or an ordinary
|
||||||
## ``key= value`` pair has been parsed.
|
## ``key= value`` pair has been parsed.
|
||||||
## ``value==""`` if it was not specified in the
|
## ``value==""`` if it was not specified in the
|
||||||
## configuration file.
|
## configuration file.
|
||||||
of cfgError: ## the parser encountered an error: `msg`
|
of cfgError: ## the parser encountered an error: `msg`
|
||||||
msg*: string ## contains the error message. No exceptions
|
msg*: string ## contains the error message. No exceptions
|
||||||
## are thrown if a parse error occurs.
|
## are thrown if a parse error occurs.
|
||||||
|
|
||||||
TokKind = enum
|
TokKind = enum
|
||||||
tkInvalid, tkEof,
|
tkInvalid, tkEof,
|
||||||
tkSymbol, tkEquals, tkColon, tkBracketLe, tkBracketRi, tkDashDash
|
tkSymbol, tkEquals, tkColon, tkBracketLe, tkBracketRi, tkDashDash
|
||||||
Token = object # a token
|
Token = object # a token
|
||||||
kind: TokKind # the type of the token
|
kind: TokKind # the type of the token
|
||||||
literal: string # the parsed (string) literal
|
literal: string # the parsed (string) literal
|
||||||
|
|
||||||
CfgParser* = object of BaseLexer ## the parser object.
|
CfgParser* = object of BaseLexer ## the parser object.
|
||||||
tok: Token
|
tok: Token
|
||||||
|
|
@ -203,7 +203,7 @@ proc handleDecChars(c: var CfgParser, xi: var int) =
|
||||||
inc(c.bufpos)
|
inc(c.bufpos)
|
||||||
|
|
||||||
proc getEscapedChar(c: var CfgParser, tok: var Token) =
|
proc getEscapedChar(c: var CfgParser, tok: var Token) =
|
||||||
inc(c.bufpos) # skip '\'
|
inc(c.bufpos) # skip '\'
|
||||||
case c.buf[c.bufpos]
|
case c.buf[c.bufpos]
|
||||||
of 'n', 'N':
|
of 'n', 'N':
|
||||||
add(tok.literal, "\n")
|
add(tok.literal, "\n")
|
||||||
|
|
@ -258,11 +258,11 @@ proc handleCRLF(c: var CfgParser, pos: int): int =
|
||||||
else: result = pos
|
else: result = pos
|
||||||
|
|
||||||
proc getString(c: var CfgParser, tok: var Token, rawMode: bool) =
|
proc getString(c: var CfgParser, tok: var Token, rawMode: bool) =
|
||||||
var pos = c.bufpos + 1 # skip "
|
var pos = c.bufpos + 1 # skip "
|
||||||
tok.kind = tkSymbol
|
tok.kind = tkSymbol
|
||||||
if (c.buf[pos] == '"') and (c.buf[pos + 1] == '"'):
|
if (c.buf[pos] == '"') and (c.buf[pos + 1] == '"'):
|
||||||
# long string literal:
|
# long string literal:
|
||||||
inc(pos, 2) # skip ""
|
inc(pos, 2) # skip ""
|
||||||
# skip leading newline:
|
# skip leading newline:
|
||||||
pos = handleCRLF(c, pos)
|
pos = handleCRLF(c, pos)
|
||||||
while true:
|
while true:
|
||||||
|
|
@ -280,13 +280,13 @@ proc getString(c: var CfgParser, tok: var Token, rawMode: bool) =
|
||||||
else:
|
else:
|
||||||
add(tok.literal, c.buf[pos])
|
add(tok.literal, c.buf[pos])
|
||||||
inc(pos)
|
inc(pos)
|
||||||
c.bufpos = pos + 3 # skip the three """
|
c.bufpos = pos + 3 # skip the three """
|
||||||
else:
|
else:
|
||||||
# ordinary string literal
|
# ordinary string literal
|
||||||
while true:
|
while true:
|
||||||
var ch = c.buf[pos]
|
var ch = c.buf[pos]
|
||||||
if ch == '"':
|
if ch == '"':
|
||||||
inc(pos) # skip '"'
|
inc(pos) # skip '"'
|
||||||
break
|
break
|
||||||
if ch in {'\c', '\L', lexbase.EndOfFile}:
|
if ch in {'\c', '\L', lexbase.EndOfFile}:
|
||||||
tok.kind = tkInvalid
|
tok.kind = tkInvalid
|
||||||
|
|
@ -320,7 +320,7 @@ proc skip(c: var CfgParser) =
|
||||||
of '\c', '\L':
|
of '\c', '\L':
|
||||||
pos = handleCRLF(c, pos)
|
pos = handleCRLF(c, pos)
|
||||||
else:
|
else:
|
||||||
break # EndOfFile also leaves the loop
|
break # EndOfFile also leaves the loop
|
||||||
c.bufpos = pos
|
c.bufpos = pos
|
||||||
|
|
||||||
proc rawGetTok(c: var CfgParser, tok: var Token) =
|
proc rawGetTok(c: var CfgParser, tok: var Token) =
|
||||||
|
|
@ -370,13 +370,13 @@ proc errorStr*(c: CfgParser, msg: string): string {.rtl, extern: "npc$1".} =
|
||||||
## returns a properly formatted error message containing current line and
|
## returns a properly formatted error message containing current line and
|
||||||
## column information.
|
## column information.
|
||||||
result = `%`("$1($2, $3) Error: $4",
|
result = `%`("$1($2, $3) Error: $4",
|
||||||
[c.filename, $getLine(c), $getColumn(c), msg])
|
[c.filename, $getLine(c), $getColumn(c), msg])
|
||||||
|
|
||||||
proc warningStr*(c: CfgParser, msg: string): string {.rtl, extern: "npc$1".} =
|
proc warningStr*(c: CfgParser, msg: string): string {.rtl, extern: "npc$1".} =
|
||||||
## returns a properly formatted warning message containing current line and
|
## returns a properly formatted warning message containing current line and
|
||||||
## column information.
|
## column information.
|
||||||
result = `%`("$1($2, $3) Warning: $4",
|
result = `%`("$1($2, $3) Warning: $4",
|
||||||
[c.filename, $getLine(c), $getColumn(c), msg])
|
[c.filename, $getLine(c), $getColumn(c), msg])
|
||||||
|
|
||||||
proc ignoreMsg*(c: CfgParser, e: CfgEvent): string {.rtl, extern: "npc$1".} =
|
proc ignoreMsg*(c: CfgParser, e: CfgEvent): string {.rtl, extern: "npc$1".} =
|
||||||
## returns a properly formatted warning message containing that
|
## returns a properly formatted warning message containing that
|
||||||
|
|
|
||||||
|
|
@ -71,12 +71,12 @@ import
|
||||||
type
|
type
|
||||||
CsvRow* = seq[string] ## A row in a CSV file.
|
CsvRow* = seq[string] ## A row in a CSV file.
|
||||||
CsvParser* = object of BaseLexer ## The parser object.
|
CsvParser* = object of BaseLexer ## The parser object.
|
||||||
##
|
##
|
||||||
## It consists of two public fields:
|
## It consists of two public fields:
|
||||||
## * `row` is the current row
|
## * `row` is the current row
|
||||||
## * `headers` are the columns that are defined in the csv file
|
## * `headers` are the columns that are defined in the csv file
|
||||||
## (read using `readHeaderRow <#readHeaderRow,CsvParser>`_).
|
## (read using `readHeaderRow <#readHeaderRow,CsvParser>`_).
|
||||||
## Used with `rowEntry <#rowEntry,CsvParser,string>`_).
|
## Used with `rowEntry <#rowEntry,CsvParser,string>`_).
|
||||||
row*: CsvRow
|
row*: CsvRow
|
||||||
filename: string
|
filename: string
|
||||||
sep, quote, esc: char
|
sep, quote, esc: char
|
||||||
|
|
|
||||||
|
|
@ -15,21 +15,21 @@ import
|
||||||
strutils, lexbase, streams, unicode
|
strutils, lexbase, streams, unicode
|
||||||
|
|
||||||
type
|
type
|
||||||
JsonEventKind* = enum ## enumeration of all events that may occur when parsing
|
JsonEventKind* = enum ## enumeration of all events that may occur when parsing
|
||||||
jsonError, ## an error occurred during parsing
|
jsonError, ## an error occurred during parsing
|
||||||
jsonEof, ## end of file reached
|
jsonEof, ## end of file reached
|
||||||
jsonString, ## a string literal
|
jsonString, ## a string literal
|
||||||
jsonInt, ## an integer literal
|
jsonInt, ## an integer literal
|
||||||
jsonFloat, ## a float literal
|
jsonFloat, ## a float literal
|
||||||
jsonTrue, ## the value ``true``
|
jsonTrue, ## the value ``true``
|
||||||
jsonFalse, ## the value ``false``
|
jsonFalse, ## the value ``false``
|
||||||
jsonNull, ## the value ``null``
|
jsonNull, ## the value ``null``
|
||||||
jsonObjectStart, ## start of an object: the ``{`` token
|
jsonObjectStart, ## start of an object: the ``{`` token
|
||||||
jsonObjectEnd, ## end of an object: the ``}`` token
|
jsonObjectEnd, ## end of an object: the ``}`` token
|
||||||
jsonArrayStart, ## start of an array: the ``[`` token
|
jsonArrayStart, ## start of an array: the ``[`` token
|
||||||
jsonArrayEnd ## start of an array: the ``]`` token
|
jsonArrayEnd ## start of an array: the ``]`` token
|
||||||
|
|
||||||
TokKind* = enum # must be synchronized with TJsonEventKind!
|
TokKind* = enum # must be synchronized with TJsonEventKind!
|
||||||
tkError,
|
tkError,
|
||||||
tkEof,
|
tkEof,
|
||||||
tkString,
|
tkString,
|
||||||
|
|
@ -45,18 +45,18 @@ type
|
||||||
tkColon,
|
tkColon,
|
||||||
tkComma
|
tkComma
|
||||||
|
|
||||||
JsonError* = enum ## enumeration that lists all errors that can occur
|
JsonError* = enum ## enumeration that lists all errors that can occur
|
||||||
errNone, ## no error
|
errNone, ## no error
|
||||||
errInvalidToken, ## invalid token
|
errInvalidToken, ## invalid token
|
||||||
errStringExpected, ## string expected
|
errStringExpected, ## string expected
|
||||||
errColonExpected, ## ``:`` expected
|
errColonExpected, ## ``:`` expected
|
||||||
errCommaExpected, ## ``,`` expected
|
errCommaExpected, ## ``,`` expected
|
||||||
errBracketRiExpected, ## ``]`` expected
|
errBracketRiExpected, ## ``]`` expected
|
||||||
errCurlyRiExpected, ## ``}`` expected
|
errCurlyRiExpected, ## ``}`` expected
|
||||||
errQuoteExpected, ## ``"`` or ``'`` expected
|
errQuoteExpected, ## ``"`` or ``'`` expected
|
||||||
errEOC_Expected, ## ``*/`` expected
|
errEOC_Expected, ## ``*/`` expected
|
||||||
errEofExpected, ## EOF expected
|
errEofExpected, ## EOF expected
|
||||||
errExprExpected ## expr expected
|
errExprExpected ## expr expected
|
||||||
|
|
||||||
ParserState = enum
|
ParserState = enum
|
||||||
stateEof, stateStart, stateObject, stateArray, stateExpectArrayComma,
|
stateEof, stateStart, stateObject, stateArray, stateExpectArrayComma,
|
||||||
|
|
|
||||||
|
|
@ -155,11 +155,11 @@ import
|
||||||
os, strutils
|
os, strutils
|
||||||
|
|
||||||
type
|
type
|
||||||
CmdLineKind* = enum ## The detected command line token.
|
CmdLineKind* = enum ## The detected command line token.
|
||||||
cmdEnd, ## End of command line reached
|
cmdEnd, ## End of command line reached
|
||||||
cmdArgument, ## An argument such as a filename
|
cmdArgument, ## An argument such as a filename
|
||||||
cmdLongOption, ## A long option such as --option
|
cmdLongOption, ## A long option such as --option
|
||||||
cmdShortOption ## A short option such as -c
|
cmdShortOption ## A short option such as -c
|
||||||
OptParser* = object of RootObj ## \
|
OptParser* = object of RootObj ## \
|
||||||
## Implementation of the command line parser.
|
## Implementation of the command line parser.
|
||||||
##
|
##
|
||||||
|
|
@ -172,10 +172,10 @@ type
|
||||||
longNoVal: seq[string]
|
longNoVal: seq[string]
|
||||||
cmds: seq[string]
|
cmds: seq[string]
|
||||||
idx: int
|
idx: int
|
||||||
kind*: CmdLineKind ## The detected command line token
|
kind*: CmdLineKind ## The detected command line token
|
||||||
key*, val*: TaintedString ## Key and value pair; the key is the option
|
key*, val*: TaintedString ## Key and value pair; the key is the option
|
||||||
## or the argument, and the value is not "" if
|
## or the argument, and the value is not "" if
|
||||||
## the option was given a value
|
## the option was given a value
|
||||||
|
|
||||||
proc parseWord(s: string, i: int, w: var string,
|
proc parseWord(s: string, i: int, w: var string,
|
||||||
delim: set[char] = {'\t', ' '}): int =
|
delim: set[char] = {'\t', ' '}): int =
|
||||||
|
|
@ -197,7 +197,7 @@ when declared(os.paramCount):
|
||||||
# we cannot provide this for NimRtl creation on Posix, because we can't
|
# we cannot provide this for NimRtl creation on Posix, because we can't
|
||||||
# access the command line arguments then!
|
# access the command line arguments then!
|
||||||
|
|
||||||
proc initOptParser*(cmdline = "", shortNoVal: set[char]={},
|
proc initOptParser*(cmdline = "", shortNoVal: set[char] = {},
|
||||||
longNoVal: seq[string] = @[];
|
longNoVal: seq[string] = @[];
|
||||||
allowWhitespaceAfterColon = true): OptParser =
|
allowWhitespaceAfterColon = true): OptParser =
|
||||||
## Initializes the command line parser.
|
## Initializes the command line parser.
|
||||||
|
|
@ -235,7 +235,7 @@ when declared(os.paramCount):
|
||||||
result.key = TaintedString""
|
result.key = TaintedString""
|
||||||
result.val = TaintedString""
|
result.val = TaintedString""
|
||||||
|
|
||||||
proc initOptParser*(cmdline: seq[TaintedString], shortNoVal: set[char]={},
|
proc initOptParser*(cmdline: seq[TaintedString], shortNoVal: set[char] = {},
|
||||||
longNoVal: seq[string] = @[];
|
longNoVal: seq[string] = @[];
|
||||||
allowWhitespaceAfterColon = true): OptParser =
|
allowWhitespaceAfterColon = true): OptParser =
|
||||||
## Initializes the command line parser.
|
## Initializes the command line parser.
|
||||||
|
|
@ -345,7 +345,8 @@ proc next*(p: var OptParser) {.rtl, extern: "npo$1".} =
|
||||||
inc(i)
|
inc(i)
|
||||||
while i < p.cmds[p.idx].len and p.cmds[p.idx][i] in {'\t', ' '}: inc(i)
|
while i < p.cmds[p.idx].len and p.cmds[p.idx][i] in {'\t', ' '}: inc(i)
|
||||||
# if we're at the end, use the next command line option:
|
# if we're at the end, use the next command line option:
|
||||||
if i >= p.cmds[p.idx].len and p.idx < p.cmds.len and p.allowWhitespaceAfterColon:
|
if i >= p.cmds[p.idx].len and p.idx < p.cmds.len and
|
||||||
|
p.allowWhitespaceAfterColon:
|
||||||
inc p.idx
|
inc p.idx
|
||||||
i = 0
|
i = 0
|
||||||
if p.idx < p.cmds.len:
|
if p.idx < p.cmds.len:
|
||||||
|
|
@ -403,7 +404,8 @@ proc remainingArgs*(p: OptParser): seq[TaintedString] {.rtl, extern: "npo$1".} =
|
||||||
result = @[]
|
result = @[]
|
||||||
for i in p.idx..<p.cmds.len: result.add TaintedString(p.cmds[i])
|
for i in p.idx..<p.cmds.len: result.add TaintedString(p.cmds[i])
|
||||||
|
|
||||||
iterator getopt*(p: var OptParser): tuple[kind: CmdLineKind, key, val: TaintedString] =
|
iterator getopt*(p: var OptParser): tuple[kind: CmdLineKind, key,
|
||||||
|
val: TaintedString] =
|
||||||
## Convenience iterator for iterating over the given
|
## Convenience iterator for iterating over the given
|
||||||
## `OptParser<#OptParser>`_.
|
## `OptParser<#OptParser>`_.
|
||||||
##
|
##
|
||||||
|
|
@ -443,7 +445,7 @@ iterator getopt*(p: var OptParser): tuple[kind: CmdLineKind, key, val: TaintedSt
|
||||||
|
|
||||||
when declared(initOptParser):
|
when declared(initOptParser):
|
||||||
iterator getopt*(cmdline: seq[TaintedString] = commandLineParams(),
|
iterator getopt*(cmdline: seq[TaintedString] = commandLineParams(),
|
||||||
shortNoVal: set[char]={}, longNoVal: seq[string] = @[]):
|
shortNoVal: set[char] = {}, longNoVal: seq[string] = @[]):
|
||||||
tuple[kind: CmdLineKind, key, val: TaintedString] =
|
tuple[kind: CmdLineKind, key, val: TaintedString] =
|
||||||
## Convenience iterator for iterating over command line arguments.
|
## Convenience iterator for iterating over command line arguments.
|
||||||
##
|
##
|
||||||
|
|
@ -484,7 +486,8 @@ when declared(initOptParser):
|
||||||
## if filename == "":
|
## if filename == "":
|
||||||
## # no filename has been written, so we show the help
|
## # no filename has been written, so we show the help
|
||||||
## writeHelp()
|
## writeHelp()
|
||||||
var p = initOptParser(cmdline, shortNoVal=shortNoVal, longNoVal=longNoVal)
|
var p = initOptParser(cmdline, shortNoVal = shortNoVal,
|
||||||
|
longNoVal = longNoVal)
|
||||||
while true:
|
while true:
|
||||||
next(p)
|
next(p)
|
||||||
if p.kind == cmdEnd: break
|
if p.kind == cmdEnd: break
|
||||||
|
|
|
||||||
|
|
@ -18,12 +18,12 @@ import
|
||||||
# ------------------- scanner -------------------------------------------------
|
# ------------------- scanner -------------------------------------------------
|
||||||
|
|
||||||
type
|
type
|
||||||
TokKind = enum ## enumeration of all SQL tokens
|
TokKind = enum ## enumeration of all SQL tokens
|
||||||
tkInvalid, ## invalid token
|
tkInvalid, ## invalid token
|
||||||
tkEof, ## end of file reached
|
tkEof, ## end of file reached
|
||||||
tkIdentifier, ## abc
|
tkIdentifier, ## abc
|
||||||
tkQuotedIdentifier, ## "abc"
|
tkQuotedIdentifier, ## "abc"
|
||||||
tkStringConstant, ## 'abc'
|
tkStringConstant, ## 'abc'
|
||||||
tkEscapeConstant, ## e'abc'
|
tkEscapeConstant, ## e'abc'
|
||||||
tkDollarQuotedConstant, ## $tag$abc$tag$
|
tkDollarQuotedConstant, ## $tag$abc$tag$
|
||||||
tkBitStringConstant, ## B'00011'
|
tkBitStringConstant, ## B'00011'
|
||||||
|
|
@ -40,9 +40,9 @@ type
|
||||||
tkBracketRi, ## ']'
|
tkBracketRi, ## ']'
|
||||||
tkDot ## '.'
|
tkDot ## '.'
|
||||||
|
|
||||||
Token = object # a token
|
Token = object # a token
|
||||||
kind: TokKind # the type of the token
|
kind: TokKind # the type of the token
|
||||||
literal: string # the parsed (string) literal
|
literal: string # the parsed (string) literal
|
||||||
|
|
||||||
SqlLexer* = object of BaseLexer ## the parser object.
|
SqlLexer* = object of BaseLexer ## the parser object.
|
||||||
filename: string
|
filename: string
|
||||||
|
|
@ -162,7 +162,7 @@ proc skip(c: var SqlLexer) =
|
||||||
break
|
break
|
||||||
of '/':
|
of '/':
|
||||||
if c.buf[pos+1] == '*':
|
if c.buf[pos+1] == '*':
|
||||||
inc(pos,2)
|
inc(pos, 2)
|
||||||
while true:
|
while true:
|
||||||
case c.buf[pos]
|
case c.buf[pos]
|
||||||
of '\0': break
|
of '\0': break
|
||||||
|
|
@ -186,7 +186,7 @@ proc skip(c: var SqlLexer) =
|
||||||
of '\c', '\L':
|
of '\c', '\L':
|
||||||
pos = handleCRLF(c, pos)
|
pos = handleCRLF(c, pos)
|
||||||
else:
|
else:
|
||||||
break # EndOfFile also leaves the loop
|
break # EndOfFile also leaves the loop
|
||||||
c.bufpos = pos
|
c.bufpos = pos
|
||||||
|
|
||||||
proc getString(c: var SqlLexer, tok: var Token, kind: TokKind) =
|
proc getString(c: var SqlLexer, tok: var Token, kind: TokKind) =
|
||||||
|
|
@ -264,12 +264,13 @@ proc getSymbol(c: var SqlLexer, tok: var Token) =
|
||||||
while true:
|
while true:
|
||||||
add(tok.literal, c.buf[pos])
|
add(tok.literal, c.buf[pos])
|
||||||
inc(pos)
|
inc(pos)
|
||||||
if c.buf[pos] notin {'a'..'z','A'..'Z','0'..'9','_','$', '\128'..'\255'}:
|
if c.buf[pos] notin {'a'..'z', 'A'..'Z', '0'..'9', '_', '$',
|
||||||
|
'\128'..'\255'}:
|
||||||
break
|
break
|
||||||
c.bufpos = pos
|
c.bufpos = pos
|
||||||
tok.kind = tkIdentifier
|
tok.kind = tkIdentifier
|
||||||
|
|
||||||
proc getQuotedIdentifier(c: var SqlLexer, tok: var Token, quote='\"') =
|
proc getQuotedIdentifier(c: var SqlLexer, tok: var Token, quote = '\"') =
|
||||||
var pos = c.bufpos + 1
|
var pos = c.bufpos + 1
|
||||||
tok.kind = tkQuotedIdentifier
|
tok.kind = tkQuotedIdentifier
|
||||||
while true:
|
while true:
|
||||||
|
|
@ -403,7 +404,7 @@ proc getTok(c: var SqlLexer, tok: var Token) =
|
||||||
of 'x', 'X':
|
of 'x', 'X':
|
||||||
if c.buf[c.bufpos + 1] == '\'':
|
if c.buf[c.bufpos + 1] == '\'':
|
||||||
tok.kind = tkHexStringConstant
|
tok.kind = tkHexStringConstant
|
||||||
getBitHexString(c, tok, {'a'..'f','A'..'F','0'..'9'})
|
getBitHexString(c, tok, {'a'..'f', 'A'..'F', '0'..'9'})
|
||||||
else:
|
else:
|
||||||
getSymbol(c, tok)
|
getSymbol(c, tok)
|
||||||
of '$': getDollarString(c, tok)
|
of '$': getDollarString(c, tok)
|
||||||
|
|
@ -504,7 +505,7 @@ type
|
||||||
nkConstraint,
|
nkConstraint,
|
||||||
nkUnique,
|
nkUnique,
|
||||||
nkIdentity,
|
nkIdentity,
|
||||||
nkColumnDef, ## name, datatype, constraints
|
nkColumnDef, ## name, datatype, constraints
|
||||||
nkInsert,
|
nkInsert,
|
||||||
nkUpdate,
|
nkUpdate,
|
||||||
nkDelete,
|
nkDelete,
|
||||||
|
|
@ -543,14 +544,14 @@ const
|
||||||
|
|
||||||
type
|
type
|
||||||
SqlParseError* = object of ValueError ## Invalid SQL encountered
|
SqlParseError* = object of ValueError ## Invalid SQL encountered
|
||||||
SqlNode* = ref SqlNodeObj ## an SQL abstract syntax tree node
|
SqlNode* = ref SqlNodeObj ## an SQL abstract syntax tree node
|
||||||
SqlNodeObj* = object ## an SQL abstract syntax tree node
|
SqlNodeObj* = object ## an SQL abstract syntax tree node
|
||||||
case kind*: SqlNodeKind ## kind of syntax tree
|
case kind*: SqlNodeKind ## kind of syntax tree
|
||||||
of LiteralNodes:
|
of LiteralNodes:
|
||||||
strVal*: string ## AST leaf: the identifier, numeric literal
|
strVal*: string ## AST leaf: the identifier, numeric literal
|
||||||
## string literal, etc.
|
## string literal, etc.
|
||||||
else:
|
else:
|
||||||
sons*: seq[SqlNode] ## the node's children
|
sons*: seq[SqlNode] ## the node's children
|
||||||
|
|
||||||
SqlParser* = object of SqlLexer ## SQL parser object
|
SqlParser* = object of SqlLexer ## SQL parser object
|
||||||
tok: Token
|
tok: Token
|
||||||
|
|
@ -714,7 +715,8 @@ proc identOrLiteral(p: var SqlParser): SqlNode =
|
||||||
getTok(p) # we must consume a token here to prevent endless loops!
|
getTok(p) # we must consume a token here to prevent endless loops!
|
||||||
|
|
||||||
proc primary(p: var SqlParser): SqlNode =
|
proc primary(p: var SqlParser): SqlNode =
|
||||||
if (p.tok.kind == tkOperator and (p.tok.literal == "+" or p.tok.literal == "-")) or isKeyw(p, "not"):
|
if (p.tok.kind == tkOperator and (p.tok.literal == "+" or p.tok.literal ==
|
||||||
|
"-")) or isKeyw(p, "not"):
|
||||||
result = newNode(nkPrefix)
|
result = newNode(nkPrefix)
|
||||||
result.add(newNode(nkIdent, p.tok.literal))
|
result.add(newNode(nkIdent, p.tok.literal))
|
||||||
getTok(p)
|
getTok(p)
|
||||||
|
|
@ -1439,7 +1441,7 @@ proc ra(n: SqlNode, s: var SqlWriter) =
|
||||||
s.addKeyw("enum")
|
s.addKeyw("enum")
|
||||||
rs(n, s)
|
rs(n, s)
|
||||||
|
|
||||||
proc renderSQL*(n: SqlNode, upperCase=false): string =
|
proc renderSQL*(n: SqlNode, upperCase = false): string =
|
||||||
## Converts an SQL abstract syntax tree to its string representation.
|
## Converts an SQL abstract syntax tree to its string representation.
|
||||||
var s: SqlWriter
|
var s: SqlWriter
|
||||||
s.buffer = ""
|
s.buffer = ""
|
||||||
|
|
@ -1493,7 +1495,7 @@ when not defined(js):
|
||||||
finally:
|
finally:
|
||||||
close(p)
|
close(p)
|
||||||
|
|
||||||
proc parseSQL*(input: string, filename=""): SqlNode =
|
proc parseSQL*(input: string, filename = ""): SqlNode =
|
||||||
## parses the SQL from `input` into an AST and returns the AST.
|
## parses the SQL from `input` into an AST and returns the AST.
|
||||||
## `filename` is only used for error messages.
|
## `filename` is only used for error messages.
|
||||||
## Syntax errors raise an `SqlParseError` exception.
|
## Syntax errors raise an `SqlParseError` exception.
|
||||||
|
|
|
||||||
|
|
@ -48,9 +48,9 @@
|
||||||
## * `other parsers<lib.html#pure-libraries-parsers>`_ for other parsers
|
## * `other parsers<lib.html#pure-libraries-parsers>`_ for other parsers
|
||||||
|
|
||||||
|
|
||||||
{.deadCodeElim: on.} # dce option deprecated
|
{.deadCodeElim: on.} # dce option deprecated
|
||||||
|
|
||||||
{.push debugger:off .} # the user does not want to trace a part
|
{.push debugger: off.} # the user does not want to trace a part
|
||||||
# of the standard library!
|
# of the standard library!
|
||||||
|
|
||||||
include "system/inclrtl"
|
include "system/inclrtl"
|
||||||
|
|
@ -64,8 +64,8 @@ const
|
||||||
proc toLower(c: char): char {.inline.} =
|
proc toLower(c: char): char {.inline.} =
|
||||||
result = if c in {'A'..'Z'}: chr(ord(c)-ord('A')+ord('a')) else: c
|
result = if c in {'A'..'Z'}: chr(ord(c)-ord('A')+ord('a')) else: c
|
||||||
|
|
||||||
proc parseBin*[T: SomeInteger](s: string, number: var T, start = 0, maxLen = 0): int
|
proc parseBin*[T: SomeInteger](s: string, number: var T, start = 0,
|
||||||
{.noSideEffect.} =
|
maxLen = 0): int {.noSideEffect.} =
|
||||||
## Parses a binary number and stores its value in ``number``.
|
## Parses a binary number and stores its value in ``number``.
|
||||||
##
|
##
|
||||||
## Returns the number of the parsed characters or 0 in case of an error.
|
## Returns the number of the parsed characters or 0 in case of an error.
|
||||||
|
|
@ -74,7 +74,7 @@ proc parseBin*[T: SomeInteger](s: string, number: var T, start = 0, maxLen = 0):
|
||||||
## If ``maxLen == 0``, the parsing continues until the first non-bin character
|
## If ``maxLen == 0``, the parsing continues until the first non-bin character
|
||||||
## or to the end of the string. Otherwise, no more than ``maxLen`` characters
|
## or to the end of the string. Otherwise, no more than ``maxLen`` characters
|
||||||
## are parsed starting from the ``start`` position.
|
## are parsed starting from the ``start`` position.
|
||||||
##
|
##
|
||||||
## It does not check for overflow. If the value represented by the string is
|
## It does not check for overflow. If the value represented by the string is
|
||||||
## too big to fit into ``number``, only the value of last fitting characters
|
## too big to fit into ``number``, only the value of last fitting characters
|
||||||
## will be stored in ``number`` without producing an error.
|
## will be stored in ``number`` without producing an error.
|
||||||
|
|
@ -111,8 +111,8 @@ proc parseBin*[T: SomeInteger](s: string, number: var T, start = 0, maxLen = 0):
|
||||||
number = output
|
number = output
|
||||||
result = i - start
|
result = i - start
|
||||||
|
|
||||||
proc parseOct*[T: SomeInteger](s: string, number: var T, start = 0, maxLen = 0): int
|
proc parseOct*[T: SomeInteger](s: string, number: var T, start = 0,
|
||||||
{.noSideEffect.} =
|
maxLen = 0): int {.noSideEffect.} =
|
||||||
## Parses an octal number and stores its value in ``number``.
|
## Parses an octal number and stores its value in ``number``.
|
||||||
##
|
##
|
||||||
## Returns the number of the parsed characters or 0 in case of an error.
|
## Returns the number of the parsed characters or 0 in case of an error.
|
||||||
|
|
@ -121,7 +121,7 @@ proc parseOct*[T: SomeInteger](s: string, number: var T, start = 0, maxLen = 0):
|
||||||
## If ``maxLen == 0``, the parsing continues until the first non-oct character
|
## If ``maxLen == 0``, the parsing continues until the first non-oct character
|
||||||
## or to the end of the string. Otherwise, no more than ``maxLen`` characters
|
## or to the end of the string. Otherwise, no more than ``maxLen`` characters
|
||||||
## are parsed starting from the ``start`` position.
|
## are parsed starting from the ``start`` position.
|
||||||
##
|
##
|
||||||
## It does not check for overflow. If the value represented by the string is
|
## It does not check for overflow. If the value represented by the string is
|
||||||
## too big to fit into ``number``, only the value of last fitting characters
|
## too big to fit into ``number``, only the value of last fitting characters
|
||||||
## will be stored in ``number`` without producing an error.
|
## will be stored in ``number`` without producing an error.
|
||||||
|
|
@ -158,8 +158,8 @@ proc parseOct*[T: SomeInteger](s: string, number: var T, start = 0, maxLen = 0):
|
||||||
number = output
|
number = output
|
||||||
result = i - start
|
result = i - start
|
||||||
|
|
||||||
proc parseHex*[T: SomeInteger](s: string, number: var T, start = 0, maxLen = 0): int
|
proc parseHex*[T: SomeInteger](s: string, number: var T, start = 0,
|
||||||
{.noSideEffect.} =
|
maxLen = 0): int {.noSideEffect.} =
|
||||||
## Parses a hexadecimal number and stores its value in ``number``.
|
## Parses a hexadecimal number and stores its value in ``number``.
|
||||||
##
|
##
|
||||||
## Returns the number of the parsed characters or 0 in case of an error.
|
## Returns the number of the parsed characters or 0 in case of an error.
|
||||||
|
|
@ -168,7 +168,7 @@ proc parseHex*[T: SomeInteger](s: string, number: var T, start = 0, maxLen = 0):
|
||||||
## If ``maxLen == 0``, the parsing continues until the first non-hex character
|
## If ``maxLen == 0``, the parsing continues until the first non-hex character
|
||||||
## or to the end of the string. Otherwise, no more than ``maxLen`` characters
|
## or to the end of the string. Otherwise, no more than ``maxLen`` characters
|
||||||
## are parsed starting from the ``start`` position.
|
## are parsed starting from the ``start`` position.
|
||||||
##
|
##
|
||||||
## It does not check for overflow. If the value represented by the string is
|
## It does not check for overflow. If the value represented by the string is
|
||||||
## too big to fit into ``number``, only the value of last fitting characters
|
## too big to fit into ``number``, only the value of last fitting characters
|
||||||
## will be stored in ``number`` without producing an error.
|
## will be stored in ``number`` without producing an error.
|
||||||
|
|
@ -468,7 +468,7 @@ proc parseInt*(s: string, number: var int, start = 0): int {.
|
||||||
number = int(res)
|
number = int(res)
|
||||||
|
|
||||||
proc parseSaturatedNatural*(s: string, b: var int, start = 0): int {.
|
proc parseSaturatedNatural*(s: string, b: var int, start = 0): int {.
|
||||||
raises: [].}=
|
raises: [].} =
|
||||||
## Parses a natural number into ``b``. This cannot raise an overflow
|
## Parses a natural number into ``b``. This cannot raise an overflow
|
||||||
## error. ``high(int)`` is returned for an overflow.
|
## error. ``high(int)`` is returned for an overflow.
|
||||||
## The number of processed character is returned.
|
## The number of processed character is returned.
|
||||||
|
|
@ -573,13 +573,13 @@ proc parseFloat*(s: string, number: var float, start = 0): int {.
|
||||||
number = bf
|
number = bf
|
||||||
|
|
||||||
type
|
type
|
||||||
InterpolatedKind* = enum ## Describes for `interpolatedFragments`
|
InterpolatedKind* = enum ## Describes for `interpolatedFragments`
|
||||||
## which part of the interpolated string is
|
## which part of the interpolated string is
|
||||||
## yielded; for example in "str$$$var${expr}"
|
## yielded; for example in "str$$$var${expr}"
|
||||||
ikStr, ## ``str`` part of the interpolated string
|
ikStr, ## ``str`` part of the interpolated string
|
||||||
ikDollar, ## escaped ``$`` part of the interpolated string
|
ikDollar, ## escaped ``$`` part of the interpolated string
|
||||||
ikVar, ## ``var`` part of the interpolated string
|
ikVar, ## ``var`` part of the interpolated string
|
||||||
ikExpr ## ``expr`` part of the interpolated string
|
ikExpr ## ``expr`` part of the interpolated string
|
||||||
|
|
||||||
iterator interpolatedFragments*(s: string): tuple[kind: InterpolatedKind,
|
iterator interpolatedFragments*(s: string): tuple[kind: InterpolatedKind,
|
||||||
value: string] =
|
value: string] =
|
||||||
|
|
@ -649,7 +649,7 @@ when isMainModule:
|
||||||
import sequtils
|
import sequtils
|
||||||
let input = "$test{} $this is ${an{ example}} "
|
let input = "$test{} $this is ${an{ example}} "
|
||||||
let expected = @[(ikVar, "test"), (ikStr, "{} "), (ikVar, "this"),
|
let expected = @[(ikVar, "test"), (ikStr, "{} "), (ikVar, "this"),
|
||||||
(ikStr, " is "), (ikExpr, "an{ example}"), (ikStr, " ")]
|
(ikStr, " is "), (ikExpr, "an{ example}"), (ikStr, " ")]
|
||||||
doAssert toSeq(interpolatedFragments(input)) == expected
|
doAssert toSeq(interpolatedFragments(input)) == expected
|
||||||
|
|
||||||
var value = 0
|
var value = 0
|
||||||
|
|
|
||||||
|
|
@ -155,41 +155,41 @@ import
|
||||||
|
|
||||||
type
|
type
|
||||||
XmlEventKind* = enum ## enumeration of all events that may occur when parsing
|
XmlEventKind* = enum ## enumeration of all events that may occur when parsing
|
||||||
xmlError, ## an error occurred during parsing
|
xmlError, ## an error occurred during parsing
|
||||||
xmlEof, ## end of file reached
|
xmlEof, ## end of file reached
|
||||||
xmlCharData, ## character data
|
xmlCharData, ## character data
|
||||||
xmlWhitespace, ## whitespace has been parsed
|
xmlWhitespace, ## whitespace has been parsed
|
||||||
xmlComment, ## a comment has been parsed
|
xmlComment, ## a comment has been parsed
|
||||||
xmlPI, ## processing instruction (``<?name something ?>``)
|
xmlPI, ## processing instruction (``<?name something ?>``)
|
||||||
xmlElementStart, ## ``<elem>``
|
xmlElementStart, ## ``<elem>``
|
||||||
xmlElementEnd, ## ``</elem>``
|
xmlElementEnd, ## ``</elem>``
|
||||||
xmlElementOpen, ## ``<elem
|
xmlElementOpen, ## ``<elem
|
||||||
xmlAttribute, ## ``key = "value"`` pair
|
xmlAttribute, ## ``key = "value"`` pair
|
||||||
xmlElementClose, ## ``>``
|
xmlElementClose, ## ``>``
|
||||||
xmlCData, ## ``<![CDATA[`` ... data ... ``]]>``
|
xmlCData, ## ``<![CDATA[`` ... data ... ``]]>``
|
||||||
xmlEntity, ## &entity;
|
xmlEntity, ## &entity;
|
||||||
xmlSpecial ## ``<! ... data ... >``
|
xmlSpecial ## ``<! ... data ... >``
|
||||||
|
|
||||||
XmlErrorKind* = enum ## enumeration that lists all errors that can occur
|
XmlErrorKind* = enum ## enumeration that lists all errors that can occur
|
||||||
errNone, ## no error
|
errNone, ## no error
|
||||||
errEndOfCDataExpected, ## ``]]>`` expected
|
errEndOfCDataExpected, ## ``]]>`` expected
|
||||||
errNameExpected, ## name expected
|
errNameExpected, ## name expected
|
||||||
errSemicolonExpected, ## ``;`` expected
|
errSemicolonExpected, ## ``;`` expected
|
||||||
errQmGtExpected, ## ``?>`` expected
|
errQmGtExpected, ## ``?>`` expected
|
||||||
errGtExpected, ## ``>`` expected
|
errGtExpected, ## ``>`` expected
|
||||||
errEqExpected, ## ``=`` expected
|
errEqExpected, ## ``=`` expected
|
||||||
errQuoteExpected, ## ``"`` or ``'`` expected
|
errQuoteExpected, ## ``"`` or ``'`` expected
|
||||||
errEndOfCommentExpected ## ``-->`` expected
|
errEndOfCommentExpected ## ``-->`` expected
|
||||||
errAttributeValueExpected ## non-empty attribute value expected
|
errAttributeValueExpected ## non-empty attribute value expected
|
||||||
|
|
||||||
ParserState = enum
|
ParserState = enum
|
||||||
stateStart, stateNormal, stateAttr, stateEmptyElementTag, stateError
|
stateStart, stateNormal, stateAttr, stateEmptyElementTag, stateError
|
||||||
|
|
||||||
XmlParseOption* = enum ## options for the XML parser
|
XmlParseOption* = enum ## options for the XML parser
|
||||||
reportWhitespace, ## report whitespace
|
reportWhitespace, ## report whitespace
|
||||||
reportComments ## report comments
|
reportComments ## report comments
|
||||||
allowUnquotedAttribs ## allow unquoted attribute values (for HTML)
|
allowUnquotedAttribs ## allow unquoted attribute values (for HTML)
|
||||||
allowEmptyAttribs ## allow empty attributes (without explicit value)
|
allowEmptyAttribs ## allow empty attributes (without explicit value)
|
||||||
|
|
||||||
XmlParser* = object of BaseLexer ## the parser object.
|
XmlParser* = object of BaseLexer ## the parser object.
|
||||||
a, b, c: string
|
a, b, c: string
|
||||||
|
|
@ -399,7 +399,7 @@ proc parseComment(my: var XmlParser) =
|
||||||
my.bufpos = pos
|
my.bufpos = pos
|
||||||
my.kind = xmlComment
|
my.kind = xmlComment
|
||||||
|
|
||||||
proc parseWhitespace(my: var XmlParser, skip=false) =
|
proc parseWhitespace(my: var XmlParser, skip = false) =
|
||||||
var pos = my.bufpos
|
var pos = my.bufpos
|
||||||
while true:
|
while true:
|
||||||
case my.buf[pos]
|
case my.buf[pos]
|
||||||
|
|
@ -562,7 +562,7 @@ proc parseTag(my: var XmlParser) =
|
||||||
my.kind = xmlCharData
|
my.kind = xmlCharData
|
||||||
add(my.a, '<')
|
add(my.a, '<')
|
||||||
return
|
return
|
||||||
parseWhitespace(my, skip=true)
|
parseWhitespace(my, skip = true)
|
||||||
if my.buf[my.bufpos] in NameStartChar:
|
if my.buf[my.bufpos] in NameStartChar:
|
||||||
# an attribute follows:
|
# an attribute follows:
|
||||||
my.kind = xmlElementOpen
|
my.kind = xmlElementOpen
|
||||||
|
|
@ -588,7 +588,7 @@ proc parseEndTag(my: var XmlParser) =
|
||||||
my.bufpos = lexbase.handleRefillChar(my, my.bufpos+1)
|
my.bufpos = lexbase.handleRefillChar(my, my.bufpos+1)
|
||||||
#inc(my.bufpos, 2)
|
#inc(my.bufpos, 2)
|
||||||
parseName(my, my.a)
|
parseName(my, my.a)
|
||||||
parseWhitespace(my, skip=true)
|
parseWhitespace(my, skip = true)
|
||||||
if my.buf[my.bufpos] == '>':
|
if my.buf[my.bufpos] == '>':
|
||||||
inc(my.bufpos)
|
inc(my.bufpos)
|
||||||
else:
|
else:
|
||||||
|
|
@ -606,7 +606,7 @@ proc parseAttribute(my: var XmlParser) =
|
||||||
return
|
return
|
||||||
|
|
||||||
let startPos = my.bufpos
|
let startPos = my.bufpos
|
||||||
parseWhitespace(my, skip=true)
|
parseWhitespace(my, skip = true)
|
||||||
if my.buf[my.bufpos] != '=':
|
if my.buf[my.bufpos] != '=':
|
||||||
if allowEmptyAttribs notin my.options or
|
if allowEmptyAttribs notin my.options or
|
||||||
(my.buf[my.bufpos] != '>' and my.bufpos == startPos):
|
(my.buf[my.bufpos] != '>' and my.bufpos == startPos):
|
||||||
|
|
@ -614,7 +614,7 @@ proc parseAttribute(my: var XmlParser) =
|
||||||
return
|
return
|
||||||
|
|
||||||
inc(my.bufpos)
|
inc(my.bufpos)
|
||||||
parseWhitespace(my, skip=true)
|
parseWhitespace(my, skip = true)
|
||||||
|
|
||||||
var pos = my.bufpos
|
var pos = my.bufpos
|
||||||
if my.buf[pos] in {'\'', '"'}:
|
if my.buf[pos] in {'\'', '"'}:
|
||||||
|
|
@ -678,7 +678,7 @@ proc parseAttribute(my: var XmlParser) =
|
||||||
add(my.b, my.buf[pos])
|
add(my.b, my.buf[pos])
|
||||||
inc pos
|
inc pos
|
||||||
my.bufpos = pos
|
my.bufpos = pos
|
||||||
parseWhitespace(my, skip=true)
|
parseWhitespace(my, skip = true)
|
||||||
|
|
||||||
proc parseCharData(my: var XmlParser) =
|
proc parseCharData(my: var XmlParser) =
|
||||||
var pos = my.bufpos
|
var pos = my.bufpos
|
||||||
|
|
@ -711,8 +711,9 @@ proc rawGetTok(my: var XmlParser) =
|
||||||
of '/':
|
of '/':
|
||||||
parseEndTag(my)
|
parseEndTag(my)
|
||||||
of '!':
|
of '!':
|
||||||
if my.buf[pos+2] == '[' and my.buf[pos+3] == 'C' and my.buf[pos+4] == 'D' and
|
if my.buf[pos+2] == '[' and my.buf[pos+3] == 'C' and
|
||||||
my.buf[pos+5] == 'A' and my.buf[pos+6] == 'T' and my.buf[pos+7] == 'A' and
|
my.buf[pos+4] == 'D' and my.buf[pos+5] == 'A' and
|
||||||
|
my.buf[pos+6] == 'T' and my.buf[pos+7] == 'A' and
|
||||||
my.buf[pos+8] == '[':
|
my.buf[pos+8] == '[':
|
||||||
parseCDATA(my)
|
parseCDATA(my)
|
||||||
elif my.buf[pos+2] == '-' and my.buf[pos+3] == '-':
|
elif my.buf[pos+2] == '-' and my.buf[pos+3] == '-':
|
||||||
|
|
@ -742,7 +743,8 @@ proc getTok(my: var XmlParser) =
|
||||||
of xmlComment:
|
of xmlComment:
|
||||||
if my.options.contains(reportComments): break
|
if my.options.contains(reportComments): break
|
||||||
of xmlWhitespace:
|
of xmlWhitespace:
|
||||||
if my.options.contains(reportWhitespace) or lastKind in {xmlCharData, xmlComment, xmlEntity}:
|
if my.options.contains(reportWhitespace) or lastKind in {xmlCharData,
|
||||||
|
xmlComment, xmlEntity}:
|
||||||
break
|
break
|
||||||
else: break
|
else: break
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,7 @@ proc parse(x: var XmlParser, errors: var seq[string]): XmlNode =
|
||||||
of xmlError:
|
of xmlError:
|
||||||
errors.add(errorMsg(x))
|
errors.add(errorMsg(x))
|
||||||
next(x)
|
next(x)
|
||||||
of xmlElementStart: ## ``<elem>``
|
of xmlElementStart: ## ``<elem>``
|
||||||
result = newElement(x.elementName)
|
result = newElement(x.elementName)
|
||||||
next(x)
|
next(x)
|
||||||
untilElementEnd(x, result, errors)
|
untilElementEnd(x, result, errors)
|
||||||
|
|
@ -169,4 +169,5 @@ when isMainModule:
|
||||||
|
|
||||||
block bug1518:
|
block bug1518:
|
||||||
var err: seq[string] = @[]
|
var err: seq[string] = @[]
|
||||||
assert $parsexml(newStringStream"<tag>One & two</tag>", "temp.xml", err) == "<tag>One & two</tag>"
|
assert $parsexml(newStringStream"<tag>One & two</tag>", "temp.xml",
|
||||||
|
err) == "<tag>One & two</tag>"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue