diff options
Diffstat (limited to 'lib/pure')
-rw-r--r-- | lib/pure/htmlparser.nim | 3 | ||||
-rw-r--r-- | lib/pure/ioselects/ioselectors_epoll.nim | 8 | ||||
-rw-r--r-- | lib/pure/logging.nim | 11 | ||||
-rw-r--r-- | lib/pure/math.nim | 54 | ||||
-rw-r--r-- | lib/pure/parsesql.nim | 25 | ||||
-rw-r--r-- | lib/pure/parsexml.nim | 28 | ||||
-rw-r--r-- | lib/pure/strscans.nim | 7 | ||||
-rw-r--r-- | lib/pure/strutils.nim | 2 | ||||
-rw-r--r-- | lib/pure/sugar.nim | 5 |
9 files changed, 116 insertions, 27 deletions
diff --git a/lib/pure/htmlparser.nim b/lib/pure/htmlparser.nim index fbf2b8e73..2d24050f2 100644 --- a/lib/pure/htmlparser.nim +++ b/lib/pure/htmlparser.nim @@ -2014,7 +2014,8 @@ proc parseHtml*(s: Stream, filename: string, ## Parses the XML from stream `s` and returns a ``XmlNode``. Every ## occurred parsing error is added to the `errors` sequence. var x: XmlParser - open(x, s, filename, {reportComments, reportWhitespace}) + open(x, s, filename, {reportComments, reportWhitespace, allowUnquotedAttribs, + allowEmptyAttribs}) next(x) # skip the DOCTYPE: if x.kind == xmlSpecial: next(x) diff --git a/lib/pure/ioselects/ioselectors_epoll.nim b/lib/pure/ioselects/ioselectors_epoll.nim index 8b3f14f34..16d901ff0 100644 --- a/lib/pure/ioselects/ioselectors_epoll.nim +++ b/lib/pure/ioselects/ioselectors_epoll.nim @@ -383,14 +383,14 @@ proc selectInto*[T](s: Selector[T], timeout: int, if (pevents and EPOLLERR) != 0 or (pevents and EPOLLHUP) != 0: if (pevents and EPOLLHUP) != 0: - rkey.errorCode = ECONNRESET.OSErrorCode + rkey.errorCode = OSErrorCode ECONNRESET else: # Try reading SO_ERROR from fd. var error: cint - var size = sizeof(error).SockLen - if getsockopt(fdi.SocketHandle, SOL_SOCKET, SO_ERROR, addr(error), + var size = SockLen sizeof(error) + if getsockopt(SocketHandle fdi, SOL_SOCKET, SO_ERROR, addr(error), addr(size)) == 0'i32: - rkey.errorCode = error.OSErrorCode + rkey.errorCode = OSErrorCode error rkey.events.incl(Event.Error) if (pevents and EPOLLOUT) != 0: diff --git a/lib/pure/logging.nim b/lib/pure/logging.nim index f2f5cac9e..cd13deec3 100644 --- a/lib/pure/logging.nim +++ b/lib/pure/logging.nim @@ -80,6 +80,7 @@ type ConsoleLogger* = ref object of Logger ## logger that writes the messages to the ## console + useStderr*: bool ## will send logs into Stderr if set when not defined(js): type @@ -150,16 +151,20 @@ method log*(logger: ConsoleLogger, level: Level, args: varargs[string, `$`]) = {.emit: "console.log(`cln`);".} else: try: - writeLine(stdout, ln) - if level in {lvlError, lvlFatal}: flushFile(stdout) + var handle = stdout + if logger.useStderr: + handle = stderr + writeLine(handle, ln) + if level in {lvlError, lvlFatal}: flushFile(handle) except IOError: discard -proc newConsoleLogger*(levelThreshold = lvlAll, fmtStr = defaultFmtStr): ConsoleLogger = +proc newConsoleLogger*(levelThreshold = lvlAll, fmtStr = defaultFmtStr, useStderr=false): ConsoleLogger = ## Creates a new console logger. This logger logs to the console. new result result.fmtStr = fmtStr result.levelThreshold = levelThreshold + result.useStderr = useStderr when not defined(js): method log*(logger: FileLogger, level: Level, args: varargs[string, `$`]) = diff --git a/lib/pure/math.nim b/lib/pure/math.nim index f04cb5050..e2ad626de 100644 --- a/lib/pure/math.nim +++ b/lib/pure/math.nim @@ -168,16 +168,19 @@ when not defined(JS): # C proc sqrt*(x: float32): float32 {.importc: "sqrtf", header: "<math.h>".} proc sqrt*(x: float64): float64 {.importc: "sqrt", header: "<math.h>".} ## Computes the square root of ``x``. + ## ## .. code-block:: nim ## echo sqrt(1.44) ## 1.2 proc cbrt*(x: float32): float32 {.importc: "cbrtf", header: "<math.h>".} proc cbrt*(x: float64): float64 {.importc: "cbrt", header: "<math.h>".} ## Computes the cubic root of ``x``. + ## ## .. code-block:: nim ## echo cbrt(2.197) ## 1.3 proc ln*(x: float32): float32 {.importc: "logf", header: "<math.h>".} proc ln*(x: float64): float64 {.importc: "log", header: "<math.h>".} ## Computes the `natural logarithm <https://en.wikipedia.org/wiki/Natural_logarithm>`_ of ``x``. + ## ## .. code-block:: nim ## echo ln(exp(4.0)) ## 4.0 else: # JS @@ -189,6 +192,7 @@ else: # JS proc log*[T: SomeFloat](x, base: T): T = ## Computes the logarithm of ``x`` to base ``base``. + ## ## .. code-block:: nim ## echo log(9.0, 3.0) ## 2.0 ln(x) / ln(base) @@ -197,51 +201,60 @@ when not defined(JS): # C proc log10*(x: float32): float32 {.importc: "log10f", header: "<math.h>".} proc log10*(x: float64): float64 {.importc: "log10", header: "<math.h>".} ## Computes the common logarithm (base 10) of ``x``. + ## ## .. code-block:: nim ## echo log10(100.0) ## 2.0 proc exp*(x: float32): float32 {.importc: "expf", header: "<math.h>".} proc exp*(x: float64): float64 {.importc: "exp", header: "<math.h>".} ## Computes the exponential function of ``x`` (pow(E, x)). + ## ## .. code-block:: nim ## echo exp(1.0) ## 2.718281828459045 ## echo ln(exp(4.0)) ## 4.0 proc sin*(x: float32): float32 {.importc: "sinf", header: "<math.h>".} proc sin*(x: float64): float64 {.importc: "sin", header: "<math.h>".} ## Computes the sine of ``x``. + ## ## .. code-block:: nim ## echo sin(PI / 6) ## 0.4999999999999999 ## echo sin(degToRad(90.0)) ## 1.0 proc cos*(x: float32): float32 {.importc: "cosf", header: "<math.h>".} proc cos*(x: float64): float64 {.importc: "cos", header: "<math.h>".} ## Computes the cosine of ``x``. + ## ## .. code-block:: nim ## echo cos(2 * PI) ## 1.0 ## echo cos(degToRad(60.0)) ## 0.5000000000000001 proc tan*(x: float32): float32 {.importc: "tanf", header: "<math.h>".} proc tan*(x: float64): float64 {.importc: "tan", header: "<math.h>".} ## Computes the tangent of ``x``. + ## ## .. code-block:: nim ## echo tan(degToRad(45.0)) ## 0.9999999999999999 ## echo tan(PI / 4) ## 0.9999999999999999 proc sinh*(x: float32): float32 {.importc: "sinhf", header: "<math.h>".} proc sinh*(x: float64): float64 {.importc: "sinh", header: "<math.h>".} ## Computes the `hyperbolic sine <https://en.wikipedia.org/wiki/Hyperbolic_function#Definitions>`_ of ``x``. + ## ## .. code-block:: nim ## echo sinh(1.0) ## 1.175201193643801 proc cosh*(x: float32): float32 {.importc: "coshf", header: "<math.h>".} proc cosh*(x: float64): float64 {.importc: "cosh", header: "<math.h>".} ## Computes the `hyperbolic cosine <https://en.wikipedia.org/wiki/Hyperbolic_function#Definitions>`_ of ``x``. + ## ## .. code-block:: nim ## echo cosh(1.0) ## 1.543080634815244 proc tanh*(x: float32): float32 {.importc: "tanhf", header: "<math.h>".} proc tanh*(x: float64): float64 {.importc: "tanh", header: "<math.h>".} ## Computes the `hyperbolic tangent <https://en.wikipedia.org/wiki/Hyperbolic_function#Definitions>`_ of ``x``. + ## ## .. code-block:: nim ## echo tanh(1.0) ## 0.7615941559557649 proc arccos*(x: float32): float32 {.importc: "acosf", header: "<math.h>".} proc arccos*(x: float64): float64 {.importc: "acos", header: "<math.h>".} ## Computes the arc cosine of ``x``. + ## ## .. code-block:: nim ## echo arccos(1.0) ## 0.0 proc arcsin*(x: float32): float32 {.importc: "asinf", header: "<math.h>".} @@ -250,6 +263,7 @@ when not defined(JS): # C proc arctan*(x: float32): float32 {.importc: "atanf", header: "<math.h>".} proc arctan*(x: float64): float64 {.importc: "atan", header: "<math.h>".} ## Calculate the arc tangent of ``x``. + ## ## .. code-block:: nim ## echo arctan(1.0) ## 0.7853981633974483 ## echo radToDeg(arctan(1.0)) ## 45.0 @@ -259,6 +273,7 @@ when not defined(JS): # C ## `arctan2` returns the arc tangent of ``y`` / ``x``; it produces correct ## results even when the resulting angle is near pi/2 or -pi/2 ## (``x`` near 0). + ## ## .. code-block:: nim ## echo arctan2(1.0, 0.0) ## 1.570796326794897 ## echo radToDeg(arctan2(1.0, 0.0)) ## 90.0 @@ -332,6 +347,7 @@ when not defined(JS): # C proc hypot*(x, y: float64): float64 {.importc: "hypot", header: "<math.h>".} ## Computes the hypotenuse of a right-angle triangle with ``x`` and ## ``y`` as its base and height. Equivalent to ``sqrt(x*x + y*y)``. + ## ## .. code-block:: nim ## echo hypot(4.0, 3.0) ## 5.0 proc pow*(x, y: float32): float32 {.importc: "powf", header: "<math.h>".} @@ -339,6 +355,7 @@ when not defined(JS): # C ## computes x to power raised of y. ## ## To compute power between integers, use ``^`` e.g. 2 ^ 6 + ## ## .. code-block:: nim ## echo pow(16.0, 0.5) ## 4.0 @@ -361,7 +378,7 @@ when not defined(JS): # C ## **Deprecated since version 0.19.0**: Use ``gamma`` instead. proc lgamma*(x: float32): float32 {.importc: "lgammaf", header: "<math.h>".} proc lgamma*(x: float64): float64 {.importc: "lgamma", header: "<math.h>".} - ## Computes the natural log of the gamma function for ``x``. + ## Computes the natural log of the gamma function for ``x``. proc floor*(x: float32): float32 {.importc: "floorf", header: "<math.h>".} proc floor*(x: float64): float64 {.importc: "floor", header: "<math.h>".} @@ -456,7 +473,11 @@ when not defined(JS): # C ## Computes the modulo operation for float values (the remainder of ``x`` divided by ``y``). ## ## .. code-block:: nim - ## echo 2.5 mod 0.3 ## 0.1 + ## ( 6.5 mod 2.5) == 1.5 + ## (-6.5 mod 2.5) == -1.5 + ## ( 6.5 mod -2.5) == 1.5 + ## (-6.5 mod -2.5) == -1.5 + else: # JS proc hypot*[T: float32|float64](x, y: T): T = return sqrt(x*x + y*y) proc pow*(x, y: float32): float32 {.importC: "Math.pow", nodecl.} @@ -474,7 +495,10 @@ else: # JS ## Computes the modulo operation for float values (the remainder of ``x`` divided by ``y``). ## ## .. code-block:: nim - ## echo 2.5 mod 0.3 ## 0.1 + ## ( 6.5 mod 2.5) == 1.5 + ## (-6.5 mod 2.5) == -1.5 + ## ( 6.5 mod -2.5) == 1.5 + ## (-6.5 mod -2.5) == -1.5 proc round*[T: float32|float64](x: T, places: int): T {.deprecated: "use format instead".} = ## Decimal rounding on a binary floating point number. @@ -498,19 +522,25 @@ proc floorDiv*[T: SomeInteger](x, y: T): T = ## This is different from the ``div`` operator, which is defined ## as ``trunc(x / y)``. That is, ``div`` rounds towards ``0`` and ``floorDiv`` ## rounds down. + ## ## .. code-block:: nim - ## echo floorDiv(13, 3) # 4 - ## echo floorDiv(-13, 3) # -5 + ## echo floorDiv( 13, 3) # 4 + ## echo floorDiv(-13, 3) # -5 + ## echo floorDiv( 13, -3) # -5 + ## echo floorDiv(-13, -3) # 4 result = x div y let r = x mod y if (r > 0 and y < 0) or (r < 0 and y > 0): result.dec 1 proc floorMod*[T: SomeNumber](x, y: T): T = - ## Floor modulus is conceptually defined as ``x - (floorDiv(x, y) * y). + ## Floor modulus is conceptually defined as ``x - (floorDiv(x, y) * y)``. ## This proc behaves the same as the ``%`` operator in Python. + ## ## .. code-block:: nim - ## echo floorMod(13, 3) # 1 - ## echo floorMod(-13, 3) # 2 + ## echo floorMod( 13, 3) # 1 + ## echo floorMod(-13, 3) # 2 + ## echo floorMod( 13, -3) # -2 + ## echo floorMod(-13, -3) # -1 result = x mod y if (result > 0 and y < 0) or (result < 0 and y > 0): result += y @@ -525,6 +555,7 @@ when not defined(JS): ## and less than 1) and the integer value n such that ``x`` (the original ## float value) equals ``m * 2**n``. frexp stores n in `exponent` and returns ## m. + ## ## .. code-block:: nim ## var x : int ## echo frexp(5.0, x) # 0.625 @@ -579,6 +610,7 @@ proc splitDecimal*[T: float32|float64](x: T): tuple[intpart: T, floatpart: T] = ## ## Both parts have the same sign as ``x``. Analogous to the ``modf`` ## function in C. + ## ## .. code-block:: nim ## echo splitDecimal(5.25) # (intpart: 5.0, floatpart: 0.25) var @@ -594,12 +626,14 @@ proc splitDecimal*[T: float32|float64](x: T): tuple[intpart: T, floatpart: T] = proc degToRad*[T: float32|float64](d: T): T {.inline.} = ## Convert from degrees to radians + ## ## .. code-block:: nim ## echo degToRad(180.0) # 3.141592653589793 result = T(d) * RadPerDeg proc radToDeg*[T: float32|float64](d: T): T {.inline.} = ## Convert from radians to degrees + ## .. code-block:: nim ## echo degToRad(2 * PI) # 360.0 result = T(d) / RadPerDeg @@ -608,6 +642,7 @@ proc sgn*[T: SomeNumber](x: T): int {.inline.} = ## Sign function. Returns -1 for negative numbers and ``NegInf``, 1 for ## positive numbers and ``Inf``, and 0 for positive zero, negative zero and ## ``NaN``. + ## ## .. code-block:: nim ## echo sgn(-5) # 1 ## echo sgn(-4.1) # -1 @@ -619,6 +654,7 @@ proc sgn*[T: SomeNumber](x: T): int {.inline.} = proc `^`*[T](x: T, y: Natural): T = ## Computes ``x`` to the power ``y``. ``x`` must be non-negative, use ## `pow <#pow,float,float>`_ for negative exponents. + ## ## .. code-block:: nim ## echo 2 ^ 3 # 8 when compiles(y >= T(0)): @@ -650,6 +686,7 @@ proc gcd*[T](x, y: T): T = proc gcd*(x, y: SomeInteger): SomeInteger = ## Computes the greatest common (positive) divisor of ``x`` and ``y``. ## Using binary GCD (aka Stein's) algorithm. + ## ## .. code-block:: nim ## echo gcd(24, 30) # 6 when x is SomeSignedInt: @@ -677,6 +714,7 @@ proc gcd*(x, y: SomeInteger): SomeInteger = proc lcm*[T](x, y: T): T = ## Computes the least common multiple of ``x`` and ``y``. + ## ## .. code-block:: nim ## echo lcm(24, 30) # 120 x div gcd(x, y) * y diff --git a/lib/pure/parsesql.nim b/lib/pure/parsesql.nim index 9aef43c1b..4b841b9e1 100644 --- a/lib/pure/parsesql.nim +++ b/lib/pure/parsesql.nim @@ -566,7 +566,6 @@ type SqlParser* = object of SqlLexer ## SQL parser object tok: Token - {.deprecated: [EInvalidSql: SqlParseError, PSqlNode: SqlNode, TSqlNode: SqlNodeObj, TSqlParser: SqlParser, TSqlNodeKind: SqlNodeKind].} @@ -591,6 +590,7 @@ proc len*(n: SqlNode): int = result = n.sons.len proc `[]`*(n: SqlNode; i: int): SqlNode = n.sons[i] +proc `[]`*(n: SqlNode; i: BackwardsIndex): SqlNode = n.sons[n.len - int(i)] proc add*(father, n: SqlNode) = add(father.sons, n) @@ -674,7 +674,7 @@ proc getPrecedence(p: SqlParser): int = result = 5 elif isOpr(p, "=") or isOpr(p, "<") or isOpr(p, ">") or isOpr(p, ">=") or isOpr(p, "<=") or isOpr(p, "<>") or isOpr(p, "!=") or isKeyw(p, "is") or - isKeyw(p, "like"): + isKeyw(p, "like") or isKeyw(p, "in"): result = 4 elif isKeyw(p, "and"): result = 3 @@ -717,7 +717,10 @@ proc identOrLiteral(p: var SqlParser): SqlNode = of tkParLe: getTok(p) result = newNode(nkPrGroup) - result.add(parseExpr(p)) + while true: + result.add(parseExpr(p)) + if p.tok.kind != tkComma: break + getTok(p) eat(p, tkParRi) else: if p.tok.literal == "*": @@ -1465,6 +1468,22 @@ proc `$`*(n: SqlNode): string = ## an alias for `renderSQL`. renderSQL(n) +proc treeReprAux(s: SqlNode, level: int, result: var string) = + result.add('\n') + for i in 0 ..< level: result.add(" ") + + result.add($s.kind) + if s.kind in LiteralNodes: + result.add(' ') + result.add(s.strVal) + else: + for son in s.sons: + treeReprAux(son, level + 1, result) + +proc treeRepr*(s: SqlNode): string = + result = newStringOfCap(128) + treeReprAux(s, 0, result) + when not defined(js): import streams diff --git a/lib/pure/parsexml.nim b/lib/pure/parsexml.nim index d8d5a7a2d..0967f7983 100644 --- a/lib/pure/parsexml.nim +++ b/lib/pure/parsexml.nim @@ -180,6 +180,7 @@ type errEqExpected, ## ``=`` expected errQuoteExpected, ## ``"`` or ``'`` expected errEndOfCommentExpected ## ``-->`` expected + errAttributeValueExpected ## non-empty attribute value expected ParserState = enum stateStart, stateNormal, stateAttr, stateEmptyElementTag, stateError @@ -187,6 +188,8 @@ type XmlParseOption* = enum ## options for the XML parser reportWhitespace, ## report whitespace reportComments ## report comments + allowUnquotedAttribs ## allow unquoted attribute values (for HTML) + allowEmptyAttribs ## allow empty attributes (without explicit value) XmlParser* = object of BaseLexer ## the parser object. a, b, c: string @@ -207,7 +210,8 @@ const "'>' expected", "'=' expected", "'\"' or \"'\" expected", - "'-->' expected" + "'-->' expected", + "attribute value expected" ] proc open*(my: var XmlParser, input: Stream, filename: string, @@ -618,10 +622,15 @@ proc parseAttribute(my: var XmlParser) = if my.a.len == 0: markError(my, errGtExpected) return + + let startPos = my.bufpos parseWhitespace(my, skip=true) if my.buf[my.bufpos] != '=': - markError(my, errEqExpected) + if allowEmptyAttribs notin my.options or + (my.buf[my.bufpos] != '>' and my.bufpos == startPos): + markError(my, errEqExpected) return + inc(my.bufpos) parseWhitespace(my, skip=true) @@ -669,6 +678,21 @@ proc parseAttribute(my: var XmlParser) = pendingSpace = false add(my.b, buf[pos]) inc(pos) + elif allowUnquotedAttribs in my.options: + const disallowedChars = {'"', '\'', '`', '=', '<', '>', ' ', + '\0', '\t', '\L', '\F', '\f'} + let startPos = pos + while (let c = buf[pos]; c notin disallowedChars): + if c == '&': + my.bufpos = pos + parseEntity(my, my.b) + my.kind = xmlAttribute # parseEntity overwrites my.kind! + pos = my.bufpos + else: + add(my.b, c) + inc(pos) + if pos == startPos: + markError(my, errAttributeValueExpected) else: markError(my, errQuoteExpected) # error corrections: guess what was meant diff --git a/lib/pure/strscans.nim b/lib/pure/strscans.nim index 77763ff43..c1c535e55 100644 --- a/lib/pure/strscans.nim +++ b/lib/pure/strscans.nim @@ -129,7 +129,7 @@ to use prefix instead of postfix operators. ``+E`` One or more ``?E`` Zero or One ``E{n,m}`` From ``n`` up to ``m`` times ``E`` -``~Ε`` Not predicate +``~E`` Not predicate ``a ^* b`` Shortcut for ``?(a *(b a))``. Usually used for separators. ``a ^* b`` Shortcut for ``?(a +(b a))``. Usually used for separators. ``'a'`` Matches a single character @@ -456,10 +456,11 @@ macro scanf*(input: string; pattern: static[string]; results: varargs[typed]): b template atom*(input: string; idx: int; c: char): bool = ## Used in scanp for the matching of atoms (usually chars). - idx < input.len and input[idx] == c + ## EOF is matched as ``'\0'``. + (idx < input.len and input[idx] == c) or (idx == input.len and c == '\0') template atom*(input: string; idx: int; s: set[char]): bool = - idx < input.len and input[idx] in s + (idx < input.len and input[idx] in s) or (idx == input.len and '\0' in s) template hasNxt*(input: string; idx: int): bool = idx < input.len diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index 82c6dc8b9..e266275cf 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -909,7 +909,7 @@ proc toHex*(x: BiggestInt, len: Positive): string {.noSideEffect, proc toHex*[T: SomeInteger](x: T): string = ## Shortcut for ``toHex(x, T.sizeOf * 2)`` runnableExamples: - doAssert toHex(1984) == "00000000000007C0" + doAssert toHex(1984'i64) == "00000000000007C0" toHex(BiggestInt(x), T.sizeOf * 2) proc toHex*(s: string): string {.noSideEffect, rtl.} = diff --git a/lib/pure/sugar.nim b/lib/pure/sugar.nim index 8ded552d9..53c31e8c9 100644 --- a/lib/pure/sugar.nim +++ b/lib/pure/sugar.nim @@ -125,6 +125,8 @@ macro `->`*(p, b: untyped): untyped = type ListComprehension = object var lc*: ListComprehension +template `|`*(lc: ListComprehension, comp: untyped): untyped = lc + macro `[]`*(lc: ListComprehension, comp, typ: untyped): untyped = ## List comprehension, returns a sequence. `comp` is the actual list ## comprehension, for example ``x | (x <- 1..10, x mod 2 == 0)``. `typ` is @@ -140,8 +142,7 @@ macro `[]`*(lc: ListComprehension, comp, typ: untyped): untyped = expectLen(comp, 3) expectKind(comp, nnkInfix) - expectKind(comp[0], nnkIdent) - assert($comp[0].ident == "|") + assert($comp[0] == "|") result = newCall( newDotExpr( |