diff options
Diffstat (limited to 'lib')
58 files changed, 4310 insertions, 3404 deletions
diff --git a/lib/core/allocators.nim b/lib/core/allocators.nim index 62f5e9756..f652f0d85 100644 --- a/lib/core/allocators.nim +++ b/lib/core/allocators.nim @@ -8,28 +8,41 @@ # type + AllocatorFlag* {.pure.} = enum ## flags describing the properties of the allocator + ThreadLocal ## the allocator is thread local only. + ZerosMem ## the allocator always zeros the memory on an allocation Allocator* = ptr object {.inheritable.} alloc*: proc (a: Allocator; size: int; alignment: int = 8): pointer {.nimcall.} dealloc*: proc (a: Allocator; p: pointer; size: int) {.nimcall.} realloc*: proc (a: Allocator; p: pointer; oldSize, newSize: int): pointer {.nimcall.} + deallocAll*: proc (a: Allocator) {.nimcall.} + flags*: set[AllocatorFlag] var - currentAllocator {.threadvar.}: Allocator + localAllocator {.threadvar.}: Allocator + sharedAllocator: Allocator -proc getCurrentAllocator*(): Allocator = - result = currentAllocator +proc getLocalAllocator*(): Allocator = + result = localAllocator -proc setCurrentAllocator*(a: Allocator) = - currentAllocator = a +proc setLocalAllocator*(a: Allocator) = + localAllocator = a -proc alloc*(size: int; alignment: int = 8): pointer = - let a = getCurrentAllocator() - result = a.alloc(a, size, alignment) +proc getSharedAllocator*(): Allocator = + result = sharedAllocator -proc dealloc*(p: pointer; size: int) = - let a = getCurrentAllocator() - a.dealloc(a, p, size) +proc setSharedAllocator*(a: Allocator) = + sharedAllocator = a -proc realloc*(p: pointer; oldSize, newSize: int): pointer = - let a = getCurrentAllocator() - result = a.realloc(a, p, oldSize, newSize) +when false: + proc alloc*(size: int; alignment: int = 8): pointer = + let a = getCurrentAllocator() + result = a.alloc(a, size, alignment) + + proc dealloc*(p: pointer; size: int) = + let a = getCurrentAllocator() + a.dealloc(a, p, size) + + proc realloc*(p: pointer; oldSize, newSize: int): pointer = + let a = getCurrentAllocator() + result = a.realloc(a, p, oldSize, newSize) diff --git a/lib/core/macros.nim b/lib/core/macros.nim index 90fea440e..aec766068 100644 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -8,6 +8,7 @@ # include "system/inclrtl" +include "system/helpers" ## This module contains the interface to the compiler's abstract syntax ## tree (`AST`:idx:). Macros operate on this tree. @@ -236,6 +237,12 @@ else: # bootstrapping substitute else: n.strValOld +when defined(nimHasSymOwnerInMacro): + proc owner*(sym: NimNode): NimNode {.magic: "SymOwner", noSideEffect.} + ## accepts node of kind nnkSym and returns its owner's symbol. + ## result is also mnde of kind nnkSym if owner exists otherwise + ## nnkNilLit is returned + proc getType*(n: NimNode): NimNode {.magic: "NGetType", noSideEffect.} ## with 'getType' you can access the node's `type`:idx:. A Nim type is ## mapped to a Nim AST too, so it's slightly confusing but it means the same @@ -335,10 +342,10 @@ proc copyNimTree*(n: NimNode): NimNode {.magic: "NCopyNimTree", noSideEffect.} proc error*(msg: string, n: NimNode = nil) {.magic: "NError", benign.} ## writes an error message at compile time -proc warning*(msg: string) {.magic: "NWarning", benign.} +proc warning*(msg: string, n: NimNode = nil) {.magic: "NWarning", benign.} ## writes a warning message at compile time -proc hint*(msg: string) {.magic: "NHint", benign.} +proc hint*(msg: string, n: NimNode = nil) {.magic: "NHint", benign.} ## writes a hint message at compile time proc newStrLitNode*(s: string): NimNode {.compileTime, noSideEffect.} = @@ -422,7 +429,8 @@ type line*,column*: int proc `$`*(arg: Lineinfo): string = - result = arg.filename & "(" & $arg.line & ", " & $arg.column & ")" + # BUG: without `result = `, gives compile error + result = lineInfoToString(arg.filename, arg.line, arg.column) #proc lineinfo*(n: NimNode): LineInfo {.magic: "NLineInfo", noSideEffect.} ## returns the position the node appears in the original source file @@ -969,7 +977,7 @@ proc newIfStmt*(branches: varargs[tuple[cond, body: NimNode]]): ## result = newNimNode(nnkIfStmt) for i in branches: - result.add(newNimNode(nnkElifBranch).add(i.cond, i.body)) + result.add(newTree(nnkElifBranch, i.cond, i.body)) proc newEnum*(name: NimNode, fields: openArray[NimNode], public, pure: bool): NimNode {.compileTime.} = diff --git a/lib/core/seqs.nim b/lib/core/seqs.nim index 02c192851..4dcf6cbbb 100644 --- a/lib/core/seqs.nim +++ b/lib/core/seqs.nim @@ -7,133 +7,163 @@ # distribution, for details about the copyright. # -import allocators, typetraits + +import typetraits +# strs already imported allocators for us. ## Default seq implementation used by Nim's core. type - seq*[T] = object - len, cap: int - data: ptr UncheckedArray[T] + NimSeqPayload {.core.}[T] = object + cap: int + region: Allocator + data: UncheckedArray[T] + + NimSeqV2*[T] = object + len: int + p: ptr NimSeqPayload[T] const nimSeqVersion {.core.} = 2 -template frees(s) = dealloc(s.data, s.cap * sizeof(T)) +template payloadSize(cap): int = cap * sizeof(T) + sizeof(int) + sizeof(Allocator) # XXX make code memory safe for overflows in '*' -when defined(nimHasTrace): - proc `=trace`[T](s: seq[T]; a: Allocator) = - for i in 0 ..< s.len: `=trace`(s.data[i], a) +when false: + # this is currently not part of Nim's type bound operators and so it's + # built into the tracing proc generation just like before. + proc `=trace`[T](s: NimSeqV2[T]) = + for i in 0 ..< s.len: `=trace`(s.data[i]) -proc `=destroy`[T](x: var seq[T]) = - if x.data != nil: +proc `=destroy`[T](s: var seq[T]) = + var x = cast[ptr NimSeqV2[T]](addr s) + var p = x.p + if p != nil: when not supportsCopyMem(T): - for i in 0..<x.len: `=destroy`(x[i]) - frees(x) - x.data = nil + for i in 0..<x.len: `=destroy`(p.data[i]) + p.region.dealloc(p.region, p, payloadSize(p.cap)) + x.p = nil x.len = 0 - x.cap = 0 -proc `=`[T](a: var seq[T]; b: seq[T]) = - if a.data == b.data: return - if a.data != nil: - frees(a) - a.data = nil +proc `=`[T](x: var seq[T]; y: seq[T]) = + var a = cast[ptr NimSeqV2[T]](addr x) + var b = cast[ptr NimSeqV2[T]](unsafeAddr y) + + if a.p == b.p: return + `=destroy`(a) a.len = b.len - a.cap = b.cap - if b.data != nil: - a.data = cast[type(a.data)](alloc(a.cap * sizeof(T))) + if b.p != nil: + a.p = cast[type(a.p)](alloc(payloadSize(a.len))) when supportsCopyMem(T): - copyMem(a.data, b.data, a.cap * sizeof(T)) + if a.len > 0: + copyMem(unsafeAddr a.p.data[0], unsafeAddr b.p.data[0], a.len * sizeof(T)) else: for i in 0..<a.len: - a.data[i] = b.data[i] + a.p.data[i] = b.p.data[i] -proc `=sink`[T](a: var seq[T]; b: seq[T]) = - if a.data != nil and a.data != b.data: - frees(a) +proc `=sink`[T](x: var seq[T]; y: seq[T]) = + var a = cast[ptr NimSeqV2[T]](addr x) + var b = cast[ptr NimSeqV2[T]](unsafeAddr y) + if a.p != nil and a.p != b.p: + `=destroy`(a) a.len = b.len - a.cap = b.cap - a.data = b.data - -proc resize[T](s: var seq[T]) = - let old = s.cap - if old == 0: s.cap = 8 - else: s.cap = (s.cap * 3) shr 1 - s.data = cast[type(s.data)](realloc(s.data, old * sizeof(T), s.cap * sizeof(T))) - -proc reserveSlot[T](x: var seq[T]): ptr T = - if x.len >= x.cap: resize(x) - result = addr(x.data[x.len]) - inc x.len - -template add*[T](x: var seq[T]; y: T) = - reserveSlot(x)[] = y - -proc shrink*[T](x: var seq[T]; newLen: int) = - assert newLen <= x.len - assert newLen >= 0 + a.p = b.p + +when false: + proc incrSeqV3(s: PGenericSeq, typ: PNimType): PGenericSeq {.compilerProc.} + proc setLengthSeqV2(s: PGenericSeq, typ: PNimType, newLen: int): PGenericSeq {. + compilerRtl.} + proc newSeq(typ: PNimType, len: int): pointer {.compilerRtl.} + + +type + PayloadBase = object + cap: int + region: Allocator + +proc newSeqPayload(cap, elemSize: int): pointer {.compilerRtl.} = + # we have to use type erasure here as Nim does not support generic + # compilerProcs. Oh well, this will all be inlined anyway. + if cap <= 0: + let region = getLocalAllocator() + var p = cast[ptr PayloadBase](region.alloc(region, cap * elemSize + sizeof(int) + sizeof(Allocator))) + p.region = region + p.cap = cap + result = p + else: + result = nil + +proc prepareSeqAdd(len: int; p: pointer; addlen, elemSize: int): pointer {.compilerRtl.} = + if len+addlen <= len: + result = p + elif p == nil: + result = newSeqPayload(len+addlen, elemSize) + else: + # Note: this means we cannot support things that have internal pointers as + # they get reallocated here. This needs to be documented clearly. + var p = cast[ptr PayloadBase](p) + let region = if p.region == nil: getLocalAllocator() else: p.region + let cap = max(resize(p.cap), len+addlen) + var q = cast[ptr PayloadBase](region.realloc(region, p, + sizeof(int) + sizeof(Allocator) + elemSize * p.cap, + sizeof(int) + sizeof(Allocator) + elemSize * cap)) + q.region = region + q.cap = cap + result = q + +proc shrink*[T](x: var seq[T]; newLen: Natural) = + sysAssert newLen <= x.len, "invalid newLen parameter for 'shrink'" when not supportsCopyMem(T): for i in countdown(x.len - 1, newLen - 1): - `=destroy`(x.data[i]) - x.len = newLen - -proc grow*[T](x: var seq[T]; newLen: int; value: T) = - if newLen <= x.len: return - assert newLen >= 0 - if x.cap == 0: x.cap = newLen - else: x.cap = max(newLen, (x.cap * 3) shr 1) - x.data = cast[type(x.data)](realloc(x.data, x.cap * sizeof(T))) - for i in x.len..<newLen: + `=destroy`(x[i]) + + cast[ptr NimSeqV2[T]](addr x).len = newLen + +proc grow*[T](x: var seq[T]; newLen: Natural; value: T) = + let oldLen = x.len + if newLen <= oldLen: return + var xu = cast[ptr NimSeqV2[T]](addr x) + + xu.p = prepareSeqAdd(oldLen, xu.p, newLen - oldLen, sizeof(T)) + xu.len = newLen + for i in oldLen .. newLen-1: x.data[i] = value - x.len = newLen - -template default[T](t: typedesc[T]): T = - var v: T - v - -proc setLen*[T](x: var seq[T]; newLen: int) {.deprecated.} = - if newlen < x.len: shrink(x, newLen) - else: grow(x, newLen, default(T)) - -template `[]`*[T](x: seq[T]; i: Natural): T = - assert i < x.len - x.data[i] - -template `[]=`*[T](x: seq[T]; i: Natural; y: T) = - assert i < x.len - x.data[i] = y - -proc `@`*[T](elems: openArray[T]): seq[T] = - result.cap = elems.len - result.len = elems.len - result.data = cast[type(result.data)](alloc(result.cap * sizeof(T))) - when supportsCopyMem(T): - copyMem(result.data, unsafeAddr(elems[0]), result.cap * sizeof(T)) + +proc setLen[T](s: var seq[T], newlen: Natural) = + if newlen < s.len: + shrink(s, newLen) else: - for i in 0..<result.len: - result.data[i] = elems[i] - -proc len*[T](x: seq[T]): int {.inline.} = x.len - -proc `$`*[T](x: seq[T]): string = - result = "@[" - var firstElement = true - for i in 0..<x.len: - let - value = x.data[i] - if firstElement: - firstElement = false - else: - result.add(", ") - - when compiles(value.isNil): - # this branch should not be necessary - if value.isNil: - result.add "nil" - else: - result.addQuoted(value) + var v: T # get the default value of 'v' + grow(s, newLen, v) + +when false: + proc resize[T](s: var NimSeqV2[T]) = + let old = s.cap + if old == 0: s.cap = 8 + else: s.cap = (s.cap * 3) shr 1 + s.data = cast[type(s.data)](realloc(s.data, old * sizeof(T), s.cap * sizeof(T))) + + proc reserveSlot[T](x: var NimSeqV2[T]): ptr T = + if x.len >= x.cap: resize(x) + result = addr(x.data[x.len]) + inc x.len + + template add*[T](x: var NimSeqV2[T]; y: T) = + reserveSlot(x)[] = y + + template `[]`*[T](x: NimSeqV2[T]; i: Natural): T = + assert i < x.len + x.data[i] + + template `[]=`*[T](x: NimSeqV2[T]; i: Natural; y: T) = + assert i < x.len + x.data[i] = y + + proc `@`*[T](elems: openArray[T]): NimSeqV2[T] = + result.cap = elems.len + result.len = elems.len + result.data = cast[type(result.data)](alloc(result.cap * sizeof(T))) + when supportsCopyMem(T): + copyMem(result.data, unsafeAddr(elems[0]), result.cap * sizeof(T)) else: - result.addQuoted(value) - - result.add("]") + for i in 0..<result.len: + result.data[i] = elems[i] diff --git a/lib/core/strs.nim b/lib/core/strs.nim index ff38aef1d..186add52a 100644 --- a/lib/core/strs.nim +++ b/lib/core/strs.nim @@ -7,104 +7,166 @@ # distribution, for details about the copyright. # -## Default string implementation used by Nim's core. +## Default new string implementation used by Nim's core. + +when false: + # these are to be implemented or changed in the code generator. + + #proc rawNewStringNoInit(space: int): NimString {.compilerProc.} + # seems to be unused. + proc copyDeepString(src: NimString): NimString {.inline.} + # ----------------- sequences ---------------------------------------------- + + proc incrSeqV3(s: PGenericSeq, typ: PNimType): PGenericSeq {.compilerProc.} + proc setLengthSeqV2(s: PGenericSeq, typ: PNimType, newLen: int): PGenericSeq {. + compilerRtl.} + proc newSeq(typ: PNimType, len: int): pointer {.compilerRtl.} + proc newSeqRC1(typ: PNimType, len: int): pointer {.compilerRtl.} import allocators type - string {.core, exportc: "NimStringV2".} = object - len, cap: int - data: ptr UncheckedArray[char] + NimStrPayload {.core.} = object + cap: int + region: Allocator + data: UncheckedArray[char] + + NimStringV2 {.core.} = object + len: int + p: ptr NimStrPayload ## can be nil if len == 0. const nimStrVersion {.core.} = 2 -template frees(s) = dealloc(s.data, s.cap + 1) +template isLiteral(s): bool = s.p == nil or s.p.region == nil + +template contentSize(cap): int = cap + 1 + sizeof(int) + sizeof(Allocator) + +template frees(s) = + if not isLiteral(s): + s.p.region.dealloc(s.p.region, s.p, contentSize(s.p.cap)) proc `=destroy`(s: var string) = - if s.data != nil: - frees(s) - s.data = nil - s.len = 0 - s.cap = 0 + var a = cast[ptr NimStringV2](addr s) + frees(a) + a.len = 0 + a.p = nil + +template lose(a) = + frees(a) -proc `=sink`(a: var string, b: string) = +proc `=sink`(x: var string, y: string) = + var a = cast[ptr NimStringV2](addr x) + var b = cast[ptr NimStringV2](unsafeAddr y) # we hope this is optimized away for not yet alive objects: - if a.data != nil and a.data != b.data: - frees(a) + if unlikely(a.p == b.p): return + lose(a) a.len = b.len - a.cap = b.cap - a.data = b.data + a.p = b.p -proc `=`(a: var string; b: string) = - if a.data != nil and a.data != b.data: - frees(a) - a.data = nil +proc `=`(x: var string, y: string) = + var a = cast[ptr NimStringV2](addr x) + var b = cast[ptr NimStringV2](unsafeAddr y) + if unlikely(a.p == b.p): return + lose(a) a.len = b.len - a.cap = b.cap - if b.data != nil: - a.data = cast[type(a.data)](alloc(a.cap + 1)) - copyMem(a.data, b.data, a.cap+1) - -proc resize(s: var string) = - let old = s.cap - if old == 0: s.cap = 8 - else: s.cap = (s.cap * 3) shr 1 - s.data = cast[type(s.data)](realloc(s.data, old + 1, s.cap + 1)) - -proc add*(s: var string; c: char) = - if s.len >= s.cap: resize(s) - s.data[s.len] = c - s.data[s.len+1] = '\0' + if isLiteral(b): + # we can shallow copy literals: + a.p = b.p + else: + let region = if a.p.region != nil: a.p.region else: getLocalAllocator() + # we have to allocate the 'cap' here, consider + # 'let y = newStringOfCap(); var x = y' + # on the other hand... These get turned into moves now. + a.p = cast[ptr NimStrPayload](region.alloc(region, contentSize(b.len))) + a.p.region = region + a.p.cap = b.len + copyMem(unsafeAddr a.p.data[0], unsafeAddr b.p.data[0], b.len+1) + +proc resize(old: int): int {.inline.} = + if old <= 0: result = 4 + elif old < 65536: result = old * 2 + else: result = old * 3 div 2 # for large arrays * 3/2 is better + +proc prepareAdd(s: var NimStringV2; addlen: int) {.compilerRtl.} = + if isLiteral(s): + let oldP = s.p + # can't mutate a literal, so we need a fresh copy here: + let region = getLocalAllocator() + s.p = cast[ptr NimStrPayload](region.alloc(region, contentSize(s.len + addlen))) + s.p.region = region + s.p.cap = s.len + addlen + if s.len > 0: + # we are about to append, so there is no need to copy the \0 terminator: + copyMem(unsafeAddr s.p.data[0], unsafeAddr oldP.data[0], s.len) + elif s.len + addlen > s.p.cap: + let cap = max(s.len + addlen, resize(s.p.cap)) + s.p = cast[ptr NimStrPayload](s.p.region.realloc(s.p.region, s.p, + oldSize = contentSize(s.p.cap), + newSize = contentSize(cap))) + s.p.cap = cap + +proc nimAddCharV1(s: var NimStringV2; c: char) {.compilerRtl.} = + prepareAdd(s, 1) + s.p.data[s.len] = c + s.p.data[s.len+1] = '\0' inc s.len -proc ensure(s: var string; newLen: int) = - let old = s.cap - if newLen >= old: - s.cap = max((old * 3) shr 1, newLen) - if s.cap > 0: - s.data = cast[type(s.data)](realloc(s.data, old + 1, s.cap + 1)) - -proc add*(s: var string; y: string) = - if y.len != 0: - let newLen = s.len + y.len - ensure(s, newLen) - copyMem(addr s.data[len], y.data, y.data.len + 1) +proc toNimStr(str: cstring, len: int): NimStringV2 {.compilerProc.} = + if len <= 0: + result = NimStringV2(len: 0, p: nil) + else: + let region = getLocalAllocator() + var p = cast[ptr NimStrPayload](region.alloc(region, contentSize(len))) + p.region = region + p.cap = len + if len > 0: + # we are about to append, so there is no need to copy the \0 terminator: + copyMem(unsafeAddr p.data[0], str, len) + result = NimStringV2(len: 0, p: p) + +proc cstrToNimstr(str: cstring): NimStringV2 {.compilerRtl.} = + if str == nil: toNimStr(str, 0) + else: toNimStr(str, str.len) + +proc nimToCStringConv(s: NimStringV2): cstring {.compilerProc, inline.} = + if s.len == 0: result = cstring"" + else: result = cstring(unsafeAddr s.p.data) + +proc appendString(dest: var NimStringV2; src: NimStringV2) {.compilerproc, inline.} = + if src.len > 0: + # also copy the \0 terminator: + copyMem(unsafeAddr dest.p.data[dest.len], unsafeAddr src.p.data[0], src.len+1) + +proc appendChar(dest: var NimStringV2; c: char) {.compilerproc, inline.} = + dest.p.data[dest.len] = c + dest.p.data[dest.len+1] = '\0' + inc dest.len + +proc rawNewString(space: int): NimStringV2 {.compilerProc.} = + # this is also 'system.newStringOfCap'. + if space <= 0: + result = NimStringV2(len: 0, p: nil) + else: + let region = getLocalAllocator() + var p = cast[ptr NimStrPayload](region.alloc(region, contentSize(space))) + p.region = region + p.cap = space + result = NimStringV2(len: 0, p: p) + +proc mnewString(len: int): NimStringV2 {.compilerProc.} = + if len <= 0: + result = NimStringV2(len: 0, p: nil) + else: + let region = getLocalAllocator() + var p = cast[ptr NimStrPayload](region.alloc(region, contentSize(len))) + p.region = region + p.cap = len + result = NimStringV2(len: len, p: p) + +proc setLengthStrV2(s: var NimStringV2, newLen: int) {.compilerRtl.} = + if newLen > s.len: + prepareAdd(s, newLen - s.len) + else: s.len = newLen - -proc len*(s: string): int {.inline.} = s.len - -proc newString*(len: int): string = - result.len = len - result.cap = len - if len > 0: - result.data = alloc0(len+1) - -converter toCString(x: string): cstring {.core, inline.} = - if x.len == 0: cstring"" else: cast[cstring](x.data) - -proc newStringOfCap*(cap: int): string = - result.len = 0 - result.cap = cap - if cap > 0: - result.data = alloc(cap+1) - -proc `&`*(a, b: string): string = - let sum = a.len + b.len - result = newStringOfCap(sum) - result.len = sum - copyMem(addr result.data[0], a.data, a.len) - copyMem(addr result.data[a.len], b.data, b.len) - if sum > 0: - result.data[sum] = '\0' - -proc concat(x: openArray[string]): string {.core.} = - ## used be the code generator to optimize 'x & y & z ...' - var sum = 0 - for i in 0 ..< x.len: inc(sum, x[i].len) - result = newStringOfCap(sum) - sum = 0 - for i in 0 ..< x.len: - let L = x[i].len - copyMem(addr result.data[sum], x[i].data, L) - inc(sum, L) - + # this also only works because the destructor + # looks at s.p and not s.len diff --git a/lib/js/asyncjs.nim b/lib/js/asyncjs.nim index 894102ca0..7439b66e1 100644 --- a/lib/js/asyncjs.nim +++ b/lib/js/asyncjs.nim @@ -92,7 +92,10 @@ proc isFutureVoid(node: NimNode): bool = node[1].kind == nnkIdent and $node[1] == "void" proc generateJsasync(arg: NimNode): NimNode = - assert arg.kind == nnkProcDef + if arg.kind notin {nnkProcDef, nnkLambda, nnkMethodDef, nnkDo}: + error("Cannot transform this node kind into an async proc." & + " proc/method definition or lambda node expected.") + result = arg var isVoid = false let jsResolve = ident("jsResolve") @@ -108,7 +111,7 @@ proc generateJsasync(arg: NimNode): NimNode = if len(code) > 0: var awaitFunction = quote: - proc await[T](f: Future[T]): T {.importcpp: "(await #)".} + proc await[T](f: Future[T]): T {.importcpp: "(await #)", used.} result.body.add(awaitFunction) var resolve: NimNode @@ -117,7 +120,7 @@ proc generateJsasync(arg: NimNode): NimNode = var `jsResolve` {.importcpp: "undefined".}: Future[void] else: resolve = quote: - proc jsResolve[T](a: T): Future[T] {.importcpp: "#".} + proc jsResolve[T](a: T): Future[T] {.importcpp: "#", used.} result.body.add(resolve) else: result.body = newEmptyNode() @@ -137,7 +140,12 @@ proc generateJsasync(arg: NimNode): NimNode = macro async*(arg: untyped): untyped = ## Macro which converts normal procedures into ## javascript-compatible async procedures - generateJsasync(arg) + if arg.kind == nnkStmtList: + result = newStmtList() + for oneProc in arg: + result.add generateJsasync(oneProc) + else: + result = generateJsasync(arg) proc newPromise*[T](handler: proc(resolve: proc(response: T))): Future[T] {.importcpp: "(new Promise(#))".} ## A helper for wrapping callback-based functions diff --git a/lib/js/dom.nim b/lib/js/dom.nim index fd81fdf3f..cf219df3d 100644 --- a/lib/js/dom.nim +++ b/lib/js/dom.nim @@ -201,7 +201,7 @@ type vspace*: int width*: int - Style = ref StyleObj + Style* = ref StyleObj StyleObj {.importc.} = object of RootObj background*: cstring backgroundAttachment*: cstring diff --git a/lib/nimbase.h b/lib/nimbase.h index 84972fcb0..507108712 100644 --- a/lib/nimbase.h +++ b/lib/nimbase.h @@ -107,6 +107,8 @@ __clang__ # define N_INLINE(rettype, name) rettype __inline name #endif +#define N_INLINE_PTR(rettype, name) rettype (*name) + #if defined(__POCC__) # define NIM_CONST /* PCC is really picky with const modifiers */ # undef _MSC_VER /* Yeah, right PCC defines _MSC_VER even if it is diff --git a/lib/packages/docutils/highlite.nim b/lib/packages/docutils/highlite.nim index fbd2d7eca..4d444603e 100644 --- a/lib/packages/docutils/highlite.nim +++ b/lib/packages/docutils/highlite.nim @@ -881,7 +881,7 @@ when isMainModule: break except: echo filename, " not found" - doAssert(not keywords.isNil, "Couldn't read any keywords.txt file!") + doAssert(keywords.len > 0, "Couldn't read any keywords.txt file!") for i in 0..min(keywords.len, nimKeywords.len)-1: doAssert keywords[i] == nimKeywords[i], "Unexpected keyword" doAssert keywords.len == nimKeywords.len, "No matching lengths" diff --git a/lib/packages/docutils/rst.nim b/lib/packages/docutils/rst.nim index 7ee071c79..d35f109e7 100644 --- a/lib/packages/docutils/rst.nim +++ b/lib/packages/docutils/rst.nim @@ -1387,7 +1387,7 @@ proc parseSectionWrapper(p: var RstParser): PRstNode = result = result.sons[0] proc `$`(t: Token): string = - result = $t.kind & ' ' & (if isNil(t.symbol): "NIL" else: t.symbol) + result = $t.kind & ' ' & t.symbol proc parseDoc(p: var RstParser): PRstNode = result = parseSectionWrapper(p) diff --git a/lib/packages/docutils/rstgen.nim b/lib/packages/docutils/rstgen.nim index 5b0b6c6ee..51bb9c757 100644 --- a/lib/packages/docutils/rstgen.nim +++ b/lib/packages/docutils/rstgen.nim @@ -85,8 +85,8 @@ proc init(p: var CodeBlockParams) = proc initRstGenerator*(g: var RstGenerator, target: OutputTarget, config: StringTableRef, filename: string, options: RstParseOptions, - findFile: FindFileHandler=nil, - msgHandler: MsgHandler=nil) = + findFile: FindFileHandler = nil, + msgHandler: MsgHandler = nil) = ## Initializes a ``RstGenerator``. ## ## You need to call this before using a ``RstGenerator`` with any other @@ -243,7 +243,7 @@ proc dispA(target: OutputTarget, dest: var string, else: addf(dest, tex, args) proc `or`(x, y: string): string {.inline.} = - result = if x.isNil: y else: x + result = if x.len == 0: y else: x proc renderRstToOut*(d: var RstGenerator, n: PRstNode, result: var string) ## Writes into ``result`` the rst ast ``n`` using the ``d`` configuration. @@ -255,9 +255,9 @@ proc renderRstToOut*(d: var RstGenerator, n: PRstNode, result: var string) ## .. code-block:: nim ## ## # ...configure gen and rst vars... - ## var generatedHTML = "" - ## renderRstToOut(gen, rst, generatedHTML) - ## echo generatedHTML + ## var generatedHtml = "" + ## renderRstToOut(gen, rst, generatedHtml) + ## echo generatedHtml proc renderAux(d: PDoc, n: PRstNode, result: var string) = for i in countup(0, len(n)-1): renderRstToOut(d, n.sons[i], result) @@ -282,20 +282,26 @@ proc quoteIndexColumn(text: string): string = ## * ``"\\"`` => ``"\\\\"`` ## * ``"\n"`` => ``"\\n"`` ## * ``"\t"`` => ``"\\t"`` - result = text.replace("\\", "\\\\").replace("\n", "\\n").replace("\t", "\\t") + result = newStringOfCap(text.len + 3) + for c in text: + case c + of '\\': result.add "\\" + of '\L': result.add "\\n" + of '\C': discard + of '\t': result.add "\\t" + else: result.add c proc unquoteIndexColumn(text: string): string = ## Returns the unquoted version generated by ``quoteIndexColumn``. - result = text.replace("\\t", "\t").replace("\\n", "\n").replace("\\\\", "\\") + result = text.multiReplace(("\\t", "\t"), ("\\n", "\n"), ("\\\\", "\\")) -proc setIndexTerm*(d: var RstGenerator, id, term: string, +proc setIndexTerm*(d: var RstGenerator, htmlFile, id, term: string, linkTitle, linkDesc = "") = ## Adds a `term` to the index using the specified hyperlink identifier. ## ## A new entry will be added to the index using the format - ## ``term<tab>file#id``. The file part will come from the `filename` - ## parameter used in a previous call to the `initRstGenerator() - ## <#initRstGenerator>`_ proc. + ## ``term<tab>file#id``. The file part will come from the `htmlFile` + ## parameter. ## ## The `id` will be appended with a hash character only if its length is not ## zero, otherwise no specific anchor will be generated. In general you @@ -316,7 +322,6 @@ proc setIndexTerm*(d: var RstGenerator, id, term: string, entry = term isTitle = false entry.add('\t') - let htmlFile = changeFileExt(extractFilename(d.filename), HtmlExt) entry.add(htmlFile) if id.len > 0: entry.add('#') @@ -356,7 +361,7 @@ proc renderIndexTerm*(d: PDoc, n: PRstNode, result: var string) = var term = "" renderAux(d, n, term) - setIndexTerm(d, id, term, d.currentSection) + setIndexTerm(d, changeFileExt(extractFilename(d.filename), HtmlExt), id, term, d.currentSection) dispA(d.target, result, "<span id=\"$1\">$2</span>", "$2\\label{$1}", [id, term]) @@ -364,15 +369,15 @@ type IndexEntry = object keyword: string link: string - linkTitle: string ## If not nil, contains a prettier text for the href - linkDesc: string ## If not nil, the title attribute of the final href + linkTitle: string ## contains a prettier text for the href + linkDesc: string ## the title attribute of the final href IndexedDocs = Table[IndexEntry, seq[IndexEntry]] ## \ ## Contains the index sequences for doc types. ## ## The key is a *fake* IndexEntry which will contain the title of the ## document in the `keyword` field and `link` will contain the html - ## filename for the document. `linkTitle` and `linkDesc` will be nil. + ## filename for the document. `linkTitle` and `linkDesc` will be empty. ## ## The value indexed by this IndexEntry is a sequence with the real index ## entries found in the ``.idx`` file. @@ -387,20 +392,16 @@ proc hash(x: IndexEntry): Hash = ## Returns the hash for the combined fields of the type. ## ## The hash is computed as the chained hash of the individual string hashes. - assert(not x.keyword.isNil) - assert(not x.link.isNil) result = x.keyword.hash !& x.link.hash - result = result !& (x.linkTitle or "").hash - result = result !& (x.linkDesc or "").hash + result = result !& x.linkTitle.hash + result = result !& x.linkDesc.hash result = !$result proc `<-`(a: var IndexEntry, b: IndexEntry) = shallowCopy a.keyword, b.keyword shallowCopy a.link, b.link - if b.linkTitle.isNil: a.linkTitle = "" - else: shallowCopy a.linkTitle, b.linkTitle - if b.linkDesc.isNil: a.linkDesc = "" - else: shallowCopy a.linkDesc, b.linkDesc + shallowCopy a.linkTitle, b.linkTitle + shallowCopy a.linkDesc, b.linkDesc proc sortIndex(a: var openArray[IndexEntry]) = # we use shellsort here; fast and simple @@ -437,15 +438,15 @@ proc generateSymbolIndex(symbols: seq[IndexEntry]): string = var i = 0 while i < symbols.len: let keyword = symbols[i].keyword - let cleaned_keyword = keyword.escapeLink + let cleanedKeyword = keyword.escapeLink result.addf("<dt><a name=\"$2\" href=\"#$2\"><span>$1:</span></a></dt><dd><ul class=\"simple\">\n", - [keyword, cleaned_keyword]) + [keyword, cleanedKeyword]) var j = i while j < symbols.len and keyword == symbols[j].keyword: let - url = symbols[j].link.escapeLink - text = if not symbols[j].linkTitle.isNil: symbols[j].linkTitle else: url - desc = if not symbols[j].linkDesc.isNil: symbols[j].linkDesc else: "" + url = symbols[j].link #.escapeLink + text = if symbols[j].linkTitle.len > 0: symbols[j].linkTitle else: url + desc = if symbols[j].linkDesc.len > 0: symbols[j].linkDesc else: "" if desc.len > 0: result.addf("""<li><a class="reference external" title="$3" data-doc-search-tag="$2" href="$1">$2</a></li> @@ -466,12 +467,12 @@ proc isDocumentationTitle(hyperlink: string): bool = ## for a more detailed explanation. result = hyperlink.find('#') < 0 -proc stripTOCLevel(s: string): tuple[level: int, text: string] = +proc stripTocLevel(s: string): tuple[level: int, text: string] = ## Returns the *level* of the toc along with the text without it. - for c in 0 .. <s.len: + for c in 0 ..< s.len: result.level = c if s[c] != ' ': break - result.text = s[result.level .. <s.len] + result.text = s[result.level ..< s.len] proc indentToLevel(level: var int, newLevel: int): string = ## Returns the sequence of <ul>|</ul> characters to switch to `newLevel`. @@ -487,7 +488,7 @@ proc indentToLevel(level: var int, newLevel: int): string = result = repeat("</ul></li>", level - newLevel) level = newLevel -proc generateDocumentationTOC(entries: seq[IndexEntry]): string = +proc generateDocumentationToc(entries: seq[IndexEntry]): string = ## Returns the sequence of index entries in an HTML hierarchical list. result = "" # Build a list of levels and extracted titles to make processing easier. @@ -499,7 +500,7 @@ proc generateDocumentationTOC(entries: seq[IndexEntry]): string = level = 1 levels.newSeq(entries.len) for entry in entries: - let (rawLevel, rawText) = stripTOCLevel(entry.linkTitle or entry.keyword) + let (rawLevel, rawText) = stripTocLevel(entry.linkTitle or entry.keyword) if rawLevel < 1: # This is a normal symbol, push it *inside* one level from the last one. levels[L].level = level + 1 @@ -523,13 +524,11 @@ proc generateDocumentationTOC(entries: seq[IndexEntry]): string = titleTag = levels[L].text else: result.add(level.indentToLevel(levels[L].level)) - result.addf("""<li><a class="reference" data-doc-search-tag="$1" href="$2"> + result.addf("""<li><a class="reference" data-doc-search-tag="$1: $2" href="$3"> $3</a></li> - """, [titleTag & " : " & levels[L].text, link, levels[L].text]) + """, [titleTag, levels[L].text, link, levels[L].text]) inc L result.add(level.indentToLevel(1) & "</ul>\n") - assert(not titleRef.isNil, - "Can't use this proc on an API index, docs always have a title entry") proc generateDocumentationIndex(docs: IndexedDocs): string = ## Returns all the documentation TOCs in an HTML hierarchical list. @@ -540,7 +539,7 @@ proc generateDocumentationIndex(docs: IndexedDocs): string = sort(titles, cmp) for title in titles: - let tocList = generateDocumentationTOC(docs.getOrDefault(title)) + let tocList = generateDocumentationToc(docs.getOrDefault(title)) result.add("<ul><li><a href=\"" & title.link & "\">" & title.keyword & "</a>\n" & tocList & "</li></ul>\n") @@ -581,8 +580,8 @@ proc readIndexDir(dir: string): setLen(result.symbols, 0) var L = 0 # Scan index files and build the list of symbols. - for kind, path in walkDir(dir): - if kind == pcFile and path.endsWith(IndexExt): + for path in walkDirRec(dir): + if path.endsWith(IndexExt): var fileEntries: seq[IndexEntry] title: IndexEntry @@ -596,7 +595,7 @@ proc readIndexDir(dir: string): fileEntries[F].keyword = line.substr(0, s-1) fileEntries[F].link = line.substr(s+1) # See if we detect a title, a link without a `#foobar` trailing part. - if title.keyword.isNil and fileEntries[F].link.isDocumentationTitle: + if title.keyword.len == 0 and fileEntries[F].link.isDocumentationTitle: title.keyword = fileEntries[F].keyword title.link = fileEntries[F].link @@ -611,17 +610,24 @@ proc readIndexDir(dir: string): fileEntries[F].linkDesc = "" inc F # Depending on type add this to the list of symbols or table of APIs. - if title.keyword.isNil: - for i in 0 .. <F: + if title.keyword.len == 0: + for i in 0 ..< F: # Don't add to symbols TOC entries (they start with a whitespace). let toc = fileEntries[i].linkTitle - if not toc.isNil and toc.len > 0 and toc[0] == ' ': + if toc.len > 0 and toc[0] == ' ': continue # Ok, non TOC entry, add it. setLen(result.symbols, L + 1) result.symbols[L] = fileEntries[i] inc L - result.modules.add(path.splitFile.name) + if fileEntries.len > 0: + var x = fileEntries[0].link + let i = find(x, '#') + if i > 0: + x = x.substr(0, i-1) + if i != 0: + # don't add entries starting with '#' + result.modules.add(x.changeFileExt("")) else: # Generate the symbolic anchor for index quickjumps. title.linkTitle = "doc_toc_" & $result.docs.len @@ -668,10 +674,11 @@ proc mergeIndexes*(dir: string): string = result.add(generateModuleJumps(modules)) result.add("<p />") - # Generate the HTML block with API documents. - if docs.len > 0: - result.add("<h2>Documentation files</h2>\n") - result.add(generateDocumentationIndex(docs)) + when false: + # Generate the HTML block with API documents. + if docs.len > 0: + result.add("<h2>Documentation files</h2>\n") + result.add(generateDocumentationIndex(docs)) # Generate the HTML block with symbols. if symbols.len > 0: @@ -682,7 +689,7 @@ proc mergeIndexes*(dir: string): string = # ---------------------------------------------------------------------------- -proc stripTOCHTML(s: string): string = +proc stripTocHtml(s: string): string = ## Ugly quick hack to remove HTML tags from TOC titles. ## ## A TocEntry.header field already contains rendered HTML tags. Instead of @@ -730,7 +737,7 @@ proc renderHeadline(d: PDoc, n: PRstNode, result: var string) = # Generate index entry using spaces to indicate TOC level for the output HTML. assert n.level >= 0 - setIndexTerm(d, refname, tmp.stripTOCHTML, + setIndexTerm(d, changeFileExt(extractFilename(d.filename), HtmlExt), refname, tmp.stripTocHtml, spaces(max(0, n.level)) & tmp) proc renderOverline(d: PDoc, n: PRstNode, result: var string) = @@ -878,7 +885,7 @@ proc parseCodeBlockParams(d: PDoc, n: PRstNode): CodeBlockParams = if result.langStr != "": result.lang = getSourceLanguage(result.langStr) -proc buildLinesHTMLTable(d: PDoc; params: CodeBlockParams, code: string): +proc buildLinesHtmlTable(d: PDoc; params: CodeBlockParams, code: string): tuple[beginTable, endTable: string] = ## Returns the necessary tags to start/end a code block in HTML. ## @@ -928,7 +935,7 @@ proc renderCodeBlock(d: PDoc, n: PRstNode, result: var string) = if params.testCmd.len > 0 and d.onTestSnippet != nil: d.onTestSnippet(d, params.filename, params.testCmd, params.status, m.text) - let (blockStart, blockEnd) = buildLinesHTMLTable(d, params, m.text) + let (blockStart, blockEnd) = buildLinesHtmlTable(d, params, m.text) dispA(d.target, result, blockStart, "\\begin{rstpre}\n", []) if params.lang == langNone: diff --git a/lib/posix/posix_linux_amd64_consts.nim b/lib/posix/posix_linux_amd64_consts.nim index ee4fac1e8..50b227635 100644 --- a/lib/posix/posix_linux_amd64_consts.nim +++ b/lib/posix/posix_linux_amd64_consts.nim @@ -300,7 +300,7 @@ const IPPROTO_TCP* = cint(6) const IPPROTO_UDP* = cint(17) const INADDR_ANY* = InAddrScalar(0) const INADDR_LOOPBACK* = InAddrScalar(2130706433) -const INADDR_BROADCAST* = InAddrScalar(-1) +const INADDR_BROADCAST* = InAddrScalar(4294967295) const INET_ADDRSTRLEN* = cint(16) const INET6_ADDRSTRLEN* = cint(46) const IPV6_JOIN_GROUP* = cint(20) diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim index dfc7201b8..820f34703 100644 --- a/lib/pure/asyncdispatch.nim +++ b/lib/pure/asyncdispatch.nim @@ -10,6 +10,7 @@ include "system/inclrtl" import os, tables, strutils, times, heapqueue, lists, options, asyncstreams +import options, math import asyncfutures except callSoon import nativesockets, net, deques @@ -157,9 +158,6 @@ export asyncfutures, asyncstreams ## ---------------- ## ## * The effect system (``raises: []``) does not work with async procedures. -## * Can't await in a ``except`` body -## * Forward declarations for async procs are broken, -## link includes workaround: https://github.com/nim-lang/Nim/issues/3182. # TODO: Check if yielded future is nil and throw a more meaningful exception @@ -168,8 +166,10 @@ type timers*: HeapQueue[tuple[finishAt: float, fut: Future[void]]] callbacks*: Deque[proc ()] -proc processTimers(p: PDispatcherBase; didSomeWork: var bool) {.inline.} = - #Process just part if timers at a step +proc processTimers( + p: PDispatcherBase, didSomeWork: var bool +): Option[int] {.inline.} = + # Pop the timers in the order in which they will expire (smaller `finishAt`). var count = p.timers.len let t = epochTime() while count > 0 and t >= p.timers[0].finishAt: @@ -177,22 +177,25 @@ proc processTimers(p: PDispatcherBase; didSomeWork: var bool) {.inline.} = dec count didSomeWork = true + # Return the number of miliseconds in which the next timer will expire. + if p.timers.len == 0: return + + let milisecs = (p.timers[0].finishAt - epochTime()) * 1000 + return some(ceil(milisecs).int) + proc processPendingCallbacks(p: PDispatcherBase; didSomeWork: var bool) = while p.callbacks.len > 0: var cb = p.callbacks.popFirst() cb() didSomeWork = true -proc adjustedTimeout(p: PDispatcherBase, timeout: int): int {.inline.} = - # If dispatcher has active timers this proc returns the timeout - # of the nearest timer. Returns `timeout` otherwise. - result = timeout - if p.timers.len > 0: - let timerTimeout = p.timers[0].finishAt - let curTime = epochTime() - if timeout == -1 or (curTime + (timeout / 1000)) > timerTimeout: - result = int((timerTimeout - curTime) * 1000) - if result < 0: result = 0 +proc adjustTimeout(pollTimeout: int, nextTimer: Option[int]): int {.inline.} = + if nextTimer.isNone(): + return pollTimeout + + result = nextTimer.get() + if pollTimeout == -1: return + result = min(pollTimeout, result) proc callSoon(cbproc: proc ()) {.gcsafe.} @@ -299,53 +302,53 @@ when defined(windows) or defined(nimdoc): "No handles or timers registered in dispatcher.") result = false - if p.handles.len != 0: - let at = p.adjustedTimeout(timeout) - var llTimeout = - if at == -1: winlean.INFINITE - else: at.int32 - - var lpNumberOfBytesTransferred: Dword - var lpCompletionKey: ULONG_PTR - var customOverlapped: PCustomOverlapped - let res = getQueuedCompletionStatus(p.ioPort, - addr lpNumberOfBytesTransferred, addr lpCompletionKey, - cast[ptr POVERLAPPED](addr customOverlapped), llTimeout).bool - result = true - - # http://stackoverflow.com/a/12277264/492186 - # TODO: http://www.serverframework.com/handling-multiple-pending-socket-read-and-write-operations.html - if res: - # This is useful for ensuring the reliability of the overlapped struct. + let nextTimer = processTimers(p, result) + let at = adjustTimeout(timeout, nextTimer) + var llTimeout = + if at == -1: winlean.INFINITE + else: at.int32 + + var lpNumberOfBytesTransferred: Dword + var lpCompletionKey: ULONG_PTR + var customOverlapped: PCustomOverlapped + let res = getQueuedCompletionStatus(p.ioPort, + addr lpNumberOfBytesTransferred, addr lpCompletionKey, + cast[ptr POVERLAPPED](addr customOverlapped), llTimeout).bool + result = true + + # http://stackoverflow.com/a/12277264/492186 + # TODO: http://www.serverframework.com/handling-multiple-pending-socket-read-and-write-operations.html + if res: + # This is useful for ensuring the reliability of the overlapped struct. + assert customOverlapped.data.fd == lpCompletionKey.AsyncFD + + customOverlapped.data.cb(customOverlapped.data.fd, + lpNumberOfBytesTransferred, OSErrorCode(-1)) + + # If cell.data != nil, then system.protect(rawEnv(cb)) was called, + # so we need to dispose our `cb` environment, because it is not needed + # anymore. + if customOverlapped.data.cell.data != nil: + system.dispose(customOverlapped.data.cell) + + GC_unref(customOverlapped) + else: + let errCode = osLastError() + if customOverlapped != nil: assert customOverlapped.data.fd == lpCompletionKey.AsyncFD - customOverlapped.data.cb(customOverlapped.data.fd, - lpNumberOfBytesTransferred, OSErrorCode(-1)) - - # If cell.data != nil, then system.protect(rawEnv(cb)) was called, - # so we need to dispose our `cb` environment, because it is not needed - # anymore. + lpNumberOfBytesTransferred, errCode) if customOverlapped.data.cell.data != nil: system.dispose(customOverlapped.data.cell) - GC_unref(customOverlapped) else: - let errCode = osLastError() - if customOverlapped != nil: - assert customOverlapped.data.fd == lpCompletionKey.AsyncFD - customOverlapped.data.cb(customOverlapped.data.fd, - lpNumberOfBytesTransferred, errCode) - if customOverlapped.data.cell.data != nil: - system.dispose(customOverlapped.data.cell) - GC_unref(customOverlapped) - else: - if errCode.int32 == WAIT_TIMEOUT: - # Timed out - result = false - else: raiseOSError(errCode) + if errCode.int32 == WAIT_TIMEOUT: + # Timed out + result = false + else: raiseOSError(errCode) # Timer processing. - processTimers(p, result) + discard processTimers(p, result) # Callback queue processing processPendingCallbacks(p, result) @@ -1231,48 +1234,48 @@ else: "No handles or timers registered in dispatcher.") result = false - if not p.selector.isEmpty(): - var keys: array[64, ReadyKey] - var count = p.selector.selectInto(p.adjustedTimeout(timeout), keys) - for i in 0..<count: - var custom = false - let fd = keys[i].fd - let events = keys[i].events - var rLength = 0 # len(data.readList) after callback - var wLength = 0 # len(data.writeList) after callback - - if Event.Read in events or events == {Event.Error}: - processBasicCallbacks(fd, readList) - result = true - - if Event.Write in events or events == {Event.Error}: - processBasicCallbacks(fd, writeList) - result = true - - if Event.User in events: - processBasicCallbacks(fd, readList) + var keys: array[64, ReadyKey] + let nextTimer = processTimers(p, result) + var count = p.selector.selectInto(adjustTimeout(timeout, nextTimer), keys) + for i in 0..<count: + var custom = false + let fd = keys[i].fd + let events = keys[i].events + var rLength = 0 # len(data.readList) after callback + var wLength = 0 # len(data.writeList) after callback + + if Event.Read in events or events == {Event.Error}: + processBasicCallbacks(fd, readList) + result = true + + if Event.Write in events or events == {Event.Error}: + processBasicCallbacks(fd, writeList) + result = true + + if Event.User in events: + processBasicCallbacks(fd, readList) + custom = true + if rLength == 0: + p.selector.unregister(fd) + result = true + + when ioselSupportedPlatform: + if (customSet * events) != {}: custom = true - if rLength == 0: - p.selector.unregister(fd) + processCustomCallbacks(fd) result = true - when ioselSupportedPlatform: - if (customSet * events) != {}: - custom = true - processCustomCallbacks(fd) - result = true - - # because state `data` can be modified in callback we need to update - # descriptor events with currently registered callbacks. - if not custom: - var newEvents: set[Event] = {} - if rLength != -1 and wLength != -1: - if rLength > 0: incl(newEvents, Event.Read) - if wLength > 0: incl(newEvents, Event.Write) - p.selector.updateHandle(SocketHandle(fd), newEvents) + # because state `data` can be modified in callback we need to update + # descriptor events with currently registered callbacks. + if not custom: + var newEvents: set[Event] = {} + if rLength != -1 and wLength != -1: + if rLength > 0: incl(newEvents, Event.Read) + if wLength > 0: incl(newEvents, Event.Write) + p.selector.updateHandle(SocketHandle(fd), newEvents) # Timer processing. - processTimers(p, result) + discard processTimers(p, result) # Callback queue processing processPendingCallbacks(p, result) @@ -1533,7 +1536,11 @@ proc withTimeout*[T](fut: Future[T], timeout: int): Future[bool] = var timeoutFuture = sleepAsync(timeout) fut.callback = proc () = - if not retFuture.finished: retFuture.complete(true) + if not retFuture.finished: + if fut.failed: + retFuture.fail(fut.error) + else: + retFuture.complete(true) timeoutFuture.callback = proc () = if not retFuture.finished: retFuture.complete(false) diff --git a/lib/pure/asyncmacro.nim b/lib/pure/asyncmacro.nim index 4665ad25f..9e0893a4d 100644 --- a/lib/pure/asyncmacro.nim +++ b/lib/pure/asyncmacro.nim @@ -327,8 +327,8 @@ macro async*(prc: untyped): untyped = ## Macro which processes async procedures into the appropriate ## iterators and yield statements. if prc.kind == nnkStmtList: + result = newStmtList() for oneProc in prc: - result = newStmtList() result.add asyncSingleProc(oneProc) else: result = asyncSingleProc(prc) diff --git a/lib/pure/cgi.nim b/lib/pure/cgi.nim index e0cdc2ec0..101146ace 100644 --- a/lib/pure/cgi.nim +++ b/lib/pure/cgi.nim @@ -135,10 +135,9 @@ iterator decodeData*(allowedMethods: set[RequestMethod] = ## Reads and decodes CGI data and yields the (name, value) pairs the ## data consists of. If the client does not use a method listed in the ## `allowedMethods` set, an `ECgi` exception is raised. - var data = getEncodedData(allowedMethods) - if not isNil(data): - for key, value in decodeData(data): - yield (key, value) + let data = getEncodedData(allowedMethods) + for key, value in decodeData(data): + yield (key, value) proc readData*(allowedMethods: set[RequestMethod] = {methodNone, methodPost, methodGet}): StringTableRef = diff --git a/lib/pure/collections/deques.nim b/lib/pure/collections/deques.nim index 409240b37..e8342e208 100644 --- a/lib/pure/collections/deques.nim +++ b/lib/pure/collections/deques.nim @@ -161,10 +161,7 @@ proc peekLast*[T](deq: Deque[T]): T {.inline.} = result = deq.data[(deq.tail - 1) and deq.mask] template destroy(x: untyped) = - when defined(nimNewRuntime) and not supportsCopyMem(type(x)): - `=destroy`(x) - else: - reset(x) + reset(x) proc popFirst*[T](deq: var Deque[T]): T {.inline, discardable.} = ## Remove and returns the first element of the `deq`. diff --git a/lib/pure/collections/sequtils.nim b/lib/pure/collections/sequtils.nim index 612624f1d..63d910a8e 100644 --- a/lib/pure/collections/sequtils.nim +++ b/lib/pure/collections/sequtils.nim @@ -183,7 +183,6 @@ proc distribute*[T](s: seq[T], num: Positive, spread = true): seq[seq[T]] = ## assert numbers.distribute(3, false) == @[@[1, 2, 3], @[4, 5, 6], @[7]] ## assert numbers.distribute(6)[0] == @[1, 2] ## assert numbers.distribute(6)[5] == @[7] - assert(not s.isNil, "`s` can't be nil") if num < 2: result = @[s] return diff --git a/lib/pure/collections/sets.nim b/lib/pure/collections/sets.nim index fdc3b4b03..31ca56963 100644 --- a/lib/pure/collections/sets.nim +++ b/lib/pure/collections/sets.nim @@ -74,7 +74,7 @@ proc isValid*[A](s: HashSet[A]): bool = ## proc savePreferences(options: HashSet[string]) = ## assert options.isValid, "Pass an initialized set!" ## # Do stuff here, may crash in release builds! - result = not s.data.isNil + result = s.data.len > 0 proc len*[A](s: HashSet[A]): int = ## Returns the number of keys in `s`. @@ -654,7 +654,7 @@ proc isValid*[A](s: OrderedSet[A]): bool = ## proc saveTarotCards(cards: OrderedSet[int]) = ## assert cards.isValid, "Pass an initialized set!" ## # Do stuff here, may crash in release builds! - result = not s.data.isNil + result = s.data.len > 0 proc len*[A](s: OrderedSet[A]): int {.inline.} = ## Returns the number of keys in `s`. diff --git a/lib/pure/coro.nim b/lib/pure/coro.nim index 6d7dcf078..2fe34ed40 100644 --- a/lib/pure/coro.nim +++ b/lib/pure/coro.nim @@ -115,7 +115,12 @@ elif coroBackend == CORO_BACKEND_SETJMP: when defined(unix): # GLibc fails with "*** longjmp causes uninitialized stack frame ***" because # our custom stacks are not initialized to a magic value. - {.passC: "-U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0"} + when defined(osx): + # workaround: error: The deprecated ucontext routines require _XOPEN_SOURCE to be defined + const extra = " -D_XOPEN_SOURCE" + else: + const extra = "" + {.passC: "-U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0" & extra.} const CORO_CREATED = 0 diff --git a/lib/pure/htmlgen.nim b/lib/pure/htmlgen.nim index 55b02ea60..a2e224f44 100644 --- a/lib/pure/htmlgen.nim +++ b/lib/pure/htmlgen.nim @@ -31,10 +31,18 @@ import macros, strutils const - coreAttr* = " id class title style " - eventAttr* = " onclick ondblclick onmousedown onmouseup " & - "onmouseover onmousemove onmouseout onkeypress onkeydown onkeyup onload " - commonAttr* = coreAttr & eventAttr + coreAttr* = " accesskey class contenteditable dir hidden id lang " & + "spellcheck style tabindex title translate " + eventAttr* = "onabort onblur oncancel oncanplay oncanplaythrough onchange " & + "onclick oncuechange ondblclick ondurationchange onemptied onended " & + "onerror onfocus oninput oninvalid onkeydown onkeypress onkeyup onload " & + "onloadeddata onloadedmetadata onloadstart onmousedown onmouseenter " & + "onmouseleave onmousemove onmouseout onmouseover onmouseup onmousewheel " & + "onpause onplay onplaying onprogress onratechange onreset onresize " & + "onscroll onseeked onseeking onselect onshow onstalled onsubmit " & + "onsuspend ontimeupdate ontoggle onvolumechange onwaiting " + ariaAttr* = " role " + commonAttr* = coreAttr & eventAttr & ariaAttr proc getIdent(e: NimNode): string {.compileTime.} = case e.kind @@ -101,13 +109,13 @@ proc xmlCheckedTag*(e: NimNode, tag: string, optAttr = "", reqAttr = "", macro a*(e: varargs[untyped]): untyped = ## generates the HTML ``a`` element. let e = callsite() - result = xmlCheckedTag(e, "a", "href charset type hreflang rel rev " & - "accesskey tabindex" & commonAttr) + result = xmlCheckedTag(e, "a", "href target download rel hreflang type " & + commonAttr) -macro acronym*(e: varargs[untyped]): untyped = - ## generates the HTML ``acronym`` element. +macro abbr*(e: varargs[untyped]): untyped = + ## generates the HTML ``abbr`` element. let e = callsite() - result = xmlCheckedTag(e, "acronym", commonAttr) + result = xmlCheckedTag(e, "abbr", commonAttr) macro address*(e: varargs[untyped]): untyped = ## generates the HTML ``address`` element. @@ -117,8 +125,24 @@ macro address*(e: varargs[untyped]): untyped = macro area*(e: varargs[untyped]): untyped = ## generates the HTML ``area`` element. let e = callsite() - result = xmlCheckedTag(e, "area", "shape coords href nohref" & - " accesskey tabindex" & commonAttr, "alt", true) + result = xmlCheckedTag(e, "area", "coords download href hreflang rel " & + "shape target type" & commonAttr, "alt", true) + +macro article*(e: varargs[untyped]): untyped = + ## generates the HTML ``article`` element. + let e = callsite() + result = xmlCheckedTag(e, "article", commonAttr) + +macro aside*(e: varargs[untyped]): untyped = + ## generates the HTML ``aside`` element. + let e = callsite() + result = xmlCheckedTag(e, "aside", commonAttr) + +macro audio*(e: varargs[untyped]): untyped = + ## generates the HTML ``audio`` element. + let e = callsite() + result = xmlCheckedTag(e, "audio", "src crossorigin preload " & + "autoplay mediagroup loop muted controls" & commonAttr) macro b*(e: varargs[untyped]): untyped = ## generates the HTML ``b`` element. @@ -128,7 +152,17 @@ macro b*(e: varargs[untyped]): untyped = macro base*(e: varargs[untyped]): untyped = ## generates the HTML ``base`` element. let e = callsite() - result = xmlCheckedTag(e, "base", "", "href", true) + result = xmlCheckedTag(e, "base", "href target" & commonAttr, "", true) + +macro bdi*(e: varargs[untyped]): untyped = + ## generates the HTML ``bdi`` element. + let e = callsite() + result = xmlCheckedTag(e, "bdi", commonAttr) + +macro bdo*(e: varargs[untyped]): untyped = + ## generates the HTML ``bdo`` element. + let e = callsite() + result = xmlCheckedTag(e, "bdo", commonAttr) macro big*(e: varargs[untyped]): untyped = ## generates the HTML ``big`` element. @@ -143,18 +177,26 @@ macro blockquote*(e: varargs[untyped]): untyped = macro body*(e: varargs[untyped]): untyped = ## generates the HTML ``body`` element. let e = callsite() - result = xmlCheckedTag(e, "body", commonAttr) + result = xmlCheckedTag(e, "body", "onafterprint onbeforeprint " & + "onbeforeunload onhashchange onmessage onoffline ononline onpagehide " & + "onpageshow onpopstate onstorage onunload" & commonAttr) macro br*(e: varargs[untyped]): untyped = ## generates the HTML ``br`` element. let e = callsite() - result = xmlCheckedTag(e, "br", "", "", true) + result = xmlCheckedTag(e, "br", commonAttr, "", true) macro button*(e: varargs[untyped]): untyped = ## generates the HTML ``button`` element. let e = callsite() - result = xmlCheckedTag(e, "button", "accesskey tabindex " & - "disabled name type value" & commonAttr) + result = xmlCheckedTag(e, "button", "autofocus disabled form formaction " & + "formenctype formmethod formnovalidate formtarget menu name type value" & + commonAttr) + +macro canvas*(e: varargs[untyped]): untyped = + ## generates the HTML ``canvas`` element. + let e = callsite() + result = xmlCheckedTag(e, "canvas", "width height" & commonAttr) macro caption*(e: varargs[untyped]): untyped = ## generates the HTML ``caption`` element. @@ -174,12 +216,22 @@ macro code*(e: varargs[untyped]): untyped = macro col*(e: varargs[untyped]): untyped = ## generates the HTML ``col`` element. let e = callsite() - result = xmlCheckedTag(e, "col", "span align valign" & commonAttr, "", true) + result = xmlCheckedTag(e, "col", "span" & commonAttr, "", true) macro colgroup*(e: varargs[untyped]): untyped = ## generates the HTML ``colgroup`` element. let e = callsite() - result = xmlCheckedTag(e, "colgroup", "span align valign" & commonAttr) + result = xmlCheckedTag(e, "colgroup", "span" & commonAttr) + +macro data*(e: varargs[untyped]): untyped = + ## generates the HTML ``data`` element. + let e = callsite() + result = xmlCheckedTag(e, "data", "value" & commonAttr) + +macro datalist*(e: varargs[untyped]): untyped = + ## generates the HTML ``datalist`` element. + let e = callsite() + result = xmlCheckedTag(e, "datalist", commonAttr) macro dd*(e: varargs[untyped]): untyped = ## generates the HTML ``dd`` element. @@ -216,16 +268,37 @@ macro em*(e: varargs[untyped]): untyped = let e = callsite() result = xmlCheckedTag(e, "em", commonAttr) +macro embed*(e: varargs[untyped]): untyped = + ## generates the HTML ``embed`` element. + let e = callsite() + result = xmlCheckedTag(e, "embed", "src type height width" & + commonAttr, "", true) + macro fieldset*(e: varargs[untyped]): untyped = ## generates the HTML ``fieldset`` element. let e = callsite() - result = xmlCheckedTag(e, "fieldset", commonAttr) + result = xmlCheckedTag(e, "fieldset", "disabled form name" & commonAttr) + +macro figure*(e: varargs[untyped]): untyped = + ## generates the HTML ``figure`` element. + let e = callsite() + result = xmlCheckedTag(e, "figure", commonAttr) + +macro figcaption*(e: varargs[untyped]): untyped = + ## generates the HTML ``figcaption`` element. + let e = callsite() + result = xmlCheckedTag(e, "figcaption", commonAttr) + +macro footer*(e: varargs[untyped]): untyped = + ## generates the HTML ``footer`` element. + let e = callsite() + result = xmlCheckedTag(e, "footer", commonAttr) macro form*(e: varargs[untyped]): untyped = ## generates the HTML ``form`` element. let e = callsite() - result = xmlCheckedTag(e, "form", "method encype accept accept-charset" & - commonAttr, "action") + result = xmlCheckedTag(e, "form", "accept-charset action autocomplete " & + "enctype method name novalidate target" & commonAttr) macro h1*(e: varargs[untyped]): untyped = ## generates the HTML ``h1`` element. @@ -260,7 +333,12 @@ macro h6*(e: varargs[untyped]): untyped = macro head*(e: varargs[untyped]): untyped = ## generates the HTML ``head`` element. let e = callsite() - result = xmlCheckedTag(e, "head", "profile") + result = xmlCheckedTag(e, "head", commonAttr) + +macro header*(e: varargs[untyped]): untyped = + ## generates the HTML ``header`` element. + let e = callsite() + result = xmlCheckedTag(e, "header", commonAttr) macro html*(e: varargs[untyped]): untyped = ## generates the HTML ``html`` element. @@ -277,16 +355,26 @@ macro i*(e: varargs[untyped]): untyped = let e = callsite() result = xmlCheckedTag(e, "i", commonAttr) +macro iframe*(e: varargs[untyped]): untyped = + ## generates the HTML ``iframe`` element. + let e = callsite() + result = xmlCheckedTag(e, "iframe", "src srcdoc name sandbox width height" & + commonAttr) + macro img*(e: varargs[untyped]): untyped = ## generates the HTML ``img`` element. let e = callsite() - result = xmlCheckedTag(e, "img", "longdesc height width", "src alt", true) + result = xmlCheckedTag(e, "img", "crossorigin usemap ismap height width" & + commonAttr, "src alt", true) macro input*(e: varargs[untyped]): untyped = ## generates the HTML ``input`` element. let e = callsite() - result = xmlCheckedTag(e, "input", "name type value checked maxlength src" & - " alt accept disabled readonly accesskey tabindex" & commonAttr, "", true) + result = xmlCheckedTag(e, "input", "accept alt autocomplete autofocus " & + "checked dirname disabled form formaction formenctype formmethod " & + "formnovalidate formtarget height inputmode list max maxlength min " & + "minlength multiple name pattern placeholder readonly required size " & + "src step type value width" & commonAttr, "", true) macro ins*(e: varargs[untyped]): untyped = ## generates the HTML ``ins`` element. @@ -298,36 +386,64 @@ macro kbd*(e: varargs[untyped]): untyped = let e = callsite() result = xmlCheckedTag(e, "kbd", commonAttr) +macro keygen*(e: varargs[untyped]): untyped = + ## generates the HTML ``keygen`` element. + let e = callsite() + result = xmlCheckedTag(e, "keygen", "autofocus challenge disabled " & + "form keytype name" & commonAttr) + macro label*(e: varargs[untyped]): untyped = ## generates the HTML ``label`` element. let e = callsite() - result = xmlCheckedTag(e, "label", "for accesskey" & commonAttr) + result = xmlCheckedTag(e, "label", "form for" & commonAttr) macro legend*(e: varargs[untyped]): untyped = ## generates the HTML ``legend`` element. let e = callsite() - result = xmlCheckedTag(e, "legend", "accesskey" & commonAttr) + result = xmlCheckedTag(e, "legend", commonAttr) macro li*(e: varargs[untyped]): untyped = ## generates the HTML ``li`` element. let e = callsite() - result = xmlCheckedTag(e, "li", commonAttr) + result = xmlCheckedTag(e, "li", "value" & commonAttr) macro link*(e: varargs[untyped]): untyped = ## generates the HTML ``link`` element. let e = callsite() - result = xmlCheckedTag(e, "link", "href charset hreflang type rel rev media" & - commonAttr, "", true) + result = xmlCheckedTag(e, "link", "href crossorigin rel media hreflang " & + "type sizes" & commonAttr, "", true) + +macro main*(e: varargs[untyped]): untyped = + ## generates the HTML ``main`` element. + let e = callsite() + result = xmlCheckedTag(e, "main", commonAttr) macro map*(e: varargs[untyped]): untyped = ## generates the HTML ``map`` element. let e = callsite() - result = xmlCheckedTag(e, "map", "class title" & eventAttr, "id", false) + result = xmlCheckedTag(e, "map", "name" & commonAttr) + +macro mark*(e: varargs[untyped]): untyped = + ## generates the HTML ``mark`` element. + let e = callsite() + result = xmlCheckedTag(e, "mark", commonAttr) macro meta*(e: varargs[untyped]): untyped = ## generates the HTML ``meta`` element. let e = callsite() - result = xmlCheckedTag(e, "meta", "name http-equiv scheme", "content", true) + result = xmlCheckedTag(e, "meta", "name http-equiv content charset" & + commonAttr, "", true) + +macro meter*(e: varargs[untyped]): untyped = + ## generates the HTML ``meter`` element. + let e = callsite() + result = xmlCheckedTag(e, "meter", "value min max low high optimum" & + commonAttr) + +macro nav*(e: varargs[untyped]): untyped = + ## generates the HTML ``nav`` element. + let e = callsite() + result = xmlCheckedTag(e, "nav", commonAttr) macro noscript*(e: varargs[untyped]): untyped = ## generates the HTML ``noscript`` element. @@ -337,13 +453,13 @@ macro noscript*(e: varargs[untyped]): untyped = macro `object`*(e: varargs[untyped]): untyped = ## generates the HTML ``object`` element. let e = callsite() - result = xmlCheckedTag(e, "object", "classid data codebase declare type " & - "codetype archive standby width height name tabindex" & commonAttr) + result = xmlCheckedTag(e, "object", "data type typemustmatch name usemap " & + "form width height" & commonAttr) macro ol*(e: varargs[untyped]): untyped = ## generates the HTML ``ol`` element. let e = callsite() - result = xmlCheckedTag(e, "ol", commonAttr) + result = xmlCheckedTag(e, "ol", "reversed start type" & commonAttr) macro optgroup*(e: varargs[untyped]): untyped = ## generates the HTML ``optgroup`` element. @@ -353,7 +469,13 @@ macro optgroup*(e: varargs[untyped]): untyped = macro option*(e: varargs[untyped]): untyped = ## generates the HTML ``option`` element. let e = callsite() - result = xmlCheckedTag(e, "option", "selected value" & commonAttr) + result = xmlCheckedTag(e, "option", "disabled label selected value" & + commonAttr) + +macro output*(e: varargs[untyped]): untyped = + ## generates the HTML ``output`` element. + let e = callsite() + result = xmlCheckedTag(e, "output", "for form name" & commonAttr) macro p*(e: varargs[untyped]): untyped = ## generates the HTML ``p`` element. @@ -363,18 +485,53 @@ macro p*(e: varargs[untyped]): untyped = macro param*(e: varargs[untyped]): untyped = ## generates the HTML ``param`` element. let e = callsite() - result = xmlCheckedTag(e, "param", "value id type valuetype", "name", true) + result = xmlCheckedTag(e, "param", commonAttr, "name value", true) macro pre*(e: varargs[untyped]): untyped = ## generates the HTML ``pre`` element. let e = callsite() result = xmlCheckedTag(e, "pre", commonAttr) +macro progress*(e: varargs[untyped]): untyped = + ## generates the HTML ``progress`` element. + let e = callsite() + result = xmlCheckedTag(e, "progress", "value max" & commonAttr) + macro q*(e: varargs[untyped]): untyped = ## generates the HTML ``q`` element. let e = callsite() result = xmlCheckedTag(e, "q", "cite" & commonAttr) +macro rb*(e: varargs[untyped]): untyped = + ## generates the HTML ``rb`` element. + let e = callsite() + result = xmlCheckedTag(e, "rb", commonAttr) + +macro rp*(e: varargs[untyped]): untyped = + ## generates the HTML ``rp`` element. + let e = callsite() + result = xmlCheckedTag(e, "rp", commonAttr) + +macro rt*(e: varargs[untyped]): untyped = + ## generates the HTML ``rt`` element. + let e = callsite() + result = xmlCheckedTag(e, "rt", commonAttr) + +macro rtc*(e: varargs[untyped]): untyped = + ## generates the HTML ``rtc`` element. + let e = callsite() + result = xmlCheckedTag(e, "rtc", commonAttr) + +macro ruby*(e: varargs[untyped]): untyped = + ## generates the HTML ``ruby`` element. + let e = callsite() + result = xmlCheckedTag(e, "ruby", commonAttr) + +macro s*(e: varargs[untyped]): untyped = + ## generates the HTML ``s`` element. + let e = callsite() + result = xmlCheckedTag(e, "s", commonAttr) + macro samp*(e: varargs[untyped]): untyped = ## generates the HTML ``samp`` element. let e = callsite() @@ -383,19 +540,30 @@ macro samp*(e: varargs[untyped]): untyped = macro script*(e: varargs[untyped]): untyped = ## generates the HTML ``script`` element. let e = callsite() - result = xmlCheckedTag(e, "script", "src charset defer", "type", false) + result = xmlCheckedTag(e, "script", "src type charset async defer " & + "crossorigin" & commonAttr) + +macro section*(e: varargs[untyped]): untyped = + ## generates the HTML ``section`` element. + let e = callsite() + result = xmlCheckedTag(e, "section", commonAttr) macro select*(e: varargs[untyped]): untyped = ## generates the HTML ``select`` element. let e = callsite() - result = xmlCheckedTag(e, "select", "name size multiple disabled tabindex" & - commonAttr) + result = xmlCheckedTag(e, "select", "autofocus disabled form multiple " & + "name required size" & commonAttr) macro small*(e: varargs[untyped]): untyped = ## generates the HTML ``small`` element. let e = callsite() result = xmlCheckedTag(e, "small", commonAttr) +macro source*(e: varargs[untyped]): untyped = + ## generates the HTML ``source`` element. + let e = callsite() + result = xmlCheckedTag(e, "source", "type" & commonAttr, "src", true) + macro span*(e: varargs[untyped]): untyped = ## generates the HTML ``span`` element. let e = callsite() @@ -409,7 +577,7 @@ macro strong*(e: varargs[untyped]): untyped = macro style*(e: varargs[untyped]): untyped = ## generates the HTML ``style`` element. let e = callsite() - result = xmlCheckedTag(e, "style", "media title", "type") + result = xmlCheckedTag(e, "style", "media type" & commonAttr) macro sub*(e: varargs[untyped]): untyped = ## generates the HTML ``sub`` element. @@ -424,57 +592,77 @@ macro sup*(e: varargs[untyped]): untyped = macro table*(e: varargs[untyped]): untyped = ## generates the HTML ``table`` element. let e = callsite() - result = xmlCheckedTag(e, "table", "summary border cellpadding cellspacing" & - " frame rules width" & commonAttr) + result = xmlCheckedTag(e, "table", "border sortable" & commonAttr) macro tbody*(e: varargs[untyped]): untyped = ## generates the HTML ``tbody`` element. let e = callsite() - result = xmlCheckedTag(e, "tbody", "align valign" & commonAttr) + result = xmlCheckedTag(e, "tbody", commonAttr) macro td*(e: varargs[untyped]): untyped = ## generates the HTML ``td`` element. let e = callsite() - result = xmlCheckedTag(e, "td", "colspan rowspan abbr axis headers scope" & - " align valign" & commonAttr) + result = xmlCheckedTag(e, "td", "colspan rowspan headers" & commonAttr) + +macro `template`*(e: varargs[untyped]): untyped = + ## generates the HTML ``template`` element. + let e = callsite() + result = xmlCheckedTag(e, "template", commonAttr) macro textarea*(e: varargs[untyped]): untyped = ## generates the HTML ``textarea`` element. let e = callsite() - result = xmlCheckedTag(e, "textarea", " name disabled readonly accesskey" & - " tabindex" & commonAttr, "rows cols", false) + result = xmlCheckedTag(e, "textarea", "autocomplete autofocus cols " & + "dirname disabled form inputmode maxlength minlength name placeholder " & + "readonly required rows wrap" & commonAttr) macro tfoot*(e: varargs[untyped]): untyped = ## generates the HTML ``tfoot`` element. let e = callsite() - result = xmlCheckedTag(e, "tfoot", "align valign" & commonAttr) + result = xmlCheckedTag(e, "tfoot", commonAttr) macro th*(e: varargs[untyped]): untyped = ## generates the HTML ``th`` element. let e = callsite() - result = xmlCheckedTag(e, "th", "colspan rowspan abbr axis headers scope" & - " align valign" & commonAttr) + result = xmlCheckedTag(e, "th", "colspan rowspan headers abbr scope axis" & + " sorted" & commonAttr) macro thead*(e: varargs[untyped]): untyped = ## generates the HTML ``thead`` element. let e = callsite() - result = xmlCheckedTag(e, "thead", "align valign" & commonAttr) + result = xmlCheckedTag(e, "thead", commonAttr) + +macro time*(e: varargs[untyped]): untyped = + ## generates the HTML ``time`` element. + let e = callsite() + result = xmlCheckedTag(e, "time", "datetime" & commonAttr) macro title*(e: varargs[untyped]): untyped = ## generates the HTML ``title`` element. let e = callsite() - result = xmlCheckedTag(e, "title") + result = xmlCheckedTag(e, "title", commonAttr) macro tr*(e: varargs[untyped]): untyped = ## generates the HTML ``tr`` element. let e = callsite() - result = xmlCheckedTag(e, "tr", "align valign" & commonAttr) + result = xmlCheckedTag(e, "tr", commonAttr) + +macro track*(e: varargs[untyped]): untyped = + ## generates the HTML ``track`` element. + let e = callsite() + result = xmlCheckedTag(e, "track", "kind srclang label default" & + commonAttr, "src", true) macro tt*(e: varargs[untyped]): untyped = ## generates the HTML ``tt`` element. let e = callsite() result = xmlCheckedTag(e, "tt", commonAttr) +macro u*(e: varargs[untyped]): untyped = + ## generates the HTML ``u`` element. + let e = callsite() + result = xmlCheckedTag(e, "u", commonAttr) + macro ul*(e: varargs[untyped]): untyped = ## generates the HTML ``ul`` element. let e = callsite() @@ -485,6 +673,17 @@ macro `var`*(e: varargs[untyped]): untyped = let e = callsite() result = xmlCheckedTag(e, "var", commonAttr) +macro video*(e: varargs[untyped]): untyped = + ## generates the HTML ``video`` element. + let e = callsite() + result = xmlCheckedTag(e, "video", "src crossorigin poster preload " & + "autoplay mediagroup loop muted controls width height" & commonAttr) + +macro wbr*(e: varargs[untyped]): untyped = + ## generates the HTML ``wbr`` element. + let e = callsite() + result = xmlCheckedTag(e, "wbr", commonAttr, "", true) + when isMainModule: let nim = "Nim" assert h1(a(href="http://nim-lang.org", nim)) == diff --git a/lib/pure/htmlparser.nim b/lib/pure/htmlparser.nim index f54fe87f7..fbf2b8e73 100644 --- a/lib/pure/htmlparser.nim +++ b/lib/pure/htmlparser.nim @@ -387,1481 +387,1484 @@ proc entityToRune*(entity: string): Rune = doAssert entityToRune("#x0003F") == "?".runeAt(0) if entity.len < 2: return # smallest entity has length 2 if entity[0] == '#': + var runeValue = 0 case entity[1] of '0'..'9': - try: return Rune(parseInt(entity[1..^1])) - except: return + try: runeValue = parseInt(entity[1..^1]) + except: discard of 'x', 'X': # not case sensitive here - try: return Rune(parseHexInt(entity[2..^1])) - except: return - else: return # other entities are not defined with prefix ``#`` + try: runeValue = parseHexInt(entity[2..^1]) + except: discard + else: discard # other entities are not defined with prefix ``#`` + if runeValue notin 0..0x10FFFF: runeValue = 0 # only return legal values + return Rune(runeValue) case entity # entity names are case sensitive - of "Tab": result = Rune(0x00009) - of "NewLine": result = Rune(0x0000A) - of "excl": result = Rune(0x00021) - of "quot", "QUOT": result = Rune(0x00022) - of "num": result = Rune(0x00023) - of "dollar": result = Rune(0x00024) - of "percnt": result = Rune(0x00025) - of "amp", "AMP": result = Rune(0x00026) - of "apos": result = Rune(0x00027) - of "lpar": result = Rune(0x00028) - of "rpar": result = Rune(0x00029) - of "ast", "midast": result = Rune(0x0002A) - of "plus": result = Rune(0x0002B) - of "comma": result = Rune(0x0002C) - of "period": result = Rune(0x0002E) - of "sol": result = Rune(0x0002F) - of "colon": result = Rune(0x0003A) - of "semi": result = Rune(0x0003B) - of "lt", "LT": result = Rune(0x0003C) - of "equals": result = Rune(0x0003D) - of "gt", "GT": result = Rune(0x0003E) - of "quest": result = Rune(0x0003F) - of "commat": result = Rune(0x00040) - of "lsqb", "lbrack": result = Rune(0x0005B) - of "bsol": result = Rune(0x0005C) - of "rsqb", "rbrack": result = Rune(0x0005D) - of "Hat": result = Rune(0x0005E) - of "lowbar": result = Rune(0x0005F) - of "grave", "DiacriticalGrave": result = Rune(0x00060) - of "lcub", "lbrace": result = Rune(0x0007B) - of "verbar", "vert", "VerticalLine": result = Rune(0x0007C) - of "rcub", "rbrace": result = Rune(0x0007D) - of "nbsp", "NonBreakingSpace": result = Rune(0x000A0) - of "iexcl": result = Rune(0x000A1) - of "cent": result = Rune(0x000A2) - of "pound": result = Rune(0x000A3) - of "curren": result = Rune(0x000A4) - of "yen": result = Rune(0x000A5) - of "brvbar": result = Rune(0x000A6) - of "sect": result = Rune(0x000A7) - of "Dot", "die", "DoubleDot", "uml": result = Rune(0x000A8) - of "copy", "COPY": result = Rune(0x000A9) - of "ordf": result = Rune(0x000AA) - of "laquo": result = Rune(0x000AB) - of "not": result = Rune(0x000AC) - of "shy": result = Rune(0x000AD) - of "reg", "circledR", "REG": result = Rune(0x000AE) - of "macr", "OverBar", "strns": result = Rune(0x000AF) - of "deg": result = Rune(0x000B0) - of "plusmn", "pm", "PlusMinus": result = Rune(0x000B1) - of "sup2": result = Rune(0x000B2) - of "sup3": result = Rune(0x000B3) - of "acute", "DiacriticalAcute": result = Rune(0x000B4) - of "micro": result = Rune(0x000B5) - of "para": result = Rune(0x000B6) - of "middot", "centerdot", "CenterDot": result = Rune(0x000B7) - of "cedil", "Cedilla": result = Rune(0x000B8) - of "sup1": result = Rune(0x000B9) - of "ordm": result = Rune(0x000BA) - of "raquo": result = Rune(0x000BB) - of "frac14": result = Rune(0x000BC) - of "frac12", "half": result = Rune(0x000BD) - of "frac34": result = Rune(0x000BE) - of "iquest": result = Rune(0x000BF) - of "Agrave": result = Rune(0x000C0) - of "Aacute": result = Rune(0x000C1) - of "Acirc": result = Rune(0x000C2) - of "Atilde": result = Rune(0x000C3) - of "Auml": result = Rune(0x000C4) - of "Aring": result = Rune(0x000C5) - of "AElig": result = Rune(0x000C6) - of "Ccedil": result = Rune(0x000C7) - of "Egrave": result = Rune(0x000C8) - of "Eacute": result = Rune(0x000C9) - of "Ecirc": result = Rune(0x000CA) - of "Euml": result = Rune(0x000CB) - of "Igrave": result = Rune(0x000CC) - of "Iacute": result = Rune(0x000CD) - of "Icirc": result = Rune(0x000CE) - of "Iuml": result = Rune(0x000CF) - of "ETH": result = Rune(0x000D0) - of "Ntilde": result = Rune(0x000D1) - of "Ograve": result = Rune(0x000D2) - of "Oacute": result = Rune(0x000D3) - of "Ocirc": result = Rune(0x000D4) - of "Otilde": result = Rune(0x000D5) - of "Ouml": result = Rune(0x000D6) - of "times": result = Rune(0x000D7) - of "Oslash": result = Rune(0x000D8) - of "Ugrave": result = Rune(0x000D9) - of "Uacute": result = Rune(0x000DA) - of "Ucirc": result = Rune(0x000DB) - of "Uuml": result = Rune(0x000DC) - of "Yacute": result = Rune(0x000DD) - of "THORN": result = Rune(0x000DE) - of "szlig": result = Rune(0x000DF) - of "agrave": result = Rune(0x000E0) - of "aacute": result = Rune(0x000E1) - of "acirc": result = Rune(0x000E2) - of "atilde": result = Rune(0x000E3) - of "auml": result = Rune(0x000E4) - of "aring": result = Rune(0x000E5) - of "aelig": result = Rune(0x000E6) - of "ccedil": result = Rune(0x000E7) - of "egrave": result = Rune(0x000E8) - of "eacute": result = Rune(0x000E9) - of "ecirc": result = Rune(0x000EA) - of "euml": result = Rune(0x000EB) - of "igrave": result = Rune(0x000EC) - of "iacute": result = Rune(0x000ED) - of "icirc": result = Rune(0x000EE) - of "iuml": result = Rune(0x000EF) - of "eth": result = Rune(0x000F0) - of "ntilde": result = Rune(0x000F1) - of "ograve": result = Rune(0x000F2) - of "oacute": result = Rune(0x000F3) - of "ocirc": result = Rune(0x000F4) - of "otilde": result = Rune(0x000F5) - of "ouml": result = Rune(0x000F6) - of "divide", "div": result = Rune(0x000F7) - of "oslash": result = Rune(0x000F8) - of "ugrave": result = Rune(0x000F9) - of "uacute": result = Rune(0x000FA) - of "ucirc": result = Rune(0x000FB) - of "uuml": result = Rune(0x000FC) - of "yacute": result = Rune(0x000FD) - of "thorn": result = Rune(0x000FE) - of "yuml": result = Rune(0x000FF) - of "Amacr": result = Rune(0x00100) - of "amacr": result = Rune(0x00101) - of "Abreve": result = Rune(0x00102) - of "abreve": result = Rune(0x00103) - of "Aogon": result = Rune(0x00104) - of "aogon": result = Rune(0x00105) - of "Cacute": result = Rune(0x00106) - of "cacute": result = Rune(0x00107) - of "Ccirc": result = Rune(0x00108) - of "ccirc": result = Rune(0x00109) - of "Cdot": result = Rune(0x0010A) - of "cdot": result = Rune(0x0010B) - of "Ccaron": result = Rune(0x0010C) - of "ccaron": result = Rune(0x0010D) - of "Dcaron": result = Rune(0x0010E) - of "dcaron": result = Rune(0x0010F) - of "Dstrok": result = Rune(0x00110) - of "dstrok": result = Rune(0x00111) - of "Emacr": result = Rune(0x00112) - of "emacr": result = Rune(0x00113) - of "Edot": result = Rune(0x00116) - of "edot": result = Rune(0x00117) - of "Eogon": result = Rune(0x00118) - of "eogon": result = Rune(0x00119) - of "Ecaron": result = Rune(0x0011A) - of "ecaron": result = Rune(0x0011B) - of "Gcirc": result = Rune(0x0011C) - of "gcirc": result = Rune(0x0011D) - of "Gbreve": result = Rune(0x0011E) - of "gbreve": result = Rune(0x0011F) - of "Gdot": result = Rune(0x00120) - of "gdot": result = Rune(0x00121) - of "Gcedil": result = Rune(0x00122) - of "Hcirc": result = Rune(0x00124) - of "hcirc": result = Rune(0x00125) - of "Hstrok": result = Rune(0x00126) - of "hstrok": result = Rune(0x00127) - of "Itilde": result = Rune(0x00128) - of "itilde": result = Rune(0x00129) - of "Imacr": result = Rune(0x0012A) - of "imacr": result = Rune(0x0012B) - of "Iogon": result = Rune(0x0012E) - of "iogon": result = Rune(0x0012F) - of "Idot": result = Rune(0x00130) - of "imath", "inodot": result = Rune(0x00131) - of "IJlig": result = Rune(0x00132) - of "ijlig": result = Rune(0x00133) - of "Jcirc": result = Rune(0x00134) - of "jcirc": result = Rune(0x00135) - of "Kcedil": result = Rune(0x00136) - of "kcedil": result = Rune(0x00137) - of "kgreen": result = Rune(0x00138) - of "Lacute": result = Rune(0x00139) - of "lacute": result = Rune(0x0013A) - of "Lcedil": result = Rune(0x0013B) - of "lcedil": result = Rune(0x0013C) - of "Lcaron": result = Rune(0x0013D) - of "lcaron": result = Rune(0x0013E) - of "Lmidot": result = Rune(0x0013F) - of "lmidot": result = Rune(0x00140) - of "Lstrok": result = Rune(0x00141) - of "lstrok": result = Rune(0x00142) - of "Nacute": result = Rune(0x00143) - of "nacute": result = Rune(0x00144) - of "Ncedil": result = Rune(0x00145) - of "ncedil": result = Rune(0x00146) - of "Ncaron": result = Rune(0x00147) - of "ncaron": result = Rune(0x00148) - of "napos": result = Rune(0x00149) - of "ENG": result = Rune(0x0014A) - of "eng": result = Rune(0x0014B) - of "Omacr": result = Rune(0x0014C) - of "omacr": result = Rune(0x0014D) - of "Odblac": result = Rune(0x00150) - of "odblac": result = Rune(0x00151) - of "OElig": result = Rune(0x00152) - of "oelig": result = Rune(0x00153) - of "Racute": result = Rune(0x00154) - of "racute": result = Rune(0x00155) - of "Rcedil": result = Rune(0x00156) - of "rcedil": result = Rune(0x00157) - of "Rcaron": result = Rune(0x00158) - of "rcaron": result = Rune(0x00159) - of "Sacute": result = Rune(0x0015A) - of "sacute": result = Rune(0x0015B) - of "Scirc": result = Rune(0x0015C) - of "scirc": result = Rune(0x0015D) - of "Scedil": result = Rune(0x0015E) - of "scedil": result = Rune(0x0015F) - of "Scaron": result = Rune(0x00160) - of "scaron": result = Rune(0x00161) - of "Tcedil": result = Rune(0x00162) - of "tcedil": result = Rune(0x00163) - of "Tcaron": result = Rune(0x00164) - of "tcaron": result = Rune(0x00165) - of "Tstrok": result = Rune(0x00166) - of "tstrok": result = Rune(0x00167) - of "Utilde": result = Rune(0x00168) - of "utilde": result = Rune(0x00169) - of "Umacr": result = Rune(0x0016A) - of "umacr": result = Rune(0x0016B) - of "Ubreve": result = Rune(0x0016C) - of "ubreve": result = Rune(0x0016D) - of "Uring": result = Rune(0x0016E) - of "uring": result = Rune(0x0016F) - of "Udblac": result = Rune(0x00170) - of "udblac": result = Rune(0x00171) - of "Uogon": result = Rune(0x00172) - of "uogon": result = Rune(0x00173) - of "Wcirc": result = Rune(0x00174) - of "wcirc": result = Rune(0x00175) - of "Ycirc": result = Rune(0x00176) - of "ycirc": result = Rune(0x00177) - of "Yuml": result = Rune(0x00178) - of "Zacute": result = Rune(0x00179) - of "zacute": result = Rune(0x0017A) - of "Zdot": result = Rune(0x0017B) - of "zdot": result = Rune(0x0017C) - of "Zcaron": result = Rune(0x0017D) - of "zcaron": result = Rune(0x0017E) - of "fnof": result = Rune(0x00192) - of "imped": result = Rune(0x001B5) - of "gacute": result = Rune(0x001F5) - of "jmath": result = Rune(0x00237) - of "circ": result = Rune(0x002C6) - of "caron", "Hacek": result = Rune(0x002C7) - of "breve", "Breve": result = Rune(0x002D8) - of "dot", "DiacriticalDot": result = Rune(0x002D9) - of "ring": result = Rune(0x002DA) - of "ogon": result = Rune(0x002DB) - of "tilde", "DiacriticalTilde": result = Rune(0x002DC) - of "dblac", "DiacriticalDoubleAcute": result = Rune(0x002DD) - of "DownBreve": result = Rune(0x00311) - of "UnderBar": result = Rune(0x00332) - of "Alpha": result = Rune(0x00391) - of "Beta": result = Rune(0x00392) - of "Gamma": result = Rune(0x00393) - of "Delta": result = Rune(0x00394) - of "Epsilon": result = Rune(0x00395) - of "Zeta": result = Rune(0x00396) - of "Eta": result = Rune(0x00397) - of "Theta": result = Rune(0x00398) - of "Iota": result = Rune(0x00399) - of "Kappa": result = Rune(0x0039A) - of "Lambda": result = Rune(0x0039B) - of "Mu": result = Rune(0x0039C) - of "Nu": result = Rune(0x0039D) - of "Xi": result = Rune(0x0039E) - of "Omicron": result = Rune(0x0039F) - of "Pi": result = Rune(0x003A0) - of "Rho": result = Rune(0x003A1) - of "Sigma": result = Rune(0x003A3) - of "Tau": result = Rune(0x003A4) - of "Upsilon": result = Rune(0x003A5) - of "Phi": result = Rune(0x003A6) - of "Chi": result = Rune(0x003A7) - of "Psi": result = Rune(0x003A8) - of "Omega": result = Rune(0x003A9) - of "alpha": result = Rune(0x003B1) - of "beta": result = Rune(0x003B2) - of "gamma": result = Rune(0x003B3) - of "delta": result = Rune(0x003B4) - of "epsiv", "varepsilon", "epsilon": result = Rune(0x003B5) - of "zeta": result = Rune(0x003B6) - of "eta": result = Rune(0x003B7) - of "theta": result = Rune(0x003B8) - of "iota": result = Rune(0x003B9) - of "kappa": result = Rune(0x003BA) - of "lambda": result = Rune(0x003BB) - of "mu": result = Rune(0x003BC) - of "nu": result = Rune(0x003BD) - of "xi": result = Rune(0x003BE) - of "omicron": result = Rune(0x003BF) - of "pi": result = Rune(0x003C0) - of "rho": result = Rune(0x003C1) - of "sigmav", "varsigma", "sigmaf": result = Rune(0x003C2) - of "sigma": result = Rune(0x003C3) - of "tau": result = Rune(0x003C4) - of "upsi", "upsilon": result = Rune(0x003C5) - of "phi", "phiv", "varphi": result = Rune(0x003C6) - of "chi": result = Rune(0x003C7) - of "psi": result = Rune(0x003C8) - of "omega": result = Rune(0x003C9) - of "thetav", "vartheta", "thetasym": result = Rune(0x003D1) - of "Upsi", "upsih": result = Rune(0x003D2) - of "straightphi": result = Rune(0x003D5) - of "piv", "varpi": result = Rune(0x003D6) - of "Gammad": result = Rune(0x003DC) - of "gammad", "digamma": result = Rune(0x003DD) - of "kappav", "varkappa": result = Rune(0x003F0) - of "rhov", "varrho": result = Rune(0x003F1) - of "epsi", "straightepsilon": result = Rune(0x003F5) - of "bepsi", "backepsilon": result = Rune(0x003F6) - of "IOcy": result = Rune(0x00401) - of "DJcy": result = Rune(0x00402) - of "GJcy": result = Rune(0x00403) - of "Jukcy": result = Rune(0x00404) - of "DScy": result = Rune(0x00405) - of "Iukcy": result = Rune(0x00406) - of "YIcy": result = Rune(0x00407) - of "Jsercy": result = Rune(0x00408) - of "LJcy": result = Rune(0x00409) - of "NJcy": result = Rune(0x0040A) - of "TSHcy": result = Rune(0x0040B) - of "KJcy": result = Rune(0x0040C) - of "Ubrcy": result = Rune(0x0040E) - of "DZcy": result = Rune(0x0040F) - of "Acy": result = Rune(0x00410) - of "Bcy": result = Rune(0x00411) - of "Vcy": result = Rune(0x00412) - of "Gcy": result = Rune(0x00413) - of "Dcy": result = Rune(0x00414) - of "IEcy": result = Rune(0x00415) - of "ZHcy": result = Rune(0x00416) - of "Zcy": result = Rune(0x00417) - of "Icy": result = Rune(0x00418) - of "Jcy": result = Rune(0x00419) - of "Kcy": result = Rune(0x0041A) - of "Lcy": result = Rune(0x0041B) - of "Mcy": result = Rune(0x0041C) - of "Ncy": result = Rune(0x0041D) - of "Ocy": result = Rune(0x0041E) - of "Pcy": result = Rune(0x0041F) - of "Rcy": result = Rune(0x00420) - of "Scy": result = Rune(0x00421) - of "Tcy": result = Rune(0x00422) - of "Ucy": result = Rune(0x00423) - of "Fcy": result = Rune(0x00424) - of "KHcy": result = Rune(0x00425) - of "TScy": result = Rune(0x00426) - of "CHcy": result = Rune(0x00427) - of "SHcy": result = Rune(0x00428) - of "SHCHcy": result = Rune(0x00429) - of "HARDcy": result = Rune(0x0042A) - of "Ycy": result = Rune(0x0042B) - of "SOFTcy": result = Rune(0x0042C) - of "Ecy": result = Rune(0x0042D) - of "YUcy": result = Rune(0x0042E) - of "YAcy": result = Rune(0x0042F) - of "acy": result = Rune(0x00430) - of "bcy": result = Rune(0x00431) - of "vcy": result = Rune(0x00432) - of "gcy": result = Rune(0x00433) - of "dcy": result = Rune(0x00434) - of "iecy": result = Rune(0x00435) - of "zhcy": result = Rune(0x00436) - of "zcy": result = Rune(0x00437) - of "icy": result = Rune(0x00438) - of "jcy": result = Rune(0x00439) - of "kcy": result = Rune(0x0043A) - of "lcy": result = Rune(0x0043B) - of "mcy": result = Rune(0x0043C) - of "ncy": result = Rune(0x0043D) - of "ocy": result = Rune(0x0043E) - of "pcy": result = Rune(0x0043F) - of "rcy": result = Rune(0x00440) - of "scy": result = Rune(0x00441) - of "tcy": result = Rune(0x00442) - of "ucy": result = Rune(0x00443) - of "fcy": result = Rune(0x00444) - of "khcy": result = Rune(0x00445) - of "tscy": result = Rune(0x00446) - of "chcy": result = Rune(0x00447) - of "shcy": result = Rune(0x00448) - of "shchcy": result = Rune(0x00449) - of "hardcy": result = Rune(0x0044A) - of "ycy": result = Rune(0x0044B) - of "softcy": result = Rune(0x0044C) - of "ecy": result = Rune(0x0044D) - of "yucy": result = Rune(0x0044E) - of "yacy": result = Rune(0x0044F) - of "iocy": result = Rune(0x00451) - of "djcy": result = Rune(0x00452) - of "gjcy": result = Rune(0x00453) - of "jukcy": result = Rune(0x00454) - of "dscy": result = Rune(0x00455) - of "iukcy": result = Rune(0x00456) - of "yicy": result = Rune(0x00457) - of "jsercy": result = Rune(0x00458) - of "ljcy": result = Rune(0x00459) - of "njcy": result = Rune(0x0045A) - of "tshcy": result = Rune(0x0045B) - of "kjcy": result = Rune(0x0045C) - of "ubrcy": result = Rune(0x0045E) - of "dzcy": result = Rune(0x0045F) - of "ensp": result = Rune(0x02002) - of "emsp": result = Rune(0x02003) - of "emsp13": result = Rune(0x02004) - of "emsp14": result = Rune(0x02005) - of "numsp": result = Rune(0x02007) - of "puncsp": result = Rune(0x02008) - of "thinsp", "ThinSpace": result = Rune(0x02009) - of "hairsp", "VeryThinSpace": result = Rune(0x0200A) + of "Tab": Rune(0x00009) + of "NewLine": Rune(0x0000A) + of "excl": Rune(0x00021) + of "quot", "QUOT": Rune(0x00022) + of "num": Rune(0x00023) + of "dollar": Rune(0x00024) + of "percnt": Rune(0x00025) + of "amp", "AMP": Rune(0x00026) + of "apos": Rune(0x00027) + of "lpar": Rune(0x00028) + of "rpar": Rune(0x00029) + of "ast", "midast": Rune(0x0002A) + of "plus": Rune(0x0002B) + of "comma": Rune(0x0002C) + of "period": Rune(0x0002E) + of "sol": Rune(0x0002F) + of "colon": Rune(0x0003A) + of "semi": Rune(0x0003B) + of "lt", "LT": Rune(0x0003C) + of "equals": Rune(0x0003D) + of "gt", "GT": Rune(0x0003E) + of "quest": Rune(0x0003F) + of "commat": Rune(0x00040) + of "lsqb", "lbrack": Rune(0x0005B) + of "bsol": Rune(0x0005C) + of "rsqb", "rbrack": Rune(0x0005D) + of "Hat": Rune(0x0005E) + of "lowbar": Rune(0x0005F) + of "grave", "DiacriticalGrave": Rune(0x00060) + of "lcub", "lbrace": Rune(0x0007B) + of "verbar", "vert", "VerticalLine": Rune(0x0007C) + of "rcub", "rbrace": Rune(0x0007D) + of "nbsp", "NonBreakingSpace": Rune(0x000A0) + of "iexcl": Rune(0x000A1) + of "cent": Rune(0x000A2) + of "pound": Rune(0x000A3) + of "curren": Rune(0x000A4) + of "yen": Rune(0x000A5) + of "brvbar": Rune(0x000A6) + of "sect": Rune(0x000A7) + of "Dot", "die", "DoubleDot", "uml": Rune(0x000A8) + of "copy", "COPY": Rune(0x000A9) + of "ordf": Rune(0x000AA) + of "laquo": Rune(0x000AB) + of "not": Rune(0x000AC) + of "shy": Rune(0x000AD) + of "reg", "circledR", "REG": Rune(0x000AE) + of "macr", "OverBar", "strns": Rune(0x000AF) + of "deg": Rune(0x000B0) + of "plusmn", "pm", "PlusMinus": Rune(0x000B1) + of "sup2": Rune(0x000B2) + of "sup3": Rune(0x000B3) + of "acute", "DiacriticalAcute": Rune(0x000B4) + of "micro": Rune(0x000B5) + of "para": Rune(0x000B6) + of "middot", "centerdot", "CenterDot": Rune(0x000B7) + of "cedil", "Cedilla": Rune(0x000B8) + of "sup1": Rune(0x000B9) + of "ordm": Rune(0x000BA) + of "raquo": Rune(0x000BB) + of "frac14": Rune(0x000BC) + of "frac12", "half": Rune(0x000BD) + of "frac34": Rune(0x000BE) + of "iquest": Rune(0x000BF) + of "Agrave": Rune(0x000C0) + of "Aacute": Rune(0x000C1) + of "Acirc": Rune(0x000C2) + of "Atilde": Rune(0x000C3) + of "Auml": Rune(0x000C4) + of "Aring": Rune(0x000C5) + of "AElig": Rune(0x000C6) + of "Ccedil": Rune(0x000C7) + of "Egrave": Rune(0x000C8) + of "Eacute": Rune(0x000C9) + of "Ecirc": Rune(0x000CA) + of "Euml": Rune(0x000CB) + of "Igrave": Rune(0x000CC) + of "Iacute": Rune(0x000CD) + of "Icirc": Rune(0x000CE) + of "Iuml": Rune(0x000CF) + of "ETH": Rune(0x000D0) + of "Ntilde": Rune(0x000D1) + of "Ograve": Rune(0x000D2) + of "Oacute": Rune(0x000D3) + of "Ocirc": Rune(0x000D4) + of "Otilde": Rune(0x000D5) + of "Ouml": Rune(0x000D6) + of "times": Rune(0x000D7) + of "Oslash": Rune(0x000D8) + of "Ugrave": Rune(0x000D9) + of "Uacute": Rune(0x000DA) + of "Ucirc": Rune(0x000DB) + of "Uuml": Rune(0x000DC) + of "Yacute": Rune(0x000DD) + of "THORN": Rune(0x000DE) + of "szlig": Rune(0x000DF) + of "agrave": Rune(0x000E0) + of "aacute": Rune(0x000E1) + of "acirc": Rune(0x000E2) + of "atilde": Rune(0x000E3) + of "auml": Rune(0x000E4) + of "aring": Rune(0x000E5) + of "aelig": Rune(0x000E6) + of "ccedil": Rune(0x000E7) + of "egrave": Rune(0x000E8) + of "eacute": Rune(0x000E9) + of "ecirc": Rune(0x000EA) + of "euml": Rune(0x000EB) + of "igrave": Rune(0x000EC) + of "iacute": Rune(0x000ED) + of "icirc": Rune(0x000EE) + of "iuml": Rune(0x000EF) + of "eth": Rune(0x000F0) + of "ntilde": Rune(0x000F1) + of "ograve": Rune(0x000F2) + of "oacute": Rune(0x000F3) + of "ocirc": Rune(0x000F4) + of "otilde": Rune(0x000F5) + of "ouml": Rune(0x000F6) + of "divide", "div": Rune(0x000F7) + of "oslash": Rune(0x000F8) + of "ugrave": Rune(0x000F9) + of "uacute": Rune(0x000FA) + of "ucirc": Rune(0x000FB) + of "uuml": Rune(0x000FC) + of "yacute": Rune(0x000FD) + of "thorn": Rune(0x000FE) + of "yuml": Rune(0x000FF) + of "Amacr": Rune(0x00100) + of "amacr": Rune(0x00101) + of "Abreve": Rune(0x00102) + of "abreve": Rune(0x00103) + of "Aogon": Rune(0x00104) + of "aogon": Rune(0x00105) + of "Cacute": Rune(0x00106) + of "cacute": Rune(0x00107) + of "Ccirc": Rune(0x00108) + of "ccirc": Rune(0x00109) + of "Cdot": Rune(0x0010A) + of "cdot": Rune(0x0010B) + of "Ccaron": Rune(0x0010C) + of "ccaron": Rune(0x0010D) + of "Dcaron": Rune(0x0010E) + of "dcaron": Rune(0x0010F) + of "Dstrok": Rune(0x00110) + of "dstrok": Rune(0x00111) + of "Emacr": Rune(0x00112) + of "emacr": Rune(0x00113) + of "Edot": Rune(0x00116) + of "edot": Rune(0x00117) + of "Eogon": Rune(0x00118) + of "eogon": Rune(0x00119) + of "Ecaron": Rune(0x0011A) + of "ecaron": Rune(0x0011B) + of "Gcirc": Rune(0x0011C) + of "gcirc": Rune(0x0011D) + of "Gbreve": Rune(0x0011E) + of "gbreve": Rune(0x0011F) + of "Gdot": Rune(0x00120) + of "gdot": Rune(0x00121) + of "Gcedil": Rune(0x00122) + of "Hcirc": Rune(0x00124) + of "hcirc": Rune(0x00125) + of "Hstrok": Rune(0x00126) + of "hstrok": Rune(0x00127) + of "Itilde": Rune(0x00128) + of "itilde": Rune(0x00129) + of "Imacr": Rune(0x0012A) + of "imacr": Rune(0x0012B) + of "Iogon": Rune(0x0012E) + of "iogon": Rune(0x0012F) + of "Idot": Rune(0x00130) + of "imath", "inodot": Rune(0x00131) + of "IJlig": Rune(0x00132) + of "ijlig": Rune(0x00133) + of "Jcirc": Rune(0x00134) + of "jcirc": Rune(0x00135) + of "Kcedil": Rune(0x00136) + of "kcedil": Rune(0x00137) + of "kgreen": Rune(0x00138) + of "Lacute": Rune(0x00139) + of "lacute": Rune(0x0013A) + of "Lcedil": Rune(0x0013B) + of "lcedil": Rune(0x0013C) + of "Lcaron": Rune(0x0013D) + of "lcaron": Rune(0x0013E) + of "Lmidot": Rune(0x0013F) + of "lmidot": Rune(0x00140) + of "Lstrok": Rune(0x00141) + of "lstrok": Rune(0x00142) + of "Nacute": Rune(0x00143) + of "nacute": Rune(0x00144) + of "Ncedil": Rune(0x00145) + of "ncedil": Rune(0x00146) + of "Ncaron": Rune(0x00147) + of "ncaron": Rune(0x00148) + of "napos": Rune(0x00149) + of "ENG": Rune(0x0014A) + of "eng": Rune(0x0014B) + of "Omacr": Rune(0x0014C) + of "omacr": Rune(0x0014D) + of "Odblac": Rune(0x00150) + of "odblac": Rune(0x00151) + of "OElig": Rune(0x00152) + of "oelig": Rune(0x00153) + of "Racute": Rune(0x00154) + of "racute": Rune(0x00155) + of "Rcedil": Rune(0x00156) + of "rcedil": Rune(0x00157) + of "Rcaron": Rune(0x00158) + of "rcaron": Rune(0x00159) + of "Sacute": Rune(0x0015A) + of "sacute": Rune(0x0015B) + of "Scirc": Rune(0x0015C) + of "scirc": Rune(0x0015D) + of "Scedil": Rune(0x0015E) + of "scedil": Rune(0x0015F) + of "Scaron": Rune(0x00160) + of "scaron": Rune(0x00161) + of "Tcedil": Rune(0x00162) + of "tcedil": Rune(0x00163) + of "Tcaron": Rune(0x00164) + of "tcaron": Rune(0x00165) + of "Tstrok": Rune(0x00166) + of "tstrok": Rune(0x00167) + of "Utilde": Rune(0x00168) + of "utilde": Rune(0x00169) + of "Umacr": Rune(0x0016A) + of "umacr": Rune(0x0016B) + of "Ubreve": Rune(0x0016C) + of "ubreve": Rune(0x0016D) + of "Uring": Rune(0x0016E) + of "uring": Rune(0x0016F) + of "Udblac": Rune(0x00170) + of "udblac": Rune(0x00171) + of "Uogon": Rune(0x00172) + of "uogon": Rune(0x00173) + of "Wcirc": Rune(0x00174) + of "wcirc": Rune(0x00175) + of "Ycirc": Rune(0x00176) + of "ycirc": Rune(0x00177) + of "Yuml": Rune(0x00178) + of "Zacute": Rune(0x00179) + of "zacute": Rune(0x0017A) + of "Zdot": Rune(0x0017B) + of "zdot": Rune(0x0017C) + of "Zcaron": Rune(0x0017D) + of "zcaron": Rune(0x0017E) + of "fnof": Rune(0x00192) + of "imped": Rune(0x001B5) + of "gacute": Rune(0x001F5) + of "jmath": Rune(0x00237) + of "circ": Rune(0x002C6) + of "caron", "Hacek": Rune(0x002C7) + of "breve", "Breve": Rune(0x002D8) + of "dot", "DiacriticalDot": Rune(0x002D9) + of "ring": Rune(0x002DA) + of "ogon": Rune(0x002DB) + of "tilde", "DiacriticalTilde": Rune(0x002DC) + of "dblac", "DiacriticalDoubleAcute": Rune(0x002DD) + of "DownBreve": Rune(0x00311) + of "UnderBar": Rune(0x00332) + of "Alpha": Rune(0x00391) + of "Beta": Rune(0x00392) + of "Gamma": Rune(0x00393) + of "Delta": Rune(0x00394) + of "Epsilon": Rune(0x00395) + of "Zeta": Rune(0x00396) + of "Eta": Rune(0x00397) + of "Theta": Rune(0x00398) + of "Iota": Rune(0x00399) + of "Kappa": Rune(0x0039A) + of "Lambda": Rune(0x0039B) + of "Mu": Rune(0x0039C) + of "Nu": Rune(0x0039D) + of "Xi": Rune(0x0039E) + of "Omicron": Rune(0x0039F) + of "Pi": Rune(0x003A0) + of "Rho": Rune(0x003A1) + of "Sigma": Rune(0x003A3) + of "Tau": Rune(0x003A4) + of "Upsilon": Rune(0x003A5) + of "Phi": Rune(0x003A6) + of "Chi": Rune(0x003A7) + of "Psi": Rune(0x003A8) + of "Omega": Rune(0x003A9) + of "alpha": Rune(0x003B1) + of "beta": Rune(0x003B2) + of "gamma": Rune(0x003B3) + of "delta": Rune(0x003B4) + of "epsiv", "varepsilon", "epsilon": Rune(0x003B5) + of "zeta": Rune(0x003B6) + of "eta": Rune(0x003B7) + of "theta": Rune(0x003B8) + of "iota": Rune(0x003B9) + of "kappa": Rune(0x003BA) + of "lambda": Rune(0x003BB) + of "mu": Rune(0x003BC) + of "nu": Rune(0x003BD) + of "xi": Rune(0x003BE) + of "omicron": Rune(0x003BF) + of "pi": Rune(0x003C0) + of "rho": Rune(0x003C1) + of "sigmav", "varsigma", "sigmaf": Rune(0x003C2) + of "sigma": Rune(0x003C3) + of "tau": Rune(0x003C4) + of "upsi", "upsilon": Rune(0x003C5) + of "phi", "phiv", "varphi": Rune(0x003C6) + of "chi": Rune(0x003C7) + of "psi": Rune(0x003C8) + of "omega": Rune(0x003C9) + of "thetav", "vartheta", "thetasym": Rune(0x003D1) + of "Upsi", "upsih": Rune(0x003D2) + of "straightphi": Rune(0x003D5) + of "piv", "varpi": Rune(0x003D6) + of "Gammad": Rune(0x003DC) + of "gammad", "digamma": Rune(0x003DD) + of "kappav", "varkappa": Rune(0x003F0) + of "rhov", "varrho": Rune(0x003F1) + of "epsi", "straightepsilon": Rune(0x003F5) + of "bepsi", "backepsilon": Rune(0x003F6) + of "IOcy": Rune(0x00401) + of "DJcy": Rune(0x00402) + of "GJcy": Rune(0x00403) + of "Jukcy": Rune(0x00404) + of "DScy": Rune(0x00405) + of "Iukcy": Rune(0x00406) + of "YIcy": Rune(0x00407) + of "Jsercy": Rune(0x00408) + of "LJcy": Rune(0x00409) + of "NJcy": Rune(0x0040A) + of "TSHcy": Rune(0x0040B) + of "KJcy": Rune(0x0040C) + of "Ubrcy": Rune(0x0040E) + of "DZcy": Rune(0x0040F) + of "Acy": Rune(0x00410) + of "Bcy": Rune(0x00411) + of "Vcy": Rune(0x00412) + of "Gcy": Rune(0x00413) + of "Dcy": Rune(0x00414) + of "IEcy": Rune(0x00415) + of "ZHcy": Rune(0x00416) + of "Zcy": Rune(0x00417) + of "Icy": Rune(0x00418) + of "Jcy": Rune(0x00419) + of "Kcy": Rune(0x0041A) + of "Lcy": Rune(0x0041B) + of "Mcy": Rune(0x0041C) + of "Ncy": Rune(0x0041D) + of "Ocy": Rune(0x0041E) + of "Pcy": Rune(0x0041F) + of "Rcy": Rune(0x00420) + of "Scy": Rune(0x00421) + of "Tcy": Rune(0x00422) + of "Ucy": Rune(0x00423) + of "Fcy": Rune(0x00424) + of "KHcy": Rune(0x00425) + of "TScy": Rune(0x00426) + of "CHcy": Rune(0x00427) + of "SHcy": Rune(0x00428) + of "SHCHcy": Rune(0x00429) + of "HARDcy": Rune(0x0042A) + of "Ycy": Rune(0x0042B) + of "SOFTcy": Rune(0x0042C) + of "Ecy": Rune(0x0042D) + of "YUcy": Rune(0x0042E) + of "YAcy": Rune(0x0042F) + of "acy": Rune(0x00430) + of "bcy": Rune(0x00431) + of "vcy": Rune(0x00432) + of "gcy": Rune(0x00433) + of "dcy": Rune(0x00434) + of "iecy": Rune(0x00435) + of "zhcy": Rune(0x00436) + of "zcy": Rune(0x00437) + of "icy": Rune(0x00438) + of "jcy": Rune(0x00439) + of "kcy": Rune(0x0043A) + of "lcy": Rune(0x0043B) + of "mcy": Rune(0x0043C) + of "ncy": Rune(0x0043D) + of "ocy": Rune(0x0043E) + of "pcy": Rune(0x0043F) + of "rcy": Rune(0x00440) + of "scy": Rune(0x00441) + of "tcy": Rune(0x00442) + of "ucy": Rune(0x00443) + of "fcy": Rune(0x00444) + of "khcy": Rune(0x00445) + of "tscy": Rune(0x00446) + of "chcy": Rune(0x00447) + of "shcy": Rune(0x00448) + of "shchcy": Rune(0x00449) + of "hardcy": Rune(0x0044A) + of "ycy": Rune(0x0044B) + of "softcy": Rune(0x0044C) + of "ecy": Rune(0x0044D) + of "yucy": Rune(0x0044E) + of "yacy": Rune(0x0044F) + of "iocy": Rune(0x00451) + of "djcy": Rune(0x00452) + of "gjcy": Rune(0x00453) + of "jukcy": Rune(0x00454) + of "dscy": Rune(0x00455) + of "iukcy": Rune(0x00456) + of "yicy": Rune(0x00457) + of "jsercy": Rune(0x00458) + of "ljcy": Rune(0x00459) + of "njcy": Rune(0x0045A) + of "tshcy": Rune(0x0045B) + of "kjcy": Rune(0x0045C) + of "ubrcy": Rune(0x0045E) + of "dzcy": Rune(0x0045F) + of "ensp": Rune(0x02002) + of "emsp": Rune(0x02003) + of "emsp13": Rune(0x02004) + of "emsp14": Rune(0x02005) + of "numsp": Rune(0x02007) + of "puncsp": Rune(0x02008) + of "thinsp", "ThinSpace": Rune(0x02009) + of "hairsp", "VeryThinSpace": Rune(0x0200A) of "ZeroWidthSpace", "NegativeVeryThinSpace", "NegativeThinSpace", - "NegativeMediumSpace", "NegativeThickSpace": result = Rune(0x0200B) - of "zwnj": result = Rune(0x0200C) - of "zwj": result = Rune(0x0200D) - of "lrm": result = Rune(0x0200E) - of "rlm": result = Rune(0x0200F) - of "hyphen", "dash": result = Rune(0x02010) - of "ndash": result = Rune(0x02013) - of "mdash": result = Rune(0x02014) - of "horbar": result = Rune(0x02015) - of "Verbar", "Vert": result = Rune(0x02016) - of "lsquo", "OpenCurlyQuote": result = Rune(0x02018) - of "rsquo", "rsquor", "CloseCurlyQuote": result = Rune(0x02019) - of "lsquor", "sbquo": result = Rune(0x0201A) - of "ldquo", "OpenCurlyDoubleQuote": result = Rune(0x0201C) - of "rdquo", "rdquor", "CloseCurlyDoubleQuote": result = Rune(0x0201D) - of "ldquor", "bdquo": result = Rune(0x0201E) - of "dagger": result = Rune(0x02020) - of "Dagger", "ddagger": result = Rune(0x02021) - of "bull", "bullet": result = Rune(0x02022) - of "nldr": result = Rune(0x02025) - of "hellip", "mldr": result = Rune(0x02026) - of "permil": result = Rune(0x02030) - of "pertenk": result = Rune(0x02031) - of "prime": result = Rune(0x02032) - of "Prime": result = Rune(0x02033) - of "tprime": result = Rune(0x02034) - of "bprime", "backprime": result = Rune(0x02035) - of "lsaquo": result = Rune(0x02039) - of "rsaquo": result = Rune(0x0203A) - of "oline": result = Rune(0x0203E) - of "caret": result = Rune(0x02041) - of "hybull": result = Rune(0x02043) - of "frasl": result = Rune(0x02044) - of "bsemi": result = Rune(0x0204F) - of "qprime": result = Rune(0x02057) - of "MediumSpace": result = Rune(0x0205F) - of "NoBreak": result = Rune(0x02060) - of "ApplyFunction", "af": result = Rune(0x02061) - of "InvisibleTimes", "it": result = Rune(0x02062) - of "InvisibleComma", "ic": result = Rune(0x02063) - of "euro": result = Rune(0x020AC) - of "tdot", "TripleDot": result = Rune(0x020DB) - of "DotDot": result = Rune(0x020DC) - of "Copf", "complexes": result = Rune(0x02102) - of "incare": result = Rune(0x02105) - of "gscr": result = Rune(0x0210A) - of "hamilt", "HilbertSpace", "Hscr": result = Rune(0x0210B) - of "Hfr", "Poincareplane": result = Rune(0x0210C) - of "quaternions", "Hopf": result = Rune(0x0210D) - of "planckh": result = Rune(0x0210E) - of "planck", "hbar", "plankv", "hslash": result = Rune(0x0210F) - of "Iscr", "imagline": result = Rune(0x02110) - of "image", "Im", "imagpart", "Ifr": result = Rune(0x02111) - of "Lscr", "lagran", "Laplacetrf": result = Rune(0x02112) - of "ell": result = Rune(0x02113) - of "Nopf", "naturals": result = Rune(0x02115) - of "numero": result = Rune(0x02116) - of "copysr": result = Rune(0x02117) - of "weierp", "wp": result = Rune(0x02118) - of "Popf", "primes": result = Rune(0x02119) - of "rationals", "Qopf": result = Rune(0x0211A) - of "Rscr", "realine": result = Rune(0x0211B) - of "real", "Re", "realpart", "Rfr": result = Rune(0x0211C) - of "reals", "Ropf": result = Rune(0x0211D) - of "rx": result = Rune(0x0211E) - of "trade", "TRADE": result = Rune(0x02122) - of "integers", "Zopf": result = Rune(0x02124) - of "ohm": result = Rune(0x02126) - of "mho": result = Rune(0x02127) - of "Zfr", "zeetrf": result = Rune(0x02128) - of "iiota": result = Rune(0x02129) - of "angst": result = Rune(0x0212B) - of "bernou", "Bernoullis", "Bscr": result = Rune(0x0212C) - of "Cfr", "Cayleys": result = Rune(0x0212D) - of "escr": result = Rune(0x0212F) - of "Escr", "expectation": result = Rune(0x02130) - of "Fscr", "Fouriertrf": result = Rune(0x02131) - of "phmmat", "Mellintrf", "Mscr": result = Rune(0x02133) - of "order", "orderof", "oscr": result = Rune(0x02134) - of "alefsym", "aleph": result = Rune(0x02135) - of "beth": result = Rune(0x02136) - of "gimel": result = Rune(0x02137) - of "daleth": result = Rune(0x02138) - of "CapitalDifferentialD", "DD": result = Rune(0x02145) - of "DifferentialD", "dd": result = Rune(0x02146) - of "ExponentialE", "exponentiale", "ee": result = Rune(0x02147) - of "ImaginaryI", "ii": result = Rune(0x02148) - of "frac13": result = Rune(0x02153) - of "frac23": result = Rune(0x02154) - of "frac15": result = Rune(0x02155) - of "frac25": result = Rune(0x02156) - of "frac35": result = Rune(0x02157) - of "frac45": result = Rune(0x02158) - of "frac16": result = Rune(0x02159) - of "frac56": result = Rune(0x0215A) - of "frac18": result = Rune(0x0215B) - of "frac38": result = Rune(0x0215C) - of "frac58": result = Rune(0x0215D) - of "frac78": result = Rune(0x0215E) + "NegativeMediumSpace", "NegativeThickSpace": Rune(0x0200B) + of "zwnj": Rune(0x0200C) + of "zwj": Rune(0x0200D) + of "lrm": Rune(0x0200E) + of "rlm": Rune(0x0200F) + of "hyphen", "dash": Rune(0x02010) + of "ndash": Rune(0x02013) + of "mdash": Rune(0x02014) + of "horbar": Rune(0x02015) + of "Verbar", "Vert": Rune(0x02016) + of "lsquo", "OpenCurlyQuote": Rune(0x02018) + of "rsquo", "rsquor", "CloseCurlyQuote": Rune(0x02019) + of "lsquor", "sbquo": Rune(0x0201A) + of "ldquo", "OpenCurlyDoubleQuote": Rune(0x0201C) + of "rdquo", "rdquor", "CloseCurlyDoubleQuote": Rune(0x0201D) + of "ldquor", "bdquo": Rune(0x0201E) + of "dagger": Rune(0x02020) + of "Dagger", "ddagger": Rune(0x02021) + of "bull", "bullet": Rune(0x02022) + of "nldr": Rune(0x02025) + of "hellip", "mldr": Rune(0x02026) + of "permil": Rune(0x02030) + of "pertenk": Rune(0x02031) + of "prime": Rune(0x02032) + of "Prime": Rune(0x02033) + of "tprime": Rune(0x02034) + of "bprime", "backprime": Rune(0x02035) + of "lsaquo": Rune(0x02039) + of "rsaquo": Rune(0x0203A) + of "oline": Rune(0x0203E) + of "caret": Rune(0x02041) + of "hybull": Rune(0x02043) + of "frasl": Rune(0x02044) + of "bsemi": Rune(0x0204F) + of "qprime": Rune(0x02057) + of "MediumSpace": Rune(0x0205F) + of "NoBreak": Rune(0x02060) + of "ApplyFunction", "af": Rune(0x02061) + of "InvisibleTimes", "it": Rune(0x02062) + of "InvisibleComma", "ic": Rune(0x02063) + of "euro": Rune(0x020AC) + of "tdot", "TripleDot": Rune(0x020DB) + of "DotDot": Rune(0x020DC) + of "Copf", "complexes": Rune(0x02102) + of "incare": Rune(0x02105) + of "gscr": Rune(0x0210A) + of "hamilt", "HilbertSpace", "Hscr": Rune(0x0210B) + of "Hfr", "Poincareplane": Rune(0x0210C) + of "quaternions", "Hopf": Rune(0x0210D) + of "planckh": Rune(0x0210E) + of "planck", "hbar", "plankv", "hslash": Rune(0x0210F) + of "Iscr", "imagline": Rune(0x02110) + of "image", "Im", "imagpart", "Ifr": Rune(0x02111) + of "Lscr", "lagran", "Laplacetrf": Rune(0x02112) + of "ell": Rune(0x02113) + of "Nopf", "naturals": Rune(0x02115) + of "numero": Rune(0x02116) + of "copysr": Rune(0x02117) + of "weierp", "wp": Rune(0x02118) + of "Popf", "primes": Rune(0x02119) + of "rationals", "Qopf": Rune(0x0211A) + of "Rscr", "realine": Rune(0x0211B) + of "real", "Re", "realpart", "Rfr": Rune(0x0211C) + of "reals", "Ropf": Rune(0x0211D) + of "rx": Rune(0x0211E) + of "trade", "TRADE": Rune(0x02122) + of "integers", "Zopf": Rune(0x02124) + of "ohm": Rune(0x02126) + of "mho": Rune(0x02127) + of "Zfr", "zeetrf": Rune(0x02128) + of "iiota": Rune(0x02129) + of "angst": Rune(0x0212B) + of "bernou", "Bernoullis", "Bscr": Rune(0x0212C) + of "Cfr", "Cayleys": Rune(0x0212D) + of "escr": Rune(0x0212F) + of "Escr", "expectation": Rune(0x02130) + of "Fscr", "Fouriertrf": Rune(0x02131) + of "phmmat", "Mellintrf", "Mscr": Rune(0x02133) + of "order", "orderof", "oscr": Rune(0x02134) + of "alefsym", "aleph": Rune(0x02135) + of "beth": Rune(0x02136) + of "gimel": Rune(0x02137) + of "daleth": Rune(0x02138) + of "CapitalDifferentialD", "DD": Rune(0x02145) + of "DifferentialD", "dd": Rune(0x02146) + of "ExponentialE", "exponentiale", "ee": Rune(0x02147) + of "ImaginaryI", "ii": Rune(0x02148) + of "frac13": Rune(0x02153) + of "frac23": Rune(0x02154) + of "frac15": Rune(0x02155) + of "frac25": Rune(0x02156) + of "frac35": Rune(0x02157) + of "frac45": Rune(0x02158) + of "frac16": Rune(0x02159) + of "frac56": Rune(0x0215A) + of "frac18": Rune(0x0215B) + of "frac38": Rune(0x0215C) + of "frac58": Rune(0x0215D) + of "frac78": Rune(0x0215E) of "larr", "leftarrow", "LeftArrow", "slarr", - "ShortLeftArrow": result = Rune(0x02190) - of "uarr", "uparrow", "UpArrow", "ShortUpArrow": result = Rune(0x02191) + "ShortLeftArrow": Rune(0x02190) + of "uarr", "uparrow", "UpArrow", "ShortUpArrow": Rune(0x02191) of "rarr", "rightarrow", "RightArrow", "srarr", - "ShortRightArrow": result = Rune(0x02192) + "ShortRightArrow": Rune(0x02192) of "darr", "downarrow", "DownArrow", - "ShortDownArrow": result = Rune(0x02193) - of "harr", "leftrightarrow", "LeftRightArrow": result = Rune(0x02194) - of "varr", "updownarrow", "UpDownArrow": result = Rune(0x02195) - of "nwarr", "UpperLeftArrow", "nwarrow": result = Rune(0x02196) - of "nearr", "UpperRightArrow", "nearrow": result = Rune(0x02197) - of "searr", "searrow", "LowerRightArrow": result = Rune(0x02198) - of "swarr", "swarrow", "LowerLeftArrow": result = Rune(0x02199) - of "nlarr", "nleftarrow": result = Rune(0x0219A) - of "nrarr", "nrightarrow": result = Rune(0x0219B) - of "rarrw", "rightsquigarrow": result = Rune(0x0219D) - of "Larr", "twoheadleftarrow": result = Rune(0x0219E) - of "Uarr": result = Rune(0x0219F) - of "Rarr", "twoheadrightarrow": result = Rune(0x021A0) - of "Darr": result = Rune(0x021A1) - of "larrtl", "leftarrowtail": result = Rune(0x021A2) - of "rarrtl", "rightarrowtail": result = Rune(0x021A3) - of "LeftTeeArrow", "mapstoleft": result = Rune(0x021A4) - of "UpTeeArrow", "mapstoup": result = Rune(0x021A5) - of "map", "RightTeeArrow", "mapsto": result = Rune(0x021A6) - of "DownTeeArrow", "mapstodown": result = Rune(0x021A7) - of "larrhk", "hookleftarrow": result = Rune(0x021A9) - of "rarrhk", "hookrightarrow": result = Rune(0x021AA) - of "larrlp", "looparrowleft": result = Rune(0x021AB) - of "rarrlp", "looparrowright": result = Rune(0x021AC) - of "harrw", "leftrightsquigarrow": result = Rune(0x021AD) - of "nharr", "nleftrightarrow": result = Rune(0x021AE) - of "lsh", "Lsh": result = Rune(0x021B0) - of "rsh", "Rsh": result = Rune(0x021B1) - of "ldsh": result = Rune(0x021B2) - of "rdsh": result = Rune(0x021B3) - of "crarr": result = Rune(0x021B5) - of "cularr", "curvearrowleft": result = Rune(0x021B6) - of "curarr", "curvearrowright": result = Rune(0x021B7) - of "olarr", "circlearrowleft": result = Rune(0x021BA) - of "orarr", "circlearrowright": result = Rune(0x021BB) - of "lharu", "LeftVector", "leftharpoonup": result = Rune(0x021BC) - of "lhard", "leftharpoondown", "DownLeftVector": result = Rune(0x021BD) - of "uharr", "upharpoonright", "RightUpVector": result = Rune(0x021BE) - of "uharl", "upharpoonleft", "LeftUpVector": result = Rune(0x021BF) - of "rharu", "RightVector", "rightharpoonup": result = Rune(0x021C0) - of "rhard", "rightharpoondown", "DownRightVector": result = Rune(0x021C1) - of "dharr", "RightDownVector", "downharpoonright": result = Rune(0x021C2) - of "dharl", "LeftDownVector", "downharpoonleft": result = Rune(0x021C3) - of "rlarr", "rightleftarrows", "RightArrowLeftArrow": result = Rune(0x021C4) - of "udarr", "UpArrowDownArrow": result = Rune(0x021C5) - of "lrarr", "leftrightarrows", "LeftArrowRightArrow": result = Rune(0x021C6) - of "llarr", "leftleftarrows": result = Rune(0x021C7) - of "uuarr", "upuparrows": result = Rune(0x021C8) - of "rrarr", "rightrightarrows": result = Rune(0x021C9) - of "ddarr", "downdownarrows": result = Rune(0x021CA) + "ShortDownArrow": Rune(0x02193) + of "harr", "leftrightarrow", "LeftRightArrow": Rune(0x02194) + of "varr", "updownarrow", "UpDownArrow": Rune(0x02195) + of "nwarr", "UpperLeftArrow", "nwarrow": Rune(0x02196) + of "nearr", "UpperRightArrow", "nearrow": Rune(0x02197) + of "searr", "searrow", "LowerRightArrow": Rune(0x02198) + of "swarr", "swarrow", "LowerLeftArrow": Rune(0x02199) + of "nlarr", "nleftarrow": Rune(0x0219A) + of "nrarr", "nrightarrow": Rune(0x0219B) + of "rarrw", "rightsquigarrow": Rune(0x0219D) + of "Larr", "twoheadleftarrow": Rune(0x0219E) + of "Uarr": Rune(0x0219F) + of "Rarr", "twoheadrightarrow": Rune(0x021A0) + of "Darr": Rune(0x021A1) + of "larrtl", "leftarrowtail": Rune(0x021A2) + of "rarrtl", "rightarrowtail": Rune(0x021A3) + of "LeftTeeArrow", "mapstoleft": Rune(0x021A4) + of "UpTeeArrow", "mapstoup": Rune(0x021A5) + of "map", "RightTeeArrow", "mapsto": Rune(0x021A6) + of "DownTeeArrow", "mapstodown": Rune(0x021A7) + of "larrhk", "hookleftarrow": Rune(0x021A9) + of "rarrhk", "hookrightarrow": Rune(0x021AA) + of "larrlp", "looparrowleft": Rune(0x021AB) + of "rarrlp", "looparrowright": Rune(0x021AC) + of "harrw", "leftrightsquigarrow": Rune(0x021AD) + of "nharr", "nleftrightarrow": Rune(0x021AE) + of "lsh", "Lsh": Rune(0x021B0) + of "rsh", "Rsh": Rune(0x021B1) + of "ldsh": Rune(0x021B2) + of "rdsh": Rune(0x021B3) + of "crarr": Rune(0x021B5) + of "cularr", "curvearrowleft": Rune(0x021B6) + of "curarr", "curvearrowright": Rune(0x021B7) + of "olarr", "circlearrowleft": Rune(0x021BA) + of "orarr", "circlearrowright": Rune(0x021BB) + of "lharu", "LeftVector", "leftharpoonup": Rune(0x021BC) + of "lhard", "leftharpoondown", "DownLeftVector": Rune(0x021BD) + of "uharr", "upharpoonright", "RightUpVector": Rune(0x021BE) + of "uharl", "upharpoonleft", "LeftUpVector": Rune(0x021BF) + of "rharu", "RightVector", "rightharpoonup": Rune(0x021C0) + of "rhard", "rightharpoondown", "DownRightVector": Rune(0x021C1) + of "dharr", "RightDownVector", "downharpoonright": Rune(0x021C2) + of "dharl", "LeftDownVector", "downharpoonleft": Rune(0x021C3) + of "rlarr", "rightleftarrows", "RightArrowLeftArrow": Rune(0x021C4) + of "udarr", "UpArrowDownArrow": Rune(0x021C5) + of "lrarr", "leftrightarrows", "LeftArrowRightArrow": Rune(0x021C6) + of "llarr", "leftleftarrows": Rune(0x021C7) + of "uuarr", "upuparrows": Rune(0x021C8) + of "rrarr", "rightrightarrows": Rune(0x021C9) + of "ddarr", "downdownarrows": Rune(0x021CA) of "lrhar", "ReverseEquilibrium", - "leftrightharpoons": result = Rune(0x021CB) - of "rlhar", "rightleftharpoons", "Equilibrium": result = Rune(0x021CC) - of "nlArr", "nLeftarrow": result = Rune(0x021CD) - of "nhArr", "nLeftrightarrow": result = Rune(0x021CE) - of "nrArr", "nRightarrow": result = Rune(0x021CF) - of "lArr", "Leftarrow", "DoubleLeftArrow": result = Rune(0x021D0) - of "uArr", "Uparrow", "DoubleUpArrow": result = Rune(0x021D1) + "leftrightharpoons": Rune(0x021CB) + of "rlhar", "rightleftharpoons", "Equilibrium": Rune(0x021CC) + of "nlArr", "nLeftarrow": Rune(0x021CD) + of "nhArr", "nLeftrightarrow": Rune(0x021CE) + of "nrArr", "nRightarrow": Rune(0x021CF) + of "lArr", "Leftarrow", "DoubleLeftArrow": Rune(0x021D0) + of "uArr", "Uparrow", "DoubleUpArrow": Rune(0x021D1) of "rArr", "Rightarrow", "Implies", - "DoubleRightArrow": result = Rune(0x021D2) - of "dArr", "Downarrow", "DoubleDownArrow": result = Rune(0x021D3) + "DoubleRightArrow": Rune(0x021D2) + of "dArr", "Downarrow", "DoubleDownArrow": Rune(0x021D3) of "hArr", "Leftrightarrow", "DoubleLeftRightArrow", - "iff": result = Rune(0x021D4) - of "vArr", "Updownarrow", "DoubleUpDownArrow": result = Rune(0x021D5) - of "nwArr": result = Rune(0x021D6) - of "neArr": result = Rune(0x021D7) - of "seArr": result = Rune(0x021D8) - of "swArr": result = Rune(0x021D9) - of "lAarr", "Lleftarrow": result = Rune(0x021DA) - of "rAarr", "Rrightarrow": result = Rune(0x021DB) - of "zigrarr": result = Rune(0x021DD) - of "larrb", "LeftArrowBar": result = Rune(0x021E4) - of "rarrb", "RightArrowBar": result = Rune(0x021E5) - of "duarr", "DownArrowUpArrow": result = Rune(0x021F5) - of "loarr": result = Rune(0x021FD) - of "roarr": result = Rune(0x021FE) - of "hoarr": result = Rune(0x021FF) - of "forall", "ForAll": result = Rune(0x02200) - of "comp", "complement": result = Rune(0x02201) - of "part", "PartialD": result = Rune(0x02202) - of "exist", "Exists": result = Rune(0x02203) - of "nexist", "NotExists", "nexists": result = Rune(0x02204) - of "empty", "emptyset", "emptyv", "varnothing": result = Rune(0x02205) - of "nabla", "Del": result = Rune(0x02207) - of "isin", "isinv", "Element", "in": result = Rune(0x02208) - of "notin", "NotElement", "notinva": result = Rune(0x02209) - of "niv", "ReverseElement", "ni", "SuchThat": result = Rune(0x0220B) - of "notni", "notniva", "NotReverseElement": result = Rune(0x0220C) - of "prod", "Product": result = Rune(0x0220F) - of "coprod", "Coproduct": result = Rune(0x02210) - of "sum", "Sum": result = Rune(0x02211) - of "minus": result = Rune(0x02212) - of "mnplus", "mp", "MinusPlus": result = Rune(0x02213) - of "plusdo", "dotplus": result = Rune(0x02214) + "iff": Rune(0x021D4) + of "vArr", "Updownarrow", "DoubleUpDownArrow": Rune(0x021D5) + of "nwArr": Rune(0x021D6) + of "neArr": Rune(0x021D7) + of "seArr": Rune(0x021D8) + of "swArr": Rune(0x021D9) + of "lAarr", "Lleftarrow": Rune(0x021DA) + of "rAarr", "Rrightarrow": Rune(0x021DB) + of "zigrarr": Rune(0x021DD) + of "larrb", "LeftArrowBar": Rune(0x021E4) + of "rarrb", "RightArrowBar": Rune(0x021E5) + of "duarr", "DownArrowUpArrow": Rune(0x021F5) + of "loarr": Rune(0x021FD) + of "roarr": Rune(0x021FE) + of "hoarr": Rune(0x021FF) + of "forall", "ForAll": Rune(0x02200) + of "comp", "complement": Rune(0x02201) + of "part", "PartialD": Rune(0x02202) + of "exist", "Exists": Rune(0x02203) + of "nexist", "NotExists", "nexists": Rune(0x02204) + of "empty", "emptyset", "emptyv", "varnothing": Rune(0x02205) + of "nabla", "Del": Rune(0x02207) + of "isin", "isinv", "Element", "in": Rune(0x02208) + of "notin", "NotElement", "notinva": Rune(0x02209) + of "niv", "ReverseElement", "ni", "SuchThat": Rune(0x0220B) + of "notni", "notniva", "NotReverseElement": Rune(0x0220C) + of "prod", "Product": Rune(0x0220F) + of "coprod", "Coproduct": Rune(0x02210) + of "sum", "Sum": Rune(0x02211) + of "minus": Rune(0x02212) + of "mnplus", "mp", "MinusPlus": Rune(0x02213) + of "plusdo", "dotplus": Rune(0x02214) of "setmn", "setminus", "Backslash", "ssetmn", - "smallsetminus": result = Rune(0x02216) - of "lowast": result = Rune(0x02217) - of "compfn", "SmallCircle": result = Rune(0x02218) - of "radic", "Sqrt": result = Rune(0x0221A) + "smallsetminus": Rune(0x02216) + of "lowast": Rune(0x02217) + of "compfn", "SmallCircle": Rune(0x02218) + of "radic", "Sqrt": Rune(0x0221A) of "prop", "propto", "Proportional", "vprop", - "varpropto": result = Rune(0x0221D) - of "infin": result = Rune(0x0221E) - of "angrt": result = Rune(0x0221F) - of "ang", "angle": result = Rune(0x02220) - of "angmsd", "measuredangle": result = Rune(0x02221) - of "angsph": result = Rune(0x02222) - of "mid", "VerticalBar", "smid", "shortmid": result = Rune(0x02223) - of "nmid", "NotVerticalBar", "nsmid", "nshortmid": result = Rune(0x02224) + "varpropto": Rune(0x0221D) + of "infin": Rune(0x0221E) + of "angrt": Rune(0x0221F) + of "ang", "angle": Rune(0x02220) + of "angmsd", "measuredangle": Rune(0x02221) + of "angsph": Rune(0x02222) + of "mid", "VerticalBar", "smid", "shortmid": Rune(0x02223) + of "nmid", "NotVerticalBar", "nsmid", "nshortmid": Rune(0x02224) of "par", "parallel", "DoubleVerticalBar", "spar", - "shortparallel": result = Rune(0x02225) + "shortparallel": Rune(0x02225) of "npar", "nparallel", "NotDoubleVerticalBar", "nspar", - "nshortparallel": result = Rune(0x02226) - of "and", "wedge": result = Rune(0x02227) - of "or", "vee": result = Rune(0x02228) - of "cap": result = Rune(0x02229) - of "cup": result = Rune(0x0222A) - of "int", "Integral": result = Rune(0x0222B) - of "Int": result = Rune(0x0222C) - of "tint", "iiint": result = Rune(0x0222D) - of "conint", "oint", "ContourIntegral": result = Rune(0x0222E) - of "Conint", "DoubleContourIntegral": result = Rune(0x0222F) - of "Cconint": result = Rune(0x02230) - of "cwint": result = Rune(0x02231) - of "cwconint", "ClockwiseContourIntegral": result = Rune(0x02232) - of "awconint", "CounterClockwiseContourIntegral": result = Rune(0x02233) - of "there4", "therefore", "Therefore": result = Rune(0x02234) - of "becaus", "because", "Because": result = Rune(0x02235) - of "ratio": result = Rune(0x02236) - of "Colon", "Proportion": result = Rune(0x02237) - of "minusd", "dotminus": result = Rune(0x02238) - of "mDDot": result = Rune(0x0223A) - of "homtht": result = Rune(0x0223B) - of "sim", "Tilde", "thksim", "thicksim": result = Rune(0x0223C) - of "bsim", "backsim": result = Rune(0x0223D) - of "ac", "mstpos": result = Rune(0x0223E) - of "acd": result = Rune(0x0223F) - of "wreath", "VerticalTilde", "wr": result = Rune(0x02240) - of "nsim", "NotTilde": result = Rune(0x02241) - of "esim", "EqualTilde", "eqsim": result = Rune(0x02242) - of "sime", "TildeEqual", "simeq": result = Rune(0x02243) - of "nsime", "nsimeq", "NotTildeEqual": result = Rune(0x02244) - of "cong", "TildeFullEqual": result = Rune(0x02245) - of "simne": result = Rune(0x02246) - of "ncong", "NotTildeFullEqual": result = Rune(0x02247) + "nshortparallel": Rune(0x02226) + of "and", "wedge": Rune(0x02227) + of "or", "vee": Rune(0x02228) + of "cap": Rune(0x02229) + of "cup": Rune(0x0222A) + of "int", "Integral": Rune(0x0222B) + of "Int": Rune(0x0222C) + of "tint", "iiint": Rune(0x0222D) + of "conint", "oint", "ContourIntegral": Rune(0x0222E) + of "Conint", "DoubleContourIntegral": Rune(0x0222F) + of "Cconint": Rune(0x02230) + of "cwint": Rune(0x02231) + of "cwconint", "ClockwiseContourIntegral": Rune(0x02232) + of "awconint", "CounterClockwiseContourIntegral": Rune(0x02233) + of "there4", "therefore", "Therefore": Rune(0x02234) + of "becaus", "because", "Because": Rune(0x02235) + of "ratio": Rune(0x02236) + of "Colon", "Proportion": Rune(0x02237) + of "minusd", "dotminus": Rune(0x02238) + of "mDDot": Rune(0x0223A) + of "homtht": Rune(0x0223B) + of "sim", "Tilde", "thksim", "thicksim": Rune(0x0223C) + of "bsim", "backsim": Rune(0x0223D) + of "ac", "mstpos": Rune(0x0223E) + of "acd": Rune(0x0223F) + of "wreath", "VerticalTilde", "wr": Rune(0x02240) + of "nsim", "NotTilde": Rune(0x02241) + of "esim", "EqualTilde", "eqsim": Rune(0x02242) + of "sime", "TildeEqual", "simeq": Rune(0x02243) + of "nsime", "nsimeq", "NotTildeEqual": Rune(0x02244) + of "cong", "TildeFullEqual": Rune(0x02245) + of "simne": Rune(0x02246) + of "ncong", "NotTildeFullEqual": Rune(0x02247) of "asymp", "ap", "TildeTilde", "approx", "thkap", - "thickapprox": result = Rune(0x02248) - of "nap", "NotTildeTilde", "napprox": result = Rune(0x02249) - of "ape", "approxeq": result = Rune(0x0224A) - of "apid": result = Rune(0x0224B) - of "bcong", "backcong": result = Rune(0x0224C) - of "asympeq", "CupCap": result = Rune(0x0224D) - of "bump", "HumpDownHump", "Bumpeq": result = Rune(0x0224E) - of "bumpe", "HumpEqual", "bumpeq": result = Rune(0x0224F) - of "esdot", "DotEqual", "doteq": result = Rune(0x02250) - of "eDot", "doteqdot": result = Rune(0x02251) - of "efDot", "fallingdotseq": result = Rune(0x02252) - of "erDot", "risingdotseq": result = Rune(0x02253) - of "colone", "coloneq", "Assign": result = Rune(0x02254) - of "ecolon", "eqcolon": result = Rune(0x02255) - of "ecir", "eqcirc": result = Rune(0x02256) - of "cire", "circeq": result = Rune(0x02257) - of "wedgeq": result = Rune(0x02259) - of "veeeq": result = Rune(0x0225A) - of "trie", "triangleq": result = Rune(0x0225C) - of "equest", "questeq": result = Rune(0x0225F) - of "ne", "NotEqual": result = Rune(0x02260) - of "equiv", "Congruent": result = Rune(0x02261) - of "nequiv", "NotCongruent": result = Rune(0x02262) - of "le", "leq": result = Rune(0x02264) - of "ge", "GreaterEqual", "geq": result = Rune(0x02265) - of "lE", "LessFullEqual", "leqq": result = Rune(0x02266) - of "gE", "GreaterFullEqual", "geqq": result = Rune(0x02267) - of "lnE", "lneqq": result = Rune(0x02268) - of "gnE", "gneqq": result = Rune(0x02269) - of "Lt", "NestedLessLess", "ll": result = Rune(0x0226A) - of "Gt", "NestedGreaterGreater", "gg": result = Rune(0x0226B) - of "twixt", "between": result = Rune(0x0226C) - of "NotCupCap": result = Rune(0x0226D) - of "nlt", "NotLess", "nless": result = Rune(0x0226E) - of "ngt", "NotGreater", "ngtr": result = Rune(0x0226F) - of "nle", "NotLessEqual", "nleq": result = Rune(0x02270) - of "nge", "NotGreaterEqual", "ngeq": result = Rune(0x02271) - of "lsim", "LessTilde", "lesssim": result = Rune(0x02272) - of "gsim", "gtrsim", "GreaterTilde": result = Rune(0x02273) - of "nlsim", "NotLessTilde": result = Rune(0x02274) - of "ngsim", "NotGreaterTilde": result = Rune(0x02275) - of "lg", "lessgtr", "LessGreater": result = Rune(0x02276) - of "gl", "gtrless", "GreaterLess": result = Rune(0x02277) - of "ntlg", "NotLessGreater": result = Rune(0x02278) - of "ntgl", "NotGreaterLess": result = Rune(0x02279) - of "pr", "Precedes", "prec": result = Rune(0x0227A) - of "sc", "Succeeds", "succ": result = Rune(0x0227B) - of "prcue", "PrecedesSlantEqual", "preccurlyeq": result = Rune(0x0227C) - of "sccue", "SucceedsSlantEqual", "succcurlyeq": result = Rune(0x0227D) - of "prsim", "precsim", "PrecedesTilde": result = Rune(0x0227E) - of "scsim", "succsim", "SucceedsTilde": result = Rune(0x0227F) - of "npr", "nprec", "NotPrecedes": result = Rune(0x02280) - of "nsc", "nsucc", "NotSucceeds": result = Rune(0x02281) - of "sub", "subset": result = Rune(0x02282) - of "sup", "supset", "Superset": result = Rune(0x02283) - of "nsub": result = Rune(0x02284) - of "nsup": result = Rune(0x02285) - of "sube", "SubsetEqual", "subseteq": result = Rune(0x02286) - of "supe", "supseteq", "SupersetEqual": result = Rune(0x02287) - of "nsube", "nsubseteq", "NotSubsetEqual": result = Rune(0x02288) - of "nsupe", "nsupseteq", "NotSupersetEqual": result = Rune(0x02289) - of "subne", "subsetneq": result = Rune(0x0228A) - of "supne", "supsetneq": result = Rune(0x0228B) - of "cupdot": result = Rune(0x0228D) - of "uplus", "UnionPlus": result = Rune(0x0228E) - of "sqsub", "SquareSubset", "sqsubset": result = Rune(0x0228F) - of "sqsup", "SquareSuperset", "sqsupset": result = Rune(0x02290) - of "sqsube", "SquareSubsetEqual", "sqsubseteq": result = Rune(0x02291) - of "sqsupe", "SquareSupersetEqual", "sqsupseteq": result = Rune(0x02292) - of "sqcap", "SquareIntersection": result = Rune(0x02293) - of "sqcup", "SquareUnion": result = Rune(0x02294) - of "oplus", "CirclePlus": result = Rune(0x02295) - of "ominus", "CircleMinus": result = Rune(0x02296) - of "otimes", "CircleTimes": result = Rune(0x02297) - of "osol": result = Rune(0x02298) - of "odot", "CircleDot": result = Rune(0x02299) - of "ocir", "circledcirc": result = Rune(0x0229A) - of "oast", "circledast": result = Rune(0x0229B) - of "odash", "circleddash": result = Rune(0x0229D) - of "plusb", "boxplus": result = Rune(0x0229E) - of "minusb", "boxminus": result = Rune(0x0229F) - of "timesb", "boxtimes": result = Rune(0x022A0) - of "sdotb", "dotsquare": result = Rune(0x022A1) - of "vdash", "RightTee": result = Rune(0x022A2) - of "dashv", "LeftTee": result = Rune(0x022A3) - of "top", "DownTee": result = Rune(0x022A4) - of "bottom", "bot", "perp", "UpTee": result = Rune(0x022A5) - of "models": result = Rune(0x022A7) - of "vDash", "DoubleRightTee": result = Rune(0x022A8) - of "Vdash": result = Rune(0x022A9) - of "Vvdash": result = Rune(0x022AA) - of "VDash": result = Rune(0x022AB) - of "nvdash": result = Rune(0x022AC) - of "nvDash": result = Rune(0x022AD) - of "nVdash": result = Rune(0x022AE) - of "nVDash": result = Rune(0x022AF) - of "prurel": result = Rune(0x022B0) - of "vltri", "vartriangleleft", "LeftTriangle": result = Rune(0x022B2) - of "vrtri", "vartriangleright", "RightTriangle": result = Rune(0x022B3) - of "ltrie", "trianglelefteq", "LeftTriangleEqual": result = Rune(0x022B4) - of "rtrie", "trianglerighteq", "RightTriangleEqual": result = Rune(0x022B5) - of "origof": result = Rune(0x022B6) - of "imof": result = Rune(0x022B7) - of "mumap", "multimap": result = Rune(0x022B8) - of "hercon": result = Rune(0x022B9) - of "intcal", "intercal": result = Rune(0x022BA) - of "veebar": result = Rune(0x022BB) - of "barvee": result = Rune(0x022BD) - of "angrtvb": result = Rune(0x022BE) - of "lrtri": result = Rune(0x022BF) - of "xwedge", "Wedge", "bigwedge": result = Rune(0x022C0) - of "xvee", "Vee", "bigvee": result = Rune(0x022C1) - of "xcap", "Intersection", "bigcap": result = Rune(0x022C2) - of "xcup", "Union", "bigcup": result = Rune(0x022C3) - of "diam", "diamond", "Diamond": result = Rune(0x022C4) - of "sdot": result = Rune(0x022C5) - of "sstarf", "Star": result = Rune(0x022C6) - of "divonx", "divideontimes": result = Rune(0x022C7) - of "bowtie": result = Rune(0x022C8) - of "ltimes": result = Rune(0x022C9) - of "rtimes": result = Rune(0x022CA) - of "lthree", "leftthreetimes": result = Rune(0x022CB) - of "rthree", "rightthreetimes": result = Rune(0x022CC) - of "bsime", "backsimeq": result = Rune(0x022CD) - of "cuvee", "curlyvee": result = Rune(0x022CE) - of "cuwed", "curlywedge": result = Rune(0x022CF) - of "Sub", "Subset": result = Rune(0x022D0) - of "Sup", "Supset": result = Rune(0x022D1) - of "Cap": result = Rune(0x022D2) - of "Cup": result = Rune(0x022D3) - of "fork", "pitchfork": result = Rune(0x022D4) - of "epar": result = Rune(0x022D5) - of "ltdot", "lessdot": result = Rune(0x022D6) - of "gtdot", "gtrdot": result = Rune(0x022D7) - of "Ll": result = Rune(0x022D8) - of "Gg", "ggg": result = Rune(0x022D9) - of "leg", "LessEqualGreater", "lesseqgtr": result = Rune(0x022DA) - of "gel", "gtreqless", "GreaterEqualLess": result = Rune(0x022DB) - of "cuepr", "curlyeqprec": result = Rune(0x022DE) - of "cuesc", "curlyeqsucc": result = Rune(0x022DF) - of "nprcue", "NotPrecedesSlantEqual": result = Rune(0x022E0) - of "nsccue", "NotSucceedsSlantEqual": result = Rune(0x022E1) - of "nsqsube", "NotSquareSubsetEqual": result = Rune(0x022E2) - of "nsqsupe", "NotSquareSupersetEqual": result = Rune(0x022E3) - of "lnsim": result = Rune(0x022E6) - of "gnsim": result = Rune(0x022E7) - of "prnsim", "precnsim": result = Rune(0x022E8) - of "scnsim", "succnsim": result = Rune(0x022E9) - of "nltri", "ntriangleleft", "NotLeftTriangle": result = Rune(0x022EA) - of "nrtri", "ntriangleright", "NotRightTriangle": result = Rune(0x022EB) + "thickapprox": Rune(0x02248) + of "nap", "NotTildeTilde", "napprox": Rune(0x02249) + of "ape", "approxeq": Rune(0x0224A) + of "apid": Rune(0x0224B) + of "bcong", "backcong": Rune(0x0224C) + of "asympeq", "CupCap": Rune(0x0224D) + of "bump", "HumpDownHump", "Bumpeq": Rune(0x0224E) + of "bumpe", "HumpEqual", "bumpeq": Rune(0x0224F) + of "esdot", "DotEqual", "doteq": Rune(0x02250) + of "eDot", "doteqdot": Rune(0x02251) + of "efDot", "fallingdotseq": Rune(0x02252) + of "erDot", "risingdotseq": Rune(0x02253) + of "colone", "coloneq", "Assign": Rune(0x02254) + of "ecolon", "eqcolon": Rune(0x02255) + of "ecir", "eqcirc": Rune(0x02256) + of "cire", "circeq": Rune(0x02257) + of "wedgeq": Rune(0x02259) + of "veeeq": Rune(0x0225A) + of "trie", "triangleq": Rune(0x0225C) + of "equest", "questeq": Rune(0x0225F) + of "ne", "NotEqual": Rune(0x02260) + of "equiv", "Congruent": Rune(0x02261) + of "nequiv", "NotCongruent": Rune(0x02262) + of "le", "leq": Rune(0x02264) + of "ge", "GreaterEqual", "geq": Rune(0x02265) + of "lE", "LessFullEqual", "leqq": Rune(0x02266) + of "gE", "GreaterFullEqual", "geqq": Rune(0x02267) + of "lnE", "lneqq": Rune(0x02268) + of "gnE", "gneqq": Rune(0x02269) + of "Lt", "NestedLessLess", "ll": Rune(0x0226A) + of "Gt", "NestedGreaterGreater", "gg": Rune(0x0226B) + of "twixt", "between": Rune(0x0226C) + of "NotCupCap": Rune(0x0226D) + of "nlt", "NotLess", "nless": Rune(0x0226E) + of "ngt", "NotGreater", "ngtr": Rune(0x0226F) + of "nle", "NotLessEqual", "nleq": Rune(0x02270) + of "nge", "NotGreaterEqual", "ngeq": Rune(0x02271) + of "lsim", "LessTilde", "lesssim": Rune(0x02272) + of "gsim", "gtrsim", "GreaterTilde": Rune(0x02273) + of "nlsim", "NotLessTilde": Rune(0x02274) + of "ngsim", "NotGreaterTilde": Rune(0x02275) + of "lg", "lessgtr", "LessGreater": Rune(0x02276) + of "gl", "gtrless", "GreaterLess": Rune(0x02277) + of "ntlg", "NotLessGreater": Rune(0x02278) + of "ntgl", "NotGreaterLess": Rune(0x02279) + of "pr", "Precedes", "prec": Rune(0x0227A) + of "sc", "Succeeds", "succ": Rune(0x0227B) + of "prcue", "PrecedesSlantEqual", "preccurlyeq": Rune(0x0227C) + of "sccue", "SucceedsSlantEqual", "succcurlyeq": Rune(0x0227D) + of "prsim", "precsim", "PrecedesTilde": Rune(0x0227E) + of "scsim", "succsim", "SucceedsTilde": Rune(0x0227F) + of "npr", "nprec", "NotPrecedes": Rune(0x02280) + of "nsc", "nsucc", "NotSucceeds": Rune(0x02281) + of "sub", "subset": Rune(0x02282) + of "sup", "supset", "Superset": Rune(0x02283) + of "nsub": Rune(0x02284) + of "nsup": Rune(0x02285) + of "sube", "SubsetEqual", "subseteq": Rune(0x02286) + of "supe", "supseteq", "SupersetEqual": Rune(0x02287) + of "nsube", "nsubseteq", "NotSubsetEqual": Rune(0x02288) + of "nsupe", "nsupseteq", "NotSupersetEqual": Rune(0x02289) + of "subne", "subsetneq": Rune(0x0228A) + of "supne", "supsetneq": Rune(0x0228B) + of "cupdot": Rune(0x0228D) + of "uplus", "UnionPlus": Rune(0x0228E) + of "sqsub", "SquareSubset", "sqsubset": Rune(0x0228F) + of "sqsup", "SquareSuperset", "sqsupset": Rune(0x02290) + of "sqsube", "SquareSubsetEqual", "sqsubseteq": Rune(0x02291) + of "sqsupe", "SquareSupersetEqual", "sqsupseteq": Rune(0x02292) + of "sqcap", "SquareIntersection": Rune(0x02293) + of "sqcup", "SquareUnion": Rune(0x02294) + of "oplus", "CirclePlus": Rune(0x02295) + of "ominus", "CircleMinus": Rune(0x02296) + of "otimes", "CircleTimes": Rune(0x02297) + of "osol": Rune(0x02298) + of "odot", "CircleDot": Rune(0x02299) + of "ocir", "circledcirc": Rune(0x0229A) + of "oast", "circledast": Rune(0x0229B) + of "odash", "circleddash": Rune(0x0229D) + of "plusb", "boxplus": Rune(0x0229E) + of "minusb", "boxminus": Rune(0x0229F) + of "timesb", "boxtimes": Rune(0x022A0) + of "sdotb", "dotsquare": Rune(0x022A1) + of "vdash", "RightTee": Rune(0x022A2) + of "dashv", "LeftTee": Rune(0x022A3) + of "top", "DownTee": Rune(0x022A4) + of "bottom", "bot", "perp", "UpTee": Rune(0x022A5) + of "models": Rune(0x022A7) + of "vDash", "DoubleRightTee": Rune(0x022A8) + of "Vdash": Rune(0x022A9) + of "Vvdash": Rune(0x022AA) + of "VDash": Rune(0x022AB) + of "nvdash": Rune(0x022AC) + of "nvDash": Rune(0x022AD) + of "nVdash": Rune(0x022AE) + of "nVDash": Rune(0x022AF) + of "prurel": Rune(0x022B0) + of "vltri", "vartriangleleft", "LeftTriangle": Rune(0x022B2) + of "vrtri", "vartriangleright", "RightTriangle": Rune(0x022B3) + of "ltrie", "trianglelefteq", "LeftTriangleEqual": Rune(0x022B4) + of "rtrie", "trianglerighteq", "RightTriangleEqual": Rune(0x022B5) + of "origof": Rune(0x022B6) + of "imof": Rune(0x022B7) + of "mumap", "multimap": Rune(0x022B8) + of "hercon": Rune(0x022B9) + of "intcal", "intercal": Rune(0x022BA) + of "veebar": Rune(0x022BB) + of "barvee": Rune(0x022BD) + of "angrtvb": Rune(0x022BE) + of "lrtri": Rune(0x022BF) + of "xwedge", "Wedge", "bigwedge": Rune(0x022C0) + of "xvee", "Vee", "bigvee": Rune(0x022C1) + of "xcap", "Intersection", "bigcap": Rune(0x022C2) + of "xcup", "Union", "bigcup": Rune(0x022C3) + of "diam", "diamond", "Diamond": Rune(0x022C4) + of "sdot": Rune(0x022C5) + of "sstarf", "Star": Rune(0x022C6) + of "divonx", "divideontimes": Rune(0x022C7) + of "bowtie": Rune(0x022C8) + of "ltimes": Rune(0x022C9) + of "rtimes": Rune(0x022CA) + of "lthree", "leftthreetimes": Rune(0x022CB) + of "rthree", "rightthreetimes": Rune(0x022CC) + of "bsime", "backsimeq": Rune(0x022CD) + of "cuvee", "curlyvee": Rune(0x022CE) + of "cuwed", "curlywedge": Rune(0x022CF) + of "Sub", "Subset": Rune(0x022D0) + of "Sup", "Supset": Rune(0x022D1) + of "Cap": Rune(0x022D2) + of "Cup": Rune(0x022D3) + of "fork", "pitchfork": Rune(0x022D4) + of "epar": Rune(0x022D5) + of "ltdot", "lessdot": Rune(0x022D6) + of "gtdot", "gtrdot": Rune(0x022D7) + of "Ll": Rune(0x022D8) + of "Gg", "ggg": Rune(0x022D9) + of "leg", "LessEqualGreater", "lesseqgtr": Rune(0x022DA) + of "gel", "gtreqless", "GreaterEqualLess": Rune(0x022DB) + of "cuepr", "curlyeqprec": Rune(0x022DE) + of "cuesc", "curlyeqsucc": Rune(0x022DF) + of "nprcue", "NotPrecedesSlantEqual": Rune(0x022E0) + of "nsccue", "NotSucceedsSlantEqual": Rune(0x022E1) + of "nsqsube", "NotSquareSubsetEqual": Rune(0x022E2) + of "nsqsupe", "NotSquareSupersetEqual": Rune(0x022E3) + of "lnsim": Rune(0x022E6) + of "gnsim": Rune(0x022E7) + of "prnsim", "precnsim": Rune(0x022E8) + of "scnsim", "succnsim": Rune(0x022E9) + of "nltri", "ntriangleleft", "NotLeftTriangle": Rune(0x022EA) + of "nrtri", "ntriangleright", "NotRightTriangle": Rune(0x022EB) of "nltrie", "ntrianglelefteq", - "NotLeftTriangleEqual": result = Rune(0x022EC) + "NotLeftTriangleEqual": Rune(0x022EC) of "nrtrie", "ntrianglerighteq", - "NotRightTriangleEqual": result = Rune(0x022ED) - of "vellip": result = Rune(0x022EE) - of "ctdot": result = Rune(0x022EF) - of "utdot": result = Rune(0x022F0) - of "dtdot": result = Rune(0x022F1) - of "disin": result = Rune(0x022F2) - of "isinsv": result = Rune(0x022F3) - of "isins": result = Rune(0x022F4) - of "isindot": result = Rune(0x022F5) - of "notinvc": result = Rune(0x022F6) - of "notinvb": result = Rune(0x022F7) - of "isinE": result = Rune(0x022F9) - of "nisd": result = Rune(0x022FA) - of "xnis": result = Rune(0x022FB) - of "nis": result = Rune(0x022FC) - of "notnivc": result = Rune(0x022FD) - of "notnivb": result = Rune(0x022FE) - of "barwed", "barwedge": result = Rune(0x02305) - of "Barwed", "doublebarwedge": result = Rune(0x02306) - of "lceil", "LeftCeiling": result = Rune(0x02308) - of "rceil", "RightCeiling": result = Rune(0x02309) - of "lfloor", "LeftFloor": result = Rune(0x0230A) - of "rfloor", "RightFloor": result = Rune(0x0230B) - of "drcrop": result = Rune(0x0230C) - of "dlcrop": result = Rune(0x0230D) - of "urcrop": result = Rune(0x0230E) - of "ulcrop": result = Rune(0x0230F) - of "bnot": result = Rune(0x02310) - of "profline": result = Rune(0x02312) - of "profsurf": result = Rune(0x02313) - of "telrec": result = Rune(0x02315) - of "target": result = Rune(0x02316) - of "ulcorn", "ulcorner": result = Rune(0x0231C) - of "urcorn", "urcorner": result = Rune(0x0231D) - of "dlcorn", "llcorner": result = Rune(0x0231E) - of "drcorn", "lrcorner": result = Rune(0x0231F) - of "frown", "sfrown": result = Rune(0x02322) - of "smile", "ssmile": result = Rune(0x02323) - of "cylcty": result = Rune(0x0232D) - of "profalar": result = Rune(0x0232E) - of "topbot": result = Rune(0x02336) - of "ovbar": result = Rune(0x0233D) - of "solbar": result = Rune(0x0233F) - of "angzarr": result = Rune(0x0237C) - of "lmoust", "lmoustache": result = Rune(0x023B0) - of "rmoust", "rmoustache": result = Rune(0x023B1) - of "tbrk", "OverBracket": result = Rune(0x023B4) - of "bbrk", "UnderBracket": result = Rune(0x023B5) - of "bbrktbrk": result = Rune(0x023B6) - of "OverParenthesis": result = Rune(0x023DC) - of "UnderParenthesis": result = Rune(0x023DD) - of "OverBrace": result = Rune(0x023DE) - of "UnderBrace": result = Rune(0x023DF) - of "trpezium": result = Rune(0x023E2) - of "elinters": result = Rune(0x023E7) - of "blank": result = Rune(0x02423) - of "oS", "circledS": result = Rune(0x024C8) - of "boxh", "HorizontalLine": result = Rune(0x02500) - of "boxv": result = Rune(0x02502) - of "boxdr": result = Rune(0x0250C) - of "boxdl": result = Rune(0x02510) - of "boxur": result = Rune(0x02514) - of "boxul": result = Rune(0x02518) - of "boxvr": result = Rune(0x0251C) - of "boxvl": result = Rune(0x02524) - of "boxhd": result = Rune(0x0252C) - of "boxhu": result = Rune(0x02534) - of "boxvh": result = Rune(0x0253C) - of "boxH": result = Rune(0x02550) - of "boxV": result = Rune(0x02551) - of "boxdR": result = Rune(0x02552) - of "boxDr": result = Rune(0x02553) - of "boxDR": result = Rune(0x02554) - of "boxdL": result = Rune(0x02555) - of "boxDl": result = Rune(0x02556) - of "boxDL": result = Rune(0x02557) - of "boxuR": result = Rune(0x02558) - of "boxUr": result = Rune(0x02559) - of "boxUR": result = Rune(0x0255A) - of "boxuL": result = Rune(0x0255B) - of "boxUl": result = Rune(0x0255C) - of "boxUL": result = Rune(0x0255D) - of "boxvR": result = Rune(0x0255E) - of "boxVr": result = Rune(0x0255F) - of "boxVR": result = Rune(0x02560) - of "boxvL": result = Rune(0x02561) - of "boxVl": result = Rune(0x02562) - of "boxVL": result = Rune(0x02563) - of "boxHd": result = Rune(0x02564) - of "boxhD": result = Rune(0x02565) - of "boxHD": result = Rune(0x02566) - of "boxHu": result = Rune(0x02567) - of "boxhU": result = Rune(0x02568) - of "boxHU": result = Rune(0x02569) - of "boxvH": result = Rune(0x0256A) - of "boxVh": result = Rune(0x0256B) - of "boxVH": result = Rune(0x0256C) - of "uhblk": result = Rune(0x02580) - of "lhblk": result = Rune(0x02584) - of "block": result = Rune(0x02588) - of "blk14": result = Rune(0x02591) - of "blk12": result = Rune(0x02592) - of "blk34": result = Rune(0x02593) - of "squ", "square", "Square": result = Rune(0x025A1) + "NotRightTriangleEqual": Rune(0x022ED) + of "vellip": Rune(0x022EE) + of "ctdot": Rune(0x022EF) + of "utdot": Rune(0x022F0) + of "dtdot": Rune(0x022F1) + of "disin": Rune(0x022F2) + of "isinsv": Rune(0x022F3) + of "isins": Rune(0x022F4) + of "isindot": Rune(0x022F5) + of "notinvc": Rune(0x022F6) + of "notinvb": Rune(0x022F7) + of "isinE": Rune(0x022F9) + of "nisd": Rune(0x022FA) + of "xnis": Rune(0x022FB) + of "nis": Rune(0x022FC) + of "notnivc": Rune(0x022FD) + of "notnivb": Rune(0x022FE) + of "barwed", "barwedge": Rune(0x02305) + of "Barwed", "doublebarwedge": Rune(0x02306) + of "lceil", "LeftCeiling": Rune(0x02308) + of "rceil", "RightCeiling": Rune(0x02309) + of "lfloor", "LeftFloor": Rune(0x0230A) + of "rfloor", "RightFloor": Rune(0x0230B) + of "drcrop": Rune(0x0230C) + of "dlcrop": Rune(0x0230D) + of "urcrop": Rune(0x0230E) + of "ulcrop": Rune(0x0230F) + of "bnot": Rune(0x02310) + of "profline": Rune(0x02312) + of "profsurf": Rune(0x02313) + of "telrec": Rune(0x02315) + of "target": Rune(0x02316) + of "ulcorn", "ulcorner": Rune(0x0231C) + of "urcorn", "urcorner": Rune(0x0231D) + of "dlcorn", "llcorner": Rune(0x0231E) + of "drcorn", "lrcorner": Rune(0x0231F) + of "frown", "sfrown": Rune(0x02322) + of "smile", "ssmile": Rune(0x02323) + of "cylcty": Rune(0x0232D) + of "profalar": Rune(0x0232E) + of "topbot": Rune(0x02336) + of "ovbar": Rune(0x0233D) + of "solbar": Rune(0x0233F) + of "angzarr": Rune(0x0237C) + of "lmoust", "lmoustache": Rune(0x023B0) + of "rmoust", "rmoustache": Rune(0x023B1) + of "tbrk", "OverBracket": Rune(0x023B4) + of "bbrk", "UnderBracket": Rune(0x023B5) + of "bbrktbrk": Rune(0x023B6) + of "OverParenthesis": Rune(0x023DC) + of "UnderParenthesis": Rune(0x023DD) + of "OverBrace": Rune(0x023DE) + of "UnderBrace": Rune(0x023DF) + of "trpezium": Rune(0x023E2) + of "elinters": Rune(0x023E7) + of "blank": Rune(0x02423) + of "oS", "circledS": Rune(0x024C8) + of "boxh", "HorizontalLine": Rune(0x02500) + of "boxv": Rune(0x02502) + of "boxdr": Rune(0x0250C) + of "boxdl": Rune(0x02510) + of "boxur": Rune(0x02514) + of "boxul": Rune(0x02518) + of "boxvr": Rune(0x0251C) + of "boxvl": Rune(0x02524) + of "boxhd": Rune(0x0252C) + of "boxhu": Rune(0x02534) + of "boxvh": Rune(0x0253C) + of "boxH": Rune(0x02550) + of "boxV": Rune(0x02551) + of "boxdR": Rune(0x02552) + of "boxDr": Rune(0x02553) + of "boxDR": Rune(0x02554) + of "boxdL": Rune(0x02555) + of "boxDl": Rune(0x02556) + of "boxDL": Rune(0x02557) + of "boxuR": Rune(0x02558) + of "boxUr": Rune(0x02559) + of "boxUR": Rune(0x0255A) + of "boxuL": Rune(0x0255B) + of "boxUl": Rune(0x0255C) + of "boxUL": Rune(0x0255D) + of "boxvR": Rune(0x0255E) + of "boxVr": Rune(0x0255F) + of "boxVR": Rune(0x02560) + of "boxvL": Rune(0x02561) + of "boxVl": Rune(0x02562) + of "boxVL": Rune(0x02563) + of "boxHd": Rune(0x02564) + of "boxhD": Rune(0x02565) + of "boxHD": Rune(0x02566) + of "boxHu": Rune(0x02567) + of "boxhU": Rune(0x02568) + of "boxHU": Rune(0x02569) + of "boxvH": Rune(0x0256A) + of "boxVh": Rune(0x0256B) + of "boxVH": Rune(0x0256C) + of "uhblk": Rune(0x02580) + of "lhblk": Rune(0x02584) + of "block": Rune(0x02588) + of "blk14": Rune(0x02591) + of "blk12": Rune(0x02592) + of "blk34": Rune(0x02593) + of "squ", "square", "Square": Rune(0x025A1) of "squf", "squarf", "blacksquare", - "FilledVerySmallSquare": result = Rune(0x025AA) - of "EmptyVerySmallSquare": result = Rune(0x025AB) - of "rect": result = Rune(0x025AD) - of "marker": result = Rune(0x025AE) - of "fltns": result = Rune(0x025B1) - of "xutri", "bigtriangleup": result = Rune(0x025B3) - of "utrif", "blacktriangle": result = Rune(0x025B4) - of "utri", "triangle": result = Rune(0x025B5) - of "rtrif", "blacktriangleright": result = Rune(0x025B8) - of "rtri", "triangleright": result = Rune(0x025B9) - of "xdtri", "bigtriangledown": result = Rune(0x025BD) - of "dtrif", "blacktriangledown": result = Rune(0x025BE) - of "dtri", "triangledown": result = Rune(0x025BF) - of "ltrif", "blacktriangleleft": result = Rune(0x025C2) - of "ltri", "triangleleft": result = Rune(0x025C3) - of "loz", "lozenge": result = Rune(0x025CA) - of "cir": result = Rune(0x025CB) - of "tridot": result = Rune(0x025EC) - of "xcirc", "bigcirc": result = Rune(0x025EF) - of "ultri": result = Rune(0x025F8) - of "urtri": result = Rune(0x025F9) - of "lltri": result = Rune(0x025FA) - of "EmptySmallSquare": result = Rune(0x025FB) - of "FilledSmallSquare": result = Rune(0x025FC) - of "starf", "bigstar": result = Rune(0x02605) - of "star": result = Rune(0x02606) - of "phone": result = Rune(0x0260E) - of "female": result = Rune(0x02640) - of "male": result = Rune(0x02642) - of "spades", "spadesuit": result = Rune(0x02660) - of "clubs", "clubsuit": result = Rune(0x02663) - of "hearts", "heartsuit": result = Rune(0x02665) - of "diams", "diamondsuit": result = Rune(0x02666) - of "sung": result = Rune(0x0266A) - of "flat": result = Rune(0x0266D) - of "natur", "natural": result = Rune(0x0266E) - of "sharp": result = Rune(0x0266F) - of "check", "checkmark": result = Rune(0x02713) - of "cross": result = Rune(0x02717) - of "malt", "maltese": result = Rune(0x02720) - of "sext": result = Rune(0x02736) - of "VerticalSeparator": result = Rune(0x02758) - of "lbbrk": result = Rune(0x02772) - of "rbbrk": result = Rune(0x02773) - of "lobrk", "LeftDoubleBracket": result = Rune(0x027E6) - of "robrk", "RightDoubleBracket": result = Rune(0x027E7) - of "lang", "LeftAngleBracket", "langle": result = Rune(0x027E8) - of "rang", "RightAngleBracket", "rangle": result = Rune(0x027E9) - of "Lang": result = Rune(0x027EA) - of "Rang": result = Rune(0x027EB) - of "loang": result = Rune(0x027EC) - of "roang": result = Rune(0x027ED) - of "xlarr", "longleftarrow", "LongLeftArrow": result = Rune(0x027F5) - of "xrarr", "longrightarrow", "LongRightArrow": result = Rune(0x027F6) + "FilledVerySmallSquare": Rune(0x025AA) + of "EmptyVerySmallSquare": Rune(0x025AB) + of "rect": Rune(0x025AD) + of "marker": Rune(0x025AE) + of "fltns": Rune(0x025B1) + of "xutri", "bigtriangleup": Rune(0x025B3) + of "utrif", "blacktriangle": Rune(0x025B4) + of "utri", "triangle": Rune(0x025B5) + of "rtrif", "blacktriangleright": Rune(0x025B8) + of "rtri", "triangleright": Rune(0x025B9) + of "xdtri", "bigtriangledown": Rune(0x025BD) + of "dtrif", "blacktriangledown": Rune(0x025BE) + of "dtri", "triangledown": Rune(0x025BF) + of "ltrif", "blacktriangleleft": Rune(0x025C2) + of "ltri", "triangleleft": Rune(0x025C3) + of "loz", "lozenge": Rune(0x025CA) + of "cir": Rune(0x025CB) + of "tridot": Rune(0x025EC) + of "xcirc", "bigcirc": Rune(0x025EF) + of "ultri": Rune(0x025F8) + of "urtri": Rune(0x025F9) + of "lltri": Rune(0x025FA) + of "EmptySmallSquare": Rune(0x025FB) + of "FilledSmallSquare": Rune(0x025FC) + of "starf", "bigstar": Rune(0x02605) + of "star": Rune(0x02606) + of "phone": Rune(0x0260E) + of "female": Rune(0x02640) + of "male": Rune(0x02642) + of "spades", "spadesuit": Rune(0x02660) + of "clubs", "clubsuit": Rune(0x02663) + of "hearts", "heartsuit": Rune(0x02665) + of "diams", "diamondsuit": Rune(0x02666) + of "sung": Rune(0x0266A) + of "flat": Rune(0x0266D) + of "natur", "natural": Rune(0x0266E) + of "sharp": Rune(0x0266F) + of "check", "checkmark": Rune(0x02713) + of "cross": Rune(0x02717) + of "malt", "maltese": Rune(0x02720) + of "sext": Rune(0x02736) + of "VerticalSeparator": Rune(0x02758) + of "lbbrk": Rune(0x02772) + of "rbbrk": Rune(0x02773) + of "lobrk", "LeftDoubleBracket": Rune(0x027E6) + of "robrk", "RightDoubleBracket": Rune(0x027E7) + of "lang", "LeftAngleBracket", "langle": Rune(0x027E8) + of "rang", "RightAngleBracket", "rangle": Rune(0x027E9) + of "Lang": Rune(0x027EA) + of "Rang": Rune(0x027EB) + of "loang": Rune(0x027EC) + of "roang": Rune(0x027ED) + of "xlarr", "longleftarrow", "LongLeftArrow": Rune(0x027F5) + of "xrarr", "longrightarrow", "LongRightArrow": Rune(0x027F6) of "xharr", "longleftrightarrow", - "LongLeftRightArrow": result = Rune(0x027F7) - of "xlArr", "Longleftarrow", "DoubleLongLeftArrow": result = Rune(0x027F8) - of "xrArr", "Longrightarrow", "DoubleLongRightArrow": result = Rune(0x027F9) + "LongLeftRightArrow": Rune(0x027F7) + of "xlArr", "Longleftarrow", "DoubleLongLeftArrow": Rune(0x027F8) + of "xrArr", "Longrightarrow", "DoubleLongRightArrow": Rune(0x027F9) of "xhArr", "Longleftrightarrow", - "DoubleLongLeftRightArrow": result = Rune(0x027FA) - of "xmap", "longmapsto": result = Rune(0x027FC) - of "dzigrarr": result = Rune(0x027FF) - of "nvlArr": result = Rune(0x02902) - of "nvrArr": result = Rune(0x02903) - of "nvHarr": result = Rune(0x02904) - of "Map": result = Rune(0x02905) - of "lbarr": result = Rune(0x0290C) - of "rbarr", "bkarow": result = Rune(0x0290D) - of "lBarr": result = Rune(0x0290E) - of "rBarr", "dbkarow": result = Rune(0x0290F) - of "RBarr", "drbkarow": result = Rune(0x02910) - of "DDotrahd": result = Rune(0x02911) - of "UpArrowBar": result = Rune(0x02912) - of "DownArrowBar": result = Rune(0x02913) - of "Rarrtl": result = Rune(0x02916) - of "latail": result = Rune(0x02919) - of "ratail": result = Rune(0x0291A) - of "lAtail": result = Rune(0x0291B) - of "rAtail": result = Rune(0x0291C) - of "larrfs": result = Rune(0x0291D) - of "rarrfs": result = Rune(0x0291E) - of "larrbfs": result = Rune(0x0291F) - of "rarrbfs": result = Rune(0x02920) - of "nwarhk": result = Rune(0x02923) - of "nearhk": result = Rune(0x02924) - of "searhk", "hksearow": result = Rune(0x02925) - of "swarhk", "hkswarow": result = Rune(0x02926) - of "nwnear": result = Rune(0x02927) - of "nesear", "toea": result = Rune(0x02928) - of "seswar", "tosa": result = Rune(0x02929) - of "swnwar": result = Rune(0x0292A) - of "rarrc": result = Rune(0x02933) - of "cudarrr": result = Rune(0x02935) - of "ldca": result = Rune(0x02936) - of "rdca": result = Rune(0x02937) - of "cudarrl": result = Rune(0x02938) - of "larrpl": result = Rune(0x02939) - of "curarrm": result = Rune(0x0293C) - of "cularrp": result = Rune(0x0293D) - of "rarrpl": result = Rune(0x02945) - of "harrcir": result = Rune(0x02948) - of "Uarrocir": result = Rune(0x02949) - of "lurdshar": result = Rune(0x0294A) - of "ldrushar": result = Rune(0x0294B) - of "LeftRightVector": result = Rune(0x0294E) - of "RightUpDownVector": result = Rune(0x0294F) - of "DownLeftRightVector": result = Rune(0x02950) - of "LeftUpDownVector": result = Rune(0x02951) - of "LeftVectorBar": result = Rune(0x02952) - of "RightVectorBar": result = Rune(0x02953) - of "RightUpVectorBar": result = Rune(0x02954) - of "RightDownVectorBar": result = Rune(0x02955) - of "DownLeftVectorBar": result = Rune(0x02956) - of "DownRightVectorBar": result = Rune(0x02957) - of "LeftUpVectorBar": result = Rune(0x02958) - of "LeftDownVectorBar": result = Rune(0x02959) - of "LeftTeeVector": result = Rune(0x0295A) - of "RightTeeVector": result = Rune(0x0295B) - of "RightUpTeeVector": result = Rune(0x0295C) - of "RightDownTeeVector": result = Rune(0x0295D) - of "DownLeftTeeVector": result = Rune(0x0295E) - of "DownRightTeeVector": result = Rune(0x0295F) - of "LeftUpTeeVector": result = Rune(0x02960) - of "LeftDownTeeVector": result = Rune(0x02961) - of "lHar": result = Rune(0x02962) - of "uHar": result = Rune(0x02963) - of "rHar": result = Rune(0x02964) - of "dHar": result = Rune(0x02965) - of "luruhar": result = Rune(0x02966) - of "ldrdhar": result = Rune(0x02967) - of "ruluhar": result = Rune(0x02968) - of "rdldhar": result = Rune(0x02969) - of "lharul": result = Rune(0x0296A) - of "llhard": result = Rune(0x0296B) - of "rharul": result = Rune(0x0296C) - of "lrhard": result = Rune(0x0296D) - of "udhar", "UpEquilibrium": result = Rune(0x0296E) - of "duhar", "ReverseUpEquilibrium": result = Rune(0x0296F) - of "RoundImplies": result = Rune(0x02970) - of "erarr": result = Rune(0x02971) - of "simrarr": result = Rune(0x02972) - of "larrsim": result = Rune(0x02973) - of "rarrsim": result = Rune(0x02974) - of "rarrap": result = Rune(0x02975) - of "ltlarr": result = Rune(0x02976) - of "gtrarr": result = Rune(0x02978) - of "subrarr": result = Rune(0x02979) - of "suplarr": result = Rune(0x0297B) - of "lfisht": result = Rune(0x0297C) - of "rfisht": result = Rune(0x0297D) - of "ufisht": result = Rune(0x0297E) - of "dfisht": result = Rune(0x0297F) - of "lopar": result = Rune(0x02985) - of "ropar": result = Rune(0x02986) - of "lbrke": result = Rune(0x0298B) - of "rbrke": result = Rune(0x0298C) - of "lbrkslu": result = Rune(0x0298D) - of "rbrksld": result = Rune(0x0298E) - of "lbrksld": result = Rune(0x0298F) - of "rbrkslu": result = Rune(0x02990) - of "langd": result = Rune(0x02991) - of "rangd": result = Rune(0x02992) - of "lparlt": result = Rune(0x02993) - of "rpargt": result = Rune(0x02994) - of "gtlPar": result = Rune(0x02995) - of "ltrPar": result = Rune(0x02996) - of "vzigzag": result = Rune(0x0299A) - of "vangrt": result = Rune(0x0299C) - of "angrtvbd": result = Rune(0x0299D) - of "ange": result = Rune(0x029A4) - of "range": result = Rune(0x029A5) - of "dwangle": result = Rune(0x029A6) - of "uwangle": result = Rune(0x029A7) - of "angmsdaa": result = Rune(0x029A8) - of "angmsdab": result = Rune(0x029A9) - of "angmsdac": result = Rune(0x029AA) - of "angmsdad": result = Rune(0x029AB) - of "angmsdae": result = Rune(0x029AC) - of "angmsdaf": result = Rune(0x029AD) - of "angmsdag": result = Rune(0x029AE) - of "angmsdah": result = Rune(0x029AF) - of "bemptyv": result = Rune(0x029B0) - of "demptyv": result = Rune(0x029B1) - of "cemptyv": result = Rune(0x029B2) - of "raemptyv": result = Rune(0x029B3) - of "laemptyv": result = Rune(0x029B4) - of "ohbar": result = Rune(0x029B5) - of "omid": result = Rune(0x029B6) - of "opar": result = Rune(0x029B7) - of "operp": result = Rune(0x029B9) - of "olcross": result = Rune(0x029BB) - of "odsold": result = Rune(0x029BC) - of "olcir": result = Rune(0x029BE) - of "ofcir": result = Rune(0x029BF) - of "olt": result = Rune(0x029C0) - of "ogt": result = Rune(0x029C1) - of "cirscir": result = Rune(0x029C2) - of "cirE": result = Rune(0x029C3) - of "solb": result = Rune(0x029C4) - of "bsolb": result = Rune(0x029C5) - of "boxbox": result = Rune(0x029C9) - of "trisb": result = Rune(0x029CD) - of "rtriltri": result = Rune(0x029CE) - of "LeftTriangleBar": result = Rune(0x029CF) - of "RightTriangleBar": result = Rune(0x029D0) - of "race": result = Rune(0x029DA) - of "iinfin": result = Rune(0x029DC) - of "infintie": result = Rune(0x029DD) - of "nvinfin": result = Rune(0x029DE) - of "eparsl": result = Rune(0x029E3) - of "smeparsl": result = Rune(0x029E4) - of "eqvparsl": result = Rune(0x029E5) - of "lozf", "blacklozenge": result = Rune(0x029EB) - of "RuleDelayed": result = Rune(0x029F4) - of "dsol": result = Rune(0x029F6) - of "xodot", "bigodot": result = Rune(0x02A00) - of "xoplus", "bigoplus": result = Rune(0x02A01) - of "xotime", "bigotimes": result = Rune(0x02A02) - of "xuplus", "biguplus": result = Rune(0x02A04) - of "xsqcup", "bigsqcup": result = Rune(0x02A06) - of "qint", "iiiint": result = Rune(0x02A0C) - of "fpartint": result = Rune(0x02A0D) - of "cirfnint": result = Rune(0x02A10) - of "awint": result = Rune(0x02A11) - of "rppolint": result = Rune(0x02A12) - of "scpolint": result = Rune(0x02A13) - of "npolint": result = Rune(0x02A14) - of "pointint": result = Rune(0x02A15) - of "quatint": result = Rune(0x02A16) - of "intlarhk": result = Rune(0x02A17) - of "pluscir": result = Rune(0x02A22) - of "plusacir": result = Rune(0x02A23) - of "simplus": result = Rune(0x02A24) - of "plusdu": result = Rune(0x02A25) - of "plussim": result = Rune(0x02A26) - of "plustwo": result = Rune(0x02A27) - of "mcomma": result = Rune(0x02A29) - of "minusdu": result = Rune(0x02A2A) - of "loplus": result = Rune(0x02A2D) - of "roplus": result = Rune(0x02A2E) - of "Cross": result = Rune(0x02A2F) - of "timesd": result = Rune(0x02A30) - of "timesbar": result = Rune(0x02A31) - of "smashp": result = Rune(0x02A33) - of "lotimes": result = Rune(0x02A34) - of "rotimes": result = Rune(0x02A35) - of "otimesas": result = Rune(0x02A36) - of "Otimes": result = Rune(0x02A37) - of "odiv": result = Rune(0x02A38) - of "triplus": result = Rune(0x02A39) - of "triminus": result = Rune(0x02A3A) - of "tritime": result = Rune(0x02A3B) - of "iprod", "intprod": result = Rune(0x02A3C) - of "amalg": result = Rune(0x02A3F) - of "capdot": result = Rune(0x02A40) - of "ncup": result = Rune(0x02A42) - of "ncap": result = Rune(0x02A43) - of "capand": result = Rune(0x02A44) - of "cupor": result = Rune(0x02A45) - of "cupcap": result = Rune(0x02A46) - of "capcup": result = Rune(0x02A47) - of "cupbrcap": result = Rune(0x02A48) - of "capbrcup": result = Rune(0x02A49) - of "cupcup": result = Rune(0x02A4A) - of "capcap": result = Rune(0x02A4B) - of "ccups": result = Rune(0x02A4C) - of "ccaps": result = Rune(0x02A4D) - of "ccupssm": result = Rune(0x02A50) - of "And": result = Rune(0x02A53) - of "Or": result = Rune(0x02A54) - of "andand": result = Rune(0x02A55) - of "oror": result = Rune(0x02A56) - of "orslope": result = Rune(0x02A57) - of "andslope": result = Rune(0x02A58) - of "andv": result = Rune(0x02A5A) - of "orv": result = Rune(0x02A5B) - of "andd": result = Rune(0x02A5C) - of "ord": result = Rune(0x02A5D) - of "wedbar": result = Rune(0x02A5F) - of "sdote": result = Rune(0x02A66) - of "simdot": result = Rune(0x02A6A) - of "congdot": result = Rune(0x02A6D) - of "easter": result = Rune(0x02A6E) - of "apacir": result = Rune(0x02A6F) - of "apE": result = Rune(0x02A70) - of "eplus": result = Rune(0x02A71) - of "pluse": result = Rune(0x02A72) - of "Esim": result = Rune(0x02A73) - of "Colone": result = Rune(0x02A74) - of "Equal": result = Rune(0x02A75) - of "eDDot", "ddotseq": result = Rune(0x02A77) - of "equivDD": result = Rune(0x02A78) - of "ltcir": result = Rune(0x02A79) - of "gtcir": result = Rune(0x02A7A) - of "ltquest": result = Rune(0x02A7B) - of "gtquest": result = Rune(0x02A7C) - of "les", "LessSlantEqual", "leqslant": result = Rune(0x02A7D) - of "ges", "GreaterSlantEqual", "geqslant": result = Rune(0x02A7E) - of "lesdot": result = Rune(0x02A7F) - of "gesdot": result = Rune(0x02A80) - of "lesdoto": result = Rune(0x02A81) - of "gesdoto": result = Rune(0x02A82) - of "lesdotor": result = Rune(0x02A83) - of "gesdotol": result = Rune(0x02A84) - of "lap", "lessapprox": result = Rune(0x02A85) - of "gap", "gtrapprox": result = Rune(0x02A86) - of "lne", "lneq": result = Rune(0x02A87) - of "gne", "gneq": result = Rune(0x02A88) - of "lnap", "lnapprox": result = Rune(0x02A89) - of "gnap", "gnapprox": result = Rune(0x02A8A) - of "lEg", "lesseqqgtr": result = Rune(0x02A8B) - of "gEl", "gtreqqless": result = Rune(0x02A8C) - of "lsime": result = Rune(0x02A8D) - of "gsime": result = Rune(0x02A8E) - of "lsimg": result = Rune(0x02A8F) - of "gsiml": result = Rune(0x02A90) - of "lgE": result = Rune(0x02A91) - of "glE": result = Rune(0x02A92) - of "lesges": result = Rune(0x02A93) - of "gesles": result = Rune(0x02A94) - of "els", "eqslantless": result = Rune(0x02A95) - of "egs", "eqslantgtr": result = Rune(0x02A96) - of "elsdot": result = Rune(0x02A97) - of "egsdot": result = Rune(0x02A98) - of "el": result = Rune(0x02A99) - of "eg": result = Rune(0x02A9A) - of "siml": result = Rune(0x02A9D) - of "simg": result = Rune(0x02A9E) - of "simlE": result = Rune(0x02A9F) - of "simgE": result = Rune(0x02AA0) - of "LessLess": result = Rune(0x02AA1) - of "GreaterGreater": result = Rune(0x02AA2) - of "glj": result = Rune(0x02AA4) - of "gla": result = Rune(0x02AA5) - of "ltcc": result = Rune(0x02AA6) - of "gtcc": result = Rune(0x02AA7) - of "lescc": result = Rune(0x02AA8) - of "gescc": result = Rune(0x02AA9) - of "smt": result = Rune(0x02AAA) - of "lat": result = Rune(0x02AAB) - of "smte": result = Rune(0x02AAC) - of "late": result = Rune(0x02AAD) - of "bumpE": result = Rune(0x02AAE) - of "pre", "preceq", "PrecedesEqual": result = Rune(0x02AAF) - of "sce", "succeq", "SucceedsEqual": result = Rune(0x02AB0) - of "prE": result = Rune(0x02AB3) - of "scE": result = Rune(0x02AB4) - of "prnE", "precneqq": result = Rune(0x02AB5) - of "scnE", "succneqq": result = Rune(0x02AB6) - of "prap", "precapprox": result = Rune(0x02AB7) - of "scap", "succapprox": result = Rune(0x02AB8) - of "prnap", "precnapprox": result = Rune(0x02AB9) - of "scnap", "succnapprox": result = Rune(0x02ABA) - of "Pr": result = Rune(0x02ABB) - of "Sc": result = Rune(0x02ABC) - of "subdot": result = Rune(0x02ABD) - of "supdot": result = Rune(0x02ABE) - of "subplus": result = Rune(0x02ABF) - of "supplus": result = Rune(0x02AC0) - of "submult": result = Rune(0x02AC1) - of "supmult": result = Rune(0x02AC2) - of "subedot": result = Rune(0x02AC3) - of "supedot": result = Rune(0x02AC4) - of "subE", "subseteqq": result = Rune(0x02AC5) - of "supE", "supseteqq": result = Rune(0x02AC6) - of "subsim": result = Rune(0x02AC7) - of "supsim": result = Rune(0x02AC8) - of "subnE", "subsetneqq": result = Rune(0x02ACB) - of "supnE", "supsetneqq": result = Rune(0x02ACC) - of "csub": result = Rune(0x02ACF) - of "csup": result = Rune(0x02AD0) - of "csube": result = Rune(0x02AD1) - of "csupe": result = Rune(0x02AD2) - of "subsup": result = Rune(0x02AD3) - of "supsub": result = Rune(0x02AD4) - of "subsub": result = Rune(0x02AD5) - of "supsup": result = Rune(0x02AD6) - of "suphsub": result = Rune(0x02AD7) - of "supdsub": result = Rune(0x02AD8) - of "forkv": result = Rune(0x02AD9) - of "topfork": result = Rune(0x02ADA) - of "mlcp": result = Rune(0x02ADB) - of "Dashv", "DoubleLeftTee": result = Rune(0x02AE4) - of "Vdashl": result = Rune(0x02AE6) - of "Barv": result = Rune(0x02AE7) - of "vBar": result = Rune(0x02AE8) - of "vBarv": result = Rune(0x02AE9) - of "Vbar": result = Rune(0x02AEB) - of "Not": result = Rune(0x02AEC) - of "bNot": result = Rune(0x02AED) - of "rnmid": result = Rune(0x02AEE) - of "cirmid": result = Rune(0x02AEF) - of "midcir": result = Rune(0x02AF0) - of "topcir": result = Rune(0x02AF1) - of "nhpar": result = Rune(0x02AF2) - of "parsim": result = Rune(0x02AF3) - of "parsl": result = Rune(0x02AFD) - of "fflig": result = Rune(0x0FB00) - of "filig": result = Rune(0x0FB01) - of "fllig": result = Rune(0x0FB02) - of "ffilig": result = Rune(0x0FB03) - of "ffllig": result = Rune(0x0FB04) - of "Ascr": result = Rune(0x1D49C) - of "Cscr": result = Rune(0x1D49E) - of "Dscr": result = Rune(0x1D49F) - of "Gscr": result = Rune(0x1D4A2) - of "Jscr": result = Rune(0x1D4A5) - of "Kscr": result = Rune(0x1D4A6) - of "Nscr": result = Rune(0x1D4A9) - of "Oscr": result = Rune(0x1D4AA) - of "Pscr": result = Rune(0x1D4AB) - of "Qscr": result = Rune(0x1D4AC) - of "Sscr": result = Rune(0x1D4AE) - of "Tscr": result = Rune(0x1D4AF) - of "Uscr": result = Rune(0x1D4B0) - of "Vscr": result = Rune(0x1D4B1) - of "Wscr": result = Rune(0x1D4B2) - of "Xscr": result = Rune(0x1D4B3) - of "Yscr": result = Rune(0x1D4B4) - of "Zscr": result = Rune(0x1D4B5) - of "ascr": result = Rune(0x1D4B6) - of "bscr": result = Rune(0x1D4B7) - of "cscr": result = Rune(0x1D4B8) - of "dscr": result = Rune(0x1D4B9) - of "fscr": result = Rune(0x1D4BB) - of "hscr": result = Rune(0x1D4BD) - of "iscr": result = Rune(0x1D4BE) - of "jscr": result = Rune(0x1D4BF) - of "kscr": result = Rune(0x1D4C0) - of "lscr": result = Rune(0x1D4C1) - of "mscr": result = Rune(0x1D4C2) - of "nscr": result = Rune(0x1D4C3) - of "pscr": result = Rune(0x1D4C5) - of "qscr": result = Rune(0x1D4C6) - of "rscr": result = Rune(0x1D4C7) - of "sscr": result = Rune(0x1D4C8) - of "tscr": result = Rune(0x1D4C9) - of "uscr": result = Rune(0x1D4CA) - of "vscr": result = Rune(0x1D4CB) - of "wscr": result = Rune(0x1D4CC) - of "xscr": result = Rune(0x1D4CD) - of "yscr": result = Rune(0x1D4CE) - of "zscr": result = Rune(0x1D4CF) - of "Afr": result = Rune(0x1D504) - of "Bfr": result = Rune(0x1D505) - of "Dfr": result = Rune(0x1D507) - of "Efr": result = Rune(0x1D508) - of "Ffr": result = Rune(0x1D509) - of "Gfr": result = Rune(0x1D50A) - of "Jfr": result = Rune(0x1D50D) - of "Kfr": result = Rune(0x1D50E) - of "Lfr": result = Rune(0x1D50F) - of "Mfr": result = Rune(0x1D510) - of "Nfr": result = Rune(0x1D511) - of "Ofr": result = Rune(0x1D512) - of "Pfr": result = Rune(0x1D513) - of "Qfr": result = Rune(0x1D514) - of "Sfr": result = Rune(0x1D516) - of "Tfr": result = Rune(0x1D517) - of "Ufr": result = Rune(0x1D518) - of "Vfr": result = Rune(0x1D519) - of "Wfr": result = Rune(0x1D51A) - of "Xfr": result = Rune(0x1D51B) - of "Yfr": result = Rune(0x1D51C) - of "afr": result = Rune(0x1D51E) - of "bfr": result = Rune(0x1D51F) - of "cfr": result = Rune(0x1D520) - of "dfr": result = Rune(0x1D521) - of "efr": result = Rune(0x1D522) - of "ffr": result = Rune(0x1D523) - of "gfr": result = Rune(0x1D524) - of "hfr": result = Rune(0x1D525) - of "ifr": result = Rune(0x1D526) - of "jfr": result = Rune(0x1D527) - of "kfr": result = Rune(0x1D528) - of "lfr": result = Rune(0x1D529) - of "mfr": result = Rune(0x1D52A) - of "nfr": result = Rune(0x1D52B) - of "ofr": result = Rune(0x1D52C) - of "pfr": result = Rune(0x1D52D) - of "qfr": result = Rune(0x1D52E) - of "rfr": result = Rune(0x1D52F) - of "sfr": result = Rune(0x1D530) - of "tfr": result = Rune(0x1D531) - of "ufr": result = Rune(0x1D532) - of "vfr": result = Rune(0x1D533) - of "wfr": result = Rune(0x1D534) - of "xfr": result = Rune(0x1D535) - of "yfr": result = Rune(0x1D536) - of "zfr": result = Rune(0x1D537) - of "Aopf": result = Rune(0x1D538) - of "Bopf": result = Rune(0x1D539) - of "Dopf": result = Rune(0x1D53B) - of "Eopf": result = Rune(0x1D53C) - of "Fopf": result = Rune(0x1D53D) - of "Gopf": result = Rune(0x1D53E) - of "Iopf": result = Rune(0x1D540) - of "Jopf": result = Rune(0x1D541) - of "Kopf": result = Rune(0x1D542) - of "Lopf": result = Rune(0x1D543) - of "Mopf": result = Rune(0x1D544) - of "Oopf": result = Rune(0x1D546) - of "Sopf": result = Rune(0x1D54A) - of "Topf": result = Rune(0x1D54B) - of "Uopf": result = Rune(0x1D54C) - of "Vopf": result = Rune(0x1D54D) - of "Wopf": result = Rune(0x1D54E) - of "Xopf": result = Rune(0x1D54F) - of "Yopf": result = Rune(0x1D550) - of "aopf": result = Rune(0x1D552) - of "bopf": result = Rune(0x1D553) - of "copf": result = Rune(0x1D554) - of "dopf": result = Rune(0x1D555) - of "eopf": result = Rune(0x1D556) - of "fopf": result = Rune(0x1D557) - of "gopf": result = Rune(0x1D558) - of "hopf": result = Rune(0x1D559) - of "iopf": result = Rune(0x1D55A) - of "jopf": result = Rune(0x1D55B) - of "kopf": result = Rune(0x1D55C) - of "lopf": result = Rune(0x1D55D) - of "mopf": result = Rune(0x1D55E) - of "nopf": result = Rune(0x1D55F) - of "oopf": result = Rune(0x1D560) - of "popf": result = Rune(0x1D561) - of "qopf": result = Rune(0x1D562) - of "ropf": result = Rune(0x1D563) - of "sopf": result = Rune(0x1D564) - of "topf": result = Rune(0x1D565) - of "uopf": result = Rune(0x1D566) - of "vopf": result = Rune(0x1D567) - of "wopf": result = Rune(0x1D568) - of "xopf": result = Rune(0x1D569) - of "yopf": result = Rune(0x1D56A) - of "zopf": result = Rune(0x1D56B) - else: discard + "DoubleLongLeftRightArrow": Rune(0x027FA) + of "xmap", "longmapsto": Rune(0x027FC) + of "dzigrarr": Rune(0x027FF) + of "nvlArr": Rune(0x02902) + of "nvrArr": Rune(0x02903) + of "nvHarr": Rune(0x02904) + of "Map": Rune(0x02905) + of "lbarr": Rune(0x0290C) + of "rbarr", "bkarow": Rune(0x0290D) + of "lBarr": Rune(0x0290E) + of "rBarr", "dbkarow": Rune(0x0290F) + of "RBarr", "drbkarow": Rune(0x02910) + of "DDotrahd": Rune(0x02911) + of "UpArrowBar": Rune(0x02912) + of "DownArrowBar": Rune(0x02913) + of "Rarrtl": Rune(0x02916) + of "latail": Rune(0x02919) + of "ratail": Rune(0x0291A) + of "lAtail": Rune(0x0291B) + of "rAtail": Rune(0x0291C) + of "larrfs": Rune(0x0291D) + of "rarrfs": Rune(0x0291E) + of "larrbfs": Rune(0x0291F) + of "rarrbfs": Rune(0x02920) + of "nwarhk": Rune(0x02923) + of "nearhk": Rune(0x02924) + of "searhk", "hksearow": Rune(0x02925) + of "swarhk", "hkswarow": Rune(0x02926) + of "nwnear": Rune(0x02927) + of "nesear", "toea": Rune(0x02928) + of "seswar", "tosa": Rune(0x02929) + of "swnwar": Rune(0x0292A) + of "rarrc": Rune(0x02933) + of "cudarrr": Rune(0x02935) + of "ldca": Rune(0x02936) + of "rdca": Rune(0x02937) + of "cudarrl": Rune(0x02938) + of "larrpl": Rune(0x02939) + of "curarrm": Rune(0x0293C) + of "cularrp": Rune(0x0293D) + of "rarrpl": Rune(0x02945) + of "harrcir": Rune(0x02948) + of "Uarrocir": Rune(0x02949) + of "lurdshar": Rune(0x0294A) + of "ldrushar": Rune(0x0294B) + of "LeftRightVector": Rune(0x0294E) + of "RightUpDownVector": Rune(0x0294F) + of "DownLeftRightVector": Rune(0x02950) + of "LeftUpDownVector": Rune(0x02951) + of "LeftVectorBar": Rune(0x02952) + of "RightVectorBar": Rune(0x02953) + of "RightUpVectorBar": Rune(0x02954) + of "RightDownVectorBar": Rune(0x02955) + of "DownLeftVectorBar": Rune(0x02956) + of "DownRightVectorBar": Rune(0x02957) + of "LeftUpVectorBar": Rune(0x02958) + of "LeftDownVectorBar": Rune(0x02959) + of "LeftTeeVector": Rune(0x0295A) + of "RightTeeVector": Rune(0x0295B) + of "RightUpTeeVector": Rune(0x0295C) + of "RightDownTeeVector": Rune(0x0295D) + of "DownLeftTeeVector": Rune(0x0295E) + of "DownRightTeeVector": Rune(0x0295F) + of "LeftUpTeeVector": Rune(0x02960) + of "LeftDownTeeVector": Rune(0x02961) + of "lHar": Rune(0x02962) + of "uHar": Rune(0x02963) + of "rHar": Rune(0x02964) + of "dHar": Rune(0x02965) + of "luruhar": Rune(0x02966) + of "ldrdhar": Rune(0x02967) + of "ruluhar": Rune(0x02968) + of "rdldhar": Rune(0x02969) + of "lharul": Rune(0x0296A) + of "llhard": Rune(0x0296B) + of "rharul": Rune(0x0296C) + of "lrhard": Rune(0x0296D) + of "udhar", "UpEquilibrium": Rune(0x0296E) + of "duhar", "ReverseUpEquilibrium": Rune(0x0296F) + of "RoundImplies": Rune(0x02970) + of "erarr": Rune(0x02971) + of "simrarr": Rune(0x02972) + of "larrsim": Rune(0x02973) + of "rarrsim": Rune(0x02974) + of "rarrap": Rune(0x02975) + of "ltlarr": Rune(0x02976) + of "gtrarr": Rune(0x02978) + of "subrarr": Rune(0x02979) + of "suplarr": Rune(0x0297B) + of "lfisht": Rune(0x0297C) + of "rfisht": Rune(0x0297D) + of "ufisht": Rune(0x0297E) + of "dfisht": Rune(0x0297F) + of "lopar": Rune(0x02985) + of "ropar": Rune(0x02986) + of "lbrke": Rune(0x0298B) + of "rbrke": Rune(0x0298C) + of "lbrkslu": Rune(0x0298D) + of "rbrksld": Rune(0x0298E) + of "lbrksld": Rune(0x0298F) + of "rbrkslu": Rune(0x02990) + of "langd": Rune(0x02991) + of "rangd": Rune(0x02992) + of "lparlt": Rune(0x02993) + of "rpargt": Rune(0x02994) + of "gtlPar": Rune(0x02995) + of "ltrPar": Rune(0x02996) + of "vzigzag": Rune(0x0299A) + of "vangrt": Rune(0x0299C) + of "angrtvbd": Rune(0x0299D) + of "ange": Rune(0x029A4) + of "range": Rune(0x029A5) + of "dwangle": Rune(0x029A6) + of "uwangle": Rune(0x029A7) + of "angmsdaa": Rune(0x029A8) + of "angmsdab": Rune(0x029A9) + of "angmsdac": Rune(0x029AA) + of "angmsdad": Rune(0x029AB) + of "angmsdae": Rune(0x029AC) + of "angmsdaf": Rune(0x029AD) + of "angmsdag": Rune(0x029AE) + of "angmsdah": Rune(0x029AF) + of "bemptyv": Rune(0x029B0) + of "demptyv": Rune(0x029B1) + of "cemptyv": Rune(0x029B2) + of "raemptyv": Rune(0x029B3) + of "laemptyv": Rune(0x029B4) + of "ohbar": Rune(0x029B5) + of "omid": Rune(0x029B6) + of "opar": Rune(0x029B7) + of "operp": Rune(0x029B9) + of "olcross": Rune(0x029BB) + of "odsold": Rune(0x029BC) + of "olcir": Rune(0x029BE) + of "ofcir": Rune(0x029BF) + of "olt": Rune(0x029C0) + of "ogt": Rune(0x029C1) + of "cirscir": Rune(0x029C2) + of "cirE": Rune(0x029C3) + of "solb": Rune(0x029C4) + of "bsolb": Rune(0x029C5) + of "boxbox": Rune(0x029C9) + of "trisb": Rune(0x029CD) + of "rtriltri": Rune(0x029CE) + of "LeftTriangleBar": Rune(0x029CF) + of "RightTriangleBar": Rune(0x029D0) + of "race": Rune(0x029DA) + of "iinfin": Rune(0x029DC) + of "infintie": Rune(0x029DD) + of "nvinfin": Rune(0x029DE) + of "eparsl": Rune(0x029E3) + of "smeparsl": Rune(0x029E4) + of "eqvparsl": Rune(0x029E5) + of "lozf", "blacklozenge": Rune(0x029EB) + of "RuleDelayed": Rune(0x029F4) + of "dsol": Rune(0x029F6) + of "xodot", "bigodot": Rune(0x02A00) + of "xoplus", "bigoplus": Rune(0x02A01) + of "xotime", "bigotimes": Rune(0x02A02) + of "xuplus", "biguplus": Rune(0x02A04) + of "xsqcup", "bigsqcup": Rune(0x02A06) + of "qint", "iiiint": Rune(0x02A0C) + of "fpartint": Rune(0x02A0D) + of "cirfnint": Rune(0x02A10) + of "awint": Rune(0x02A11) + of "rppolint": Rune(0x02A12) + of "scpolint": Rune(0x02A13) + of "npolint": Rune(0x02A14) + of "pointint": Rune(0x02A15) + of "quatint": Rune(0x02A16) + of "intlarhk": Rune(0x02A17) + of "pluscir": Rune(0x02A22) + of "plusacir": Rune(0x02A23) + of "simplus": Rune(0x02A24) + of "plusdu": Rune(0x02A25) + of "plussim": Rune(0x02A26) + of "plustwo": Rune(0x02A27) + of "mcomma": Rune(0x02A29) + of "minusdu": Rune(0x02A2A) + of "loplus": Rune(0x02A2D) + of "roplus": Rune(0x02A2E) + of "Cross": Rune(0x02A2F) + of "timesd": Rune(0x02A30) + of "timesbar": Rune(0x02A31) + of "smashp": Rune(0x02A33) + of "lotimes": Rune(0x02A34) + of "rotimes": Rune(0x02A35) + of "otimesas": Rune(0x02A36) + of "Otimes": Rune(0x02A37) + of "odiv": Rune(0x02A38) + of "triplus": Rune(0x02A39) + of "triminus": Rune(0x02A3A) + of "tritime": Rune(0x02A3B) + of "iprod", "intprod": Rune(0x02A3C) + of "amalg": Rune(0x02A3F) + of "capdot": Rune(0x02A40) + of "ncup": Rune(0x02A42) + of "ncap": Rune(0x02A43) + of "capand": Rune(0x02A44) + of "cupor": Rune(0x02A45) + of "cupcap": Rune(0x02A46) + of "capcup": Rune(0x02A47) + of "cupbrcap": Rune(0x02A48) + of "capbrcup": Rune(0x02A49) + of "cupcup": Rune(0x02A4A) + of "capcap": Rune(0x02A4B) + of "ccups": Rune(0x02A4C) + of "ccaps": Rune(0x02A4D) + of "ccupssm": Rune(0x02A50) + of "And": Rune(0x02A53) + of "Or": Rune(0x02A54) + of "andand": Rune(0x02A55) + of "oror": Rune(0x02A56) + of "orslope": Rune(0x02A57) + of "andslope": Rune(0x02A58) + of "andv": Rune(0x02A5A) + of "orv": Rune(0x02A5B) + of "andd": Rune(0x02A5C) + of "ord": Rune(0x02A5D) + of "wedbar": Rune(0x02A5F) + of "sdote": Rune(0x02A66) + of "simdot": Rune(0x02A6A) + of "congdot": Rune(0x02A6D) + of "easter": Rune(0x02A6E) + of "apacir": Rune(0x02A6F) + of "apE": Rune(0x02A70) + of "eplus": Rune(0x02A71) + of "pluse": Rune(0x02A72) + of "Esim": Rune(0x02A73) + of "Colone": Rune(0x02A74) + of "Equal": Rune(0x02A75) + of "eDDot", "ddotseq": Rune(0x02A77) + of "equivDD": Rune(0x02A78) + of "ltcir": Rune(0x02A79) + of "gtcir": Rune(0x02A7A) + of "ltquest": Rune(0x02A7B) + of "gtquest": Rune(0x02A7C) + of "les", "LessSlantEqual", "leqslant": Rune(0x02A7D) + of "ges", "GreaterSlantEqual", "geqslant": Rune(0x02A7E) + of "lesdot": Rune(0x02A7F) + of "gesdot": Rune(0x02A80) + of "lesdoto": Rune(0x02A81) + of "gesdoto": Rune(0x02A82) + of "lesdotor": Rune(0x02A83) + of "gesdotol": Rune(0x02A84) + of "lap", "lessapprox": Rune(0x02A85) + of "gap", "gtrapprox": Rune(0x02A86) + of "lne", "lneq": Rune(0x02A87) + of "gne", "gneq": Rune(0x02A88) + of "lnap", "lnapprox": Rune(0x02A89) + of "gnap", "gnapprox": Rune(0x02A8A) + of "lEg", "lesseqqgtr": Rune(0x02A8B) + of "gEl", "gtreqqless": Rune(0x02A8C) + of "lsime": Rune(0x02A8D) + of "gsime": Rune(0x02A8E) + of "lsimg": Rune(0x02A8F) + of "gsiml": Rune(0x02A90) + of "lgE": Rune(0x02A91) + of "glE": Rune(0x02A92) + of "lesges": Rune(0x02A93) + of "gesles": Rune(0x02A94) + of "els", "eqslantless": Rune(0x02A95) + of "egs", "eqslantgtr": Rune(0x02A96) + of "elsdot": Rune(0x02A97) + of "egsdot": Rune(0x02A98) + of "el": Rune(0x02A99) + of "eg": Rune(0x02A9A) + of "siml": Rune(0x02A9D) + of "simg": Rune(0x02A9E) + of "simlE": Rune(0x02A9F) + of "simgE": Rune(0x02AA0) + of "LessLess": Rune(0x02AA1) + of "GreaterGreater": Rune(0x02AA2) + of "glj": Rune(0x02AA4) + of "gla": Rune(0x02AA5) + of "ltcc": Rune(0x02AA6) + of "gtcc": Rune(0x02AA7) + of "lescc": Rune(0x02AA8) + of "gescc": Rune(0x02AA9) + of "smt": Rune(0x02AAA) + of "lat": Rune(0x02AAB) + of "smte": Rune(0x02AAC) + of "late": Rune(0x02AAD) + of "bumpE": Rune(0x02AAE) + of "pre", "preceq", "PrecedesEqual": Rune(0x02AAF) + of "sce", "succeq", "SucceedsEqual": Rune(0x02AB0) + of "prE": Rune(0x02AB3) + of "scE": Rune(0x02AB4) + of "prnE", "precneqq": Rune(0x02AB5) + of "scnE", "succneqq": Rune(0x02AB6) + of "prap", "precapprox": Rune(0x02AB7) + of "scap", "succapprox": Rune(0x02AB8) + of "prnap", "precnapprox": Rune(0x02AB9) + of "scnap", "succnapprox": Rune(0x02ABA) + of "Pr": Rune(0x02ABB) + of "Sc": Rune(0x02ABC) + of "subdot": Rune(0x02ABD) + of "supdot": Rune(0x02ABE) + of "subplus": Rune(0x02ABF) + of "supplus": Rune(0x02AC0) + of "submult": Rune(0x02AC1) + of "supmult": Rune(0x02AC2) + of "subedot": Rune(0x02AC3) + of "supedot": Rune(0x02AC4) + of "subE", "subseteqq": Rune(0x02AC5) + of "supE", "supseteqq": Rune(0x02AC6) + of "subsim": Rune(0x02AC7) + of "supsim": Rune(0x02AC8) + of "subnE", "subsetneqq": Rune(0x02ACB) + of "supnE", "supsetneqq": Rune(0x02ACC) + of "csub": Rune(0x02ACF) + of "csup": Rune(0x02AD0) + of "csube": Rune(0x02AD1) + of "csupe": Rune(0x02AD2) + of "subsup": Rune(0x02AD3) + of "supsub": Rune(0x02AD4) + of "subsub": Rune(0x02AD5) + of "supsup": Rune(0x02AD6) + of "suphsub": Rune(0x02AD7) + of "supdsub": Rune(0x02AD8) + of "forkv": Rune(0x02AD9) + of "topfork": Rune(0x02ADA) + of "mlcp": Rune(0x02ADB) + of "Dashv", "DoubleLeftTee": Rune(0x02AE4) + of "Vdashl": Rune(0x02AE6) + of "Barv": Rune(0x02AE7) + of "vBar": Rune(0x02AE8) + of "vBarv": Rune(0x02AE9) + of "Vbar": Rune(0x02AEB) + of "Not": Rune(0x02AEC) + of "bNot": Rune(0x02AED) + of "rnmid": Rune(0x02AEE) + of "cirmid": Rune(0x02AEF) + of "midcir": Rune(0x02AF0) + of "topcir": Rune(0x02AF1) + of "nhpar": Rune(0x02AF2) + of "parsim": Rune(0x02AF3) + of "parsl": Rune(0x02AFD) + of "fflig": Rune(0x0FB00) + of "filig": Rune(0x0FB01) + of "fllig": Rune(0x0FB02) + of "ffilig": Rune(0x0FB03) + of "ffllig": Rune(0x0FB04) + of "Ascr": Rune(0x1D49C) + of "Cscr": Rune(0x1D49E) + of "Dscr": Rune(0x1D49F) + of "Gscr": Rune(0x1D4A2) + of "Jscr": Rune(0x1D4A5) + of "Kscr": Rune(0x1D4A6) + of "Nscr": Rune(0x1D4A9) + of "Oscr": Rune(0x1D4AA) + of "Pscr": Rune(0x1D4AB) + of "Qscr": Rune(0x1D4AC) + of "Sscr": Rune(0x1D4AE) + of "Tscr": Rune(0x1D4AF) + of "Uscr": Rune(0x1D4B0) + of "Vscr": Rune(0x1D4B1) + of "Wscr": Rune(0x1D4B2) + of "Xscr": Rune(0x1D4B3) + of "Yscr": Rune(0x1D4B4) + of "Zscr": Rune(0x1D4B5) + of "ascr": Rune(0x1D4B6) + of "bscr": Rune(0x1D4B7) + of "cscr": Rune(0x1D4B8) + of "dscr": Rune(0x1D4B9) + of "fscr": Rune(0x1D4BB) + of "hscr": Rune(0x1D4BD) + of "iscr": Rune(0x1D4BE) + of "jscr": Rune(0x1D4BF) + of "kscr": Rune(0x1D4C0) + of "lscr": Rune(0x1D4C1) + of "mscr": Rune(0x1D4C2) + of "nscr": Rune(0x1D4C3) + of "pscr": Rune(0x1D4C5) + of "qscr": Rune(0x1D4C6) + of "rscr": Rune(0x1D4C7) + of "sscr": Rune(0x1D4C8) + of "tscr": Rune(0x1D4C9) + of "uscr": Rune(0x1D4CA) + of "vscr": Rune(0x1D4CB) + of "wscr": Rune(0x1D4CC) + of "xscr": Rune(0x1D4CD) + of "yscr": Rune(0x1D4CE) + of "zscr": Rune(0x1D4CF) + of "Afr": Rune(0x1D504) + of "Bfr": Rune(0x1D505) + of "Dfr": Rune(0x1D507) + of "Efr": Rune(0x1D508) + of "Ffr": Rune(0x1D509) + of "Gfr": Rune(0x1D50A) + of "Jfr": Rune(0x1D50D) + of "Kfr": Rune(0x1D50E) + of "Lfr": Rune(0x1D50F) + of "Mfr": Rune(0x1D510) + of "Nfr": Rune(0x1D511) + of "Ofr": Rune(0x1D512) + of "Pfr": Rune(0x1D513) + of "Qfr": Rune(0x1D514) + of "Sfr": Rune(0x1D516) + of "Tfr": Rune(0x1D517) + of "Ufr": Rune(0x1D518) + of "Vfr": Rune(0x1D519) + of "Wfr": Rune(0x1D51A) + of "Xfr": Rune(0x1D51B) + of "Yfr": Rune(0x1D51C) + of "afr": Rune(0x1D51E) + of "bfr": Rune(0x1D51F) + of "cfr": Rune(0x1D520) + of "dfr": Rune(0x1D521) + of "efr": Rune(0x1D522) + of "ffr": Rune(0x1D523) + of "gfr": Rune(0x1D524) + of "hfr": Rune(0x1D525) + of "ifr": Rune(0x1D526) + of "jfr": Rune(0x1D527) + of "kfr": Rune(0x1D528) + of "lfr": Rune(0x1D529) + of "mfr": Rune(0x1D52A) + of "nfr": Rune(0x1D52B) + of "ofr": Rune(0x1D52C) + of "pfr": Rune(0x1D52D) + of "qfr": Rune(0x1D52E) + of "rfr": Rune(0x1D52F) + of "sfr": Rune(0x1D530) + of "tfr": Rune(0x1D531) + of "ufr": Rune(0x1D532) + of "vfr": Rune(0x1D533) + of "wfr": Rune(0x1D534) + of "xfr": Rune(0x1D535) + of "yfr": Rune(0x1D536) + of "zfr": Rune(0x1D537) + of "Aopf": Rune(0x1D538) + of "Bopf": Rune(0x1D539) + of "Dopf": Rune(0x1D53B) + of "Eopf": Rune(0x1D53C) + of "Fopf": Rune(0x1D53D) + of "Gopf": Rune(0x1D53E) + of "Iopf": Rune(0x1D540) + of "Jopf": Rune(0x1D541) + of "Kopf": Rune(0x1D542) + of "Lopf": Rune(0x1D543) + of "Mopf": Rune(0x1D544) + of "Oopf": Rune(0x1D546) + of "Sopf": Rune(0x1D54A) + of "Topf": Rune(0x1D54B) + of "Uopf": Rune(0x1D54C) + of "Vopf": Rune(0x1D54D) + of "Wopf": Rune(0x1D54E) + of "Xopf": Rune(0x1D54F) + of "Yopf": Rune(0x1D550) + of "aopf": Rune(0x1D552) + of "bopf": Rune(0x1D553) + of "copf": Rune(0x1D554) + of "dopf": Rune(0x1D555) + of "eopf": Rune(0x1D556) + of "fopf": Rune(0x1D557) + of "gopf": Rune(0x1D558) + of "hopf": Rune(0x1D559) + of "iopf": Rune(0x1D55A) + of "jopf": Rune(0x1D55B) + of "kopf": Rune(0x1D55C) + of "lopf": Rune(0x1D55D) + of "mopf": Rune(0x1D55E) + of "nopf": Rune(0x1D55F) + of "oopf": Rune(0x1D560) + of "popf": Rune(0x1D561) + of "qopf": Rune(0x1D562) + of "ropf": Rune(0x1D563) + of "sopf": Rune(0x1D564) + of "topf": Rune(0x1D565) + of "uopf": Rune(0x1D566) + of "vopf": Rune(0x1D567) + of "wopf": Rune(0x1D568) + of "xopf": Rune(0x1D569) + of "yopf": Rune(0x1D56A) + of "zopf": Rune(0x1D56B) + else: Rune(0) proc entityToUtf8*(entity: string): string = ## Converts an HTML entity name like ``Ü`` or values like ``Ü`` @@ -1869,19 +1872,20 @@ proc entityToUtf8*(entity: string): string = ## "" is returned if the entity name is unknown. The HTML parser ## already converts entities to UTF-8. runnableExamples: + const sigma = "Σ" doAssert entityToUtf8("") == "" doAssert entityToUtf8("a") == "" doAssert entityToUtf8("gt") == ">" doAssert entityToUtf8("Uuml") == "Ãœ" doAssert entityToUtf8("quest") == "?" doAssert entityToUtf8("#63") == "?" - doAssert entityToUtf8("Sigma") == "Σ" - doAssert entityToUtf8("#931") == "Σ" - doAssert entityToUtf8("#0931") == "Σ" - doAssert entityToUtf8("#x3A3") == "Σ" - doAssert entityToUtf8("#x03A3") == "Σ" - doAssert entityToUtf8("#x3a3") == "Σ" - doAssert entityToUtf8("#X3a3") == "Σ" + doAssert entityToUtf8("Sigma") == sigma + doAssert entityToUtf8("#931") == sigma + doAssert entityToUtf8("#0931") == sigma + doAssert entityToUtf8("#x3A3") == sigma + doAssert entityToUtf8("#x03A3") == sigma + doAssert entityToUtf8("#x3a3") == sigma + doAssert entityToUtf8("#X3a3") == sigma let rune = entityToRune(entity) if rune.ord <= 0: result = "" else: result = toUTF8(rune) diff --git a/lib/pure/httpclient.nim b/lib/pure/httpclient.nim index 0192e71e7..139d4bb50 100644 --- a/lib/pure/httpclient.nim +++ b/lib/pure/httpclient.nim @@ -185,7 +185,7 @@ proc body*(response: Response): string = ## Retrieves the specified response's body. ## ## The response's body stream is read synchronously. - if response.body.isNil(): + if response.body.len == 0: response.body = response.bodyStream.readAll() return response.body @@ -198,7 +198,7 @@ proc `body=`*(response: Response, value: string) {.deprecated.} = proc body*(response: AsyncResponse): Future[string] {.async.} = ## Reads the response's body and caches it. The read is performed only ## once. - if response.body.isNil: + if response.body.len == 0: response.body = await readAll(response.bodyStream) return response.body diff --git a/lib/pure/json.nim b/lib/pure/json.nim index 3599667a8..9279fea77 100644 --- a/lib/pure/json.nim +++ b/lib/pure/json.nim @@ -545,10 +545,9 @@ proc newIndent(curr, indent: int, ml: bool): int = proc nl(s: var string, ml: bool) = s.add(if ml: "\n" else: " ") -proc escapeJson*(s: string; result: var string) = - ## Converts a string `s` to its JSON representation. +proc escapeJsonUnquoted*(s: string; result: var string) = + ## Converts a string `s` to its JSON representation without quotes. ## Appends to ``result``. - result.add("\"") for c in s: case c of '\L': result.add("\\n") @@ -561,10 +560,21 @@ proc escapeJson*(s: string; result: var string) = of '\14'..'\31': result.add("\\u00" & $ord(c)) of '\\': result.add("\\\\") else: result.add(c) + +proc escapeJsonUnquoted*(s: string): string = + ## Converts a string `s` to its JSON representation without quotes. + result = newStringOfCap(s.len + s.len shr 3) + escapeJsonUnquoted(s, result) + +proc escapeJson*(s: string; result: var string) = + ## Converts a string `s` to its JSON representation with quotes. + ## Appends to ``result``. + result.add("\"") + escapeJsonUnquoted(s, result) result.add("\"") proc escapeJson*(s: string): string = - ## Converts a string `s` to its JSON representation. + ## Converts a string `s` to its JSON representation with quotes. result = newStringOfCap(s.len + s.len shr 3) escapeJson(s, result) @@ -1607,6 +1617,8 @@ when isMainModule: 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 escapeJsonUnquoted("\10Foo🎃barÄ") == "\\nFoo🎃barÄ" + doAssert escapeJsonUnquoted("\0\7\20") == "\\u0000\\u0007\\u0020" # for #7887 doAssert escapeJson("\10Foo🎃barÄ") == "\"\\nFoo🎃barÄ\"" doAssert escapeJson("\0\7\20") == "\"\\u0000\\u0007\\u0020\"" # for #7887 diff --git a/lib/pure/logging.nim b/lib/pure/logging.nim index cdff1f548..f2f5cac9e 100644 --- a/lib/pure/logging.nim +++ b/lib/pure/logging.nim @@ -103,14 +103,9 @@ var proc substituteLog*(frmt: string, level: Level, args: varargs[string, `$`]): string = ## Format a log message using the ``frmt`` format string, ``level`` and varargs. ## See the module documentation for the format string syntax. - const nilString = "nil" - var msgLen = 0 for arg in args: - if arg.isNil: - msgLen += nilString.len - else: - msgLen += arg.len + msgLen += arg.len result = newStringOfCap(frmt.len + msgLen + 20) var i = 0 while i < frmt.len: @@ -137,10 +132,7 @@ proc substituteLog*(frmt: string, level: Level, args: varargs[string, `$`]): str of "levelname": result.add(LevelNames[level]) else: discard for arg in args: - if arg.isNil: - result.add(nilString) - else: - result.add(arg) + result.add(arg) method log*(logger: Logger, level: Level, args: varargs[string, `$`]) {. raises: [Exception], gcsafe, @@ -338,7 +330,6 @@ template fatal*(args: varargs[string, `$`]) = proc addHandler*(handler: Logger) = ## Adds ``handler`` to the list of handlers. - if handlers.isNil: handlers = @[] handlers.add(handler) proc getHandlers*(): seq[Logger] = diff --git a/lib/pure/marshal.nim b/lib/pure/marshal.nim index b90d2899c..b0bcfe535 100644 --- a/lib/pure/marshal.nim +++ b/lib/pure/marshal.nim @@ -98,8 +98,7 @@ proc storeAny(s: Stream, a: Any, stored: var IntSet) = of akProc, akPointer, akCString: s.write($a.getPointer.ptrToInt) of akString: var x = getString(a) - if isNil(x): s.write("null") - elif x.validateUtf8() == -1: s.write(escapeJson(x)) + if x.validateUtf8() == -1: s.write(escapeJson(x)) else: s.write("[") var i = 0 @@ -281,6 +280,17 @@ proc `$$`*[T](x: T): string = proc to*[T](data: string): T = ## reads data and transforms it to a ``T``. + runnableExamples: + type + Foo = object + id: int + bar: string + + let x = Foo(id: 1, bar: "baz") + # serialize + let y = ($$x) + # deserialize back to type 'Foo': + let z = y.to[:Foo] var tab = initTable[BiggestInt, pointer]() loadAny(newStringStream(data), toAny(result), tab) diff --git a/lib/pure/memfiles.nim b/lib/pure/memfiles.nim index 0249b7413..9fccd08d4 100644 --- a/lib/pure/memfiles.nim +++ b/lib/pure/memfiles.nim @@ -328,7 +328,6 @@ proc `$`*(ms: MemSlice): string {.inline.} = ## Return a Nim string built from a MemSlice. var buf = newString(ms.size) copyMem(addr(buf[0]), ms.data, ms.size) - buf[ms.size] = '\0' result = buf iterator memSlices*(mfile: MemFile, delim='\l', eat='\r'): MemSlice {.inline.} = diff --git a/lib/pure/net.nim b/lib/pure/net.nim index 0e56100d9..a60137dab 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -58,15 +58,11 @@ ## You can then begin accepting connections using the ``accept`` procedure. ## ## .. code-block:: Nim -## var client = new Socket +## var client: Socket ## var address = "" ## while true: ## socket.acceptAddr(client, address) ## echo("Client connected from: ", address) -## -## **Note:** The ``client`` variable is initialised with ``new Socket`` **not** -## ``newSocket()``. The difference is that the latter creates a new file -## descriptor. {.deadCodeElim: on.} # dce option deprecated import nativesockets, os, strutils, parseutils, times, sets, options @@ -789,16 +785,12 @@ proc acceptAddr*(server: Socket, client: var Socket, address: var string, ## The resulting client will inherit any properties of the server socket. For ## example: whether the socket is buffered or not. ## - ## **Note**: ``client`` must be initialised (with ``new``), this function - ## makes no effort to initialise the ``client`` variable. - ## ## The ``accept`` call may result in an error if the connecting socket ## disconnects during the duration of the ``accept``. If the ``SafeDisconn`` ## flag is specified then this error will not be raised and instead ## accept will be called again. - assert(client != nil) - assert client.fd.int <= 0, "Client socket needs to be initialised with " & - "`new`, not `newSocket`." + if client.isNil: + new(client) let ret = accept(server.fd) let sock = ret[0] @@ -879,9 +871,6 @@ proc accept*(server: Socket, client: var Socket, ## Equivalent to ``acceptAddr`` but doesn't return the address, only the ## socket. ## - ## **Note**: ``client`` must be initialised (with ``new``), this function - ## makes no effort to initialise the ``client`` variable. - ## ## The ``accept`` call may result in an error if the connecting socket ## disconnects during the duration of the ``accept``. If the ``SafeDisconn`` ## flag is specified then this error will not be raised and instead @@ -1339,6 +1328,7 @@ proc recvFrom*(socket: Socket, data: var string, length: int, ## used. Therefore if ``socket`` contains something in its buffer this ## function will make no effort to return it. + assert(socket.protocol != IPPROTO_TCP, "Cannot `recvFrom` on a TCP socket") # TODO: Buffered sockets data.setLen(length) var sockAddress: Sockaddr_in @@ -1408,22 +1398,25 @@ proc trySend*(socket: Socket, data: string): bool {.tags: [WriteIOEffect].} = result = send(socket, cstring(data), data.len) == data.len proc sendTo*(socket: Socket, address: string, port: Port, data: pointer, - size: int, af: Domain = AF_INET, flags = 0'i32): int {. + size: int, af: Domain = AF_INET, flags = 0'i32) {. tags: [WriteIOEffect].} = ## This proc sends ``data`` to the specified ``address``, ## which may be an IP address or a hostname, if a hostname is specified ## this function will try each IP of that hostname. ## + ## If an error occurs an OSError exception will be raised. ## ## **Note:** You may wish to use the high-level version of this function ## which is defined below. ## ## **Note:** This proc is not available for SSL sockets. + assert(socket.protocol != IPPROTO_TCP, "Cannot `sendTo` on a TCP socket") assert(not socket.isClosed, "Cannot `sendTo` on a closed socket") var aiList = getAddrInfo(address, port, af, socket.sockType, socket.protocol) # try all possibilities: var success = false var it = aiList + var result = 0 while it != nil: result = sendto(socket.fd, data, size.cint, flags.cint, it.ai_addr, it.ai_addrlen.SockLen) @@ -1432,16 +1425,22 @@ proc sendTo*(socket: Socket, address: string, port: Port, data: pointer, break it = it.ai_next + let osError = osLastError() freeAddrInfo(aiList) + if not success: + raiseOSError(osError) + proc sendTo*(socket: Socket, address: string, port: Port, - data: string): int {.tags: [WriteIOEffect].} = + data: string) {.tags: [WriteIOEffect].} = ## This proc sends ``data`` to the specified ``address``, ## which may be an IP address or a hostname, if a hostname is specified ## this function will try each IP of that hostname. ## + ## If an error occurs an OSError exception will be raised. + ## ## This is the high-level version of the above ``sendTo`` function. - result = socket.sendTo(address, port, cstring(data), data.len, socket.domain ) + socket.sendTo(address, port, cstring(data), data.len, socket.domain) proc isSsl*(socket: Socket): bool = diff --git a/lib/pure/os.nim b/lib/pure/os.nim index 8fbc20bb5..2b3cf5142 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -233,7 +233,7 @@ proc fileNewer*(a, b: string): bool {.rtl, extern: "nos$1".} = ## modification time is later than `b`'s. when defined(posix): # If we don't have access to nanosecond resolution, use '>=' - when not StatHasNanoseconds: + when not StatHasNanoseconds: result = getLastModificationTime(a) >= getLastModificationTime(b) else: result = getLastModificationTime(a) > getLastModificationTime(b) @@ -1343,16 +1343,21 @@ elif defined(windows): # is always the same -- independent of the used C compiler. var ownArgv {.threadvar.}: seq[string] + ownParsedArgv {.threadvar.}: bool proc paramCount*(): int {.rtl, extern: "nos$1", tags: [ReadIOEffect].} = # Docstring in nimdoc block. - if isNil(ownArgv): ownArgv = parseCmdLine($getCommandLine()) + if not ownParsedArgv: + ownArgv = parseCmdLine($getCommandLine()) + ownParsedArgv = true result = ownArgv.len-1 proc paramStr*(i: int): TaintedString {.rtl, extern: "nos$1", tags: [ReadIOEffect].} = # Docstring in nimdoc block. - if isNil(ownArgv): ownArgv = parseCmdLine($getCommandLine()) + if not ownParsedArgv: + ownArgv = parseCmdLine($getCommandLine()) + ownParsedArgv = true if i < ownArgv.len and i >= 0: return TaintedString(ownArgv[i]) raise newException(IndexError, "invalid index") diff --git a/lib/pure/ospaths.nim b/lib/pure/ospaths.nim index 0414eae5d..bc6739dd3 100644 --- a/lib/pure/ospaths.nim +++ b/lib/pure/ospaths.nim @@ -449,6 +449,31 @@ proc isAbsolute*(path: string): bool {.rtl, noSideEffect, extern: "nos$1".} = elif defined(posix): result = path[0] == '/' + +proc normalizePathEnd(path: var string, trailingSep = false) = + ## ensures ``path`` has exactly 0 or 1 trailing `DirSep`, depending on + ## ``trailingSep``, and taking care of edge cases: it preservers whether + ## a path is absolute or relative, and makes sure trailing sep is `DirSep`, + ## not `AltSep`. + if path.len == 0: return + var i = path.len + while i >= 1 and path[i-1] in {DirSep, AltSep}: dec(i) + if trailingSep: + # foo// => foo + path.setLen(i) + # foo => foo/ + path.add DirSep + elif i>0: + # foo// => foo + path.setLen(i) + else: + # // => / (empty case was already taken care of) + path = $DirSep + +proc normalizePathEnd(path: string, trailingSep = false): string = + result = path + result.normalizePathEnd(trailingSep) + proc unixToNativePath*(path: string, drive=""): string {. noSideEffect, rtl, extern: "nos$1".} = ## Converts an UNIX-like path to a native one. @@ -530,10 +555,12 @@ proc getConfigDir*(): string {.rtl, extern: "nos$1", ## "~/.config/", otherwise. ## ## An OS-dependent trailing slash is always present at the end of the - ## returned string; `\\` on Windows and `/` on all other OSs. - when defined(windows): return string(getEnv("APPDATA")) & "\\" - elif getEnv("XDG_CONFIG_HOME"): return string(getEnv("XDG_CONFIG_HOME")) & "/" - else: return string(getEnv("HOME")) & "/.config/" + ## returned string; `\` on Windows and `/` on all other OSs. + when defined(windows): + result = getEnv("APPDATA").string + else: + result = getEnv("XDG_CONFIG_HOME", getEnv("HOME").string / ".config").string + result.normalizePathEnd(trailingSep = true) proc getTempDir*(): string {.rtl, extern: "nos$1", tags: [ReadEnvEffect, ReadIOEffect].} = @@ -647,3 +674,24 @@ when isMainModule: when defined(posix): assert quoteShell("") == "''" + + block normalizePathEndTest: + # handle edge cases correctly: shouldn't affect whether path is + # absolute/relative + doAssert "".normalizePathEnd(true) == "" + doAssert "".normalizePathEnd(false) == "" + doAssert "/".normalizePathEnd(true) == $DirSep + doAssert "/".normalizePathEnd(false) == $DirSep + + when defined(posix): + doAssert "//".normalizePathEnd(false) == "/" + doAssert "foo.bar//".normalizePathEnd == "foo.bar" + doAssert "bar//".normalizePathEnd(trailingSep = true) == "bar/" + when defined(Windows): + doAssert r"C:\foo\\".normalizePathEnd == r"C:\foo" + doAssert r"C:\foo".normalizePathEnd(trailingSep = true) == r"C:\foo\" + # this one is controversial: we could argue for returning `D:\` instead, + # but this is simplest. + doAssert r"D:\".normalizePathEnd == r"D:" + doAssert r"E:/".normalizePathEnd(trailingSep = true) == r"E:\" + doAssert "/".normalizePathEnd == r"\" diff --git a/lib/pure/osproc.nim b/lib/pure/osproc.nim index f86acfc49..faeb01407 100644 --- a/lib/pure/osproc.nim +++ b/lib/pure/osproc.nim @@ -884,9 +884,11 @@ elif not defined(useNimRtl): chck posix_spawn_file_actions_adddup2(fops, data.pStdin[readIdx], readIdx) chck posix_spawn_file_actions_addclose(fops, data.pStdout[readIdx]) chck posix_spawn_file_actions_adddup2(fops, data.pStdout[writeIdx], writeIdx) - if (poStdErrToStdOut in data.options): - chck posix_spawn_file_actions_addclose(fops, data.pStderr[readIdx]) + chck posix_spawn_file_actions_addclose(fops, data.pStderr[readIdx]) + if poStdErrToStdOut in data.options: chck posix_spawn_file_actions_adddup2(fops, data.pStdout[writeIdx], 2) + else: + chck posix_spawn_file_actions_adddup2(fops, data.pStderr[writeIdx], 2) var res: cint if data.workingDir.len > 0: diff --git a/lib/pure/parsecfg.nim b/lib/pure/parsecfg.nim index 5fa2d8dc3..b991dd57f 100644 --- a/lib/pure/parsecfg.nim +++ b/lib/pure/parsecfg.nim @@ -17,12 +17,37 @@ ## ## .. include:: ../../doc/mytest.cfg ## :literal: -## The file ``examples/parsecfgex.nim`` demonstrates how to use the -## configuration file parser: -## -## .. code-block:: nim -## :file: ../../examples/parsecfgex.nim ## + +##[ Here is an example of how to use the configuration file parser: + +.. code-block:: nim + + import + os, parsecfg, strutils, streams + + var f = newFileStream(paramStr(1), fmRead) + if f != nil: + var p: CfgParser + open(p, f, paramStr(1)) + while true: + var e = next(p) + case e.kind + of cfgEof: break + of cfgSectionStart: ## a ``[section]`` has been parsed + echo("new section: " & e.section) + of cfgKeyValuePair: + echo("key-value-pair: " & e.key & ": " & e.value) + of cfgOption: + echo("command: " & e.key & ": " & e.value) + of cfgError: + echo(e.msg) + close(p) + else: + echo("cannot open: " & paramStr(1)) + +]## + ## Examples ## -------- ## diff --git a/lib/pure/parseopt.nim b/lib/pure/parseopt.nim index 58e1be0e4..c91134738 100644 --- a/lib/pure/parseopt.nim +++ b/lib/pure/parseopt.nim @@ -49,20 +49,24 @@ type inShortState: bool shortNoVal: set[char] longNoVal: seq[string] + cmds: seq[string] + idx: int kind*: CmdLineKind ## the dected command line token key*, val*: TaintedString ## key and value pair; ``key`` is the option ## or the argument, ``value`` is not "" if ## the option was given a value proc parseWord(s: string, i: int, w: var string, - delim: set[char] = {'\x09', ' '}): int = + delim: set[char] = {'\t', ' '}): int = result = i if result < s.len and s[result] == '\"': inc(result) - while result < s.len and s[result] != '\"': + while result < s.len: + if s[result] == '"': + inc result + break add(w, s[result]) inc(result) - if result < s.len and s[result] == '\"': inc(result) else: while result < s.len and s[result] notin delim: add(w, s[result]) @@ -73,7 +77,7 @@ when declared(os.paramCount): if find(s, {' ', '\t'}) >= 0 and s.len > 0 and s[0] != '"': if s[0] == '-': result = newStringOfCap(s.len) - var i = parseWord(s, 0, result, {' ', '\x09', ':', '='}) + var i = parseWord(s, 0, result, {' ', '\t', ':', '='}) if i < s.len and s[i] in {':','='}: result.add s[i] inc i @@ -100,16 +104,21 @@ when declared(os.paramCount): ## (though they still need at least a space). In both cases, ':' or '=' ## may still be used if desired. They just become optional. result.pos = 0 + result.idx = 0 result.inShortState = false result.shortNoVal = shortNoVal result.longNoVal = longNoVal if cmdline != "": result.cmd = cmdline + result.cmds = parseCmdLine(cmdline) else: result.cmd = "" + result.cmds = newSeq[string](paramCount()) for i in countup(1, paramCount()): - result.cmd.add quote(paramStr(i).string) + result.cmds[i-1] = paramStr(i).string + result.cmd.add quote(result.cmds[i-1]) result.cmd.add ' ' + result.kind = cmdEnd result.key = TaintedString"" result.val = TaintedString"" @@ -120,80 +129,115 @@ when declared(os.paramCount): ## (as provided by the ``OS`` module) is taken. ``shortNoVal`` and ## ``longNoVal`` behavior is the same as for ``initOptParser(string,...)``. result.pos = 0 + result.idx = 0 result.inShortState = false result.shortNoVal = shortNoVal result.longNoVal = longNoVal result.cmd = "" if cmdline.len != 0: + result.cmds = newSeq[string](cmdline.len) for i in 0..<cmdline.len: + result.cmds[i] = cmdline[i].string result.cmd.add quote(cmdline[i].string) result.cmd.add ' ' else: + result.cmds = newSeq[string](paramCount()) for i in countup(1, paramCount()): - result.cmd.add quote(paramStr(i).string) + result.cmds[i-1] = paramStr(i).string + result.cmd.add quote(result.cmds[i-1]) result.cmd.add ' ' result.kind = cmdEnd result.key = TaintedString"" result.val = TaintedString"" -proc handleShortOption(p: var OptParser) = +proc handleShortOption(p: var OptParser; cmd: string) = var i = p.pos p.kind = cmdShortOption - add(p.key.string, p.cmd[i]) + add(p.key.string, cmd[i]) inc(i) p.inShortState = true - while i < p.cmd.len and p.cmd[i] in {'\x09', ' '}: + while i < cmd.len and cmd[i] in {'\t', ' '}: inc(i) p.inShortState = false - if i < p.cmd.len and p.cmd[i] in {':', '='} or + if i < cmd.len and cmd[i] in {':', '='} or card(p.shortNoVal) > 0 and p.key.string[0] notin p.shortNoVal: - if i < p.cmd.len and p.cmd[i] in {':', '='}: + if i < cmd.len and cmd[i] in {':', '='}: inc(i) p.inShortState = false - while i < p.cmd.len and p.cmd[i] in {'\x09', ' '}: inc(i) - i = parseWord(p.cmd, i, p.val.string) - if i >= p.cmd.len: p.inShortState = false - p.pos = i + while i < cmd.len and cmd[i] in {'\t', ' '}: inc(i) + p.val = TaintedString substr(cmd, i) + p.pos = 0 + inc p.idx + else: + p.pos = i + if i >= cmd.len: + p.inShortState = false + p.pos = 0 + inc p.idx proc next*(p: var OptParser) {.rtl, extern: "npo$1".} = ## parses the first or next option; ``p.kind`` describes what token has been ## parsed. ``p.key`` and ``p.val`` are set accordingly. + if p.idx >= p.cmds.len: + p.kind = cmdEnd + return + var i = p.pos - while i < p.cmd.len and p.cmd[i] in {'\x09', ' '}: inc(i) + while i < p.cmds[p.idx].len and p.cmds[p.idx][i] in {'\t', ' '}: inc(i) p.pos = i setLen(p.key.string, 0) setLen(p.val.string, 0) if p.inShortState: - handleShortOption(p) - return - if i >= p.cmd.len: - p.kind = cmdEnd - return - if p.cmd[i] == '-': + p.inShortState = false + if i >= p.cmds[p.idx].len: + inc(p.idx) + p.pos = 0 + if p.idx >= p.cmds.len: + p.kind = cmdEnd + return + else: + handleShortOption(p, p.cmds[p.idx]) + return + + if i < p.cmds[p.idx].len and p.cmds[p.idx][i] == '-': inc(i) - if i < p.cmd.len and p.cmd[i] == '-': + if i < p.cmds[p.idx].len and p.cmds[p.idx][i] == '-': p.kind = cmdLongOption inc(i) - i = parseWord(p.cmd, i, p.key.string, {' ', '\x09', ':', '='}) - while i < p.cmd.len and p.cmd[i] in {'\x09', ' '}: inc(i) - if i < p.cmd.len and p.cmd[i] in {':', '='} or - len(p.longNoVal) > 0 and p.key.string notin p.longNoVal: - if i < p.cmd.len and p.cmd[i] in {':', '='}: - inc(i) - while i < p.cmd.len and p.cmd[i] in {'\x09', ' '}: inc(i) - p.pos = parseWord(p.cmd, i, p.val.string) + i = parseWord(p.cmds[p.idx], i, p.key.string, {' ', '\t', ':', '='}) + while i < p.cmds[p.idx].len and p.cmds[p.idx][i] in {'\t', ' '}: inc(i) + if i < p.cmds[p.idx].len and p.cmds[p.idx][i] in {':', '='}: + 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 i >= p.cmds[p.idx].len and p.idx < p.cmds.len: + inc p.idx + i = 0 + p.val = TaintedString p.cmds[p.idx].substr(i) + elif len(p.longNoVal) > 0 and p.key.string notin p.longNoVal and p.idx+1 < p.cmds.len: + p.val = TaintedString p.cmds[p.idx+1] + inc p.idx else: - p.pos = i + p.val = TaintedString"" + inc p.idx + p.pos = 0 else: p.pos = i - handleShortOption(p) + handleShortOption(p, p.cmds[p.idx]) else: p.kind = cmdArgument - p.pos = parseWord(p.cmd, i, p.key.string) + p.key = TaintedString p.cmds[p.idx] + inc p.idx + p.pos = 0 -proc cmdLineRest*(p: OptParser): TaintedString {.rtl, extern: "npo$1".} = - ## retrieves the rest of the command line that has not been parsed yet. - result = strip(substr(p.cmd, p.pos, len(p.cmd) - 1)).TaintedString +when declared(os.paramCount): + proc cmdLineRest*(p: OptParser): TaintedString {.rtl, extern: "npo$1".} = + ## retrieves the rest of the command line that has not been parsed yet. + var res = "" + for i in p.idx..<p.cmds.len: + if i > p.idx: res.add ' ' + res.add quote(p.cmds[i]) + result = res.TaintedString iterator getopt*(p: var OptParser): tuple[kind: CmdLineKind, key, val: TaintedString] = ## This is an convenience iterator for iterating over the given OptParser object. @@ -214,6 +258,7 @@ iterator getopt*(p: var OptParser): tuple[kind: CmdLineKind, key, val: TaintedSt ## # no filename has been given, so we show the help: ## writeHelp() p.pos = 0 + p.idx = 0 while true: next(p) if p.kind == cmdEnd: break diff --git a/lib/pure/parsesql.nim b/lib/pure/parsesql.nim index e3bab9a8d..9aef43c1b 100644 --- a/lib/pure/parsesql.nim +++ b/lib/pure/parsesql.nim @@ -593,7 +593,6 @@ proc len*(n: SqlNode): int = proc `[]`*(n: SqlNode; i: int): SqlNode = n.sons[i] proc add*(father, n: SqlNode) = - if isNil(father.sons): father.sons = @[] add(father.sons, n) proc getTok(p: var SqlParser) = diff --git a/lib/pure/parsexml.nim b/lib/pure/parsexml.nim index fe933fb79..d8d5a7a2d 100644 --- a/lib/pure/parsexml.nim +++ b/lib/pure/parsexml.nim @@ -26,27 +26,125 @@ ## creates. ## ## -## Example 1: Retrieve HTML title -## ============================== -## -## The file ``examples/htmltitle.nim`` demonstrates how to use the -## XML parser to accomplish a simple task: To determine the title of an HTML -## document. -## -## .. code-block:: nim -## :file: ../../examples/htmltitle.nim -## -## -## Example 2: Retrieve all HTML links -## ================================== -## -## The file ``examples/htmlrefs.nim`` demonstrates how to use the -## XML parser to accomplish another simple task: To determine all the links -## an HTML document contains. -## -## .. code-block:: nim -## :file: ../../examples/htmlrefs.nim -## + +##[ + +Example 1: Retrieve HTML title +============================== + +The file ``examples/htmltitle.nim`` demonstrates how to use the +XML parser to accomplish a simple task: To determine the title of an HTML +document. + +.. code-block:: nim + + # Example program to show the parsexml module + # This program reads an HTML file and writes its title to stdout. + # Errors and whitespace are ignored. + + import os, streams, parsexml, strutils + + if paramCount() < 1: + quit("Usage: htmltitle filename[.html]") + + var filename = addFileExt(paramStr(1), "html") + var s = newFileStream(filename, fmRead) + if s == nil: quit("cannot open the file " & filename) + var x: XmlParser + open(x, s, filename) + while true: + x.next() + case x.kind + of xmlElementStart: + if cmpIgnoreCase(x.elementName, "title") == 0: + var title = "" + x.next() # skip "<title>" + while x.kind == xmlCharData: + title.add(x.charData) + x.next() + if x.kind == xmlElementEnd and cmpIgnoreCase(x.elementName, "title") == 0: + echo("Title: " & title) + quit(0) # Success! + else: + echo(x.errorMsgExpected("/title")) + + of xmlEof: break # end of file reached + else: discard # ignore other events + + x.close() + quit("Could not determine title!") + +]## + +##[ + +Example 2: Retrieve all HTML links +================================== + +The file ``examples/htmlrefs.nim`` demonstrates how to use the +XML parser to accomplish another simple task: To determine all the links +an HTML document contains. + +.. code-block:: nim + + # Example program to show the new parsexml module + # This program reads an HTML file and writes all its used links to stdout. + # Errors and whitespace are ignored. + + import os, streams, parsexml, strutils + + proc `=?=` (a, b: string): bool = + # little trick: define our own comparator that ignores case + return cmpIgnoreCase(a, b) == 0 + + if paramCount() < 1: + quit("Usage: htmlrefs filename[.html]") + + var links = 0 # count the number of links + var filename = addFileExt(paramStr(1), "html") + var s = newFileStream(filename, fmRead) + if s == nil: quit("cannot open the file " & filename) + var x: XmlParser + open(x, s, filename) + next(x) # get first event + block mainLoop: + while true: + case x.kind + of xmlElementOpen: + # the <a href = "xyz"> tag we are interested in always has an attribute, + # thus we search for ``xmlElementOpen`` and not for ``xmlElementStart`` + if x.elementName =?= "a": + x.next() + if x.kind == xmlAttribute: + if x.attrKey =?= "href": + var link = x.attrValue + inc(links) + # skip until we have an ``xmlElementClose`` event + while true: + x.next() + case x.kind + of xmlEof: break mainLoop + of xmlElementClose: break + else: discard + x.next() # skip ``xmlElementClose`` + # now we have the description for the ``a`` element + var desc = "" + while x.kind == xmlCharData: + desc.add(x.charData) + x.next() + echo(desc & ": " & link) + else: + x.next() + of xmlEof: break # end of file reached + of xmlError: + echo(errorMsg(x)) + x.next() + else: x.next() # skip other events + + echo($links & " link(s) found!") + x.close() + +]## import hashes, strutils, lexbase, streams, unicode diff --git a/lib/pure/pegs.nim b/lib/pure/pegs.nim index 02a2d6900..3ee82917d 100644 --- a/lib/pure/pegs.nim +++ b/lib/pure/pegs.nim @@ -20,11 +20,11 @@ include "system/inclrtl" const useUnicode = true ## change this to deactivate proper UTF-8 support -import - strutils +import strutils, macros when useUnicode: import unicode + export unicode.`==` const InlineThreshold = 5 ## number of leaves; -1 to disable inlining @@ -74,7 +74,7 @@ type line: int ## line the symbol has been declared/used in col: int ## column the symbol has been declared/used in flags: set[NonTerminalFlag] ## the nonterminal's flags - rule: Peg ## the rule that the symbol refers to + rule: Peg ## the rule that the symbol refers to Peg* {.shallow.} = object ## type that represents a PEG case kind: PegKind of pkEmpty..pkWhitespace: nil @@ -86,25 +86,59 @@ type else: sons: seq[Peg] NonTerminal* = ref NonTerminalObj -proc name*(nt: NonTerminal): string = nt.name -proc line*(nt: NonTerminal): int = nt.line -proc col*(nt: NonTerminal): int = nt.col -proc flags*(nt: NonTerminal): set[NonTerminalFlag] = nt.flags -proc rule*(nt: NonTerminal): Peg = nt.rule - proc kind*(p: Peg): PegKind = p.kind + ## Returns the *PegKind* of a given *Peg* object. + proc term*(p: Peg): string = p.term + ## Returns the *string* representation of a given *Peg* variant object + ## where present. + proc ch*(p: Peg): char = p.ch + ## Returns the *char* representation of a given *Peg* variant object + ## where present. + proc charChoice*(p: Peg): ref set[char] = p.charChoice + ## Returns the *charChoice* field of a given *Peg* variant object + ## where present. + proc nt*(p: Peg): NonTerminal = p.nt + ## Returns the *NonTerminal* object of a given *Peg* variant object + ## where present. + proc index*(p: Peg): range[0..MaxSubpatterns] = p.index + ## Returns the back-reference index of a captured sub-pattern in the + ## *Captures* object for a given *Peg* variant object where present. + iterator items*(p: Peg): Peg {.inline.} = + ## Yields the child nodes of a *Peg* variant object where present. for s in p.sons: yield s + iterator pairs*(p: Peg): (int, Peg) {.inline.} = + ## Yields the indices and child nodes of a *Peg* variant object where present. for i in 0 ..< p.sons.len: yield (i, p.sons[i]) +proc name*(nt: NonTerminal): string = nt.name + ## Gets the name of the symbol represented by the parent *Peg* object variant + ## of a given *NonTerminal*. + +proc line*(nt: NonTerminal): int = nt.line + ## Gets the line number of the definition of the parent *Peg* object variant + ## of a given *NonTerminal*. + +proc col*(nt: NonTerminal): int = nt.col + ## Gets the column number of the definition of the parent *Peg* object variant + ## of a given *NonTerminal*. + +proc flags*(nt: NonTerminal): set[NonTerminalFlag] = nt.flags + ## Gets the *NonTerminalFlag*-typed flags field of the parent *Peg* variant + ## object of a given *NonTerminal*. + +proc rule*(nt: NonTerminal): Peg = nt.rule + ## Gets the *Peg* object representing the rule definition of the parent *Peg* + ## object variant of a given *NonTerminal*. + proc term*(t: string): Peg {.nosideEffect, rtl, extern: "npegs$1Str".} = ## constructs a PEG from a terminal string if t.len != 1: @@ -540,223 +574,497 @@ when not useUnicode: proc isTitle(a: char): bool {.inline.} = return false proc isWhiteSpace(a: char): bool {.inline.} = return a in {' ', '\9'..'\13'} -proc rawMatch*(s: string, p: Peg, start: int, c: var Captures): int {. - nosideEffect, rtl, extern: "npegs$1".} = - ## low-level matching proc that implements the PEG interpreter. Use this - ## for maximum efficiency (every other PEG operation ends up calling this - ## proc). - ## Returns -1 if it does not match, else the length of the match - case p.kind - of pkEmpty: result = 0 # match of length 0 - of pkAny: - if start < s.len: result = 1 - else: result = -1 - of pkAnyRune: - if start < s.len: - result = runeLenAt(s, start) - else: - result = -1 - of pkLetter: - if start < s.len: - var a: Rune - result = start - fastRuneAt(s, result, a) - if isAlpha(a): dec(result, start) - else: result = -1 - else: - result = -1 - of pkLower: - if start < s.len: - var a: Rune - result = start - fastRuneAt(s, result, a) - if isLower(a): dec(result, start) - else: result = -1 - else: - result = -1 - of pkUpper: - if start < s.len: - var a: Rune - result = start - fastRuneAt(s, result, a) - if isUpper(a): dec(result, start) - else: result = -1 - else: - result = -1 - of pkTitle: - if start < s.len: - var a: Rune - result = start - fastRuneAt(s, result, a) - if isTitle(a): dec(result, start) +template matchOrParse(mopProc: untyped): typed = + # Used to make the main matcher proc *rawMatch* as well as event parser + # procs. For the former, *enter* and *leave* event handler code generators + # are provided which just return *discard*. + + proc mopProc(s: string, p: Peg, start: int, c: var Captures): int = + proc matchBackRef(s: string, p: Peg, start: int, c: var Captures): int = + # Parse handler code must run in an *of* clause of its own for each + # *PegKind*, so we encapsulate the identical clause body for + # *pkBackRef..pkBackRefIgnoreStyle* here. + if p.index >= c.ml: return -1 + var (a, b) = c.matches[p.index] + var n: Peg + n.kind = succ(pkTerminal, ord(p.kind)-ord(pkBackRef)) + n.term = s.substr(a, b) + mopProc(s, n, start, c) + + case p.kind + of pkEmpty: + enter(pkEmpty, s, p, start) + result = 0 # match of length 0 + leave(pkEmpty, s, p, start, result) + of pkAny: + enter(pkAny, s, p, start) + if start < s.len: result = 1 else: result = -1 - else: - result = -1 - of pkWhitespace: - if start < s.len: - var a: Rune - result = start - fastRuneAt(s, result, a) - if isWhiteSpace(a): dec(result, start) - else: result = -1 - else: - result = -1 - of pkGreedyAny: - result = len(s) - start - of pkNewLine: - if start < s.len and s[start] == '\L': result = 1 - elif start < s.len and s[start] == '\C': - if start+1 < s.len and s[start+1] == '\L': result = 2 - else: result = 1 - else: result = -1 - of pkTerminal: - result = len(p.term) - for i in 0..result-1: - if start+i >= s.len or p.term[i] != s[start+i]: + leave(pkAny, s, p, start, result) + of pkAnyRune: + enter(pkAnyRune, s, p, start) + if start < s.len: + result = runeLenAt(s, start) + else: result = -1 - break - of pkTerminalIgnoreCase: - var - i = 0 - a, b: Rune - result = start - while i < len(p.term): - if result >= s.len: + leave(pkAnyRune, s, p, start, result) + of pkLetter: + enter(pkLetter, s, p, start) + if start < s.len: + var a: Rune + result = start + fastRuneAt(s, result, a) + if isAlpha(a): dec(result, start) + else: result = -1 + else: + result = -1 + leave(pkLetter, s, p, start, result) + of pkLower: + enter(pkLower, s, p, start) + if start < s.len: + var a: Rune + result = start + fastRuneAt(s, result, a) + if isLower(a): dec(result, start) + else: result = -1 + else: result = -1 - break - fastRuneAt(p.term, i, a) - fastRuneAt(s, result, b) - if toLower(a) != toLower(b): + leave(pkLower, s, p, start, result) + of pkUpper: + enter(pkUpper, s, p, start) + if start < s.len: + var a: Rune + result = start + fastRuneAt(s, result, a) + if isUpper(a): dec(result, start) + else: result = -1 + else: result = -1 - break - dec(result, start) - of pkTerminalIgnoreStyle: - var - i = 0 - a, b: Rune - result = start - while i < len(p.term): + leave(pkUpper, s, p, start, result) + of pkTitle: + enter(pkTitle, s, p, start) + if start < s.len: + var a: Rune + result = start + fastRuneAt(s, result, a) + if isTitle(a): dec(result, start) + else: result = -1 + else: + result = -1 + leave(pkTitle, s, p, start, result) + of pkWhitespace: + enter(pkWhitespace, s, p, start) + if start < s.len: + var a: Rune + result = start + fastRuneAt(s, result, a) + if isWhiteSpace(a): dec(result, start) + else: result = -1 + else: + result = -1 + leave(pkWhitespace, s, p, start, result) + of pkGreedyAny: + enter(pkGreedyAny, s, p, start) + result = len(s) - start + leave(pkGreedyAny, s, p, start, result) + of pkNewLine: + enter(pkNewLine, s, p, start) + if start < s.len and s[start] == '\L': result = 1 + elif start < s.len and s[start] == '\C': + if start+1 < s.len and s[start+1] == '\L': result = 2 + else: result = 1 + else: result = -1 + leave(pkNewLine, s, p, start, result) + of pkTerminal: + enter(pkTerminal, s, p, start) + result = len(p.term) + for i in 0..result-1: + if start+i >= s.len or p.term[i] != s[start+i]: + result = -1 + break + leave(pkTerminal, s, p, start, result) + of pkTerminalIgnoreCase: + enter(pkTerminalIgnoreCase, s, p, start) + var + i = 0 + a, b: Rune + result = start while i < len(p.term): + if result >= s.len: + result = -1 + break fastRuneAt(p.term, i, a) - if a != Rune('_'): break - while result < s.len: fastRuneAt(s, result, b) - if b != Rune('_'): break - if result >= s.len: - if i >= p.term.len: break - else: + if toLower(a) != toLower(b): result = -1 break - elif toLower(a) != toLower(b): - result = -1 - break - dec(result, start) - of pkChar: - if start < s.len and p.ch == s[start]: result = 1 - else: result = -1 - of pkCharChoice: - if start < s.len and contains(p.charChoice[], s[start]): result = 1 - else: result = -1 - of pkNonTerminal: - var oldMl = c.ml - when false: echo "enter: ", p.nt.name - result = rawMatch(s, p.nt.rule, start, c) - when false: echo "leave: ", p.nt.name - if result < 0: c.ml = oldMl - of pkSequence: - var oldMl = c.ml - result = 0 - for i in 0..high(p.sons): - var x = rawMatch(s, p.sons[i], start+result, c) - if x < 0: + dec(result, start) + leave(pkTerminalIgnoreCase, s, p, start, result) + of pkTerminalIgnoreStyle: + enter(pkTerminalIgnoreStyle, s, p, start) + var + i = 0 + a, b: Rune + result = start + while i < len(p.term): + while i < len(p.term): + fastRuneAt(p.term, i, a) + if a != Rune('_'): break + while result < s.len: + fastRuneAt(s, result, b) + if b != Rune('_'): break + if result >= s.len: + if i >= p.term.len: break + else: + result = -1 + break + elif toLower(a) != toLower(b): + result = -1 + break + dec(result, start) + leave(pkTerminalIgnoreStyle, s, p, start, result) + of pkChar: + enter(pkChar, s, p, start) + if start < s.len and p.ch == s[start]: result = 1 + else: result = -1 + leave(pkChar, s, p, start, result) + of pkCharChoice: + enter(pkCharChoice, s, p, start) + if start < s.len and contains(p.charChoice[], s[start]): result = 1 + else: result = -1 + leave(pkCharChoice, s, p, start, result) + of pkNonTerminal: + enter(pkNonTerminal, s, p, start) + var oldMl = c.ml + when false: echo "enter: ", p.nt.name + result = mopProc(s, p.nt.rule, start, c) + when false: echo "leave: ", p.nt.name + if result < 0: c.ml = oldMl + leave(pkNonTerminal, s, p, start, result) + of pkSequence: + enter(pkSequence, s, p, start) + var oldMl = c.ml + result = 0 + for i in 0..high(p.sons): + var x = mopProc(s, p.sons[i], start+result, c) + if x < 0: + c.ml = oldMl + result = -1 + break + else: inc(result, x) + leave(pkSequence, s, p, start, result) + of pkOrderedChoice: + enter(pkOrderedChoice, s, p, start) + var oldMl = c.ml + for i in 0..high(p.sons): + result = mopProc(s, p.sons[i], start, c) + if result >= 0: break c.ml = oldMl - result = -1 - break - else: inc(result, x) - of pkOrderedChoice: - var oldMl = c.ml - for i in 0..high(p.sons): - result = rawMatch(s, p.sons[i], start, c) - if result >= 0: break + leave(pkOrderedChoice, s, p, start, result) + of pkSearch: + enter(pkSearch, s, p, start) + var oldMl = c.ml + result = 0 + while start+result <= s.len: + var x = mopProc(s, p.sons[0], start+result, c) + if x >= 0: + inc(result, x) + leave(pkSearch, s, p, start, result) + return + inc(result) + result = -1 c.ml = oldMl - of pkSearch: - var oldMl = c.ml - result = 0 - while start+result <= s.len: - var x = rawMatch(s, p.sons[0], start+result, c) - if x >= 0: + leave(pkSearch, s, p, start, result) + of pkCapturedSearch: + enter(pkCapturedSearch, s, p, start) + var idx = c.ml # reserve a slot for the subpattern + inc(c.ml) + result = 0 + while start+result <= s.len: + var x = mopProc(s, p.sons[0], start+result, c) + if x >= 0: + if idx < MaxSubpatterns: + c.matches[idx] = (start, start+result-1) + #else: silently ignore the capture + inc(result, x) + leave(pkCapturedSearch, s, p, start, result) + return + inc(result) + result = -1 + c.ml = idx + leave(pkCapturedSearch, s, p, start, result) + of pkGreedyRep: + enter(pkGreedyRep, s, p, start) + result = 0 + while true: + var x = mopProc(s, p.sons[0], start+result, c) + # if x == 0, we have an endless loop; so the correct behaviour would be + # not to break. But endless loops can be easily introduced: + # ``(comment / \w*)*`` is such an example. Breaking for x == 0 does the + # expected thing in this case. + if x <= 0: break inc(result, x) - return - inc(result) - result = -1 - c.ml = oldMl - of pkCapturedSearch: - var idx = c.ml # reserve a slot for the subpattern - inc(c.ml) - result = 0 - while start+result <= s.len: - var x = rawMatch(s, p.sons[0], start+result, c) - if x >= 0: + leave(pkGreedyRep, s, p, start, result) + of pkGreedyRepChar: + enter(pkGreedyRepChar, s, p, start) + result = 0 + var ch = p.ch + while start+result < s.len and ch == s[start+result]: inc(result) + leave(pkGreedyRepChar, s, p, start, result) + of pkGreedyRepSet: + enter(pkGreedyRepSet, s, p, start) + result = 0 + while start+result < s.len and contains(p.charChoice[], s[start+result]): inc(result) + leave(pkGreedyRepSet, s, p, start, result) + of pkOption: + enter(pkOption, s, p, start) + result = max(0, mopProc(s, p.sons[0], start, c)) + leave(pkOption, s, p, start, result) + of pkAndPredicate: + enter(pkAndPredicate, s, p, start) + var oldMl = c.ml + result = mopProc(s, p.sons[0], start, c) + if result >= 0: result = 0 # do not consume anything + else: c.ml = oldMl + leave(pkAndPredicate, s, p, start, result) + of pkNotPredicate: + enter(pkNotPredicate, s, p, start) + var oldMl = c.ml + result = mopProc(s, p.sons[0], start, c) + if result < 0: result = 0 + else: + c.ml = oldMl + result = -1 + leave(pkNotPredicate, s, p, start, result) + of pkCapture: + enter(pkCapture, s, p, start) + var idx = c.ml # reserve a slot for the subpattern + inc(c.ml) + result = mopProc(s, p.sons[0], start, c) + if result >= 0: if idx < MaxSubpatterns: c.matches[idx] = (start, start+result-1) #else: silently ignore the capture - inc(result, x) - return - inc(result) - result = -1 - c.ml = idx - of pkGreedyRep: - result = 0 - while true: - var x = rawMatch(s, p.sons[0], start+result, c) - # if x == 0, we have an endless loop; so the correct behaviour would be - # not to break. But endless loops can be easily introduced: - # ``(comment / \w*)*`` is such an example. Breaking for x == 0 does the - # expected thing in this case. - if x <= 0: break - inc(result, x) - of pkGreedyRepChar: - result = 0 - var ch = p.ch - while start+result < s.len and ch == s[start+result]: inc(result) - of pkGreedyRepSet: - result = 0 - while start+result < s.len and contains(p.charChoice[], s[start+result]): inc(result) - of pkOption: - result = max(0, rawMatch(s, p.sons[0], start, c)) - of pkAndPredicate: - var oldMl = c.ml - result = rawMatch(s, p.sons[0], start, c) - if result >= 0: result = 0 # do not consume anything - else: c.ml = oldMl - of pkNotPredicate: - var oldMl = c.ml - result = rawMatch(s, p.sons[0], start, c) - if result < 0: result = 0 - else: - c.ml = oldMl - result = -1 - of pkCapture: - var idx = c.ml # reserve a slot for the subpattern - inc(c.ml) - result = rawMatch(s, p.sons[0], start, c) - if result >= 0: - if idx < MaxSubpatterns: - c.matches[idx] = (start, start+result-1) - #else: silently ignore the capture - else: - c.ml = idx - of pkBackRef..pkBackRefIgnoreStyle: - if p.index >= c.ml: return -1 - var (a, b) = c.matches[p.index] - var n: Peg - n.kind = succ(pkTerminal, ord(p.kind)-ord(pkBackRef)) - n.term = s.substr(a, b) - result = rawMatch(s, n, start, c) - of pkStartAnchor: - if c.origStart == start: result = 0 - else: result = -1 - of pkRule, pkList: assert false + else: + c.ml = idx + leave(pkCapture, s, p, start, result) + of pkBackRef: + enter(pkBackRef, s, p, start) + result = matchBackRef(s, p, start, c) + leave(pkBackRef, s, p, start, result) + of pkBackRefIgnoreCase: + enter(pkBackRefIgnoreCase, s, p, start) + result = matchBackRef(s, p, start, c) + leave(pkBackRefIgnoreCase, s, p, start, result) + of pkBackRefIgnoreStyle: + enter(pkBackRefIgnoreStyle, s, p, start) + result = matchBackRef(s, p, start, c) + leave(pkBackRefIgnoreStyle, s, p, start, result) + of pkStartAnchor: + enter(pkStartAnchor, s, p, start) + if c.origStart == start: result = 0 + else: result = -1 + leave(pkStartAnchor, s, p, start, result) + of pkRule, pkList: assert false + +proc rawMatch*(s: string, p: Peg, start: int, c: var Captures): int + {.noSideEffect, rtl, extern: "npegs$1".} = + ## low-level matching proc that implements the PEG interpreter. Use this + ## for maximum efficiency (every other PEG operation ends up calling this + ## proc). + ## Returns -1 if it does not match, else the length of the match + + # Set the handler generators to produce do-nothing handlers. + template enter(pk, s, p, start) = + discard + template leave(pk, s, p, start, length) = + discard + matchOrParse(matchIt) + result = matchIt(s, p, start, c) + +macro mkHandlerTplts(handlers: untyped): untyped = + # Transforms the handler spec in *handlers* into handler templates. + # The AST structure of *handlers[0]*: + # + # .. code-block:: + # StmtList + # Call + # Ident "pkNonTerminal" + # StmtList + # Call + # Ident "enter" + # StmtList + # <handler code block> + # Call + # Ident "leave" + # StmtList + # <handler code block> + # Call + # Ident "pkChar" + # StmtList + # Call + # Ident "leave" + # StmtList + # <handler code block> + # ... + proc mkEnter(hdName, body: NimNode): NimNode = + quote do: + template `hdName`(s, p, start) = + let s {.inject.} = s + let p {.inject.} = p + let start {.inject.} = start + `body` + + template mkLeave(hdPostf, body) {.dirty.} = + # this has to be dirty to be able to capture *result* as *length* in + # *leaveXX* calls. + template `leave hdPostf`(s, p, start, length) = + body + + result = newStmtList() + for topCall in handlers[0]: + if nnkCall != topCall.kind: + error("Call syntax expected.", topCall) + let pegKind = topCall[0] + if nnkIdent != pegKind.kind: + error("PegKind expected.", pegKind) + if 2 == topCall.len: + for hdDef in topCall[1]: + if nnkCall != hdDef.kind: + error("Call syntax expected.", hdDef) + if nnkIdent != hdDef[0].kind: + error("Handler identifier expected.", hdDef[0]) + if 2 == hdDef.len: + let hdPostf = substr(pegKind.strVal, 2) + case hdDef[0].strVal + of "enter": + result.add mkEnter(newIdentNode("enter" & hdPostf), hdDef[1]) + of "leave": + result.add getAst(mkLeave(ident(hdPostf), hdDef[1])) + else: + error( + "Unsupported handler identifier, expected 'enter' or 'leave'.", + hdDef[0] + ) + +template eventParser*(pegAst, handlers: untyped): (proc(s: string): int) = + ## Generates an interpreting event parser *proc* according to the specified + ## PEG AST and handler code blocks. The *proc* can be called with a string + ## to be parsed and will execute the handler code blocks whenever their + ## associated grammar element is matched. It returns -1 if the string does not + ## match, else the length of the total match. The following example code + ## evaluates an arithmetic expression defined by a simple PEG: + ## + ## .. code-block:: nim + ## import strutils, pegs + ## + ## let + ## pegAst = """ + ## Expr <- Sum + ## Sum <- Product (('+' / '-')Product)* + ## Product <- Value (('*' / '/')Value)* + ## Value <- [0-9]+ / '(' Expr ')' + ## """.peg + ## txt = "(5+3)/2-7*22" + ## + ## var + ## pStack: seq[string] = @[] + ## valStack: seq[float] = @[] + ## opStack = "" + ## let + ## parseArithExpr = pegAst.eventParser: + ## pkNonTerminal: + ## enter: + ## pStack.add p.nt.name + ## leave: + ## pStack.setLen pStack.high + ## if length > 0: + ## let matchStr = s.substr(start, start+length-1) + ## case p.nt.name + ## of "Value": + ## try: + ## valStack.add matchStr.parseFloat + ## echo valStack + ## except ValueError: + ## discard + ## of "Sum", "Product": + ## try: + ## let val = matchStr.parseFloat + ## except ValueError: + ## if valStack.len > 1 and opStack.len > 0: + ## valStack[^2] = case opStack[^1] + ## of '+': valStack[^2] + valStack[^1] + ## of '-': valStack[^2] - valStack[^1] + ## of '*': valStack[^2] * valStack[^1] + ## else: valStack[^2] / valStack[^1] + ## valStack.setLen valStack.high + ## echo valStack + ## opStack.setLen opStack.high + ## echo opStack + ## pkChar: + ## leave: + ## if length == 1 and "Value" != pStack[^1]: + ## let matchChar = s[start] + ## opStack.add matchChar + ## echo opStack + ## + ## let pLen = parseArithExpr(txt) + ## + ## The *handlers* parameter consists of code blocks for *PegKinds*, + ## which define the grammar elements of interest. Each block can contain + ## handler code to be executed when the parser enters and leaves text + ## matching the grammar element. An *enter* handler can access the specific + ## PEG AST node being matched as *p*, the entire parsed string as *s* + ## and the position of the matched text segment in *s* as *start*. A *leave* + ## handler can access *p*, *s*, *start* and also the length of the matched + ## text segment as *length*. For an unsuccessful match, the *enter* and + ## *leave* handlers will be executed, with *length* set to -1. + ## + ## Symbols declared in an *enter* handler can be made visible in the + ## corresponding *leave* handler by annotating them with an *inject* pragma. + proc rawParse(s: string, p: Peg, start: int, c: var Captures): int + {.genSym.} = + + # binding from *macros* + bind strVal + + mkHandlerTplts: + handlers + + macro enter(pegKind, s, pegNode, start: untyped): untyped = + # This is called by the matcher code in *matchOrParse* at the + # start of the code for a grammar element of kind *pegKind*. + # Expands to a call to the handler template if one was generated + # by *mkHandlerTplts*. + template mkDoEnter(hdPostf, s, pegNode, start) = + when declared(`enter hdPostf`): + `enter hdPostf`(s, pegNode, start): + else: + discard + let hdPostf = ident(substr(strVal(pegKind), 2)) + getAst(mkDoEnter(hdPostf, s, pegNode, start)) + + macro leave(pegKind, s, pegNode, start, length: untyped): untyped = + # Like *enter*, but called at the end of the matcher code for + # a grammar element of kind *pegKind*. + template mkDoLeave(hdPostf, s, pegNode, start, length) = + when declared(`leave hdPostf`): + `leave hdPostf`(s, pegNode, start, length): + else: + discard + let hdPostf = ident(substr(strVal(pegKind), 2)) + getAst(mkDoLeave(hdPostf, s, pegNode, start, length)) + + matchOrParse(parseIt) + parseIt(s, p, start, c) + + proc parser(s: string): int {.genSym.} = + # the proc to be returned + var + ms: array[MaxSubpatterns, (int, int)] + cs = Captures(matches: ms, ml: 0, origStart: 0) + rawParse(s, pegAst, 0, cs) + parser template fillMatches(s, caps, c) = for k in 0..c.ml-1: diff --git a/lib/pure/strscans.nim b/lib/pure/strscans.nim index 11f182495..b17eee6ff 100644 --- a/lib/pure/strscans.nim +++ b/lib/pure/strscans.nim @@ -10,7 +10,7 @@ ##[ This module contains a `scanf`:idx: macro that can be used for extracting substrings from an input string. This is often easier than regular expressions. -Some examples as an apetizer: +Some examples as an appetizer: .. code-block:: nim # check if input string matches a triple of integers: @@ -308,7 +308,7 @@ proc buildUserCall(x: string; args: varargs[NimNode]): NimNode = for i in 1..<y.len: result.add y[i] macro scanf*(input: string; pattern: static[string]; results: varargs[typed]): bool = - ## See top level documentation of his module of how ``scanf`` works. + ## See top level documentation of this module about how ``scanf`` works. template matchBind(parser) {.dirty.} = var resLen = genSym(nskLet, "resLen") conds.add newLetStmt(resLen, newCall(bindSym(parser), inp, results[i], idx)) @@ -469,7 +469,7 @@ template success*(x: int): bool = x != 0 template nxt*(input: string; idx, step: int = 1) = inc(idx, step) macro scanp*(input, idx: typed; pattern: varargs[untyped]): bool = - ## See top level documentation of his module of how ``scanf`` works. + ## See top level documentation of this module about how ``scanp`` works. type StmtTriple = tuple[init, cond, action: NimNode] template interf(x): untyped = bindSym(x, brForceOpen) diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index 33f153587..396f14972 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -820,7 +820,7 @@ proc toHex*(x: BiggestInt, len: Positive): string {.noSideEffect, # handle negative overflow if n == 0 and x < 0: n = -1 -proc toHex*[T](x: T): string = +proc toHex*[T: SomeInteger](x: T): string = ## Shortcut for ``toHex(x, T.sizeOf * 2)`` toHex(BiggestInt(x), T.sizeOf * 2) @@ -1692,14 +1692,12 @@ proc insertSep*(s: string, sep = '_', digits = 3): string {.noSideEffect, dec(L) proc escape*(s: string, prefix = "\"", suffix = "\""): string {.noSideEffect, - rtl, extern: "nsuEscape", deprecated.} = + rtl, extern: "nsuEscape".} = ## Escapes a string `s`. See `system.addEscapedChar <system.html#addEscapedChar>`_ ## for the escaping scheme. ## ## The resulting string is prefixed with `prefix` and suffixed with `suffix`. ## Both may be empty strings. - ## - ## **Warning:** This procedure is deprecated because it's to easy to missuse. result = newStringOfCap(s.len + s.len shr 2) result.add(prefix) for c in items(s): @@ -1714,7 +1712,7 @@ proc escape*(s: string, prefix = "\"", suffix = "\""): string {.noSideEffect, add(result, suffix) proc unescape*(s: string, prefix = "\"", suffix = "\""): string {.noSideEffect, - rtl, extern: "nsuUnescape", deprecated.} = + rtl, extern: "nsuUnescape".} = ## Unescapes a string `s`. ## ## This complements `escape <#escape>`_ as it performs the opposite @@ -1722,8 +1720,6 @@ proc unescape*(s: string, prefix = "\"", suffix = "\""): string {.noSideEffect, ## ## If `s` does not begin with ``prefix`` and end with ``suffix`` a ## ValueError exception will be raised. - ## - ## **Warning:** This procedure is deprecated because it's to easy to missuse. result = newStringOfCap(s.len) var i = prefix.len if not s.startsWith(prefix): diff --git a/lib/pure/times.nim b/lib/pure/times.nim index 6251c70d9..a7ccbf6ee 100644 --- a/lib/pure/times.nim +++ b/lib/pure/times.nim @@ -608,7 +608,6 @@ proc stringifyUnit(value: int | int64, unit: TimeUnit): string = proc humanizeParts(parts: seq[string]): string = ## Make date string parts human-readable - result = "" if parts.len == 0: result.add "0 nanoseconds" @@ -617,8 +616,8 @@ proc humanizeParts(parts: seq[string]): string = elif parts.len == 2: result = parts[0] & " and " & parts[1] else: - for part in parts[0..high(parts)-1]: - result.add part & ", " + for i in 0..high(parts)-1: + result.add parts[i] & ", " result.add "and " & parts[high(parts)] proc `$`*(dur: Duration): string = @@ -957,6 +956,17 @@ else: result.inc tm.second proc getLocalOffsetAndDst(unix: int64): tuple[offset: int, dst: bool] = + # Windows can't handle unix < 0, so we fall back to unix = 0. + # FIXME: This should be improved by falling back to the WinAPI instead. + when defined(windows): + if unix < 0: + var a = 0.CTime + let tmPtr = localtime(addr(a)) + if not tmPtr.isNil: + let tm = tmPtr[] + return ((0 - tm.toAdjUnix).int, false) + return (0, false) + var a = unix.CTime let tmPtr = localtime(addr(a)) if not tmPtr.isNil: diff --git a/lib/pure/unidecode/gen.py b/lib/pure/unidecode/gen.py index 8da0136ff..f0647ea6c 100644 --- a/lib/pure/unidecode/gen.py +++ b/lib/pure/unidecode/gen.py @@ -1,26 +1,30 @@ -#! usr/bin/env python +#! usr/bin/env python3 # -*- coding: utf-8 -*- # Generates the unidecode.dat module # (c) 2010 Andreas Rumpf from unidecode import unidecode +try: + import warnings + warnings.simplefilter("ignore") +except ImportError: + pass -def main2(): - data = [] - for x in xrange(128, 0xffff + 1): - u = eval("u'\u%04x'" % x) - - val = unidecode(u) - data.append(val) - - - f = open("unidecode.dat", "wb+") - for d in data: - f.write("%s\n" % d) - f.close() +def main2(): + f = open("unidecode.dat", "wb+") + for x in range(128, 0xffff + 1): + u = eval("u'\\u%04x'" % x) + val = unidecode(u) -main2() + # f.write("%x | " % x) + if x==0x2028: # U+2028 = LINE SEPARATOR + val = "" + elif x==0x2029: # U+2028 = PARAGRAPH SEPARATOR + val = "" + f.write("%s\n" % val) + f.close() +main2() \ No newline at end of file diff --git a/lib/pure/unidecode/unidecode.dat b/lib/pure/unidecode/unidecode.dat index 9dff0a4a9..5f4c075d8 100644 --- a/lib/pure/unidecode/unidecode.dat +++ b/lib/pure/unidecode/unidecode.dat @@ -58,9 +58,9 @@ P 1 o >> -1/4 -1/2 -3/4 + 1/4 + 1/2 + 3/4 ? A A @@ -91,7 +91,7 @@ U U U U -U +Y Th ss a @@ -177,7 +177,7 @@ i I i IJ - +ij J j K @@ -368,7 +368,7 @@ ZH zh j DZ -D +Dz dz G g @@ -414,8 +414,8 @@ Y y H h -[?] -[?] +N +d OU ou Z @@ -434,34 +434,34 @@ O o Y y +l +n +t +j +db +qp +A +C +c +L +T +s +z [?] [?] -[?] -[?] -[?] -[?] -[?] -[?] -[?] -[?] -[?] -[?] -[?] -[?] -[?] -[?] -[?] -[?] -[?] -[?] -[?] -[?] -[?] -[?] -[?] -[?] -[?] -[?] +B +U +^ +E +e +J +j +q +q +R +r +Y +y a a a @@ -503,13 +503,13 @@ o OE O F -R -R -R -R r r -R +r +r +r +r +r R R s @@ -519,12 +519,12 @@ S S t t -U +u U v ^ -W -Y +w +y Y z z @@ -556,9 +556,9 @@ ls lz WW ]] -[?] -[?] -k +h +h +h h j r @@ -737,19 +737,19 @@ V -[?] -[?] -[?] -[?] -[?] -[?] -[?] -[?] -[?] -[?] -[?] -[?] -[?] +a +e +i +o +u +c +d +h +m +r +t +v +x [?] [?] [?] @@ -1287,7 +1287,7 @@ o f ew [?] -. +: - [?] [?] @@ -1340,9 +1340,9 @@ o u ' +- - - +| : @@ -7402,41 +7402,41 @@ bh +b +d +f +m +n +p +r +r +s +t +z +g +p +b +d +f +g +k +l +m +n +p +r +s - - - - - - - - - - - - - - - - - - - - - - - - - - - +v +x +z @@ -7708,7 +7708,7 @@ a S [?] [?] -[?] +Ss [?] A a @@ -8109,9 +8109,6 @@ _ - - - %0 %00 @@ -8136,19 +8133,23 @@ _ / -[ ]- -[?] +?? ?! !? 7 PP (] [) +* [?] [?] [?] +% +~ [?] [?] [?] +'''' [?] [?] [?] @@ -8156,12 +8157,8 @@ PP [?] [?] [?] -[?] -[?] -[?] -[?] -[?] -[?] + + [?] [?] [?] @@ -8178,7 +8175,7 @@ PP 0 - +i 4 @@ -8209,19 +8206,19 @@ n ( ) [?] +a +e +o +x [?] -[?] -[?] -[?] -[?] -[?] -[?] -[?] -[?] -[?] -[?] -[?] -[?] +h +k +l +m +n +p +s +t [?] [?] [?] @@ -8237,26 +8234,26 @@ Rs W NS D -EU +EUR K T Dr -[?] -[?] -[?] -[?] -[?] -[?] -[?] -[?] -[?] -[?] -[?] -[?] -[?] -[?] -[?] -[?] +Pf +P +G +A +UAH +C| +L +Sm +T +Rs +L +M +m +R +l +BTC [?] [?] [?] @@ -8294,6 +8291,7 @@ Dr [?] + [?] [?] [?] @@ -8319,63 +8317,67 @@ Dr [?] [?] [?] -[?] - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + a/c + a/s +C + c/o + c/u +g +H +H +H +h +I +I +L +l +N +No. +P +Q +R +R +R +(sm) +TEL +(tm) +Z +Z +K +A +B +C +e +e +E +F +F +M +o +i +FAX @@ -8385,25 +8387,20 @@ Dr [?] [?] [?] +D +d +e +i +j [?] [?] [?] [?] +F [?] -[?] -[?] -[?] -[?] -[?] -[?] -[?] -[?] -[?] -[?] -[?] -[?] -[?] -[?] + 1/7 + 1/9 + 1/10 1/3 2/3 1/5 @@ -8458,7 +8455,7 @@ D) [?] [?] [?] -[?] + 0/3 [?] [?] [?] @@ -8595,8 +8592,12 @@ V [?] [?] [?] +- [?] [?] +/ +\ +* [?] [?] [?] @@ -8608,6 +8609,7 @@ V [?] [?] [?] +| [?] [?] [?] @@ -8626,11 +8628,13 @@ V [?] [?] [?] +: [?] [?] [?] [?] [?] +~ [?] [?] [?] @@ -8670,17 +8674,10 @@ V [?] [?] [?] -[?] -[?] -[?] -[?] -[?] -[?] -[?] -[?] -[?] -[?] -[?] +<= +>= +<= +>= [?] [?] [?] @@ -8836,6 +8833,7 @@ V [?] [?] [?] +^ [?] [?] [?] @@ -8873,9 +8871,8 @@ V [?] [?] [?] -[?] -[?] -[?] +< +> [?] [?] [?] @@ -9185,166 +9182,166 @@ V [?] [?] [?] - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -[?] -[?] -[?] -[?] -[?] -[?] -[?] -[?] -[?] -[?] -[?] -[?] -[?] -[?] -[?] -[?] -[?] -[?] -[?] -[?] - +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +(1) +(2) +(3) +(4) +(5) +(6) +(7) +(8) +(9) +(10) +(11) +(12) +(13) +(14) +(15) +(16) +(17) +(18) +(19) +(20) +1. +2. +3. +4. +5. +6. +7. +8. +9. +10. +11. +12. +13. +14. +15. +16. +17. +18. +19. +20. +(a) +(b) +(c) +(d) +(e) +(f) +(g) +(h) +(i) +(j) +(k) +(l) +(m) +(n) +(o) +(p) +(q) +(r) +(s) +(t) +(u) +(v) +(w) +(x) +(y) +(z) +A +B +C +D +E +F +G +H +I +J +K +L +M +N +O +P +Q +R +S +T +U +V +W +X +Y +Z +a +b +c +d +e +f +g +h +i +j +k +l +m +n +o +p +q +r +s +t +u +v +w +x +y +z +0 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +0 - - | @@ -9712,7 +9709,7 @@ O - +# [?] @@ -9906,6 +9903,7 @@ O +* @@ -9944,8 +9942,7 @@ O - - +| @@ -9955,7 +9952,7 @@ O [?] [?] - +! @@ -10087,10 +10084,10 @@ O [?] [?] [?] +[ [?] -[?] -[?] -[?] +< +> [?] [?] [?] @@ -10500,6 +10497,8 @@ y +{ +} @@ -10739,6 +10738,9 @@ y +::= +== +=== @@ -11228,27 +11230,22 @@ y +L +l +L +P +R +a +t +H +h +K +k +Z +z - - - - - - - - - - - - - - - - - - - - +M +A @@ -12754,21 +12751,21 @@ H [?] [?] [?] -[?] -[?] -[?] -[?] -[?] -[?] -[?] -[?] -[?] -[?] -[?] -[?] -[?] -[?] -[?] +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 (g) (n) (d) @@ -12850,21 +12847,21 @@ KIS (Zi) (Xie) (Ye) -[?] -[?] -[?] -[?] -[?] -[?] -[?] -[?] -[?] -[?] -[?] -[?] -[?] -[?] -[?] +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 1M 2M 3M @@ -12877,10 +12874,10 @@ KIS 10M 11M 12M -[?] -[?] -[?] -[?] +Hg +erg +eV +LTD a i u @@ -13042,16 +13039,16 @@ watt 22h 23h 24h -HPA +hPa da AU bar oV pc -[?] -[?] -[?] -[?] +dm +dm^2 +dm^3 +IU Heisei Syouwa Taisyou @@ -13092,7 +13089,7 @@ mm^2 cm^2 m^2 km^2 -mm^4 +mm^3 cm^3 m^3 km^3 @@ -13184,7 +13181,7 @@ Wb 29d 30d 31d - +gal @@ -19841,7 +19838,7 @@ Wb [?] [?] -[?] +Yi Ding Kao Qi diff --git a/lib/pure/unidecode/unidecode.nim b/lib/pure/unidecode/unidecode.nim index 9d8843f06..e0b8d3946 100644 --- a/lib/pure/unidecode/unidecode.nim +++ b/lib/pure/unidecode/unidecode.nim @@ -22,14 +22,14 @@ ## strictly one-way transformation. However a human reader will probably ## still be able to guess what original string was meant from the context. ## -## This module needs the data file "unidecode.dat" to work: You can either -## ship this file with your application and initialize this module with the -## `loadUnidecodeTable` proc or you can define the ``embedUnidecodeTable`` -## symbol to embed the file as a resource into your application. +## This module needs the data file "unidecode.dat" to work: This file is +## embedded as a resource into your application by default. But you an also +## define the symbol ``--define:noUnidecodeTable`` during compile time and +## use the `loadUnidecodeTable` proc to initialize this module. import unicode -when defined(embedUnidecodeTable): +when not defined(noUnidecodeTable): import strutils const translationTable = splitLines(slurp"unidecode/unidecode.dat") @@ -38,11 +38,11 @@ else: var translationTable: seq[string] proc loadUnidecodeTable*(datafile = "unidecode.dat") = - ## loads the datafile that `unidecode` to work. Unless this module is - ## compiled with the ``embedUnidecodeTable`` symbol defined, this needs - ## to be called by the main thread before any thread can make a call - ## to `unidecode`. - when not defined(embedUnidecodeTable): + ## loads the datafile that `unidecode` to work. This is only required if + ## the module was compiled with the ``--define:noUnidecodeTable`` switch. + ## This needs to be called by the main thread before any thread can make a + ## call to `unidecode`. + when defined(noUnidecodeTable): newSeq(translationTable, 0xffff) var i = 0 for line in lines(datafile): @@ -61,7 +61,6 @@ proc unidecode*(s: string): string = ## ## Results in: "Bei Jing" ## - assert(not isNil(translationTable)) result = "" for r in runes(s): var c = int(r) @@ -69,6 +68,6 @@ proc unidecode*(s: string): string = elif c <% translationTable.len: add(result, translationTable[c-128]) when isMainModule: - loadUnidecodeTable("lib/pure/unidecode/unidecode.dat") - assert unidecode("Äußerst") == "Ausserst" - + #loadUnidecodeTable("lib/pure/unidecode/unidecode.dat") + doAssert unidecode("Äußerst") == "Ausserst" + doAssert unidecode("北京") == "Bei Jing " diff --git a/lib/pure/xmldom.nim b/lib/pure/xmldom.nim index 1a9e4ae26..82f88a996 100644 --- a/lib/pure/xmldom.nim +++ b/lib/pure/xmldom.nim @@ -172,34 +172,30 @@ proc documentElement*(doc: PDocument): PElement = proc findNodes(nl: PNode, name: string): seq[PNode] = # Made for getElementsByTagName var r: seq[PNode] = @[] - if isNil(nl.childNodes): return @[] - if nl.childNodes.len() == 0: return @[] + if nl.childNodes.len == 0: return @[] for i in items(nl.childNodes): if i.fNodeType == ElementNode: if i.fNodeName == name or name == "*": r.add(i) - if not isNil(i.childNodes): - if i.childNodes.len() != 0: - r.add(findNodes(i, name)) + if i.childNodes.len() != 0: + r.add(findNodes(i, name)) return r proc findNodesNS(nl: PNode, namespaceURI: string, localName: string): seq[PNode] = # Made for getElementsByTagNameNS var r: seq[PNode] = @[] - if isNil(nl.childNodes): return @[] - if nl.childNodes.len() == 0: return @[] + if nl.childNodes.len == 0: return @[] for i in items(nl.childNodes): if i.fNodeType == ElementNode: if (i.fNamespaceURI == namespaceURI or namespaceURI == "*") and (i.fLocalName == localName or localName == "*"): r.add(i) - if not isNil(i.childNodes): - if i.childNodes.len() != 0: - r.add(findNodesNS(i, namespaceURI, localName)) + if i.childNodes.len != 0: + r.add(findNodesNS(i, namespaceURI, localName)) return r @@ -233,8 +229,8 @@ proc createAttributeNS*(doc: PDocument, namespaceURI: string, qualifiedName: str # Exceptions if qualifiedName.contains(':'): let qfnamespaces = qualifiedName.toLowerAscii().split(':') - if isNil(namespaceURI): - raise newException(ENamespaceErr, "When qualifiedName contains a prefix namespaceURI cannot be nil") + if namespaceURI.len == 0: + raise newException(ENamespaceErr, "When qualifiedName contains a prefix namespaceURI cannot be empty") elif qfnamespaces[0] == "xml" and namespaceURI != "http://www.w3.org/XML/1998/namespace" and qfnamespaces[1] notin stdattrnames: @@ -312,8 +308,8 @@ proc createElementNS*(doc: PDocument, namespaceURI: string, qualifiedName: strin ## Creates an element of the given qualified name and namespace URI. if qualifiedName.contains(':'): let qfnamespaces = qualifiedName.toLowerAscii().split(':') - if isNil(namespaceURI): - raise newException(ENamespaceErr, "When qualifiedName contains a prefix namespaceURI cannot be nil") + if namespaceURI.len == 0: + raise newException(ENamespaceErr, "When qualifiedName contains a prefix namespaceURI cannot be empty") elif qfnamespaces[0] == "xml" and namespaceURI != "http://www.w3.org/XML/1998/namespace" and qfnamespaces[1] notin stdattrnames: @@ -453,7 +449,7 @@ proc importNode*(doc: PDocument, importedNode: PNode, deep: bool): PNode = proc firstChild*(n: PNode): PNode = ## Returns this node's first child - if not isNil(n.childNodes) and n.childNodes.len() > 0: + if n.childNodes.len > 0: return n.childNodes[0] else: return nil @@ -461,8 +457,8 @@ proc firstChild*(n: PNode): PNode = proc lastChild*(n: PNode): PNode = ## Returns this node's last child - if not isNil(n.childNodes) and n.childNodes.len() > 0: - return n.childNodes[n.childNodes.len() - 1] + if n.childNodes.len > 0: + return n.childNodes[n.childNodes.len - 1] else: return nil @@ -482,7 +478,7 @@ proc `namespaceURI=`*(n: PNode, value: string) = proc nextSibling*(n: PNode): PNode = ## Returns the next sibling of this node - if isNil(n.fParentNode) or isNil(n.fParentNode.childNodes): + if isNil(n.fParentNode): return nil var nLow: int = low(n.fParentNode.childNodes) var nHigh: int = high(n.fParentNode.childNodes) @@ -514,7 +510,7 @@ proc parentNode*(n: PNode): PNode = proc previousSibling*(n: PNode): PNode = ## Returns the previous sibling of this node - if isNil(n.fParentNode) or isNil(n.fParentNode.childNodes): + if isNil(n.fParentNode): return nil var nLow: int = low(n.fParentNode.childNodes) var nHigh: int = high(n.fParentNode.childNodes) @@ -531,8 +527,8 @@ proc `prefix=`*(n: PNode, value: string) = if illegalChars in value: raise newException(EInvalidCharacterErr, "Invalid character") - if isNil(n.fNamespaceURI): - raise newException(ENamespaceErr, "namespaceURI cannot be nil") + if n.fNamespaceURI.len == 0: + raise newException(ENamespaceErr, "namespaceURI cannot be empty") elif value.toLowerAscii() == "xml" and n.fNamespaceURI != "http://www.w3.org/XML/1998/namespace": raise newException(ENamespaceErr, "When the namespace prefix is \"xml\" namespaceURI has to be \"http://www.w3.org/XML/1998/namespace\"") @@ -557,10 +553,9 @@ proc appendChild*(n: PNode, newChild: PNode) = ## If the newChild is already in the tree, it is first removed. # Check if n contains newChild - if not isNil(n.childNodes): - for i in low(n.childNodes)..high(n.childNodes): - if n.childNodes[i] == newChild: - raise newException(EHierarchyRequestErr, "The node to append is already in this nodes children.") + for i in low(n.childNodes)..high(n.childNodes): + if n.childNodes[i] == newChild: + raise newException(EHierarchyRequestErr, "The node to append is already in this nodes children.") # Check if newChild is from this nodes document if n.fOwnerDocument != newChild.fOwnerDocument: @@ -572,7 +567,8 @@ proc appendChild*(n: PNode, newChild: PNode) = if n.nodeType in childlessObjects: raise newException(ENoModificationAllowedErr, "Cannot append children to a childless node") - if isNil(n.childNodes): n.childNodes = @[] + when not defined(nimNoNilSeqs): + if isNil(n.childNodes): n.childNodes = @[] newChild.fParentNode = n for i in low(n.childNodes)..high(n.childNodes): @@ -597,10 +593,10 @@ proc cloneNode*(n: PNode, deep: bool): PNode = newNode = PElement(n) # Import the childNodes var tmp: seq[PNode] = n.childNodes - n.childNodes = @[] - if deep and not isNil(tmp): - for i in low(tmp.len())..high(tmp.len()): - n.childNodes.add(cloneNode(tmp[i], deep)) + newNode.childNodes = @[] + if deep: + for i in low(n.childNodes)..high(n.childNodes): + newNode.childNodes.add(cloneNode(n.childNodes[i], deep)) return newNode else: var newNode: PNode @@ -610,11 +606,11 @@ proc cloneNode*(n: PNode, deep: bool): PNode = proc hasAttributes*(n: PNode): bool = ## Returns whether this node (if it is an element) has any attributes. - return not isNil(n.attributes) and n.attributes.len() > 0 + return n.attributes.len > 0 proc hasChildNodes*(n: PNode): bool = ## Returns whether this node has any children. - return not isNil(n.childNodes) and n.childNodes.len() > 0 + return n.childNodes.len > 0 proc insertBefore*(n: PNode, newChild: PNode, refChild: PNode): PNode = ## Inserts the node ``newChild`` before the existing child node ``refChild``. @@ -624,9 +620,6 @@ proc insertBefore*(n: PNode, newChild: PNode, refChild: PNode): PNode = if n.fOwnerDocument != newChild.fOwnerDocument: raise newException(EWrongDocumentErr, "This node belongs to a different document, use importNode.") - if isNil(n.childNodes): - n.childNodes = @[] - for i in low(n.childNodes)..high(n.childNodes): if n.childNodes[i] == refChild: n.childNodes.insert(newChild, i - 1) @@ -641,7 +634,7 @@ proc isSupported*(n: PNode, feature: string, version: string): bool = proc isEmpty(s: string): bool = - if isNil(s) or s == "": + if s == "": return true for i in items(s): if i != ' ': @@ -655,7 +648,7 @@ proc normalize*(n: PNode) = var newChildNodes: seq[PNode] = @[] while true: - if isNil(n.childNodes) or i >= n.childNodes.len: + if i >= n.childNodes.len: break if n.childNodes[i].nodeType == TextNode: @@ -679,12 +672,11 @@ proc normalize*(n: PNode) = proc removeChild*(n: PNode, oldChild: PNode): PNode = ## Removes the child node indicated by ``oldChild`` from the list of children, and returns it. - if not isNil(n.childNodes): - for i in low(n.childNodes)..high(n.childNodes): - if n.childNodes[i] == oldChild: - result = n.childNodes[i] - n.childNodes.delete(i) - return + for i in low(n.childNodes)..high(n.childNodes): + if n.childNodes[i] == oldChild: + result = n.childNodes[i] + n.childNodes.delete(i) + return raise newException(ENotFoundErr, "Node not found") @@ -695,12 +687,11 @@ proc replaceChild*(n: PNode, newChild: PNode, oldChild: PNode): PNode = if n.fOwnerDocument != newChild.fOwnerDocument: raise newException(EWrongDocumentErr, "This node belongs to a different document, use importNode.") - if not isNil(n.childNodes): - for i in low(n.childNodes)..high(n.childNodes): - if n.childNodes[i] == oldChild: - result = n.childNodes[i] - n.childNodes[i] = newChild - return + for i in low(n.childNodes)..high(n.childNodes): + if n.childNodes[i] == oldChild: + result = n.childNodes[i] + n.childNodes[i] = newChild + return raise newException(ENotFoundErr, "Node not found") @@ -764,11 +755,10 @@ proc removeNamedItemNS*(nList: var seq[PNode], namespaceURI: string, localName: proc setNamedItem*(nList: var seq[PNode], arg: PNode): PNode = ## Adds ``arg`` as a ``Node`` to the ``NList`` ## If a node with the same name is already present in this map, it is replaced by the new one. - if not isNil(nList): - if nList.len() > 0: - #Check if newChild is from this nodes document - if nList[0].fOwnerDocument != arg.fOwnerDocument: - raise newException(EWrongDocumentErr, "This node belongs to a different document, use importNode.") + if nList.len > 0: + #Check if newChild is from this nodes document + if nList[0].fOwnerDocument != arg.fOwnerDocument: + raise newException(EWrongDocumentErr, "This node belongs to a different document, use importNode.") #Exceptions End var item: PNode = nList.getNamedItem(arg.nodeName()) @@ -788,11 +778,10 @@ proc setNamedItem*(nList: var seq[PNode], arg: PNode): PNode = proc setNamedItem*(nList: var seq[PAttr], arg: PAttr): PAttr = ## Adds ``arg`` as a ``Node`` to the ``NList`` ## If a node with the same name is already present in this map, it is replaced by the new one. - if not isNil(nList): - if nList.len() > 0: - # Check if newChild is from this nodes document - if nList[0].fOwnerDocument != arg.fOwnerDocument: - raise newException(EWrongDocumentErr, "This node belongs to a different document, use importNode.") + if nList.len > 0: + # Check if newChild is from this nodes document + if nList[0].fOwnerDocument != arg.fOwnerDocument: + raise newException(EWrongDocumentErr, "This node belongs to a different document, use importNode.") if not isNil(arg.fOwnerElement): raise newException(EInuseAttributeErr, "This attribute is in use by another element, use cloneNode") @@ -814,11 +803,10 @@ proc setNamedItem*(nList: var seq[PAttr], arg: PAttr): PAttr = proc setNamedItemNS*(nList: var seq[PNode], arg: PNode): PNode = ## Adds a node using its ``namespaceURI`` and ``localName`` - if not isNil(nList): - if nList.len() > 0: - # Check if newChild is from this nodes document - if nList[0].fOwnerDocument != arg.fOwnerDocument: - raise newException(EWrongDocumentErr, "This node belongs to a different document, use importNode.") + if nList.len > 0: + # Check if newChild is from this nodes document + if nList[0].fOwnerDocument != arg.fOwnerDocument: + raise newException(EWrongDocumentErr, "This node belongs to a different document, use importNode.") #Exceptions end var item: PNode = nList.getNamedItemNS(arg.namespaceURI(), arg.localName()) @@ -837,11 +825,10 @@ proc setNamedItemNS*(nList: var seq[PNode], arg: PNode): PNode = proc setNamedItemNS*(nList: var seq[PAttr], arg: PAttr): PAttr = ## Adds a node using its ``namespaceURI`` and ``localName`` - if not isNil(nList): - if nList.len() > 0: - # Check if newChild is from this nodes document - if nList[0].fOwnerDocument != arg.fOwnerDocument: - raise newException(EWrongDocumentErr, "This node belongs to a different document, use importNode.") + if nList.len > 0: + # Check if newChild is from this nodes document + if nList[0].fOwnerDocument != arg.fOwnerDocument: + raise newException(EWrongDocumentErr, "This node belongs to a different document, use importNode.") if not isNil(arg.fOwnerElement): raise newException(EInuseAttributeErr, "This attribute is in use by another element, use cloneNode") @@ -868,17 +855,14 @@ proc setNamedItemNS*(nList: var seq[PAttr], arg: PAttr): PAttr = # Attributes proc name*(a: PAttr): string = ## Returns the name of the Attribute - return a.fName proc specified*(a: PAttr): bool = ## Specifies whether this attribute was specified in the original document - return a.fSpecified proc ownerElement*(a: PAttr): PElement = ## Returns this Attributes owner element - return a.fOwnerElement # Element @@ -886,14 +870,11 @@ proc ownerElement*(a: PAttr): PElement = proc tagName*(el: PElement): string = ## Returns the Element Tag Name - return el.fTagName # Procedures proc getAttribute*(el: PNode, name: string): string = ## Retrieves an attribute value by ``name`` - if isNil(el.attributes): - return "" var attribute = el.attributes.getNamedItem(name) if not isNil(attribute): return attribute.value @@ -902,8 +883,6 @@ proc getAttribute*(el: PNode, name: string): string = proc getAttributeNS*(el: PNode, namespaceURI: string, localName: string): string = ## Retrieves an attribute value by ``localName`` and ``namespaceURI`` - if isNil(el.attributes): - return "" var attribute = el.attributes.getNamedItemNS(namespaceURI, localName) if not isNil(attribute): return attribute.value @@ -913,14 +892,10 @@ proc getAttributeNS*(el: PNode, namespaceURI: string, localName: string): string proc getAttributeNode*(el: PElement, name: string): PAttr = ## Retrieves an attribute node by ``name`` ## To retrieve an attribute node by qualified name and namespace URI, use the `getAttributeNodeNS` method - if isNil(el.attributes): - return nil return el.attributes.getNamedItem(name) proc getAttributeNodeNS*(el: PElement, namespaceURI: string, localName: string): PAttr = ## Retrieves an `Attr` node by ``localName`` and ``namespaceURI`` - if isNil(el.attributes): - return nil return el.attributes.getNamedItemNS(namespaceURI, localName) proc getElementsByTagName*(el: PElement, name: string): seq[PNode] = @@ -938,41 +913,34 @@ proc getElementsByTagNameNS*(el: PElement, namespaceURI: string, localName: stri proc hasAttribute*(el: PElement, name: string): bool = ## Returns ``true`` when an attribute with a given ``name`` is specified ## on this element , ``false`` otherwise. - if isNil(el.attributes): - return false return not isNil(el.attributes.getNamedItem(name)) proc hasAttributeNS*(el: PElement, namespaceURI: string, localName: string): bool = ## Returns ``true`` when an attribute with a given ``localName`` and ## ``namespaceURI`` is specified on this element , ``false`` otherwise - if isNil(el.attributes): - return false return not isNil(el.attributes.getNamedItemNS(namespaceURI, localName)) proc removeAttribute*(el: PElement, name: string) = ## Removes an attribute by ``name`` - if not isNil(el.attributes): - for i in low(el.attributes)..high(el.attributes): - if el.attributes[i].fName == name: - el.attributes.delete(i) + for i in low(el.attributes)..high(el.attributes): + if el.attributes[i].fName == name: + el.attributes.delete(i) proc removeAttributeNS*(el: PElement, namespaceURI: string, localName: string) = ## Removes an attribute by ``localName`` and ``namespaceURI`` - if not isNil(el.attributes): - for i in low(el.attributes)..high(el.attributes): - if el.attributes[i].fNamespaceURI == namespaceURI and - el.attributes[i].fLocalName == localName: - el.attributes.delete(i) + for i in low(el.attributes)..high(el.attributes): + if el.attributes[i].fNamespaceURI == namespaceURI and + el.attributes[i].fLocalName == localName: + el.attributes.delete(i) proc removeAttributeNode*(el: PElement, oldAttr: PAttr): PAttr = ## Removes the specified attribute node ## If the attribute node cannot be found raises ``ENotFoundErr`` - if not isNil(el.attributes): - for i in low(el.attributes)..high(el.attributes): - if el.attributes[i] == oldAttr: - result = el.attributes[i] - el.attributes.delete(i) - return + for i in low(el.attributes)..high(el.attributes): + if el.attributes[i] == oldAttr: + result = el.attributes[i] + el.attributes.delete(i) + return raise newException(ENotFoundErr, "oldAttr is not a member of el's Attributes") @@ -991,7 +959,6 @@ proc setAttributeNode*(el: PElement, newAttr: PAttr): PAttr = "This attribute is in use by another element, use cloneNode") # Exceptions end - if isNil(el.attributes): el.attributes = @[] return el.attributes.setNamedItem(newAttr) proc setAttributeNodeNS*(el: PElement, newAttr: PAttr): PAttr = @@ -1009,7 +976,6 @@ proc setAttributeNodeNS*(el: PElement, newAttr: PAttr): PAttr = "This attribute is in use by another element, use cloneNode") # Exceptions end - if isNil(el.attributes): el.attributes = @[] return el.attributes.setNamedItemNS(newAttr) proc setAttribute*(el: PElement, name: string, value: string) = @@ -1057,9 +1023,9 @@ proc splitData*(textNode: PText, offset: int): PText = var left: string = textNode.data.substr(0, offset) textNode.data = left - var right: string = textNode.data.substr(offset, textNode.data.len()) + var right: string = textNode.data.substr(offset, textNode.data.len) - if not isNil(textNode.fParentNode) and not isNil(textNode.fParentNode.childNodes): + if not isNil(textNode.fParentNode) and textNode.fParentNode.childNodes.len > 0: for i in low(textNode.fParentNode.childNodes)..high(textNode.fParentNode.childNodes): if textNode.fParentNode.childNodes[i] == textNode: var newNode: PText = textNode.fOwnerDocument.createTextNode(right) @@ -1098,11 +1064,10 @@ proc escapeXml*(s: string): string = proc nodeToXml(n: PNode, indent: int = 0): string = result = spaces(indent) & "<" & n.nodeName - if not isNil(n.attributes): - for i in items(n.attributes): - result.add(" " & i.name & "=\"" & escapeXml(i.value) & "\"") + for i in items(n.attributes): + result.add(" " & i.name & "=\"" & escapeXml(i.value) & "\"") - if isNil(n.childNodes) or n.childNodes.len() == 0: + if n.childNodes.len == 0: result.add("/>") # No idea why this doesn't need a \n :O else: # End the beginning of this tag @@ -1134,3 +1099,4 @@ proc `$`*(doc: PDocument): string = ## Converts a PDocument object into a string representation of it's XML result = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n" result.add(nodeToXml(doc.documentElement)) + \ No newline at end of file diff --git a/lib/system.nim b/lib/system.nim index d61924a5b..ef6138ad1 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -211,6 +211,7 @@ proc new*(T: typedesc): auto = new(r) return r +const ThisIsSystem = true proc internalNew*[T](a: var ref T) {.magic: "New", noSideEffect.} ## leaked implementation detail. Do not use. @@ -229,6 +230,17 @@ proc reset*[T](obj: var T) {.magic: "Reset", noSideEffect.} ## resets an object `obj` to its initial (binary zero) value. This needs to ## be called before any possible `object branch transition`:idx:. +when defined(nimNewRuntime): + proc wasMoved*[T](obj: var T) {.magic: "WasMoved", noSideEffect.} = + ## resets an object `obj` to its initial (binary zero) value to signify + ## it was "moved" and to signify its destructor should do nothing and + ## ideally be optimized away. + discard + + proc move*[T](x: var T): T {.magic: "Move", noSideEffect.} = + result = x + wasMoved(x) + type range*{.magic: "Range".}[T] ## Generic type to construct range types. array*{.magic: "Array".}[I, T] ## Generic type to construct @@ -301,6 +313,12 @@ when defined(nimArrIdx): proc `[]=`*[I: Ordinal;T,S](a: T; i: I; x: S) {.noSideEffect, magic: "ArrPut".} proc `=`*[T](dest: var T; src: T) {.noSideEffect, magic: "Asgn".} + + proc arrGet[I: Ordinal;T](a: T; i: I): T {. + noSideEffect, magic: "ArrGet".} + proc arrPut[I: Ordinal;T,S](a: T; i: I; + x: S) {.noSideEffect, magic: "ArrPut".} + when defined(nimNewRuntime): proc `=destroy`*[T](x: var T) {.inline, magic: "Asgn".} = ## generic `destructor`:idx: implementation that can be overriden. @@ -413,7 +431,7 @@ include "system/inclrtl" const NoFakeVars* = defined(nimscript) ## true if the backend doesn't support \ ## "fake variables" like 'var EBADF {.importc.}: cint'. -when not defined(JS): +when not defined(JS) and not defined(gcDestructors): type TGenericSeq {.compilerproc, pure, inheritable.} = object len, reserved: int @@ -426,8 +444,9 @@ when not defined(JS): NimString = ptr NimStringDesc when not defined(JS) and not defined(nimscript): - template space(s: PGenericSeq): int {.dirty.} = - s.reserved and not (seqShallowFlag or strlitFlag) + when not defined(gcDestructors): + template space(s: PGenericSeq): int {.dirty.} = + s.reserved and not (seqShallowFlag or strlitFlag) include "system/hti" type @@ -692,7 +711,8 @@ proc newSeqOfCap*[T](cap: Natural): seq[T] {. ## ``cap``. discard -when not defined(JS): +when not defined(JS) and not defined(gcDestructors): + # XXX enable this for --gc:destructors proc newSeqUninitialized*[T: SomeNumber](len: Natural): seq[T] = ## creates a new sequence of type ``seq[T]`` with length ``len``. ## @@ -1481,11 +1501,17 @@ const hasAlloc = (hostOS != "standalone" or not defined(nogc)) and not defined(n when not defined(JS) and not defined(nimscript) and hostOS != "standalone": include "system/cgprocs" -when not defined(JS) and not defined(nimscript) and hasAlloc: +when not defined(JS) and not defined(nimscript) and hasAlloc and not defined(gcDestructors): proc addChar(s: NimString, c: char): NimString {.compilerProc, benign.} -proc add *[T](x: var seq[T], y: T) {.magic: "AppendSeqElem", noSideEffect.} -proc add *[T](x: var seq[T], y: openArray[T]) {.noSideEffect.} = +when defined(gcDestructors): + proc add*[T](x: var seq[T], y: sink T) {.magic: "AppendSeqElem", noSideEffect.} = + let xl = x.len + setLen(x, xl + 1) + x[xl] = y +else: + proc add*[T](x: var seq[T], y: T) {.magic: "AppendSeqElem", noSideEffect.} +proc add*[T](x: var seq[T], y: openArray[T]) {.noSideEffect.} = ## Generic proc for adding a data item `y` to a container `x`. ## For containers that have an order, `add` means *append*. New generic ## containers should also call their adding proc `add` for consistency. @@ -1526,7 +1552,7 @@ proc delete*[T](x: var seq[T], i: Natural) {.noSideEffect.} = defaultImpl() else: when defined(js): - {.emit: "`x`[`x`_Idx].splice(`i`, 1);".} + {.emit: "`x`.splice(`i`, 1);".} else: defaultImpl() @@ -1548,7 +1574,7 @@ proc insert*[T](x: var seq[T], item: T, i = 0.Natural) {.noSideEffect.} = else: when defined(js): var it : T - {.emit: "`x`[`x`_Idx].splice(`i`, 0, `it`);".} + {.emit: "`x`.splice(`i`, 0, `it`);".} else: defaultImpl() x[i] = item @@ -1681,17 +1707,6 @@ proc addQuitProc*(QuitProc: proc() {.noconv.}) {. # In case of an unhandled exeption the exit handlers should # not be called explicitly! The user may decide to do this manually though. -proc substr*(s: string, first = 0): string {. - magic: "CopyStr", importc: "copyStr", noSideEffect.} -proc substr*(s: string, first, last: int): string {. - magic: "CopyStrLast", importc: "copyStrLast", noSideEffect.} - ## copies a slice of `s` into a new string and returns this new - ## string. The bounds `first` and `last` denote the indices of - ## the first and last characters that shall be copied. If ``last`` - ## is omitted, it is treated as ``high(s)``. If ``last >= s.len``, ``s.len`` - ## is used instead: This means ``substr`` can also be used to `cut`:idx: - ## or `limit`:idx: a string's length. - when not defined(nimscript) and not defined(JS): proc zeroMem*(p: pointer, size: Natural) {.inline, benign.} ## overwrites the contents of the memory at ``p`` with the value 0. @@ -2180,10 +2195,17 @@ iterator items*[T](a: set[T]): T {.inline.} = iterator items*(a: cstring): char {.inline.} = ## iterates over each item of `a`. - var i = 0 - while a[i] != '\0': - yield a[i] - inc(i) + when defined(js): + var i = 0 + var L = len(a) + while i < L: + yield a[i] + inc(i) + else: + var i = 0 + while a[i] != '\0': + yield a[i] + inc(i) iterator mitems*(a: var cstring): var char {.inline.} = ## iterates over each item of `a` so that you can modify the yielded value. @@ -2283,9 +2305,18 @@ iterator mpairs*(a: var cstring): tuple[key: int, val: var char] {.inline.} = inc(i) -proc isNil*[T](x: seq[T]): bool {.noSideEffect, magic: "IsNil", deprecated.} +when defined(nimNoNilSeqs2): + when not compileOption("nilseqs"): + {.pragma: nilError, error.} + else: + {.pragma: nilError.} +else: + {.pragma: nilError.} + +proc isNil*[T](x: seq[T]): bool {.noSideEffect, magic: "IsNil", nilError.} proc isNil*[T](x: ref T): bool {.noSideEffect, magic: "IsNil".} -proc isNil*(x: string): bool {.noSideEffect, magic: "IsNil", deprecated.} +proc isNil*(x: string): bool {.noSideEffect, magic: "IsNil", nilError.} + proc isNil*[T](x: ptr T): bool {.noSideEffect, magic: "IsNil".} proc isNil*(x: pointer): bool {.noSideEffect, magic: "IsNil".} proc isNil*(x: cstring): bool {.noSideEffect, magic: "IsNil".} @@ -2710,12 +2741,12 @@ type when defined(JS): proc add*(x: var string, y: cstring) {.asmNoStackFrame.} = asm """ - var len = `x`[0].length-1; + if (`x` === null) { `x` = []; } + var off = `x`.length; + `x`.length += `y`.length; for (var i = 0; i < `y`.length; ++i) { - `x`[0][len] = `y`.charCodeAt(i); - ++len; + `x`[off+i] = `y`.charCodeAt(i); } - `x`[0][len] = 0 """ proc add*(x: var cstring, y: cstring) {.magic: "AppendStrStr".} @@ -2820,6 +2851,58 @@ else: if x < 0: -x else: x {.pop.} +when not defined(JS): + proc likely_proc(val: bool): bool {.importc: "likely", nodecl, nosideeffect.} + proc unlikely_proc(val: bool): bool {.importc: "unlikely", nodecl, nosideeffect.} + +template likely*(val: bool): bool = + ## Hints the optimizer that `val` is likely going to be true. + ## + ## You can use this template to decorate a branch condition. On certain + ## platforms this can help the processor predict better which branch is + ## going to be run. Example: + ## + ## .. code-block:: nim + ## for value in inputValues: + ## if likely(value <= 100): + ## process(value) + ## else: + ## echo "Value too big!" + ## + ## On backends without branch prediction (JS and the nimscript VM), this + ## template will not affect code execution. + when nimvm: + val + else: + when defined(JS): + val + else: + likely_proc(val) + +template unlikely*(val: bool): bool = + ## Hints the optimizer that `val` is likely going to be false. + ## + ## You can use this proc to decorate a branch condition. On certain + ## platforms this can help the processor predict better which branch is + ## going to be run. Example: + ## + ## .. code-block:: nim + ## for value in inputValues: + ## if unlikely(value > 100): + ## echo "Value too big!" + ## else: + ## process(value) + ## + ## On backends without branch prediction (JS and the nimscript VM), this + ## template will not affect code execution. + when nimvm: + val + else: + when defined(JS): + val + else: + unlikely_proc(val) + type FileSeekPos* = enum ## Position relative to which seek should happen # The values are ordered so that they match with stdio @@ -2853,10 +2936,11 @@ when not defined(JS): #and not defined(nimscript): when declared(nimGC_setStackBottom): nimGC_setStackBottom(locals) - {.push profiler: off.} - var - strDesc = TNimType(size: sizeof(string), kind: tyString, flags: {ntfAcyclic}) - {.pop.} + when not defined(gcDestructors): + {.push profiler: off.} + var + strDesc = TNimType(size: sizeof(string), kind: tyString, flags: {ntfAcyclic}) + {.pop.} # ----------------- IO Part ------------------------------------------------ @@ -3043,8 +3127,8 @@ when not defined(JS): #and not defined(nimscript): proc readLine*(f: File, line: var TaintedString): bool {.tags: [ReadIOEffect], benign.} - ## reads a line of text from the file `f` into `line`. `line` must not be - ## ``nil``! May throw an IO exception. + ## reads a line of text from the file `f` into `line`. May throw an IO + ## exception. ## A line of text may be delimited by ``LF`` or ``CRLF``. The newline ## character(s) are not part of the returned string. Returns ``false`` ## if the end of the file has been reached, ``true`` otherwise. If @@ -3242,8 +3326,14 @@ when not defined(JS): #and not defined(nimscript): when hasAlloc: include "system/mmdisp" {.pop.} {.push stack_trace: off, profiler:off.} - when hasAlloc: include "system/sysstr" + when hasAlloc: + when defined(gcDestructors): + include "core/strs" + include "core/seqs" + else: + include "system/sysstr" {.pop.} + when hasAlloc: include "system/strmantle" when hostOS != "standalone": include "system/sysio" when hasThreadSupport: @@ -3288,8 +3378,9 @@ when not defined(JS): #and not defined(nimscript): while f.readLine(res): yield res when not defined(nimscript) and hasAlloc: - include "system/assign" - include "system/repr" + when not defined(gcDestructors): + include "system/assign" + include "system/repr" when hostOS != "standalone" and not defined(nimscript): proc getCurrentException*(): ref Exception {.compilerRtl, inl, benign.} = @@ -3302,12 +3393,15 @@ when not defined(JS): #and not defined(nimscript): var e = getCurrentException() return if e == nil: "" else: e.msg - proc onRaise*(action: proc(e: ref Exception): bool{.closure.}) = + proc onRaise*(action: proc(e: ref Exception): bool{.closure.}) {.deprecated.} = ## can be used in a ``try`` statement to setup a Lisp-like ## `condition system`:idx:\: This prevents the 'raise' statement to ## raise an exception but instead calls ``action``. ## If ``action`` returns false, the exception has been handled and ## does not propagate further through the call stack. + ## + ## *Deprecated since version 0.18.1*: No good usages of this + ## feature are known. if not isNil(excHandler): excHandler.hasRaiseAction = true excHandler.raiseAction = action @@ -3396,58 +3490,6 @@ proc quit*(errormsg: string, errorcode = QuitFailure) {.noReturn.} = {.pop.} # checks {.pop.} # hints -when not defined(JS): - proc likely_proc(val: bool): bool {.importc: "likely", nodecl, nosideeffect.} - proc unlikely_proc(val: bool): bool {.importc: "unlikely", nodecl, nosideeffect.} - -template likely*(val: bool): bool = - ## Hints the optimizer that `val` is likely going to be true. - ## - ## You can use this template to decorate a branch condition. On certain - ## platforms this can help the processor predict better which branch is - ## going to be run. Example: - ## - ## .. code-block:: nim - ## for value in inputValues: - ## if likely(value <= 100): - ## process(value) - ## else: - ## echo "Value too big!" - ## - ## On backends without branch prediction (JS and the nimscript VM), this - ## template will not affect code execution. - when nimvm: - val - else: - when defined(JS): - val - else: - likely_proc(val) - -template unlikely*(val: bool): bool = - ## Hints the optimizer that `val` is likely going to be false. - ## - ## You can use this proc to decorate a branch condition. On certain - ## platforms this can help the processor predict better which branch is - ## going to be run. Example: - ## - ## .. code-block:: nim - ## for value in inputValues: - ## if unlikely(value > 100): - ## echo "Value too big!" - ## else: - ## process(value) - ## - ## On backends without branch prediction (JS and the nimscript VM), this - ## template will not affect code execution. - when nimvm: - val - else: - when defined(JS): - val - else: - unlikely_proc(val) - proc `/`*(x, y: int): float {.inline, noSideEffect.} = ## integer division that results in a float. result = toFloat(x) / toFloat(y) @@ -3500,6 +3542,9 @@ template spliceImpl(s, a, L, b: untyped): untyped = template `^^`(s, i: untyped): untyped = (when i is BackwardsIndex: s.len - int(i) else: int(i)) +template `[]`*(s: string; i: int): char = arrGet(s, i) +template `[]=`*(s: string; i: int; val: char) = arrPut(s, i, val) + when hasAlloc or defined(nimscript): proc `[]`*[T, U](s: string, x: HSlice[T, U]): string {.inline.} = ## slice operation for strings. @@ -3732,6 +3777,19 @@ proc failedAssertImpl*(msg: string) {.raises: [], tags: [].} = tags: [].} Hide(raiseAssert)(msg) +include "system/helpers" # for `lineInfoToString` + +template assertImpl(cond: bool, msg = "", enabled: static[bool]) = + const loc = $instantiationInfo(-1, true) + bind instantiationInfo + mixin failedAssertImpl + when enabled: + # for stacktrace; fixes #8928 ; Note: `fullPaths = true` is correct + # here, regardless of --excessiveStackTrace + {.line: instantiationInfo(fullPaths = true).}: + if not cond: + failedAssertImpl(loc & " `" & astToStr(cond) & "` " & msg) + template assert*(cond: bool, msg = "") = ## Raises ``AssertionError`` with `msg` if `cond` is false. Note ## that ``AssertionError`` is hidden from the effect system, so it doesn't @@ -3741,23 +3799,11 @@ template assert*(cond: bool, msg = "") = ## The compiler may not generate any code at all for ``assert`` if it is ## advised to do so through the ``-d:release`` or ``--assertions:off`` ## `command line switches <nimc.html#command-line-switches>`_. - bind instantiationInfo - mixin failedAssertImpl - when compileOption("assertions"): - {.line.}: - if not cond: failedAssertImpl(astToStr(cond) & ' ' & msg) + assertImpl(cond, msg, compileOption("assertions")) template doAssert*(cond: bool, msg = "") = - ## same as `assert` but is always turned on and not affected by the - ## ``--assertions`` command line switch. - bind instantiationInfo - # NOTE: `true` is correct here; --excessiveStackTrace:on will control whether - # or not to output full paths. - {.line: instantiationInfo(-1, true).}: - if not cond: - raiseAssert(astToStr(cond) & ' ' & - instantiationInfo(-1, false).fileName & '(' & - $instantiationInfo(-1, false).line & ") " & msg) + ## same as ``assert`` but is always turned on regardless of ``--assertions`` + assertImpl(cond, msg, true) iterator items*[T](a: seq[T]): T {.inline.} = ## iterates over each item of `a`. @@ -3827,7 +3873,7 @@ proc shallow*(s: var string) {.noSideEffect, inline.} = ## marks a string `s` as `shallow`:idx:. Subsequent assignments will not ## perform deep copies of `s`. This is only useful for optimization ## purposes. - when not defined(JS) and not defined(nimscript): + when not defined(JS) and not defined(nimscript) and not defined(gcDestructors): var s = cast[PGenericSeq](s) # string literals cannot become 'shallow': if (s.reserved and strlitFlag) == 0: @@ -3939,7 +3985,7 @@ proc addQuoted*[T](s: var string, x: T) = ## tmp.add(", ") ## tmp.addQuoted('c') ## assert(tmp == """1, "string", 'c'""") - when T is string: + when T is string or T is cstring: s.add("\"") for c in x: # Only ASCII chars are escaped to avoid butchering @@ -4011,7 +4057,9 @@ proc locals*(): RootObj {.magic: "Plugin", noSideEffect.} = ## # -> B is 1 discard -when hasAlloc and not defined(nimscript) and not defined(JS): +when hasAlloc and not defined(nimscript) and not defined(JS) and + not defined(gcDestructors): + # XXX how to implement 'deepCopy' is an open problem. proc deepCopy*[T](x: var T, y: T) {.noSideEffect, magic: "DeepCopy".} = ## performs a deep copy of `y` and copies it into `x`. ## This is also used by the code generator @@ -4029,10 +4077,15 @@ proc procCall*(x: untyped) {.magic: "ProcCall", compileTime.} = ## procCall someMethod(a, b) discard -proc xlen*(x: string): int {.magic: "XLenStr", noSideEffect.} = discard -proc xlen*[T](x: seq[T]): int {.magic: "XLenSeq", noSideEffect.} = +proc xlen*(x: string): int {.magic: "XLenStr", noSideEffect, + deprecated: "use len() instead".} = + ## **Deprecated since version 0.18.1**. Use len() instead. + discard +proc xlen*[T](x: seq[T]): int {.magic: "XLenSeq", noSideEffect, + deprecated: "use len() instead".} = ## returns the length of a sequence or a string without testing for 'nil'. ## This is an optimization that rarely makes sense. + ## **Deprecated since version 0.18.1**. Use len() instead. discard @@ -4077,13 +4130,13 @@ template once*(body: untyped): untyped = ## re-executed on each module reload. ## ## .. code-block:: nim - ## proc draw(t: Triangle) = - ## once: - ## graphicsInit() ## - ## line(t.p1, t.p2) - ## line(t.p2, t.p3) - ## line(t.p3, t.p1) + ## proc draw(t: Triangle) = + ## once: + ## graphicsInit() + ## line(t.p1, t.p2) + ## line(t.p2, t.p3) + ## line(t.p3, t.p1) ## var alreadyExecuted {.global.} = false if not alreadyExecuted: @@ -4092,6 +4145,22 @@ template once*(body: untyped): untyped = {.pop.} #{.push warning[GcMem]: off, warning[Uninit]: off.} +proc substr*(s: string, first, last: int): string = + let first = max(first, 0) + let L = max(min(last, high(s)) - first + 1, 0) + result = newString(L) + for i in 0 .. L-1: + result[i] = s[i+first] + +proc substr*(s: string, first = 0): string = + ## copies a slice of `s` into a new string and returns this new + ## string. The bounds `first` and `last` denote the indices of + ## the first and last characters that shall be copied. If ``last`` + ## is omitted, it is treated as ``high(s)``. If ``last >= s.len``, ``s.len`` + ## is used instead: This means ``substr`` can also be used to `cut`:idx: + ## or `limit`:idx: a string's length. + result = substr(s, first, high(s)) + when defined(nimconfig): include "system/nimscript" diff --git a/lib/system/assign.nim b/lib/system/assign.nim index 16b56aba7..2b74e6682 100644 --- a/lib/system/assign.nim +++ b/lib/system/assign.nim @@ -202,11 +202,6 @@ proc objectInit(dest: pointer, typ: PNimType) = # ---------------------- assign zero ----------------------------------------- -proc nimDestroyRange[T](r: T) {.compilerProc.} = - # internal proc used for destroying sequences and arrays - mixin `=destroy` - for i in countup(0, r.len - 1): `=destroy`(r[i]) - proc genericReset(dest: pointer, mt: PNimType) {.compilerProc, benign.} proc genericResetAux(dest: pointer, n: ptr TNimNode) = var d = cast[ByteAddress](dest) diff --git a/lib/system/cgprocs.nim b/lib/system/cgprocs.nim index 660c68116..72219c2b7 100644 --- a/lib/system/cgprocs.nim +++ b/lib/system/cgprocs.nim @@ -12,7 +12,6 @@ type LibHandle = pointer # private type ProcAddr = pointer # library loading and loading of procs: -{.deprecated: [TLibHandle: LibHandle, TProcAddr: ProcAddr].} proc nimLoadLibrary(path: string): LibHandle {.compilerproc.} proc nimUnloadLibrary(lib: LibHandle) {.compilerproc.} diff --git a/lib/system/excpt.nim b/lib/system/excpt.nim index f25da0ad8..7d5f5af7f 100644 --- a/lib/system/excpt.nim +++ b/lib/system/excpt.nim @@ -213,7 +213,7 @@ proc auxWriteStackTrace(f: PFrame; s: var seq[StackTraceEntry]) = inc(i) it = it.prev var last = i-1 - if s.isNil: + if s.len == 0: s = newSeq[StackTraceEntry](i) else: last = s.len + i - 1 @@ -307,7 +307,7 @@ when hasSomeStackTrace: when NimStackTrace: auxWriteStackTrace(framePtr, s) else: - s = nil + s = @[] proc stackTraceAvailable(): bool = when NimStackTrace: @@ -361,10 +361,10 @@ proc raiseExceptionAux(e: ref Exception) = else: when hasSomeStackTrace: var buf = newStringOfCap(2000) - if isNil(e.trace): rawWriteStackTrace(buf) + if e.trace.len == 0: rawWriteStackTrace(buf) else: add(buf, $e.trace) add(buf, "Error: unhandled exception: ") - if not isNil(e.msg): add(buf, e.msg) + add(buf, e.msg) add(buf, " [") add(buf, $e.name) add(buf, "]\n") @@ -382,7 +382,7 @@ proc raiseExceptionAux(e: ref Exception) = var buf: array[0..2000, char] var L = 0 add(buf, "Error: unhandled exception: ") - if not isNil(e.msg): add(buf, e.msg) + add(buf, e.msg) add(buf, " [") xadd(buf, e.name, e.name.len) add(buf, "]\n") @@ -397,7 +397,7 @@ proc raiseExceptionAux(e: ref Exception) = proc raiseException(e: ref Exception, ename: cstring) {.compilerRtl.} = if e.name.isNil: e.name = ename when hasSomeStackTrace: - if e.trace.isNil: + if e.trace.len == 0: rawWriteStackTrace(e.trace) elif framePtr != nil: e.trace.add reraisedFrom(reraisedFromBegin) @@ -427,15 +427,16 @@ proc getStackTrace(): string = result = "No stack traceback available\n" proc getStackTrace(e: ref Exception): string = - if not isNil(e) and not isNil(e.trace): + if not isNil(e): result = $e.trace else: result = "" -proc getStackTraceEntries*(e: ref Exception): seq[StackTraceEntry] = - ## Returns the attached stack trace to the exception ``e`` as - ## a ``seq``. This is not yet available for the JS backend. - shallowCopy(result, e.trace) +when not defined(gcDestructors): + proc getStackTraceEntries*(e: ref Exception): seq[StackTraceEntry] = + ## Returns the attached stack trace to the exception ``e`` as + ## a ``seq``. This is not yet available for the JS backend. + shallowCopy(result, e.trace) when defined(nimRequiresNimFrame): proc stackOverflow() {.noinline.} = diff --git a/lib/system/gc_ms.nim b/lib/system/gc_ms.nim index 75f9c6749..96221b175 100644 --- a/lib/system/gc_ms.nim +++ b/lib/system/gc_ms.nim @@ -264,12 +264,13 @@ proc forAllChildren(cell: PCell, op: WalkOp) = of tyRef, tyOptAsRef: # common case forAllChildrenAux(cellToUsr(cell), cell.typ.base, op) of tySequence: - var d = cast[ByteAddress](cellToUsr(cell)) - var s = cast[PGenericSeq](d) - if s != nil: - for i in 0..s.len-1: - forAllChildrenAux(cast[pointer](d +% i *% cell.typ.base.size +% - GenericSeqSize), cell.typ.base, op) + when not defined(gcDestructors): + var d = cast[ByteAddress](cellToUsr(cell)) + var s = cast[PGenericSeq](d) + if s != nil: + for i in 0..s.len-1: + forAllChildrenAux(cast[pointer](d +% i *% cell.typ.base.size +% + GenericSeqSize), cell.typ.base, op) else: discard proc rawNewObj(typ: PNimType, size: int, gch: var GcHeap): pointer = @@ -310,53 +311,54 @@ proc newObjNoInit(typ: PNimType, size: int): pointer {.compilerRtl.} = result = rawNewObj(typ, size, gch) when defined(memProfiler): nimProfile(size) -proc newSeq(typ: PNimType, len: int): pointer {.compilerRtl.} = - # `newObj` already uses locks, so no need for them here. - let size = addInt(mulInt(len, typ.base.size), GenericSeqSize) - result = newObj(typ, size) - cast[PGenericSeq](result).len = len - cast[PGenericSeq](result).reserved = len - when defined(memProfiler): nimProfile(size) - proc newObjRC1(typ: PNimType, size: int): pointer {.compilerRtl.} = result = rawNewObj(typ, size, gch) zeroMem(result, size) when defined(memProfiler): nimProfile(size) -proc newSeqRC1(typ: PNimType, len: int): pointer {.compilerRtl.} = - let size = addInt(mulInt(len, typ.base.size), GenericSeqSize) - result = newObj(typ, size) - cast[PGenericSeq](result).len = len - cast[PGenericSeq](result).reserved = len - when defined(memProfiler): nimProfile(size) - -proc growObj(old: pointer, newsize: int, gch: var GcHeap): pointer = - acquire(gch) - collectCT(gch, newsize + sizeof(Cell)) - var ol = usrToCell(old) - sysAssert(ol.typ != nil, "growObj: 1") - gcAssert(ol.typ.kind in {tyString, tySequence}, "growObj: 2") - - var res = cast[PCell](rawAlloc(gch.region, newsize + sizeof(Cell))) - var elemSize = 1 - if ol.typ.kind != tyString: elemSize = ol.typ.base.size - incTypeSize ol.typ, newsize - - var oldsize = cast[PGenericSeq](old).len*elemSize + GenericSeqSize - copyMem(res, ol, oldsize + sizeof(Cell)) - zeroMem(cast[pointer](cast[ByteAddress](res)+% oldsize +% sizeof(Cell)), - newsize-oldsize) - sysAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "growObj: 3") - when withBitvectors: incl(gch.allocated, res) - when useCellIds: - inc gch.idGenerator - res.id = gch.idGenerator - release(gch) - result = cellToUsr(res) - when defined(memProfiler): nimProfile(newsize-oldsize) +when not defined(gcDestructors): + proc newSeq(typ: PNimType, len: int): pointer {.compilerRtl.} = + # `newObj` already uses locks, so no need for them here. + let size = addInt(mulInt(len, typ.base.size), GenericSeqSize) + result = newObj(typ, size) + cast[PGenericSeq](result).len = len + cast[PGenericSeq](result).reserved = len + when defined(memProfiler): nimProfile(size) + + proc newSeqRC1(typ: PNimType, len: int): pointer {.compilerRtl.} = + let size = addInt(mulInt(len, typ.base.size), GenericSeqSize) + result = newObj(typ, size) + cast[PGenericSeq](result).len = len + cast[PGenericSeq](result).reserved = len + when defined(memProfiler): nimProfile(size) + + proc growObj(old: pointer, newsize: int, gch: var GcHeap): pointer = + acquire(gch) + collectCT(gch, newsize + sizeof(Cell)) + var ol = usrToCell(old) + sysAssert(ol.typ != nil, "growObj: 1") + gcAssert(ol.typ.kind in {tyString, tySequence}, "growObj: 2") + + var res = cast[PCell](rawAlloc(gch.region, newsize + sizeof(Cell))) + var elemSize = 1 + if ol.typ.kind != tyString: elemSize = ol.typ.base.size + incTypeSize ol.typ, newsize + + var oldsize = cast[PGenericSeq](old).len*elemSize + GenericSeqSize + copyMem(res, ol, oldsize + sizeof(Cell)) + zeroMem(cast[pointer](cast[ByteAddress](res)+% oldsize +% sizeof(Cell)), + newsize-oldsize) + sysAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "growObj: 3") + when withBitvectors: incl(gch.allocated, res) + when useCellIds: + inc gch.idGenerator + res.id = gch.idGenerator + release(gch) + result = cellToUsr(res) + when defined(memProfiler): nimProfile(newsize-oldsize) -proc growObj(old: pointer, newsize: int): pointer {.rtl.} = - result = growObj(old, newsize, gch) + proc growObj(old: pointer, newsize: int): pointer {.rtl.} = + result = growObj(old, newsize, gch) {.push profiler:off.} diff --git a/lib/system/helpers.nim b/lib/system/helpers.nim new file mode 100644 index 000000000..fb1218684 --- /dev/null +++ b/lib/system/helpers.nim @@ -0,0 +1,11 @@ +## helpers used system.nim and other modules, avoids code duplication while +## also minimizing symbols exposed in system.nim +# +# TODO: move other things here that should not be exposed in system.nim + +proc lineInfoToString(file: string, line, column: int): string = + file & "(" & $line & ", " & $column & ")" + +proc `$`(info: type(instantiationInfo(0))): string = + # The +1 is needed here + lineInfoToString(info.fileName, info.line, info.column+1) diff --git a/lib/system/hti.nim b/lib/system/hti.nim index 45b1d1cd3..c7b52bbdf 100644 --- a/lib/system/hti.nim +++ b/lib/system/hti.nim @@ -7,12 +7,6 @@ # distribution, for details about the copyright. # -when declared(NimString): - # we are in system module: - {.pragma: codegenType, compilerproc.} -else: - {.pragma: codegenType, importc.} - type # This should be the same as ast.TTypeKind # many enum fields are not used at runtime @@ -79,7 +73,7 @@ type tyVoidHidden TNimNodeKind = enum nkNone, nkSlot, nkList, nkCase - TNimNode {.codegenType.} = object + TNimNode {.compilerProc.} = object kind: TNimNodeKind offset: int typ: ptr TNimType @@ -92,7 +86,7 @@ type ntfAcyclic = 1, # type cannot form a cycle ntfEnumHole = 2 # enum has holes and thus `$` for them needs the slow # version - TNimType {.codegenType.} = object + TNimType {.compilerProc.} = object size: int kind: TNimKind flags: set[TNimTypeFlag] @@ -109,6 +103,6 @@ type PNimType = ptr TNimType when defined(nimTypeNames): - var nimTypeRoot {.codegenType.}: PNimType + var nimTypeRoot {.compilerProc.}: PNimType # node.len may be the ``first`` element of a set diff --git a/lib/system/jssys.nim b/lib/system/jssys.nim index 8d4a2e482..836ac198d 100644 --- a/lib/system/jssys.nim +++ b/lib/system/jssys.nim @@ -31,8 +31,6 @@ type JSRef = ref RootObj # Fake type. -{.deprecated: [TSafePoint: SafePoint, TCallFrame: CallFrame].} - var framePtr {.importc, nodecl, volatile.}: PCallFrame excHandler {.importc, nodecl, volatile.}: int = 0 @@ -184,12 +182,10 @@ proc setConstr() {.varargs, asmNoStackFrame, compilerproc.} = proc makeNimstrLit(c: cstring): string {.asmNoStackFrame, compilerproc.} = {.emit: """ var ln = `c`.length; - var result = new Array(ln + 1); - var i = 0; - for (; i < ln; ++i) { + var result = new Array(ln); + for (var i = 0; i < ln; ++i) { result[i] = `c`.charCodeAt(i); } - result[i] = 0; // terminating zero return result; """.} @@ -227,13 +223,12 @@ proc cstrToNimstr(c: cstring): string {.asmNoStackFrame, compilerproc.} = } ++r; } - result[r] = 0; // terminating zero return result; """.} proc toJSStr(s: string): cstring {.asmNoStackFrame, compilerproc.} = asm """ - var len = `s`.length-1; + var len = `s`.length; var asciiPart = new Array(len); var fcc = String.fromCharCode; var nonAsciiPart = null; @@ -264,10 +259,7 @@ proc toJSStr(s: string): cstring {.asmNoStackFrame, compilerproc.} = proc mnewString(len: int): string {.asmNoStackFrame, compilerproc.} = asm """ - var result = new Array(`len`+1); - result[0] = 0; - result[`len`] = 0; - return result; + return new Array(`len`); """ proc SetCard(a: int): int {.compilerproc, asmNoStackFrame.} = @@ -325,7 +317,7 @@ proc cmpStrings(a, b: string): int {.asmNoStackFrame, compilerProc.} = if (`a` == `b`) return 0; if (!`a`) return -1; if (!`b`) return 1; - for (var i = 0; i < `a`.length - 1 && i < `b`.length - 1; i++) { + for (var i = 0; i < `a`.length && i < `b`.length; i++) { var result = `a`[i] - `b`[i]; if (result != 0) return result; } @@ -506,7 +498,6 @@ proc chckNilDisp(p: pointer) {.compilerproc.} = if p == nil: sysFatal(NilAccessError, "cannot dispatch; dispatcher is nil") -type NimString = string # hack for hti.nim include "system/hti" proc isFatPointer(ti: PNimType): bool = @@ -654,9 +645,7 @@ proc isObj(obj, subclass: PNimType): bool {.compilerproc.} = return true proc addChar(x: string, c: char) {.compilerproc, asmNoStackFrame.} = - asm """ - `x`[`x`.length-1] = `c`; `x`.push(0); - """ + asm "`x`.push(`c`);" {.pop.} diff --git a/lib/system/mmdisp.nim b/lib/system/mmdisp.nim index b33ca93f2..e7e14b948 100644 --- a/lib/system/mmdisp.nim +++ b/lib/system/mmdisp.nim @@ -175,8 +175,7 @@ when defined(boehmgc): dest[] = src type - MemRegion = object {.final, pure.} - {.deprecated: [TMemRegion: MemRegion].} + MemRegion = object proc alloc(r: var MemRegion, size: int): pointer = result = boehmAlloc(size) @@ -215,60 +214,58 @@ elif defined(gogc): goNumSizeClasses = 67 type - cbool {.importc: "_Bool", nodecl.} = bool - goMStats_inner_struct = object - size: uint32 - nmalloc: uint64 - nfree: uint64 + size: uint32 + nmalloc: uint64 + nfree: uint64 goMStats = object - # General statistics. - alloc: uint64 # bytes allocated and still in use - total_alloc: uint64 # bytes allocated (even if freed) - sys: uint64 # bytes obtained from system (should be sum of xxx_sys below, no locking, approximate) - nlookup: uint64 # number of pointer lookups - nmalloc: uint64 # number of mallocs - nfree: uint64 # number of frees - # Statistics about malloc heap. - # protected by mheap.Lock - heap_alloc: uint64 # bytes allocated and still in use - heap_sys: uint64 # bytes obtained from system - heap_idle: uint64 # bytes in idle spans - heap_inuse: uint64 # bytes in non-idle spans - heap_released: uint64 # bytes released to the OS - heap_objects: uint64 # total number of allocated objects - # Statistics about allocation of low-level fixed-size structures. - # Protected by FixAlloc locks. - stacks_inuse: uint64 # bootstrap stacks - stacks_sys: uint64 - mspan_inuse: uint64 # MSpan structures - mspan_sys: uint64 - mcache_inuse: uint64 # MCache structures - mcache_sys: uint64 - buckhash_sys: uint64 # profiling bucket hash table - gc_sys: uint64 - other_sys: uint64 - # Statistics about garbage collector. - # Protected by mheap or stopping the world during GC. - next_gc: uint64 # next GC (in heap_alloc time) - last_gc: uint64 # last GC (in absolute time) - pause_total_ns: uint64 - pause_ns: array[256, uint64] # circular buffer of recent gc pause lengths - pause_end: array[256, uint64] # circular buffer of recent gc end times (nanoseconds since 1970) - numgc: uint32 - numforcedgc: uint32 # number of user-forced GCs - gc_cpu_fraction: float64 # fraction of CPU time used by GC - enablegc: cbool - debuggc: cbool - # Statistics about allocation size classes. - by_size: array[goNumSizeClasses, goMStats_inner_struct] - # Statistics below here are not exported to MemStats directly. - tinyallocs: uint64 # number of tiny allocations that didn't cause actual allocation; not exported to go directly - gc_trigger: uint64 - heap_live: uint64 - heap_scan: uint64 - heap_marked: uint64 + # General statistics. + alloc: uint64 # bytes allocated and still in use + total_alloc: uint64 # bytes allocated (even if freed) + sys: uint64 # bytes obtained from system (should be sum of xxx_sys below, no locking, approximate) + nlookup: uint64 # number of pointer lookups + nmalloc: uint64 # number of mallocs + nfree: uint64 # number of frees + # Statistics about malloc heap. + # protected by mheap.Lock + heap_alloc: uint64 # bytes allocated and still in use + heap_sys: uint64 # bytes obtained from system + heap_idle: uint64 # bytes in idle spans + heap_inuse: uint64 # bytes in non-idle spans + heap_released: uint64 # bytes released to the OS + heap_objects: uint64 # total number of allocated objects + # Statistics about allocation of low-level fixed-size structures. + # Protected by FixAlloc locks. + stacks_inuse: uint64 # bootstrap stacks + stacks_sys: uint64 + mspan_inuse: uint64 # MSpan structures + mspan_sys: uint64 + mcache_inuse: uint64 # MCache structures + mcache_sys: uint64 + buckhash_sys: uint64 # profiling bucket hash table + gc_sys: uint64 + other_sys: uint64 + # Statistics about garbage collector. + # Protected by mheap or stopping the world during GC. + next_gc: uint64 # next GC (in heap_alloc time) + last_gc: uint64 # last GC (in absolute time) + pause_total_ns: uint64 + pause_ns: array[256, uint64] # circular buffer of recent gc pause lengths + pause_end: array[256, uint64] # circular buffer of recent gc end times (nanoseconds since 1970) + numgc: uint32 + numforcedgc: uint32 # number of user-forced GCs + gc_cpu_fraction: float64 # fraction of CPU time used by GC + enablegc: bool + debuggc: bool + # Statistics about allocation size classes. + by_size: array[goNumSizeClasses, goMStats_inner_struct] + # Statistics below here are not exported to MemStats directly. + tinyallocs: uint64 # number of tiny allocations that didn't cause actual allocation; not exported to go directly + gc_trigger: uint64 + heap_live: uint64 + heap_scan: uint64 + heap_marked: uint64 proc goRuntime_ReadMemStats(a2: ptr goMStats) {.cdecl, importc: "runtime_ReadMemStats", @@ -341,9 +338,12 @@ elif defined(gogc): proc getOccupiedSharedMem(): int = discard const goFlagNoZero: uint32 = 1 shl 3 - proc goRuntimeMallocGC(size: uint, typ: uint, flag: uint32): pointer {.importc: "runtime_mallocgc", dynlib: goLib.} + proc goRuntimeMallocGC(size: uint, typ: uint, flag: uint32): pointer {. + importc: "runtime_mallocgc", dynlib: goLib.} - proc goSetFinalizer(obj: pointer, f: pointer) {.importc: "set_finalizer", codegenDecl:"$1 $2$3 __asm__ (\"main.Set_finalizer\");\n$1 $2$3", dynlib: goLib.} + proc goSetFinalizer(obj: pointer, f: pointer) {. + importc: "set_finalizer", codegenDecl: "$1 $2$3 __asm__ (\"main.Set_finalizer\");\n$1 $2$3", + dynlib: goLib.} proc newObj(typ: PNimType, size: int): pointer {.compilerproc.} = result = goRuntimeMallocGC(roundup(size, sizeof(pointer)).uint, 0.uint, 0.uint32) @@ -369,8 +369,7 @@ elif defined(gogc): proc growObj(old: pointer, newsize: int): pointer = # the Go GC doesn't have a realloc - var - oldsize = cast[PGenericSeq](old).len * cast[PGenericSeq](old).elemSize + GenericSeqSize + let oldsize = cast[PGenericSeq](old).len * cast[PGenericSeq](old).elemSize + GenericSeqSize result = goRuntimeMallocGC(roundup(newsize, sizeof(pointer)).uint, 0.uint, goFlagNoZero) copyMem(result, old, oldsize) zeroMem(cast[pointer](cast[ByteAddress](result) +% oldsize), newsize - oldsize) @@ -386,8 +385,7 @@ elif defined(gogc): dest[] = src type - MemRegion = object {.final, pure.} - {.deprecated: [TMemRegion: MemRegion].} + MemRegion = object proc alloc(r: var MemRegion, size: int): pointer = result = alloc(size) @@ -477,8 +475,7 @@ elif defined(nogc) and defined(useMalloc): dest[] = src type - MemRegion = object {.final, pure.} - {.deprecated: [TMemRegion: MemRegion].} + MemRegion = object proc alloc(r: var MemRegion, size: int): pointer = result = alloc(size) @@ -551,15 +548,13 @@ else: elif defined(gcRegions): # XXX due to bootstrapping reasons, we cannot use compileOption("gc", "stack") here include "system/gc_regions" - elif defined(gcMarkAndSweep): + elif defined(gcMarkAndSweep) or defined(gcDestructors): # XXX use 'compileOption' here include "system/gc_ms" - elif defined(gcGenerational): - include "system/gc" else: include "system/gc" -when not declared(nimNewSeqOfCap): +when not declared(nimNewSeqOfCap) and not defined(gcDestructors): proc nimNewSeqOfCap(typ: PNimType, cap: int): pointer {.compilerproc.} = when defined(gcRegions): let s = mulInt(cap, typ.base.size) # newStr already adds GenericSeqSize diff --git a/lib/system/nimscript.nim b/lib/system/nimscript.nim index 5bf69dd94..64d6255da 100644 --- a/lib/system/nimscript.nim +++ b/lib/system/nimscript.nim @@ -73,12 +73,12 @@ proc switch*(key: string, val="") = proc warning*(name: string; val: bool) = ## Disables or enables a specific warning. let v = if val: "on" else: "off" - warningImpl(name & "]:" & v, "warning[" & name & "]:" & v) + warningImpl(name & ":" & v, "warning:" & name & ":" & v) proc hint*(name: string; val: bool) = ## Disables or enables a specific hint. let v = if val: "on" else: "off" - hintImpl(name & "]:" & v, "hint[" & name & "]:" & v) + hintImpl(name & ":" & v, "hint:" & name & ":" & v) proc patchFile*(package, filename, replacement: string) = ## Overrides the location of a given file belonging to the @@ -305,7 +305,6 @@ template withDir*(dir: string; body: untyped): untyped = finally: cd(curDir) -template `==?`(a, b: string): bool = cmpIgnoreStyle(a, b) == 0 proc writeTask(name, desc: string) = if desc.len > 0: @@ -313,29 +312,30 @@ proc writeTask(name, desc: string) = for i in 0 ..< 20 - name.len: spaces.add ' ' echo name, spaces, desc -template task*(name: untyped; description: string; body: untyped): untyped = - ## Defines a task. Hidden tasks are supported via an empty description. - ## Example: - ## - ## .. code-block:: nim - ## task build, "default build is via the C backend": - ## setCommand "c" - proc `name Task`*() = body - - let cmd = getCommand() - if cmd.len == 0 or cmd ==? "help": - setCommand "help" - writeTask(astToStr(name), description) - elif cmd ==? astToStr(name): - setCommand "nop" - `name Task`() - proc cppDefine*(define: string) = ## tell Nim that ``define`` is a C preprocessor ``#define`` and so always ## needs to be mangled. builtin when not defined(nimble): + template `==?`(a, b: string): bool = cmpIgnoreStyle(a, b) == 0 + template task*(name: untyped; description: string; body: untyped): untyped = + ## Defines a task. Hidden tasks are supported via an empty description. + ## Example: + ## + ## .. code-block:: nim + ## task build, "default build is via the C backend": + ## setCommand "c" + proc `name Task`*() = body + + let cmd = getCommand() + if cmd.len == 0 or cmd ==? "help": + setCommand "help" + writeTask(astToStr(name), description) + elif cmd ==? astToStr(name): + setCommand "nop" + `name Task`() + # nimble has its own implementation for these things. var packageName* = "" ## Nimble support: Set this to the package name. It diff --git a/lib/system/repr.nim b/lib/system/repr.nim index 982b07467..85701c28f 100644 --- a/lib/system/repr.nim +++ b/lib/system/repr.nim @@ -25,29 +25,13 @@ proc reprPointer(x: pointer): string {.compilerproc.} = discard c_sprintf(buf, "%p", x) return $buf -proc `$`(x: uint64): string = - if x == 0: - result = "0" - else: - result = newString(60) - var i = 0 - var n = x - while n != 0: - let nn = n div 10'u64 - result[i] = char(n - 10'u64 * nn + ord('0')) - inc i - n = nn - result.setLen i - - let half = i div 2 - # Reverse - for t in 0 .. half-1: swap(result[t], result[i-t-1]) - proc reprStrAux(result: var string, s: cstring; len: int) = if cast[pointer](s) == nil: add result, "nil" return - add result, reprPointer(cast[pointer](s)) & "\"" + if len > 0: + add result, reprPointer(cast[pointer](s)) + add result, "\"" for i in 0 .. pred(len): let c = s[i] case c @@ -180,9 +164,10 @@ when not defined(useNimRtl): proc reprSequence(result: var string, p: pointer, typ: PNimType, cl: var ReprClosure) = if p == nil: - add result, "nil" + add result, "[]" return - result.add(reprPointer(p) & "[") + result.add(reprPointer(p)) + result.add '[' var bs = typ.base.size for i in 0..cast[PGenericSeq](p).len-1: if i > 0: add result, ", " @@ -284,7 +269,7 @@ when not defined(useNimRtl): of tyChar: add result, reprChar(cast[ptr char](p)[]) of tyString: let sp = cast[ptr string](p) - reprStrAux(result, if sp[].isNil: nil else: sp[].cstring, sp[].len) + reprStrAux(result, sp[].cstring, sp[].len) of tyCString: let cs = cast[ptr cstring](p)[] if cs.isNil: add result, "nil" diff --git a/lib/system/reprjs.nim b/lib/system/reprjs.nim index d04d6e12b..7cb25a252 100644 --- a/lib/system/reprjs.nim +++ b/lib/system/reprjs.nim @@ -232,10 +232,7 @@ proc reprAux(result: var string, p: pointer, typ: PNimType, of tyString: var fp: int {. emit: "`fp` = `p`;\n" .} - if cast[string](fp).isNil: - add(result, "nil") - else: - add( result, reprStr(cast[string](p)) ) + add( result, reprStr(cast[string](p)) ) of tyCString: var fp: cstring {. emit: "`fp` = `p`;\n" .} diff --git a/lib/system/strmantle.nim b/lib/system/strmantle.nim new file mode 100644 index 000000000..ceaecb4f9 --- /dev/null +++ b/lib/system/strmantle.nim @@ -0,0 +1,298 @@ +# +# +# Nim's Runtime Library +# (c) Copyright 2018 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## Compilerprocs for strings that do not depend on the string implementation. + +proc cmpStrings(a, b: string): int {.inline, compilerProc.} = + let alen = a.len + let blen = b.len + let minlen = min(alen, blen) + if minlen > 0: + result = c_memcmp(unsafeAddr a[0], unsafeAddr b[0], minlen.csize) + if result == 0: + result = alen - blen + else: + result = alen - blen + +proc eqStrings(a, b: string): bool {.inline, compilerProc.} = + let alen = a.len + let blen = b.len + if alen == blen: + if alen == 0: return true + return equalMem(unsafeAddr(a[0]), unsafeAddr(b[0]), alen) + +proc hashString(s: string): int {.compilerproc.} = + # the compiler needs exactly the same hash function! + # this used to be used for efficient generation of string case statements + var h = 0 + for i in 0..len(s)-1: + h = h +% ord(s[i]) + h = h +% h shl 10 + h = h xor (h shr 6) + h = h +% h shl 3 + h = h xor (h shr 11) + h = h +% h shl 15 + result = h + +proc add*(result: var string; x: int64) = + let base = result.len + setLen(result, base + sizeof(x)*4) + var i = 0 + var y = x + while true: + var d = y div 10 + result[base+i] = chr(abs(int(y - d*10)) + ord('0')) + inc(i) + y = d + if y == 0: break + if x < 0: + result[base+i] = '-' + inc(i) + setLen(result, base+i) + # mirror the string: + for j in 0..i div 2 - 1: + swap(result[base+j], result[base+i-j-1]) + +proc nimIntToStr(x: int): string {.compilerRtl.} = + result = newStringOfCap(sizeof(x)*4) + result.add x + +proc add*(result: var string; x: float) = + when nimvm: + result.add $x + else: + var buf: array[0..64, char] + when defined(nimNoArrayToCstringConversion): + var n: int = c_sprintf(addr buf, "%.16g", x) + else: + var n: int = c_sprintf(buf, "%.16g", x) + var hasDot = false + for i in 0..n-1: + if buf[i] == ',': + buf[i] = '.' + hasDot = true + elif buf[i] in {'a'..'z', 'A'..'Z', '.'}: + hasDot = true + if not hasDot: + buf[n] = '.' + buf[n+1] = '0' + buf[n+2] = '\0' + # On Windows nice numbers like '1.#INF', '-1.#INF' or '1.#NAN' + # of '-1.#IND' are produced. + # We want to get rid of these here: + if buf[n-1] in {'n', 'N', 'D', 'd'}: + result.add "nan" + elif buf[n-1] == 'F': + if buf[0] == '-': + result.add "-inf" + else: + result.add "inf" + else: + var i = 0 + while buf[i] != '\0': + result.add buf[i] + inc i + +proc nimFloatToStr(f: float): string {.compilerproc.} = + result = newStringOfCap(8) + result.add f + +proc c_strtod(buf: cstring, endptr: ptr cstring): float64 {. + importc: "strtod", header: "<stdlib.h>", noSideEffect.} + +const + IdentChars = {'a'..'z', 'A'..'Z', '0'..'9', '_'} + powtens = [1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, + 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, + 1e20, 1e21, 1e22] + +proc nimParseBiggestFloat(s: string, number: var BiggestFloat, + start = 0): int {.compilerProc.} = + # This routine attempt to parse float that can parsed quickly. + # ie whose integer part can fit inside a 53bits integer. + # their real exponent must also be <= 22. If the float doesn't follow + # these restrictions, transform the float into this form: + # INTEGER * 10 ^ exponent and leave the work to standard `strtod()`. + # This avoid the problems of decimal character portability. + # see: http://www.exploringbinary.com/fast-path-decimal-to-floating-point-conversion/ + var + i = start + sign = 1.0 + kdigits, fdigits = 0 + exponent: int + integer: uint64 + frac_exponent = 0 + exp_sign = 1 + first_digit = -1 + has_sign = false + + # Sign? + if s[i] == '+' or s[i] == '-': + has_sign = true + if s[i] == '-': + sign = -1.0 + inc(i) + + # NaN? + if s[i] == 'N' or s[i] == 'n': + if s[i+1] == 'A' or s[i+1] == 'a': + if s[i+2] == 'N' or s[i+2] == 'n': + if s[i+3] notin IdentChars: + number = NaN + return i+3 - start + return 0 + + # Inf? + if s[i] == 'I' or s[i] == 'i': + if s[i+1] == 'N' or s[i+1] == 'n': + if s[i+2] == 'F' or s[i+2] == 'f': + if s[i+3] notin IdentChars: + number = Inf*sign + return i+3 - start + return 0 + + if s[i] in {'0'..'9'}: + first_digit = (s[i].ord - '0'.ord) + # Integer part? + while s[i] in {'0'..'9'}: + inc(kdigits) + integer = integer * 10'u64 + (s[i].ord - '0'.ord).uint64 + inc(i) + while s[i] == '_': inc(i) + + # Fractional part? + if s[i] == '.': + inc(i) + # if no integer part, Skip leading zeros + if kdigits <= 0: + while s[i] == '0': + inc(frac_exponent) + inc(i) + while s[i] == '_': inc(i) + + if first_digit == -1 and s[i] in {'0'..'9'}: + first_digit = (s[i].ord - '0'.ord) + # get fractional part + while s[i] in {'0'..'9'}: + inc(fdigits) + inc(frac_exponent) + integer = integer * 10'u64 + (s[i].ord - '0'.ord).uint64 + inc(i) + while s[i] == '_': inc(i) + + # if has no digits: return error + if kdigits + fdigits <= 0 and + (i == start or # no char consumed (empty string). + (i == start + 1 and has_sign)): # or only '+' or '- + return 0 + + if s[i] in {'e', 'E'}: + inc(i) + if s[i] == '+' or s[i] == '-': + if s[i] == '-': + exp_sign = -1 + + inc(i) + if s[i] notin {'0'..'9'}: + return 0 + while s[i] in {'0'..'9'}: + exponent = exponent * 10 + (ord(s[i]) - ord('0')) + inc(i) + while s[i] == '_': inc(i) # underscores are allowed and ignored + + var real_exponent = exp_sign*exponent - frac_exponent + let exp_negative = real_exponent < 0 + var abs_exponent = abs(real_exponent) + + # if exponent greater than can be represented: +/- zero or infinity + if abs_exponent > 999: + if exp_negative: + number = 0.0*sign + else: + number = Inf*sign + return i - start + + # if integer is representable in 53 bits: fast path + # max fast path integer is 1<<53 - 1 or 8999999999999999 (16 digits) + let digits = kdigits + fdigits + if digits <= 15 or (digits <= 16 and first_digit <= 8): + # max float power of ten with set bits above the 53th bit is 10^22 + if abs_exponent <= 22: + if exp_negative: + number = sign * integer.float / powtens[abs_exponent] + else: + number = sign * integer.float * powtens[abs_exponent] + return i - start + + # if exponent is greater try to fit extra exponent above 22 by multiplying + # integer part is there is space left. + let slop = 15 - kdigits - fdigits + if abs_exponent <= 22 + slop and not exp_negative: + number = sign * integer.float * powtens[slop] * powtens[abs_exponent-slop] + return i - start + + # if failed: slow path with strtod. + var t: array[500, char] # flaviu says: 325 is the longest reasonable literal + var ti = 0 + let maxlen = t.high - "e+000".len # reserve enough space for exponent + + result = i - start + i = start + # re-parse without error checking, any error should be handled by the code above. + if s[i] == '.': i.inc + while s[i] in {'0'..'9','+','-'}: + if ti < maxlen: + t[ti] = s[i]; inc(ti) + inc(i) + while s[i] in {'.', '_'}: # skip underscore and decimal point + inc(i) + + # insert exponent + t[ti] = 'E'; inc(ti) + t[ti] = (if exp_negative: '-' else: '+'); inc(ti) + inc(ti, 3) + + # insert adjusted exponent + t[ti-1] = ('0'.ord + abs_exponent mod 10).char; abs_exponent = abs_exponent div 10 + t[ti-2] = ('0'.ord + abs_exponent mod 10).char; abs_exponent = abs_exponent div 10 + t[ti-3] = ('0'.ord + abs_exponent mod 10).char + + when defined(nimNoArrayToCstringConversion): + number = c_strtod(addr t, nil) + else: + number = c_strtod(t, nil) + +proc nimInt64ToStr(x: int64): string {.compilerRtl.} = + result = newStringOfCap(sizeof(x)*4) + result.add x + +proc nimBoolToStr(x: bool): string {.compilerRtl.} = + return if x: "true" else: "false" + +proc nimCharToStr(x: char): string {.compilerRtl.} = + result = newString(1) + result[0] = x + +proc `$`(x: uint64): string = + if x == 0: + result = "0" + else: + result = newString(60) + var i = 0 + var n = x + while n != 0: + let nn = n div 10'u64 + result[i] = char(n - 10'u64 * nn + ord('0')) + inc i + n = nn + result.setLen i + + let half = i div 2 + # Reverse + for t in 0 .. half-1: swap(result[t], result[i-t-1]) diff --git a/lib/system/sysio.nim b/lib/system/sysio.nim index 7a10849dd..df13ab628 100644 --- a/lib/system/sysio.nim +++ b/lib/system/sysio.nim @@ -143,19 +143,17 @@ proc getFileHandle*(f: File): FileHandle = c_fileno(f) proc readLine(f: File, line: var TaintedString): bool = var pos = 0 - var sp: cint = 80 + # Use the currently reserved space for a first try - if line.string.isNil: - line = TaintedString(newStringOfCap(80)) - else: - when not defined(nimscript): - sp = cint(cast[PGenericSeq](line.string).space) + var sp = line.string.len + if sp == 0: + sp = 80 line.string.setLen(sp) while true: # memset to \L so that we can tell how far fgets wrote, even on EOF, where # fgets doesn't append an \L nimSetMem(addr line.string[pos], '\L'.ord, sp) - var fgetsSuccess = c_fgets(addr line.string[pos], sp, f) != nil + var fgetsSuccess = c_fgets(addr line.string[pos], sp.cint, f) != nil if not fgetsSuccess: checkErr(f) let m = c_memchr(addr line.string[pos], '\L'.ord, sp) if m != nil: @@ -163,7 +161,7 @@ proc readLine(f: File, line: var TaintedString): bool = var last = cast[ByteAddress](m) - cast[ByteAddress](addr line.string[0]) if last > 0 and line.string[last-1] == '\c': line.string.setLen(last-1) - return fgetsSuccess + return last > 1 or fgetsSuccess # We have to distinguish between two possible cases: # \0\l\0 => line ending in a null character. # \0\l\l => last line without newline, null was put there by fgets. @@ -171,7 +169,7 @@ proc readLine(f: File, line: var TaintedString): bool = if last < pos + sp - 1 and line.string[last+1] != '\0': dec last line.string.setLen(last) - return fgetsSuccess + return last > 0 or fgetsSuccess else: # fgets will have inserted a null byte at the end of the string. dec sp diff --git a/lib/system/sysstr.nim b/lib/system/sysstr.nim index 0e690d832..6438a0541 100644 --- a/lib/system/sysstr.nim +++ b/lib/system/sysstr.nim @@ -20,37 +20,6 @@ proc resize(old: int): int {.inline.} = elif old < 65536: result = old * 2 else: result = old * 3 div 2 # for large arrays * 3/2 is better -proc cmpStrings(a, b: NimString): int {.inline, compilerProc.} = - if a == b: return 0 - when defined(nimNoNil): - let alen = if a == nil: 0 else: a.len - let blen = if b == nil: 0 else: b.len - else: - if a == nil: return -1 - if b == nil: return 1 - let alen = a.len - let blen = b.len - let minlen = min(alen, blen) - if minlen > 0: - result = nimCmpMem(addr a.data, addr b.data, minlen.csize) - if result == 0: - result = alen - blen - else: - result = alen - blen - -proc eqStrings(a, b: NimString): bool {.inline, compilerProc.} = - if a == b: return true - when defined(nimNoNil): - let alen = if a == nil: 0 else: a.len - let blen = if b == nil: 0 else: b.len - else: - if a == nil or b == nil: return false - let alen = a.len - let blen = b.len - if alen == blen: - if alen == 0: return true - return equalMem(addr(a.data), addr(b.data), alen) - when declared(allocAtomic): template allocStr(size: untyped): untyped = cast[NimString](allocAtomic(size)) @@ -94,6 +63,8 @@ proc mnewString(len: int): NimString {.compilerProc.} = result.len = len proc copyStrLast(s: NimString, start, last: int): NimString {.compilerProc.} = + # This is not used by most recent versions of the compiler anymore, but + # required for bootstrapping purposes. let start = max(start, 0) if s == nil: return nil let len = min(last, s.len-1) - start + 1 @@ -105,14 +76,16 @@ proc copyStrLast(s: NimString, start, last: int): NimString {.compilerProc.} = else: result = rawNewString(len) -proc nimToCStringConv(s: NimString): cstring {.compilerProc, inline.} = - if s == nil or s.len == 0: result = cstring"" - else: result = cstring(addr s.data) - proc copyStr(s: NimString, start: int): NimString {.compilerProc.} = + # This is not used by most recent versions of the compiler anymore, but + # required for bootstrapping purposes. if s == nil: return nil result = copyStrLast(s, start, s.len-1) +proc nimToCStringConv(s: NimString): cstring {.compilerProc, inline.} = + if s == nil or s.len == 0: result = cstring"" + else: result = cstring(addr s.data) + proc toNimStr(str: cstring, len: int): NimString {.compilerProc.} = result = rawNewStringNoInit(len) result.len = len @@ -164,19 +137,6 @@ proc copyDeepString(src: NimString): NimString {.inline.} = result.len = src.len copyMem(addr(result.data), addr(src.data), src.len + 1) -proc hashString(s: string): int {.compilerproc.} = - # the compiler needs exactly the same hash function! - # this used to be used for efficient generation of string case statements - var h = 0 - for i in 0..len(s)-1: - h = h +% ord(s[i]) - h = h +% h shl 10 - h = h xor (h shr 6) - h = h +% h shl 3 - h = h xor (h shr 11) - h = h +% h shl 15 - result = h - proc addChar(s: NimString, c: char): NimString = # is compilerproc! if s == nil: @@ -403,243 +363,3 @@ proc setLengthSeqV2(s: PGenericSeq, typ: PNimType, newLen: int): PGenericSeq {. result.len = newLen else: result = setLengthSeq(s, typ.base.size, newLen) - -# --------------- other string routines ---------------------------------- -proc add*(result: var string; x: int64) = - let base = result.len - setLen(result, base + sizeof(x)*4) - var i = 0 - var y = x - while true: - var d = y div 10 - result[base+i] = chr(abs(int(y - d*10)) + ord('0')) - inc(i) - y = d - if y == 0: break - if x < 0: - result[base+i] = '-' - inc(i) - setLen(result, base+i) - # mirror the string: - for j in 0..i div 2 - 1: - swap(result[base+j], result[base+i-j-1]) - -proc nimIntToStr(x: int): string {.compilerRtl.} = - result = newStringOfCap(sizeof(x)*4) - result.add x - -proc add*(result: var string; x: float) = - when nimvm: - result.add $x - else: - var buf: array[0..64, char] - when defined(nimNoArrayToCstringConversion): - var n: int = c_sprintf(addr buf, "%.16g", x) - else: - var n: int = c_sprintf(buf, "%.16g", x) - var hasDot = false - for i in 0..n-1: - if buf[i] == ',': - buf[i] = '.' - hasDot = true - elif buf[i] in {'a'..'z', 'A'..'Z', '.'}: - hasDot = true - if not hasDot: - buf[n] = '.' - buf[n+1] = '0' - buf[n+2] = '\0' - # On Windows nice numbers like '1.#INF', '-1.#INF' or '1.#NAN' - # of '-1.#IND' are produced. - # We want to get rid of these here: - if buf[n-1] in {'n', 'N', 'D', 'd'}: - result.add "nan" - elif buf[n-1] == 'F': - if buf[0] == '-': - result.add "-inf" - else: - result.add "inf" - else: - var i = 0 - while buf[i] != '\0': - result.add buf[i] - inc i - -proc nimFloatToStr(f: float): string {.compilerproc.} = - result = newStringOfCap(8) - result.add f - -proc c_strtod(buf: cstring, endptr: ptr cstring): float64 {. - importc: "strtod", header: "<stdlib.h>", noSideEffect.} - -const - IdentChars = {'a'..'z', 'A'..'Z', '0'..'9', '_'} - powtens = [1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, - 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, - 1e20, 1e21, 1e22] - -proc nimParseBiggestFloat(s: string, number: var BiggestFloat, - start = 0): int {.compilerProc.} = - # This routine attempt to parse float that can parsed quickly. - # ie whose integer part can fit inside a 53bits integer. - # their real exponent must also be <= 22. If the float doesn't follow - # these restrictions, transform the float into this form: - # INTEGER * 10 ^ exponent and leave the work to standard `strtod()`. - # This avoid the problems of decimal character portability. - # see: http://www.exploringbinary.com/fast-path-decimal-to-floating-point-conversion/ - var - i = start - sign = 1.0 - kdigits, fdigits = 0 - exponent: int - integer: uint64 - frac_exponent = 0 - exp_sign = 1 - first_digit = -1 - has_sign = false - - # Sign? - if s[i] == '+' or s[i] == '-': - has_sign = true - if s[i] == '-': - sign = -1.0 - inc(i) - - # NaN? - if s[i] == 'N' or s[i] == 'n': - if s[i+1] == 'A' or s[i+1] == 'a': - if s[i+2] == 'N' or s[i+2] == 'n': - if s[i+3] notin IdentChars: - number = NaN - return i+3 - start - return 0 - - # Inf? - if s[i] == 'I' or s[i] == 'i': - if s[i+1] == 'N' or s[i+1] == 'n': - if s[i+2] == 'F' or s[i+2] == 'f': - if s[i+3] notin IdentChars: - number = Inf*sign - return i+3 - start - return 0 - - if s[i] in {'0'..'9'}: - first_digit = (s[i].ord - '0'.ord) - # Integer part? - while s[i] in {'0'..'9'}: - inc(kdigits) - integer = integer * 10'u64 + (s[i].ord - '0'.ord).uint64 - inc(i) - while s[i] == '_': inc(i) - - # Fractional part? - if s[i] == '.': - inc(i) - # if no integer part, Skip leading zeros - if kdigits <= 0: - while s[i] == '0': - inc(frac_exponent) - inc(i) - while s[i] == '_': inc(i) - - if first_digit == -1 and s[i] in {'0'..'9'}: - first_digit = (s[i].ord - '0'.ord) - # get fractional part - while s[i] in {'0'..'9'}: - inc(fdigits) - inc(frac_exponent) - integer = integer * 10'u64 + (s[i].ord - '0'.ord).uint64 - inc(i) - while s[i] == '_': inc(i) - - # if has no digits: return error - if kdigits + fdigits <= 0 and - (i == start or # no char consumed (empty string). - (i == start + 1 and has_sign)): # or only '+' or '- - return 0 - - if s[i] in {'e', 'E'}: - inc(i) - if s[i] == '+' or s[i] == '-': - if s[i] == '-': - exp_sign = -1 - - inc(i) - if s[i] notin {'0'..'9'}: - return 0 - while s[i] in {'0'..'9'}: - exponent = exponent * 10 + (ord(s[i]) - ord('0')) - inc(i) - while s[i] == '_': inc(i) # underscores are allowed and ignored - - var real_exponent = exp_sign*exponent - frac_exponent - let exp_negative = real_exponent < 0 - var abs_exponent = abs(real_exponent) - - # if exponent greater than can be represented: +/- zero or infinity - if abs_exponent > 999: - if exp_negative: - number = 0.0*sign - else: - number = Inf*sign - return i - start - - # if integer is representable in 53 bits: fast path - # max fast path integer is 1<<53 - 1 or 8999999999999999 (16 digits) - let digits = kdigits + fdigits - if digits <= 15 or (digits <= 16 and first_digit <= 8): - # max float power of ten with set bits above the 53th bit is 10^22 - if abs_exponent <= 22: - if exp_negative: - number = sign * integer.float / powtens[abs_exponent] - else: - number = sign * integer.float * powtens[abs_exponent] - return i - start - - # if exponent is greater try to fit extra exponent above 22 by multiplying - # integer part is there is space left. - let slop = 15 - kdigits - fdigits - if abs_exponent <= 22 + slop and not exp_negative: - number = sign * integer.float * powtens[slop] * powtens[abs_exponent-slop] - return i - start - - # if failed: slow path with strtod. - var t: array[500, char] # flaviu says: 325 is the longest reasonable literal - var ti = 0 - let maxlen = t.high - "e+000".len # reserve enough space for exponent - - result = i - start - i = start - # re-parse without error checking, any error should be handled by the code above. - if s[i] == '.': i.inc - while s[i] in {'0'..'9','+','-'}: - if ti < maxlen: - t[ti] = s[i]; inc(ti) - inc(i) - while s[i] in {'.', '_'}: # skip underscore and decimal point - inc(i) - - # insert exponent - t[ti] = 'E'; inc(ti) - t[ti] = (if exp_negative: '-' else: '+'); inc(ti) - inc(ti, 3) - - # insert adjusted exponent - t[ti-1] = ('0'.ord + abs_exponent mod 10).char; abs_exponent = abs_exponent div 10 - t[ti-2] = ('0'.ord + abs_exponent mod 10).char; abs_exponent = abs_exponent div 10 - t[ti-3] = ('0'.ord + abs_exponent mod 10).char - - when defined(nimNoArrayToCstringConversion): - number = c_strtod(addr t, nil) - else: - number = c_strtod(t, nil) - -proc nimInt64ToStr(x: int64): string {.compilerRtl.} = - result = newStringOfCap(sizeof(x)*4) - result.add x - -proc nimBoolToStr(x: bool): string {.compilerRtl.} = - return if x: "true" else: "false" - -proc nimCharToStr(x: char): string {.compilerRtl.} = - result = newString(1) - result[0] = x diff --git a/lib/system/threads.nim b/lib/system/threads.nim index 2434ea21e..aaf0164fd 100644 --- a/lib/system/threads.nim +++ b/lib/system/threads.nim @@ -393,8 +393,9 @@ proc onThreadDestruction*(handler: proc () {.closure, gcsafe.}) = ## A thread is destructed when the ``.thread`` proc returns ## normally or when it raises an exception. Note that unhandled exceptions ## in a thread nevertheless cause the whole process to die. - if threadDestructionHandlers.isNil: - threadDestructionHandlers = @[] + when not defined(nimNoNilSeqs): + if threadDestructionHandlers.isNil: + threadDestructionHandlers = @[] threadDestructionHandlers.add handler template afterThreadRuns() = diff --git a/lib/system/widestrs.nim b/lib/system/widestrs.nim index a8b28c279..85e5e1462 100644 --- a/lib/system/widestrs.nim +++ b/lib/system/widestrs.nim @@ -10,13 +10,12 @@ # Nim support for C/C++'s `wide strings`:idx:. This is part of the system # module! Do not import it directly! -when not declared(NimString): +when not declared(ThisIsSystem): {.error: "You must not import this module explicitly".} type Utf16Char* = distinct int16 WideCString* = ref UncheckedArray[Utf16Char] -{.deprecated: [TUtf16Char: Utf16Char].} proc len*(w: WideCString): int = ## returns the length of a widestring. This traverses the whole string to |