implemented multi methods

This commit is contained in:
Andreas Rumpf 2009-09-23 23:38:00 +02:00
commit 3f3dda5a77
65 changed files with 11086 additions and 1258 deletions

View file

@ -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]]]

View file

@ -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.}

View file

@ -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")

View file

@ -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:

View file

@ -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

View file

@ -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:

View file

@ -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)

View file

@ -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

View file

@ -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

View file

@ -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