implemented multi methods
This commit is contained in:
parent
66a7e3d37c
commit
3f3dda5a77
65 changed files with 11086 additions and 1258 deletions
|
|
@ -51,20 +51,21 @@ type
|
|||
nnkObjDownConv, nnkObjUpConv, nnkChckRangeF, nnkChckRange64,
|
||||
nnkChckRange, nnkStringToCString, nnkCStringToString, nnkPassAsOpenArray,
|
||||
nnkAsgn, nnkFastAsgn, nnkGenericParams, nnkFormalParams,
|
||||
nnkOfInherit, nnkModule, nnkProcDef, nnkConverterDef,
|
||||
nnkMacroDef, nnkTemplateDef, nnkIteratorDef, nnkOfBranch,
|
||||
nnkElifBranch, nnkExceptBranch, nnkElse, nnkMacroStmt,
|
||||
nnkAsmStmt, nnkPragma, nnkIfStmt, nnkWhenStmt,
|
||||
nnkForStmt, nnkWhileStmt, nnkCaseStmt, nnkVarSection,
|
||||
nnkConstSection, nnkConstDef, nnkTypeSection, nnkTypeDef,
|
||||
nnkYieldStmt, nnkTryStmt, nnkFinally, nnkRaiseStmt,
|
||||
nnkReturnStmt, nnkBreakStmt, nnkContinueStmt, nnkBlockStmt,
|
||||
nnkDiscardStmt, nnkStmtList, nnkImportStmt, nnkFromStmt,
|
||||
nnkIncludeStmt, nnkCommentStmt, nnkStmtListExpr, nnkBlockExpr,
|
||||
nnkStmtListType, nnkBlockType, nnkTypeOfExpr, nnkObjectTy,
|
||||
nnkTupleTy, nnkRecList, nnkRecCase, nnkRecWhen,
|
||||
nnkRefTy, nnkPtrTy, nnkVarTy, nnkDistinctTy,
|
||||
nnkProcTy, nnkEnumTy, nnkEnumFieldDef, nnkReturnToken
|
||||
nnkOfInherit, nnkModule, nnkProcDef, nnkMethodDef,
|
||||
nnkConverterDef, nnkMacroDef, nnkTemplateDef, nnkIteratorDef,
|
||||
nnkOfBranch, nnkElifBranch, nnkExceptBranch, nnkElse,
|
||||
nnkMacroStmt, nnkAsmStmt, nnkPragma, nnkIfStmt,
|
||||
nnkWhenStmt, nnkForStmt, nnkWhileStmt, nnkCaseStmt,
|
||||
nnkVarSection, nnkConstSection, nnkConstDef, nnkTypeSection,
|
||||
nnkTypeDef, nnkYieldStmt, nnkTryStmt, nnkFinally,
|
||||
nnkRaiseStmt, nnkReturnStmt, nnkBreakStmt, nnkContinueStmt,
|
||||
nnkBlockStmt, nnkDiscardStmt, nnkStmtList, nnkImportStmt,
|
||||
nnkFromStmt, nnkIncludeStmt, nnkCommentStmt, nnkStmtListExpr,
|
||||
nnkBlockExpr, nnkStmtListType, nnkBlockType, nnkTypeOfExpr,
|
||||
nnkObjectTy, nnkTupleTy, nnkRecList, nnkRecCase,
|
||||
nnkRecWhen, nnkRefTy, nnkPtrTy, nnkVarTy,
|
||||
nnkDistinctTy, nnkProcTy, nnkEnumTy, nnkEnumFieldDef,
|
||||
nnkReturnToken
|
||||
TNimNodeKinds* = set[TNimrodNodeKind]
|
||||
TNimrodTypeKind* = enum
|
||||
ntyNone, ntyBool, ntyChar, ntyEmpty,
|
||||
|
|
@ -81,9 +82,10 @@ type
|
|||
TNimrodSymKind* = enum
|
||||
nskUnknown, nskConditional, nskDynLib, nskParam,
|
||||
nskGenericParam, nskTemp, nskType, nskConst,
|
||||
nskVar, nskProc, nskIterator, nskConverter,
|
||||
nskMacro, nskTemplate, nskField, nskEnumField,
|
||||
nskForVar, nskModule, nskLabel, nskStub
|
||||
nskVar, nskProc, nskMethod, nskIterator,
|
||||
nskConverter, nskMacro, nskTemplate, nskField,
|
||||
nskEnumField, nskForVar, nskModule, nskLabel,
|
||||
nskStub
|
||||
TNimSymKinds* = set[TNimrodSymKind]
|
||||
#[[[end]]]
|
||||
|
||||
|
|
|
|||
127
lib/pure/os.nim
127
lib/pure/os.nim
|
|
@ -363,7 +363,24 @@ proc `/` * (head, tail: string): string {.noSideEffect.} =
|
|||
## The same as ``joinPath(head, tail)``
|
||||
return joinPath(head, tail)
|
||||
|
||||
proc SplitPath*(path: string, head, tail: var string) {.noSideEffect.} =
|
||||
proc SplitPath*(path: string, head, tail: var string) {.noSideEffect,
|
||||
deprecated.} =
|
||||
## **Deprecated since version 0.8.2**: use the version that returns a tuple
|
||||
## instead
|
||||
var
|
||||
sepPos = -1
|
||||
for i in countdown(len(path)-1, 0):
|
||||
if path[i] in {dirsep, altsep}:
|
||||
sepPos = i
|
||||
break
|
||||
if sepPos >= 0:
|
||||
head = copy(path, 0, sepPos-1)
|
||||
tail = copy(path, sepPos+1)
|
||||
else:
|
||||
head = ""
|
||||
tail = path # make a string copy here
|
||||
|
||||
proc SplitPath*(path: string): tuple[head, tail: string] {.noSideEffect.} =
|
||||
## Splits a directory into (head, tail), so that
|
||||
## ``JoinPath(head, tail) == path``.
|
||||
##
|
||||
|
|
@ -378,11 +395,11 @@ proc SplitPath*(path: string, head, tail: var string) {.noSideEffect.} =
|
|||
sepPos = i
|
||||
break
|
||||
if sepPos >= 0:
|
||||
head = copy(path, 0, sepPos-1)
|
||||
tail = copy(path, sepPos+1)
|
||||
result.head = copy(path, 0, sepPos-1)
|
||||
result.tail = copy(path, sepPos+1)
|
||||
else:
|
||||
head = ""
|
||||
tail = path # make a string copy here
|
||||
result.head = ""
|
||||
result.tail = path
|
||||
|
||||
proc parentDir*(path: string): string {.noSideEffect.} =
|
||||
## Returns the parent directory of `path`.
|
||||
|
|
@ -422,25 +439,50 @@ proc searchExtPos(s: string): int =
|
|||
elif s[i] in {dirsep, altsep}:
|
||||
break # do not skip over path
|
||||
|
||||
proc extractDir*(path: string): string {.noSideEffect.} =
|
||||
proc splitFile*(path: string): tuple[dir, name, ext: string] {.noSideEffect.} =
|
||||
## Splits a filename into (dir, filename, extension).
|
||||
## `dir` does not end in `DirSep`.
|
||||
## `extension` includes the leading dot.
|
||||
##
|
||||
## Example:
|
||||
##
|
||||
## .. code-block:: nimrod
|
||||
## var (dir, name, ext) = splitFile("usr/local/nimrodc.html")
|
||||
## assert dir == "usr/local"
|
||||
## assert name == "nimrodc"
|
||||
## assert ext == ".html"
|
||||
## If `path` has no extension, `ext` is the empty string.
|
||||
## If `path` has no directory component, `dir` is the empty string.
|
||||
## If `path` has no filename component, `name` and `ext` are empty strings.
|
||||
if path.len == 0 or path[path.len-1] in {dirSep, altSep}:
|
||||
result = (path, "", "")
|
||||
else:
|
||||
var sepPos = -1
|
||||
var dotPos = path.len
|
||||
for i in countdown(len(path)-1, 0):
|
||||
if path[i] == ExtSep:
|
||||
if dotPos == path.len: dotPos = i
|
||||
elif path[i] in {dirsep, altsep}:
|
||||
sepPos = i
|
||||
break
|
||||
result.dir = copy(path, 0, sepPos-1)
|
||||
result.name = copy(path, sepPos+1, dotPos-1)
|
||||
result.ext = copy(path, dotPos)
|
||||
|
||||
proc extractDir*(path: string): string {.noSideEffect, deprecated.} =
|
||||
## Extracts the directory of a given path. This is almost the
|
||||
## same as the `head` result of `splitPath`, except that
|
||||
## ``extractDir("/usr/lib/") == "/usr/lib/"``.
|
||||
if path.len == 0 or path[path.len-1] in {dirSep, altSep}:
|
||||
result = path
|
||||
else:
|
||||
var tail: string
|
||||
splitPath(path, result, tail)
|
||||
## **Deprecated since version 0.8.2**: Use ``splitFile(path).dir`` instead.
|
||||
result = splitFile(path).dir
|
||||
|
||||
proc extractFilename*(path: string): string {.noSideEffect.} =
|
||||
## Extracts the filename of a given `path`. This is almost the
|
||||
## same as the `tail` result of `splitPath`, except that
|
||||
## ``extractFilename("/usr/lib/") == ""``.
|
||||
## Extracts the filename of a given `path`. This is the same as
|
||||
## ``name & ext`` from ``splitFile(path)``.
|
||||
if path.len == 0 or path[path.len-1] in {dirSep, altSep}:
|
||||
result = ""
|
||||
else:
|
||||
var head: string
|
||||
splitPath(path, head, result)
|
||||
result = splitPath(path).tail
|
||||
|
||||
proc expandFilename*(filename: string): string =
|
||||
## Returns the full path of `filename`, raises EOS in case of an error.
|
||||
|
|
@ -457,13 +499,14 @@ proc expandFilename*(filename: string): string =
|
|||
c_free(res)
|
||||
|
||||
proc SplitFilename*(filename: string, name, extension: var string) {.
|
||||
noSideEffect.} =
|
||||
noSideEffect, deprecated.} =
|
||||
## Splits a filename into (name, extension), so that
|
||||
## ``name & extension == filename``.
|
||||
##
|
||||
## Example: After ``SplitFilename("usr/local/nimrodc.html", name, ext)``,
|
||||
## `name` is "usr/local/nimrodc" and `ext` is ".html".
|
||||
## It the file has no extension, extention is the empty string.
|
||||
## If the file has no extension, extension is the empty string.
|
||||
## **Deprecated since version 0.8.2**: Use ``splitFile(filename)`` instead.
|
||||
var extPos = searchExtPos(filename)
|
||||
if extPos >= 0:
|
||||
name = copy(filename, 0, extPos-1)
|
||||
|
|
@ -472,18 +515,19 @@ proc SplitFilename*(filename: string, name, extension: var string) {.
|
|||
name = filename # make a string copy here
|
||||
extension = ""
|
||||
|
||||
proc extractFileExt*(filename: string): string {.noSideEffect.} =
|
||||
proc extractFileExt*(filename: string): string {.noSideEffect, deprecated.} =
|
||||
## Extracts the file extension of a given `filename`. This is the
|
||||
## same as the `extension` result of `splitFilename`.
|
||||
var dummy: string
|
||||
splitFilename(filename, dummy, result)
|
||||
## **Deprecated since version 0.8.2**: Use ``splitFile(filename).ext``
|
||||
## instead.
|
||||
result = splitFile(filename).ext
|
||||
|
||||
proc extractFileTrunk*(filename: string): string {.noSideEffect.} =
|
||||
proc extractFileTrunk*(filename: string): string {.noSideEffect, deprecated.} =
|
||||
## Extracts the file name of a given `filename`. This removes any
|
||||
## directory information and the file extension.
|
||||
var dummy: string
|
||||
splitFilename(extractFilename(filename), result, dummy)
|
||||
|
||||
## **Deprecated since version 0.8.2**: Use ``splitFile(path).name`` instead.
|
||||
result = splitFile(filename).name
|
||||
|
||||
proc ChangeFileExt*(filename, ext: string): string {.noSideEffect.} =
|
||||
## Changes the file extension to `ext`.
|
||||
##
|
||||
|
|
@ -496,8 +540,8 @@ proc ChangeFileExt*(filename, ext: string): string {.noSideEffect.} =
|
|||
if extPos < 0: result = filename & normExt(ext)
|
||||
else: result = copy(filename, 0, extPos-1) & normExt(ext)
|
||||
|
||||
proc AppendFileExt*(filename, ext: string): string {.noSideEffect.} =
|
||||
## Appends the file extension `ext` to `filename`, unless
|
||||
proc addFileExt*(filename, ext: string): string {.noSideEffect.} =
|
||||
## Adds the file extension `ext` to `filename`, unless
|
||||
## `filename` already has an extension.
|
||||
##
|
||||
## `Ext` should be given without the leading '.', because some
|
||||
|
|
@ -505,7 +549,12 @@ proc AppendFileExt*(filename, ext: string): string {.noSideEffect.} =
|
|||
## (Although I know of none such beast.)
|
||||
var extPos = searchExtPos(filename)
|
||||
if extPos < 0: result = filename & normExt(ext)
|
||||
else: result = filename #make a string copy here
|
||||
else: result = filename
|
||||
|
||||
proc AppendFileExt*(filename, ext: string): string {.
|
||||
noSideEffect, deprecated.} =
|
||||
## **Deprecated since version 0.8.2**: Use `addFileExt` instead.
|
||||
result = addFileExt(filename, ext)
|
||||
|
||||
proc cmpPaths*(pathA, pathB: string): int {.noSideEffect.} =
|
||||
## Compares two paths.
|
||||
|
|
@ -610,14 +659,18 @@ proc removeFile*(file: string) =
|
|||
## Removes the `file`. If this fails, `EOS` is raised.
|
||||
if cremove(file) != 0'i32: OSError()
|
||||
|
||||
proc executeShellCommand*(command: string): int =
|
||||
proc executeShellCommand*(command: string): int {.deprecated.} =
|
||||
## **Deprecated since version 0.8.2**: Use `execShellCmd` instead.
|
||||
result = csystem(command)
|
||||
|
||||
proc execShellCmd*(command: string): int =
|
||||
## Executes a shell command.
|
||||
##
|
||||
## Command has the form 'program args' where args are the command
|
||||
## line arguments given to program. The proc returns the error code
|
||||
## of the shell when it has finished. The proc does not return until
|
||||
## the process has finished. To execute a program without having a
|
||||
## shell involved, use the `executeProcess` proc of the `osproc`
|
||||
## shell involved, use the `execProcess` proc of the `osproc`
|
||||
## module.
|
||||
result = csystem(command)
|
||||
|
||||
|
|
@ -707,7 +760,16 @@ proc putEnv*(key, val: string) =
|
|||
if SetEnvironmentVariableA(key, val) == 0'i32:
|
||||
OSError()
|
||||
|
||||
iterator iterOverEnvironment*(): tuple[key, value: string] =
|
||||
iterator iterOverEnvironment*(): tuple[key, value: string] {.deprecated.} =
|
||||
## Iterate over all environments variables. In the first component of the
|
||||
## tuple is the name of the current variable stored, in the second its value.
|
||||
## **Deprecated since version 0.8.2**: Use `envPairs` instead.
|
||||
getEnvVarsC()
|
||||
for i in 0..high(environment):
|
||||
var p = find(environment[i], '=')
|
||||
yield (copy(environment[i], 0, p-1), copy(environment[i], p+1))
|
||||
|
||||
iterator envPairs*(): tuple[key, value: string] =
|
||||
## Iterate over all environments variables. In the first component of the
|
||||
## tuple is the name of the current variable stored, in the second its value.
|
||||
getEnvVarsC()
|
||||
|
|
@ -1039,7 +1101,6 @@ proc getApplicationFilename*(): string =
|
|||
|
||||
proc getApplicationDir*(): string =
|
||||
## Returns the directory of the application's executable.
|
||||
var tail: string
|
||||
splitPath(getApplicationFilename(), result, tail)
|
||||
result = splitFile(getApplicationFilename()).dir
|
||||
|
||||
{.pop.}
|
||||
|
|
|
|||
|
|
@ -36,16 +36,28 @@ type
|
|||
## often creates a security whole!
|
||||
poStdErrToStdOut ## merge stdout and stderr to the stdout stream
|
||||
|
||||
proc executeProcess*(command: string,
|
||||
options: set[TProcessOption] = {poStdErrToStdOut,
|
||||
poUseShell}): string
|
||||
proc execProcess*(command: string,
|
||||
options: set[TProcessOption] = {poStdErrToStdOut,
|
||||
poUseShell}): string
|
||||
## A convience procedure that executes ``command`` with ``startProcess``
|
||||
## and returns its output as a string.
|
||||
|
||||
proc executeCommand*(command: string): int
|
||||
proc executeProcess*(command: string,
|
||||
options: set[TProcessOption] = {poStdErrToStdOut,
|
||||
poUseShell}): string {.
|
||||
deprecated.} =
|
||||
## **Deprecated since version 0.8.2**: Use `execProcess` instead.
|
||||
result = execProcess(command, options)
|
||||
|
||||
proc execCmd*(command: string): int
|
||||
## Executes ``command`` and returns its error code. Standard input, output,
|
||||
## error streams are inherited from the calling process.
|
||||
|
||||
proc executeCommand*(command: string): int {.deprecated.} =
|
||||
## **Deprecated since version 0.8.2**: Use `execCmd` instead.
|
||||
result = execCmd(command)
|
||||
|
||||
|
||||
proc startProcess*(command: string,
|
||||
workingDir: string = "",
|
||||
args: openarray[string] = [],
|
||||
|
|
@ -56,11 +68,12 @@ proc startProcess*(command: string,
|
|||
## is used. `args` are the command line arguments that are passed to the
|
||||
## process. On many operating systems, the first command line argument is the
|
||||
## name of the executable. `args` should not contain this argument!
|
||||
## `startProcess` takes care of that. `env` is the environment that will be
|
||||
## passed to the process. If ``env == nil`` the environment is inherited of
|
||||
## `env` is the environment that will be passed to the process.
|
||||
## If ``env == nil`` the environment is inherited of
|
||||
## the parent process. `options` are additional flags that may be passed
|
||||
## to `startProcess`. See the documentation of ``TProcessOption`` for the
|
||||
## meaning of these flags.
|
||||
##
|
||||
## Return value: The newly created process object. Nil is never returned,
|
||||
## but ``EOS`` is raised in case of an error.
|
||||
|
||||
|
|
@ -104,9 +117,9 @@ proc outputStream*(p: PProcess): PStream
|
|||
proc errorStream*(p: PProcess): PStream
|
||||
## returns ``p``'s output stream for reading from
|
||||
|
||||
proc executeProcess*(command: string,
|
||||
options: set[TProcessOption] = {poStdErrToStdOut,
|
||||
poUseShell}): string =
|
||||
proc execProcess(command: string,
|
||||
options: set[TProcessOption] = {poStdErrToStdOut,
|
||||
poUseShell}): string =
|
||||
var c = parseCmdLine(command)
|
||||
var a: seq[string] = @[] # slicing is not yet implemented :-(
|
||||
for i in 1 .. c.len-1: add(a, c[i])
|
||||
|
|
@ -208,24 +221,24 @@ when defined(Windows):
|
|||
SI.dwFlags = STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES
|
||||
CreatePipeHandles(SI.hStdInput, HI)
|
||||
CreatePipeHandles(HO, Si.hStdOutput)
|
||||
#SI.hStdInput = GetStdHandle(STD_INPUT_HANDLE())
|
||||
#SI.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE())
|
||||
if poStdErrToStdOut in options:
|
||||
SI.hStdError = SI.hStdOutput
|
||||
HE = HO
|
||||
else:
|
||||
CreatePipeHandles(HE, Si.hStdError)
|
||||
#SI.hStdError = GetStdHandle(STD_ERROR_HANDLE())
|
||||
#result.inputHandle = open_osfhandle(HI, O_WRONLY)
|
||||
#if result.inputHandle == -1'i32: OSError()
|
||||
result.inputHandle = hi
|
||||
result.outputHandle = ho
|
||||
result.errorHandle = he
|
||||
#result.outputHandle = open_osfhandle(HO, O_RDONLY)
|
||||
#if result.outputHandle == -1'i32: OSError()
|
||||
#result.errorHandle = open_osfhandle(HE, O_RDONLY)
|
||||
#if result.errorHandle == -1'i32: OSError()
|
||||
var cmdl = buildCommandLine(command, args)
|
||||
var cmdl: cstring
|
||||
if poUseShell in options:
|
||||
var comspec = getEnv("COMSPEC")
|
||||
var a: seq[string] = @[]
|
||||
add(a, "/c")
|
||||
add(a, command)
|
||||
add(a, args)
|
||||
cmdl = buildCommandLine(comspec, a)
|
||||
else:
|
||||
cmdl = buildCommandLine(command, args)
|
||||
var wd: cstring = nil
|
||||
if len(workingDir) > 0: wd = workingDir
|
||||
if env == nil:
|
||||
|
|
@ -239,6 +252,9 @@ when defined(Windows):
|
|||
dealloc(cmdl)
|
||||
if success == 0:
|
||||
OSError()
|
||||
# NEW:
|
||||
# Close the handles now so anyone waiting is woken.
|
||||
discard closeHandle(procInfo.hThread)
|
||||
result.FProcessHandle = procInfo.hProcess
|
||||
result.FThreadHandle = procInfo.hThread
|
||||
result.id = procInfo.dwProcessID
|
||||
|
|
@ -258,7 +274,7 @@ when defined(Windows):
|
|||
discard TerminateProcess(p.FProcessHandle, 0)
|
||||
|
||||
proc waitForExit(p: PProcess): int =
|
||||
discard CloseHandle(p.FThreadHandle)
|
||||
#CloseHandle(p.FThreadHandle)
|
||||
discard WaitForSingleObject(p.FProcessHandle, Infinite)
|
||||
var res: int32
|
||||
discard GetExitCodeProcess(p.FProcessHandle, res)
|
||||
|
|
@ -274,7 +290,7 @@ when defined(Windows):
|
|||
proc errorStream(p: PProcess): PStream =
|
||||
result = newFileHandleStream(p.errorHandle)
|
||||
|
||||
proc executeCommand(command: string): int =
|
||||
proc execCmd(command: string): int =
|
||||
var
|
||||
SI: TStartupInfo
|
||||
ProcInfo: TProcessInformation
|
||||
|
|
@ -420,8 +436,8 @@ else:
|
|||
|
||||
proc csystem(cmd: cstring): cint {.nodecl, importc: "system".}
|
||||
|
||||
proc executeCommand(command: string): int =
|
||||
proc execCmd(command: string): int =
|
||||
result = csystem(command)
|
||||
|
||||
when isMainModule:
|
||||
echo executeCommand("gcc -v")
|
||||
echo execCmd("gcc -v")
|
||||
|
|
|
|||
|
|
@ -138,7 +138,7 @@ proc getEscapedChar(c: var TCfgParser, tok: var TToken) =
|
|||
inc(c.bufpos) # skip '\'
|
||||
case c.buf[c.bufpos]
|
||||
of 'n', 'N':
|
||||
add(tok.literal, nl)
|
||||
add(tok.literal, "\n")
|
||||
Inc(c.bufpos)
|
||||
of 'r', 'R', 'c', 'C':
|
||||
add(tok.literal, '\c')
|
||||
|
|
@ -208,7 +208,7 @@ proc getString(c: var TCfgParser, tok: var TToken, rawMode: bool) =
|
|||
of '\c', '\L':
|
||||
pos = HandleCRLF(c, pos)
|
||||
buf = c.buf
|
||||
add(tok.literal, nl)
|
||||
add(tok.literal, "\n")
|
||||
of lexbase.EndOfFile:
|
||||
tok.kind = tkInvalid
|
||||
break
|
||||
|
|
@ -302,7 +302,7 @@ proc rawGetTok(c: var TCfgParser, tok: var TToken) =
|
|||
|
||||
proc errorStr(c: TCfgParser, msg: string): string =
|
||||
result = `%`("$1($2, $3) Error: $4",
|
||||
[c.filename, toString(getLine(c)), toString(getColumn(c)), msg])
|
||||
[c.filename, $getLine(c), $getColumn(c), msg])
|
||||
|
||||
proc getKeyValPair(c: var TCfgParser, kind: TCfgEventKind): TCfgEvent =
|
||||
if c.tok.kind == tkSymbol:
|
||||
|
|
|
|||
|
|
@ -32,21 +32,10 @@ type
|
|||
## or the argument, ``value`` is not "" if
|
||||
## the option was given a value
|
||||
|
||||
proc init*(cmdline: string = ""): TOptParser
|
||||
proc initOptParser*(cmdline = ""): TOptParser =
|
||||
## inits the option parser. If ``cmdline == ""``, the real command line
|
||||
## (as provided by the ``OS`` module) is taken.
|
||||
|
||||
proc next*(p: var TOptParser)
|
||||
## parses the first or next option; ``p.kind`` describes what token has been
|
||||
## parsed. ``p.key`` and ``p.val`` are set accordingly.
|
||||
|
||||
proc getRestOfCommandLine*(p: TOptParser): string
|
||||
## retrieves the rest of the command line that has not been parsed yet.
|
||||
|
||||
# implementation
|
||||
|
||||
proc init(cmdline: string = ""): TOptParser =
|
||||
result.pos = strStart
|
||||
result.pos = 0
|
||||
result.inShortState = false
|
||||
if cmdline != "":
|
||||
result.cmd = cmdline
|
||||
|
|
@ -58,6 +47,10 @@ proc init(cmdline: string = ""): TOptParser =
|
|||
result.key = ""
|
||||
result.val = ""
|
||||
|
||||
proc init*(cmdline: string = ""): TOptParser {.deprecated.} =
|
||||
## **Deprecated since version 0.8.2**: Use `initOptParser` instead.
|
||||
result = initOptParser(cmdline)
|
||||
|
||||
proc parseWord(s: string, i: int, w: var string,
|
||||
delim: TCharSet = {'\x09', ' ', '\0'}): int =
|
||||
result = i
|
||||
|
|
@ -89,7 +82,9 @@ proc handleShortOption(p: var TOptParser) =
|
|||
if p.cmd[i] == '\0': p.inShortState = false
|
||||
p.pos = i
|
||||
|
||||
proc next(p: var TOptParser) =
|
||||
proc next*(p: var TOptParser) =
|
||||
## parses the first or next option; ``p.kind`` describes what token has been
|
||||
## parsed. ``p.key`` and ``p.val`` are set accordingly.
|
||||
var i = p.pos
|
||||
while p.cmd[i] in {'\x09', ' '}: inc(i)
|
||||
p.pos = i
|
||||
|
|
@ -121,12 +116,17 @@ proc next(p: var TOptParser) =
|
|||
p.kind = cmdArgument
|
||||
p.pos = parseWord(p.cmd, i, p.key)
|
||||
|
||||
proc getRestOfCommandLine(p: TOptParser): string =
|
||||
result = strip(copy(p.cmd, p.pos + strStart, len(p.cmd) - 1))
|
||||
proc cmdLineRest*(p: TOptParser): string =
|
||||
## retrieves the rest of the command line that has not been parsed yet.
|
||||
result = strip(copy(p.cmd, p.pos, len(p.cmd) - 1))
|
||||
|
||||
proc getRestOfCommandLine*(p: TOptParser): string {.deprecated.} =
|
||||
## **Deprecated since version 0.8.2**: Use `cmdLineRest` instead.
|
||||
result = cmdLineRest(p)
|
||||
|
||||
iterator getopt*(): tuple[kind: TCmdLineKind, key, val: string] =
|
||||
##this is an convenience iterator for iterating over the command line.
|
||||
##This uses the TOptParser object. Example:
|
||||
## This is an convenience iterator for iterating over the command line.
|
||||
## This uses the TOptParser object. Example:
|
||||
##
|
||||
## .. code-block:: nimrod
|
||||
## var
|
||||
|
|
@ -143,7 +143,7 @@ iterator getopt*(): tuple[kind: TCmdLineKind, key, val: string] =
|
|||
## if filename == "":
|
||||
## # no filename has been given, so we show the help:
|
||||
## writeHelp()
|
||||
var p = init()
|
||||
var p = initOptParser()
|
||||
while true:
|
||||
next(p)
|
||||
if p.kind == cmdEnd: break
|
||||
|
|
|
|||
|
|
@ -483,7 +483,7 @@ proc errorStr(L: TSqlLexer, msg: string): string =
|
|||
# OR left logical disjunction
|
||||
|
||||
type
|
||||
TSqlNodeKind* = enum
|
||||
TSqlNodeKind* = enum ## kind of SQL abstract syntax tree
|
||||
nkNone,
|
||||
nkIdent,
|
||||
nkStringLit,
|
||||
|
|
@ -536,17 +536,18 @@ type
|
|||
nkEnumDef
|
||||
|
||||
type
|
||||
EInvalidSql* = object of EBase
|
||||
PSqlNode* = ref TSqlNode
|
||||
TSqlNode* = object
|
||||
case kind*: TSqlNodeKind
|
||||
EInvalidSql* = object of EBase ## Invalid SQL encountered
|
||||
PSqlNode* = ref TSqlNode ## an SQL abstract syntax tree node
|
||||
TSqlNode* = object ## an SQL abstract syntax tree node
|
||||
case kind*: TSqlNodeKind ## kind of syntax tree
|
||||
of nkIdent, nkStringLit, nkBitStringLit, nkHexStringLit,
|
||||
nkIntegerLit, nkNumericLit:
|
||||
strVal*: string
|
||||
strVal*: string ## AST leaf: the identifier, numeric literal
|
||||
## string literal, etc.
|
||||
else:
|
||||
sons*: seq[PSqlNode]
|
||||
sons*: seq[PSqlNode] ## the node's children
|
||||
|
||||
TSqlParser = object of TSqlLexer
|
||||
TSqlParser* = object of TSqlLexer ## SQL parser object
|
||||
tok: TToken
|
||||
|
||||
proc newNode(k: TSqlNodeKind): PSqlNode =
|
||||
|
|
@ -1070,7 +1071,17 @@ proc parseStmt(p: var TSqlParser): PSqlNode =
|
|||
else:
|
||||
sqlError(p, "CREATE expected")
|
||||
|
||||
proc parse*(p: var TSqlParser): PSqlNode =
|
||||
proc open(p: var TSqlParser, input: PStream, filename: string) =
|
||||
## opens the parser `p` and assigns the input stream `input` to it.
|
||||
## `filename` is only used for error messages.
|
||||
open(TSqlLexer(p), input, filename)
|
||||
p.tok.kind = tkInvalid
|
||||
p.tok.literal = ""
|
||||
getTok(p)
|
||||
|
||||
proc parse(p: var TSqlParser): PSqlNode =
|
||||
## parses the content of `p`'s input stream and returns the SQL AST.
|
||||
## Syntax errors raise an `EInvalidSql` exception.
|
||||
result = newNode(nkStmtList)
|
||||
while p.tok.kind != tkEof:
|
||||
var s = parseStmt(p)
|
||||
|
|
@ -1078,21 +1089,21 @@ proc parse*(p: var TSqlParser): PSqlNode =
|
|||
result.add(s)
|
||||
if result.len == 1:
|
||||
result = result.sons[0]
|
||||
|
||||
proc open*(p: var TSqlParser, input: PStream, filename: string) =
|
||||
open(TSqlLexer(p), input, filename)
|
||||
p.tok.kind = tkInvalid
|
||||
p.tok.literal = ""
|
||||
getTok(p)
|
||||
|
||||
proc close*(p: var TSqlParser) =
|
||||
proc close(p: var TSqlParser) =
|
||||
## closes the parser `p`. The associated input stream is closed too.
|
||||
close(TSqlLexer(p))
|
||||
|
||||
proc parseSQL*(input: PStream, filename: string): PSqlNode =
|
||||
## parses the SQL from `input` into an AST and returns the AST.
|
||||
## `filename` is only used for error messages.
|
||||
## Syntax errors raise an `EInvalidSql` exception.
|
||||
var p: TSqlParser
|
||||
open(p, input, filename)
|
||||
result = parse(p)
|
||||
close(p)
|
||||
try:
|
||||
result = parse(p)
|
||||
finally:
|
||||
close(p)
|
||||
|
||||
proc ra(n: PSqlNode, s: var string, indent: int)
|
||||
|
||||
|
|
@ -1114,7 +1125,7 @@ proc ra(n: PSqlNode, s: var string, indent: int) =
|
|||
if allCharsInSet(n.strVal, {'\33'..'\127'}):
|
||||
s.add(n.strVal)
|
||||
else:
|
||||
s.add("\"" & replaceStr(n.strVal, "\"", "\"\"") & "\"")
|
||||
s.add("\"" & replace(n.strVal, "\"", "\"\"") & "\"")
|
||||
of nkStringLit:
|
||||
s.add(escape(n.strVal, "e'", "'"))
|
||||
of nkBitStringLit:
|
||||
|
|
|
|||
|
|
@ -297,7 +297,7 @@ proc parseEntity(my: var TXmlParser, dest: var string) =
|
|||
var buf = my.buf
|
||||
my.kind = xmlCharData
|
||||
if buf[pos] == '#':
|
||||
var r: TRune
|
||||
var r: int
|
||||
inc(pos)
|
||||
if buf[pos] == 'x':
|
||||
inc(pos)
|
||||
|
|
@ -312,7 +312,7 @@ proc parseEntity(my: var TXmlParser, dest: var string) =
|
|||
while buf[pos] in {'0'..'9'}:
|
||||
r = r * 10 + (ord(buf[pos]) - ord('0'))
|
||||
inc(pos)
|
||||
add(dest, toUTF8(r))
|
||||
add(dest, toUTF8(TRune(r)))
|
||||
elif buf[pos] == 'l' and buf[pos+1] == 't':
|
||||
add(dest, '<')
|
||||
inc(pos, 2)
|
||||
|
|
|
|||
|
|
@ -8,6 +8,9 @@
|
|||
#
|
||||
|
||||
## Regular expression support for Nimrod.
|
||||
## **Deprecated** since version 0.8.2. Use the module `re` instead.
|
||||
{.deprecated.}
|
||||
|
||||
## Currently this module is implemented by providing a wrapper around the
|
||||
## `PRCE (Perl-Compatible Regular Expressions) <http://www.pcre.org>`_
|
||||
## C library. This means that your application will depend on the PRCE
|
||||
|
|
@ -131,13 +134,14 @@ template `=~` *(s, pattern: expr): expr =
|
|||
## echo("comment: ", matches[1])
|
||||
## else:
|
||||
## echo("syntax error")
|
||||
##
|
||||
var matches: array[0..maxSubPatterns-1, string]
|
||||
##
|
||||
when not definedInScope(matches):
|
||||
var matches: array[0..maxSubPatterns-1, string]
|
||||
match(s, pattern, matches)
|
||||
|
||||
|
||||
const ## common regular expressions
|
||||
reIdentifier* = r"\b[a-zA-Z_]+[a-zA-Z_0-9]*\b" ## describes an identifier
|
||||
reIdentifier* = r"\b[a-zA-Z_][a-zA-Z_0-9]*\b" ## describes an identifier
|
||||
reNatural* = r"\b\d+\b" ## describes a natural number
|
||||
reInteger* = r"\b[-+]?\d+\b" ## describes an integer
|
||||
reHex* = r"\b0[xX][0-9a-fA-F]+\b" ## describes a hexadecimal number
|
||||
|
|
|
|||
|
|
@ -45,9 +45,9 @@ const
|
|||
IdentStartChars* = {'a'..'z', 'A'..'Z', '_'}
|
||||
## the set of characters an identifier can start with
|
||||
|
||||
strStart* = 0 ## this is only for bootstraping
|
||||
## XXX: remove this someday
|
||||
nl* = "\n" ## this is only for bootstraping XXX: remove this somehow
|
||||
# strStart* = 0 ## this is only for bootstraping
|
||||
# ## XXX: remove this someday
|
||||
# nl* = "\n" ## this is only for bootstraping XXX: remove this someday
|
||||
|
||||
proc `%` *(formatstr: string, a: openarray[string]): string {.noSideEffect.}
|
||||
## The `substitution`:idx: operator performs string substitutions in
|
||||
|
|
@ -272,43 +272,39 @@ iterator splitLines*(s: string): string =
|
|||
else: break # was '\0'
|
||||
first = last
|
||||
|
||||
template iterToProc(iter: expr): stmt =
|
||||
result = @[]
|
||||
for x in iter: add(result, x)
|
||||
|
||||
proc splitLinesSeq*(s: string): seq[string] {.noSideEffect, deprecated.} =
|
||||
## The same as `splitLines`, but is a proc that returns a sequence
|
||||
## of substrings.
|
||||
## **Deprecated since version 0.8.0**: Use `splitLines` instead.
|
||||
iterToProc(splitLines(s))
|
||||
accumulateResult(splitLines(s))
|
||||
|
||||
proc splitSeq*(s: string, seps: set[char] = Whitespace): seq[string] {.
|
||||
noSideEffect, deprecated.} =
|
||||
## The same as `split`, but is a proc that returns a sequence of substrings.
|
||||
## **Deprecated since version 0.8.0**: Use `split` instead.
|
||||
iterToProc(split(s, seps))
|
||||
accumulateResult(split(s, seps))
|
||||
|
||||
proc splitSeq*(s: string, sep: char): seq[string] {.noSideEffect,
|
||||
deprecated.} =
|
||||
## The same as `split`, but is a proc that returns a sequence of substrings.
|
||||
## **Deprecated since version 0.8.0**: Use `split` instead.
|
||||
iterToProc(split(s, sep))
|
||||
accumulateResult(split(s, sep))
|
||||
|
||||
proc splitLines*(s: string): seq[string] {.noSideEffect.} =
|
||||
## The same as the `splitLines` iterator, but is a proc that returns a
|
||||
## sequence of substrings.
|
||||
iterToProc(splitLines(s))
|
||||
accumulateResult(splitLines(s))
|
||||
|
||||
proc split*(s: string, seps: set[char] = Whitespace): seq[string] {.
|
||||
noSideEffect.} =
|
||||
## The same as the `split` iterator, but is a proc that returns a
|
||||
## sequence of substrings.
|
||||
iterToProc(split(s, seps))
|
||||
accumulateResult(split(s, seps))
|
||||
|
||||
proc split*(s: string, sep: char): seq[string] {.noSideEffect.} =
|
||||
## The same as the `split` iterator, but is a proc that returns a sequence
|
||||
## of substrings.
|
||||
iterToProc(split(s, sep))
|
||||
accumulateResult(split(s, sep))
|
||||
|
||||
proc cmpIgnoreCase*(a, b: string): int {.noSideEffect.}
|
||||
## Compares two strings in a case insensitive manner. Returns:
|
||||
|
|
@ -358,8 +354,10 @@ proc ParseFloat*(s: string): float {.noSideEffect.}
|
|||
## ``INF``, ``-INF`` are also supported (case insensitive comparison).
|
||||
|
||||
# the stringify and format operators:
|
||||
proc toString*[Ty](x: Ty): string
|
||||
proc toString*[Ty](x: Ty): string {.deprecated.}
|
||||
## This generic proc is the same as the stringify operator `$`.
|
||||
##
|
||||
## **Deprecated since version 0.8.2:** Use `$` instead.
|
||||
|
||||
proc repeatChar*(count: int, c: Char = ' '): string
|
||||
## Returns a string of length `count` consisting only of
|
||||
|
|
|
|||
|
|
@ -12,9 +12,14 @@
|
|||
{.deadCodeElim: on.}
|
||||
|
||||
type
|
||||
TRune* = int ## type that can hold any Unicode character
|
||||
TRune16* = int16 ## 16 bit Unicode character
|
||||
irune = int # underlying type of TRune
|
||||
TRune* = distinct irune ## type that can hold any Unicode character
|
||||
TRune16* = distinct int16 ## 16 bit Unicode character
|
||||
|
||||
proc `<=%`*(a, b: TRune): bool {.borrow.}
|
||||
proc `<%`*(a, b: TRune): bool {.borrow.}
|
||||
proc `==`*(a, b: TRune): bool {.borrow.}
|
||||
|
||||
template ones(n: expr): expr = ((1 shl n)-1)
|
||||
|
||||
proc runeLen*(s: string): int =
|
||||
|
|
@ -28,77 +33,71 @@ proc runeLen*(s: string): int =
|
|||
else: assert(false)
|
||||
inc(result)
|
||||
|
||||
proc runeLenAt*(s: string, i: int): int =
|
||||
## returns the number of bytes the rune starting at ``s[i]`` takes.
|
||||
if ord(s[i]) <=% 127: result = 1
|
||||
elif ord(s[i]) shr 5 == 0b110: result = 2
|
||||
elif ord(s[i]) shr 4 == 0b1110: result = 3
|
||||
elif ord(s[i]) shr 3 == 0b11110: result = 4
|
||||
else: assert(false)
|
||||
|
||||
template fastRuneAt*(s: string, i: int, result: expr, doInc = true) =
|
||||
## Returns the unicode character ``s[i]`` in `result`. If ``doInc == true``
|
||||
## `i` is incremented by the number of bytes that have been processed.
|
||||
when not defined(ones):
|
||||
template ones(n: expr): expr = ((1 shl n)-1)
|
||||
|
||||
if ord(s[i]) <=% 127:
|
||||
result = TRune(ord(s[i]))
|
||||
when doInc: inc(i)
|
||||
elif ord(s[i]) shr 5 == 0b110:
|
||||
assert(ord(s[i+1]) shr 6 == 0b10)
|
||||
result = TRune((ord(s[i]) and ones(5)) shl 6 or (ord(s[i+1]) and ones(6)))
|
||||
when doInc: inc(i, 2)
|
||||
elif ord(s[i]) shr 4 == 0b1110:
|
||||
assert(ord(s[i+1]) shr 6 == 0b10)
|
||||
assert(ord(s[i+2]) shr 6 == 0b10)
|
||||
result = TRune((ord(s[i]) and ones(4)) shl 12 or
|
||||
(ord(s[i+1]) and ones(6)) shl 6 or
|
||||
(ord(s[i+2]) and ones(6)))
|
||||
when doInc: inc(i, 3)
|
||||
elif ord(s[i]) shr 3 == 0b11110:
|
||||
assert(ord(s[i+1]) shr 6 == 0b10)
|
||||
assert(ord(s[i+2]) shr 6 == 0b10)
|
||||
assert(ord(s[i+3]) shr 6 == 0b10)
|
||||
result = TRune((ord(s[i]) and ones(3)) shl 18 or
|
||||
(ord(s[i+1]) and ones(6)) shl 12 or
|
||||
(ord(s[i+2]) and ones(6)) shl 6 or
|
||||
(ord(s[i+3]) and ones(6)))
|
||||
when doInc: inc(i, 4)
|
||||
else:
|
||||
assert(false)
|
||||
|
||||
proc runeAt*(s: string, i: int): TRune =
|
||||
## returns the unicode character in `s` at byte index `i`
|
||||
if ord(s[i]) <=% 127:
|
||||
result = ord(s[i])
|
||||
elif ord(s[i]) shr 5 == 0b110:
|
||||
assert(ord(s[i+1]) shr 6 == 0b10)
|
||||
result = (ord(s[i]) and ones(5)) shl 6 or (ord(s[i+1]) and ones(6))
|
||||
elif ord(s[i]) shr 4 == 0b1110:
|
||||
assert(ord(s[i+1]) shr 6 == 0b10)
|
||||
assert(ord(s[i+2]) shr 6 == 0b10)
|
||||
result = (ord(s[i]) and ones(4)) shl 12 or
|
||||
(ord(s[i+1]) and ones(6)) shl 6 or
|
||||
(ord(s[i+2]) and ones(6))
|
||||
elif ord(s[i]) shr 3 == 0b11110:
|
||||
assert(ord(s[i+1]) shr 6 == 0b10)
|
||||
assert(ord(s[i+2]) shr 6 == 0b10)
|
||||
assert(ord(s[i+3]) shr 6 == 0b10)
|
||||
result = (ord(s[i]) and ones(3)) shl 18 or
|
||||
(ord(s[i+1]) and ones(6)) shl 12 or
|
||||
(ord(s[i+2]) and ones(6)) shl 6 or
|
||||
(ord(s[i+3]) and ones(6))
|
||||
else:
|
||||
assert(false)
|
||||
|
||||
template fastRuneAt(s, i, result: expr): stmt =
|
||||
if ord(s[i]) <=% 127:
|
||||
result = ord(s[i])
|
||||
inc(i)
|
||||
elif ord(s[i]) shr 5 == 0b110:
|
||||
assert(ord(s[i+1]) shr 6 == 0b10)
|
||||
result = (ord(s[i]) and ones(5)) shl 6 or (ord(s[i+1]) and ones(6))
|
||||
inc(i, 2)
|
||||
elif ord(s[i]) shr 4 == 0b1110:
|
||||
assert(ord(s[i+1]) shr 6 == 0b10)
|
||||
assert(ord(s[i+2]) shr 6 == 0b10)
|
||||
result = (ord(s[i]) and ones(4)) shl 12 or
|
||||
(ord(s[i+1]) and ones(6)) shl 6 or
|
||||
(ord(s[i+2]) and ones(6))
|
||||
inc(i, 3)
|
||||
elif ord(s[i]) shr 3 == 0b11110:
|
||||
assert(ord(s[i+1]) shr 6 == 0b10)
|
||||
assert(ord(s[i+2]) shr 6 == 0b10)
|
||||
assert(ord(s[i+3]) shr 6 == 0b10)
|
||||
result = (ord(s[i]) and ones(3)) shl 18 or
|
||||
(ord(s[i+1]) and ones(6)) shl 12 or
|
||||
(ord(s[i+2]) and ones(6)) shl 6 or
|
||||
(ord(s[i+3]) and ones(6))
|
||||
inc(i, 4)
|
||||
else:
|
||||
assert(false)
|
||||
fastRuneAt(s, i, result, false)
|
||||
|
||||
proc toUTF8*(c: TRune): string =
|
||||
## converts a character into its UTF8 representation
|
||||
if c <=% 127:
|
||||
## converts a rune into its UTF8 representation
|
||||
var i = irune(c)
|
||||
if i <=% 127:
|
||||
result = newString(1)
|
||||
result[0] = chr(c)
|
||||
elif c <=% 0x07FF:
|
||||
result[0] = chr(i)
|
||||
elif i <=% 0x07FF:
|
||||
result = newString(2)
|
||||
result[0] = chr(c shr 6 or 0b110_0000)
|
||||
result[1] = chr(c and ones(6) or 0b10_000000)
|
||||
elif c <=% 0xFFFF:
|
||||
result[0] = chr(i shr 6 or 0b110_0000)
|
||||
result[1] = chr(i and ones(6) or 0b10_000000)
|
||||
elif i <=% 0xFFFF:
|
||||
result = newString(3)
|
||||
result[0] = chr(c shr 12 or 0b1110_0000)
|
||||
result[1] = chr(c shr 6 and ones(6) or 0b10_0000_00)
|
||||
result[2] = chr(c and ones(6) or 0b10_0000_00)
|
||||
elif c <=% 0x0010FFFF:
|
||||
result[0] = chr(i shr 12 or 0b1110_0000)
|
||||
result[1] = chr(i shr 6 and ones(6) or 0b10_0000_00)
|
||||
result[2] = chr(i and ones(6) or 0b10_0000_00)
|
||||
elif i <=% 0x0010FFFF:
|
||||
result = newString(4)
|
||||
result[0] = chr(c shr 18 or 0b1111_0000)
|
||||
result[1] = chr(c shr 12 and ones(6) or 0b10_0000_00)
|
||||
result[2] = chr(c shr 6 and ones(6) or 0b10_0000_00)
|
||||
result[3] = chr(c and ones(6) or 0b10_0000_00)
|
||||
result[0] = chr(i shr 18 or 0b1111_0000)
|
||||
result[1] = chr(i shr 12 and ones(6) or 0b10_0000_00)
|
||||
result[2] = chr(i shr 6 and ones(6) or 0b10_0000_00)
|
||||
result[3] = chr(i and ones(6) or 0b10_0000_00)
|
||||
else:
|
||||
assert false
|
||||
|
||||
|
|
@ -1061,7 +1060,7 @@ const
|
|||
0x01f1, 501, # DZ Dz
|
||||
0x01f3, 499] # dz Dz
|
||||
|
||||
proc binarySearch(c: TRune, tab: openArray[TRune], len, stride: int): int =
|
||||
proc binarySearch(c: irune, tab: openArray[iRune], len, stride: int): int =
|
||||
var n = len
|
||||
var t = 0
|
||||
while n > 1:
|
||||
|
|
@ -1078,32 +1077,39 @@ proc binarySearch(c: TRune, tab: openArray[TRune], len, stride: int): int =
|
|||
|
||||
proc toLower*(c: TRune): TRune =
|
||||
## Converts `c` into lower case. This works for any Unicode character.
|
||||
## If possible, prefer `toLower` over `toUpper`.
|
||||
var c = irune(c)
|
||||
var p = binarySearch(c, tolowerRanges, len(toLowerRanges) div 3, 3)
|
||||
if p >= 0 and c >= tolowerRanges[p] and c <= tolowerRanges[p+1]:
|
||||
return c + tolowerRanges[p+2] - 500
|
||||
return TRune(c + tolowerRanges[p+2] - 500)
|
||||
p = binarySearch(c, toLowerSinglets, len(toLowerSinglets) div 2, 2)
|
||||
if p >= 0 and c == toLowerSinglets[p]:
|
||||
return c + toLowerSinglets[p+1] - 500
|
||||
return c
|
||||
return TRune(c + toLowerSinglets[p+1] - 500)
|
||||
return TRune(c)
|
||||
|
||||
proc toUpper*(c: TRune): TRune =
|
||||
## Converts `c` into upper case. This works for any Unicode character.
|
||||
## If possible, prefer `toLower` over `toUpper`.
|
||||
var c = irune(c)
|
||||
var p = binarySearch(c, toUpperRanges, len(toUpperRanges) div 3, 3)
|
||||
if p >= 0 and c >= toUpperRanges[p] and c <= toUpperRanges[p+1]:
|
||||
return c + toUpperRanges[p+2] - 500
|
||||
return TRune(c + toUpperRanges[p+2] - 500)
|
||||
p = binarySearch(c, toUpperSinglets, len(toUpperSinglets) div 2, 2)
|
||||
if p >= 0 and c == toUpperSinglets[p]:
|
||||
return c + toUpperSinglets[p+1] - 500
|
||||
return c
|
||||
return TRune(c + toUpperSinglets[p+1] - 500)
|
||||
return TRune(c)
|
||||
|
||||
proc toTitle*(c: TRune): TRune =
|
||||
var c = irune(c)
|
||||
var p = binarySearch(c, toTitleSinglets, len(toTitleSinglets) div 2, 2)
|
||||
if p >= 0 and c == toTitleSinglets[p]:
|
||||
return c + toTitleSinglets[p+1] - 500
|
||||
return c
|
||||
return TRune(c + toTitleSinglets[p+1] - 500)
|
||||
return TRune(c)
|
||||
|
||||
proc isLower*(c: TRune): bool =
|
||||
## returns true iff `c` is a lower case Unicode character
|
||||
## If possible, prefer `isLower` over `isUpper`.
|
||||
var c = irune(c)
|
||||
# Note: toUpperRanges is correct here!
|
||||
var p = binarySearch(c, toUpperRanges, len(toUpperRanges) div 3, 3)
|
||||
if p >= 0 and c >= toUpperRanges[p] and c <= toUpperRanges[p+1]:
|
||||
|
|
@ -1114,6 +1120,8 @@ proc isLower*(c: TRune): bool =
|
|||
|
||||
proc isUpper*(c: TRune): bool =
|
||||
## returns true iff `c` is a upper case Unicode character
|
||||
## If possible, prefer `isLower` over `isUpper`.
|
||||
var c = irune(c)
|
||||
# Note: toLowerRanges is correct here!
|
||||
var p = binarySearch(c, toLowerRanges, len(toLowerRanges) div 3, 3)
|
||||
if p >= 0 and c >= toLowerRanges[p] and c <= toLowerRanges[p+1]:
|
||||
|
|
@ -1126,6 +1134,7 @@ proc isAlpha*(c: TRune): bool =
|
|||
## returns true iff `c` is an *alpha* Unicode character (i.e. a letter)
|
||||
if isUpper(c) or isLower(c):
|
||||
return true
|
||||
var c = irune(c)
|
||||
var p = binarySearch(c, alphaRanges, len(alphaRanges) div 2, 2)
|
||||
if p >= 0 and c >= alphaRanges[p] and c <= alphaRanges[p+1]:
|
||||
return true
|
||||
|
|
@ -1138,6 +1147,7 @@ proc isTitle*(c: TRune): bool =
|
|||
|
||||
proc isWhiteSpace*(c: TRune): bool =
|
||||
## returns true iff `c` is a Unicode whitespace character
|
||||
var c = irune(c)
|
||||
var p = binarySearch(c, spaceRanges, len(spaceRanges) div 2, 2)
|
||||
if p >= 0 and c >= spaceRanges[p] and c <= spaceRanges[p+1]:
|
||||
return true
|
||||
|
|
@ -1148,7 +1158,7 @@ iterator runes*(s: string): TRune =
|
|||
i = 0
|
||||
result: TRune
|
||||
while i < len(s):
|
||||
fastRuneAt(s, i, result)
|
||||
fastRuneAt(s, i, result, true)
|
||||
yield result
|
||||
|
||||
proc cmpRunesIgnoreCase*(a, b: string): int =
|
||||
|
|
@ -1164,7 +1174,7 @@ proc cmpRunesIgnoreCase*(a, b: string): int =
|
|||
# slow path:
|
||||
fastRuneAt(a, i, ar)
|
||||
fastRuneAt(b, j, br)
|
||||
result = toLower(ar) - toLower(br)
|
||||
result = irune(toLower(ar)) - irune(toLower(br))
|
||||
if result != 0: return
|
||||
result = a.len - b.len
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue