bugfix: proper cache for generic instantiations
This commit is contained in:
parent
81a917390b
commit
569c1ce5ec
24 changed files with 459 additions and 643 deletions
|
|
@ -1,7 +1,7 @@
|
|||
#
|
||||
#
|
||||
# Nimrod's Runtime Library
|
||||
# (c) Copyright 2010 Andreas Rumpf
|
||||
# (c) Copyright 2011 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
|
|
@ -21,10 +21,6 @@
|
|||
##
|
||||
## <h1><a href="http://force7.de/nimrod">Nimrod</a></h1>
|
||||
##
|
||||
## **Deprecated since version 0.8.8.** Use the macro ``<>`` in xmltree
|
||||
## instead.
|
||||
|
||||
{.deprecated.}
|
||||
|
||||
import
|
||||
macros, strutils
|
||||
|
|
@ -58,7 +54,6 @@ proc xmlCheckedTag*(e: PNimrodNode, tag: string,
|
|||
# will be modified, so that each attribute is only given one value
|
||||
var req = split(reqAttr)
|
||||
var opt = split(optAttr)
|
||||
echo "##", optAttr, "##", opt.len
|
||||
result = newNimNode(nnkBracket, e)
|
||||
result.add(newStrLitNode("<"))
|
||||
result.add(newStrLitNode(tag))
|
||||
51
lib/pure/matchers.nim
Normal file
51
lib/pure/matchers.nim
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
#
|
||||
#
|
||||
# Nimrod's Runtime Library
|
||||
# (c) Copyright 2011 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
## This module contains various string matchers for email addresses, etc.
|
||||
{.deadCodeElim: on.}
|
||||
|
||||
{.push debugger:off .} # the user does not want to trace a part
|
||||
# of the standard library!
|
||||
|
||||
include "system/inclrtl"
|
||||
|
||||
import strutils
|
||||
|
||||
proc validEmailAddress*(s: string): bool {.noSideEffect,
|
||||
rtl, extern: "nsuValidEmailAddress".} =
|
||||
## returns true if `s` seems to be a valid e-mail address.
|
||||
## The checking also uses a domain list.
|
||||
const
|
||||
chars = Letters + Digits + {'!','#','$','%','&',
|
||||
'\'','*','+','/','=','?','^','_','`','{','}','|','~','-','.'}
|
||||
var i = 0
|
||||
if s[i] notin chars or s[i] == '.': return false
|
||||
while s[i] in chars:
|
||||
if s[i] == '.' and s[i+1] == '.': return false
|
||||
inc(i)
|
||||
if s[i] != '@': return false
|
||||
var j = len(s)-1
|
||||
if s[j] notin letters: return false
|
||||
while j >= i and s[j] in letters: dec(j)
|
||||
inc(i) # skip '@'
|
||||
while s[i] in {'0'..'9', 'a'..'z', '-', '.'}: inc(i)
|
||||
if s[i] != '\0': return false
|
||||
|
||||
var x = substr(s, j+1)
|
||||
if len(x) == 2 and x[0] in Letters and x[1] in Letters: return true
|
||||
case toLower(x)
|
||||
of "com", "org", "net", "gov", "mil", "biz", "info", "mobi", "name",
|
||||
"aero", "jobs", "museum": return true
|
||||
return false
|
||||
|
||||
when isMainModule:
|
||||
assert "wuseldusel@codehome.com".validEmailAddress
|
||||
|
||||
{.pop.}
|
||||
|
||||
|
|
@ -351,23 +351,6 @@ 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,
|
||||
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 = substr(path, 0, sepPos-1)
|
||||
tail = substr(path, sepPos+1)
|
||||
else:
|
||||
head = ""
|
||||
tail = path # make a string copy here
|
||||
|
||||
proc SplitPath*(path: string): tuple[head, tail: string] {.
|
||||
noSideEffect, rtl, extern: "nos$1".} =
|
||||
## Splits a directory into (head, tail), so that
|
||||
|
|
@ -466,13 +449,6 @@ proc splitFile*(path: string): tuple[dir, name, ext: string] {.
|
|||
result.name = substr(path, sepPos+1, dotPos-1)
|
||||
result.ext = substr(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/"``.
|
||||
## **Deprecated since version 0.8.2**: Use ``splitFile(path).dir`` instead.
|
||||
result = splitFile(path).dir
|
||||
|
||||
proc extractFilename*(path: string): string {.
|
||||
noSideEffect, rtl, extern: "nos$1".} =
|
||||
## Extracts the filename of a given `path`. This is the same as
|
||||
|
|
@ -495,37 +471,7 @@ proc expandFilename*(filename: string): string {.rtl, extern: "nos$1".} =
|
|||
if res == nil: OSError()
|
||||
result = $res
|
||||
c_free(res)
|
||||
|
||||
proc SplitFilename*(filename: string, name, extension: var string) {.
|
||||
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".
|
||||
## 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 = substr(filename, 0, extPos-1)
|
||||
extension = substr(filename, extPos)
|
||||
else:
|
||||
name = filename # make a string copy here
|
||||
extension = ""
|
||||
|
||||
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`.
|
||||
## **Deprecated since version 0.8.2**: Use ``splitFile(filename).ext``
|
||||
## instead.
|
||||
result = splitFile(filename).ext
|
||||
|
||||
proc extractFileTrunk*(filename: string): string {.noSideEffect, deprecated.} =
|
||||
## Extracts the file name of a given `filename`. This removes any
|
||||
## directory information and the file extension.
|
||||
## **Deprecated since version 0.8.2**: Use ``splitFile(path).name`` instead.
|
||||
result = splitFile(filename).name
|
||||
|
||||
|
||||
proc ChangeFileExt*(filename, ext: string): string {.
|
||||
noSideEffect, rtl, extern: "nos$1".} =
|
||||
## Changes the file extension to `ext`.
|
||||
|
|
@ -551,11 +497,6 @@ proc addFileExt*(filename, ext: string): string {.
|
|||
if extPos < 0: result = filename & normExt(ext)
|
||||
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, rtl, extern: "nos$1".} =
|
||||
## Compares two paths.
|
||||
|
|
@ -661,10 +602,6 @@ proc removeFile*(file: string) {.rtl, extern: "nos$1".} =
|
|||
## Removes the `file`. If this fails, `EOS` is raised.
|
||||
if cremove(file) != 0'i32: OSError()
|
||||
|
||||
proc executeShellCommand*(command: string): int {.deprecated.} =
|
||||
## **Deprecated since version 0.8.2**: Use `execShellCmd` instead.
|
||||
result = csystem(command)
|
||||
|
||||
proc execShellCmd*(command: string): int {.rtl, extern: "nos$1".} =
|
||||
## Executes a `shell command`:idx:.
|
||||
##
|
||||
|
|
@ -781,15 +718,6 @@ proc putEnv*(key, val: string) =
|
|||
if SetEnvironmentVariableA(key, val) == 0'i32:
|
||||
OSError()
|
||||
|
||||
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 (substr(environment[i], 0, p-1), substr(environment[i], p+1))
|
||||
|
||||
iterator envPairs*(): tuple[key, value: string] =
|
||||
## Iterate over all `environments variables`:idx:. In the first component
|
||||
## of the tuple is the name of the current variable stored, in the second
|
||||
|
|
@ -837,10 +765,6 @@ type
|
|||
pcDir, ## path refers to a directory
|
||||
pcLinkToDir ## path refers to a symbolic link to a directory
|
||||
|
||||
const
|
||||
pcDirectory* {.deprecated.} = pcDir ## deprecated alias
|
||||
pcLinkToDirectory* {.deprecated.} = pcLinkToDir ## deprecated alias
|
||||
|
||||
iterator walkDir*(dir: string): tuple[kind: TPathComponent, path: string] =
|
||||
## walks over the directory `dir` and yields for each directory or file in
|
||||
## `dir`. The component type and full path for each item is returned.
|
||||
|
|
|
|||
|
|
@ -46,22 +46,10 @@ proc execProcess*(command: string,
|
|||
## A convenience procedure that executes ``command`` with ``startProcess``
|
||||
## and returns its output as a string.
|
||||
|
||||
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 {.rtl, extern: "nosp$1".}
|
||||
## 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] = [],
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#
|
||||
#
|
||||
# Nimrod's Runtime Library
|
||||
# (c) Copyright 2010 Andreas Rumpf
|
||||
# (c) Copyright 2011 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
|
|
@ -53,10 +53,6 @@ when defined(os.ParamCount):
|
|||
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
|
||||
|
|
@ -128,10 +124,6 @@ proc cmdLineRest*(p: TOptParser): string {.
|
|||
## retrieves the rest of the command line that has not been parsed yet.
|
||||
result = strip(substr(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)
|
||||
|
||||
when defined(initOptParser):
|
||||
|
||||
iterator getopt*(): tuple[kind: TCmdLineKind, key, val: string] =
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#
|
||||
#
|
||||
# Nimrod's Runtime Library
|
||||
# (c) Copyright 2010 Andreas Rumpf
|
||||
# (c) Copyright 2011 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
|
|
|
|||
|
|
@ -1,179 +0,0 @@
|
|||
#
|
||||
#
|
||||
# Nimrod's Runtime Library
|
||||
# (c) Copyright 2009 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
## Regular expression support for Nimrod.
|
||||
## 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
|
||||
## library's licence when using this module, which should not be a problem
|
||||
## though.
|
||||
## PRCE's licence follows:
|
||||
##
|
||||
## .. include:: ../doc/regexprs.txt
|
||||
##
|
||||
|
||||
# This is not just a convenient wrapper for the pcre library; the
|
||||
# API will stay the same if the implementation should change.
|
||||
|
||||
{.deprecated.}
|
||||
|
||||
import
|
||||
pcre, strutils
|
||||
|
||||
type
|
||||
EInvalidRegEx* = object of EInvalidValue
|
||||
## is raised if the pattern is no valid regular expression.
|
||||
|
||||
const
|
||||
MaxSubpatterns* = 10
|
||||
## defines the maximum number of subpatterns that can be captured.
|
||||
## More subpatterns cannot be captured!
|
||||
|
||||
proc match*(s, pattern: string, matches: var openarray[string],
|
||||
start: int = 0): bool
|
||||
## returns ``true`` if ``s[start..]`` matches the ``pattern`` and
|
||||
## the captured substrings in the array ``matches``. If it does not
|
||||
## match, nothing is written into ``matches`` and ``false`` is
|
||||
## returned.
|
||||
|
||||
proc match*(s, pattern: string, start: int = 0): bool
|
||||
## returns ``true`` if ``s`` matches the ``pattern`` beginning from ``start``.
|
||||
|
||||
proc matchLen*(s, pattern: string, matches: var openarray[string],
|
||||
start: int = 0): int
|
||||
## the same as ``match``, but it returns the length of the match,
|
||||
## if there is no match, -1 is returned. Note that a match length
|
||||
## of zero can happen.
|
||||
|
||||
proc find*(s, pattern: string, matches: var openarray[string],
|
||||
start: int = 0): bool
|
||||
## returns ``true`` if ``pattern`` occurs in ``s`` and the captured
|
||||
## substrings in the array ``matches``. If it does not match, nothing
|
||||
## is written into ``matches``.
|
||||
|
||||
proc find*(s, pattern: string, start: int = 0): bool
|
||||
## returns ``true`` if ``pattern`` occurs in ``s``.
|
||||
|
||||
proc rawCompile(pattern: string, flags: cint): PPcre =
|
||||
var
|
||||
msg: CString
|
||||
offset: cint
|
||||
com = pcre.Compile(pattern, flags, addr(msg), addr(offset), nil)
|
||||
if com == nil:
|
||||
var e: ref EInvalidRegEx
|
||||
new(e)
|
||||
e.msg = $msg & "\n" & pattern & "\n" & repeatChar(offset) & "^\n"
|
||||
raise e
|
||||
return com
|
||||
|
||||
proc matchOrFind(s: string, pattern: PPcre, matches: var openarray[string],
|
||||
start: cint): cint =
|
||||
var
|
||||
rawMatches: array [0..maxSubpatterns * 3 - 1, cint]
|
||||
res = int(pcre.Exec(pattern, nil, s, len(s), start, 0,
|
||||
cast[ptr cint](addr(rawMatches)), maxSubpatterns * 3))
|
||||
dealloc(pattern)
|
||||
if res < 0: return res
|
||||
for i in 0..res-1:
|
||||
var
|
||||
a = rawMatches[i * 2]
|
||||
b = rawMatches[i * 2 + 1]
|
||||
if a >= 0'i32: matches[i] = substr(s, a, int(b)-1)
|
||||
else: matches[i] = ""
|
||||
return res
|
||||
|
||||
proc matchOrFind(s: string, pattern: PPcre, start: cint): cint =
|
||||
var
|
||||
rawMatches: array [0..maxSubpatterns * 3 - 1, cint]
|
||||
res = pcre.Exec(pattern, nil, s, len(s), start, 0,
|
||||
cast[ptr cint](addr(rawMatches)), maxSubpatterns * 3)
|
||||
dealloc(pattern)
|
||||
return res
|
||||
|
||||
proc match(s, pattern: string, matches: var openarray[string],
|
||||
start: int = 0): bool =
|
||||
return matchOrFind(s, rawCompile(pattern, PCRE.ANCHORED),
|
||||
matches, start) >= 0'i32
|
||||
|
||||
proc matchLen(s, pattern: string, matches: var openarray[string],
|
||||
start: int = 0): int =
|
||||
return matchOrFind(s, rawCompile(pattern, PCRE.ANCHORED), matches, start)
|
||||
|
||||
proc find(s, pattern: string, matches: var openarray[string],
|
||||
start: int = 0): bool =
|
||||
return matchOrFind(s, rawCompile(pattern, PCRE.MULTILINE),
|
||||
matches, start) >= 0'i32
|
||||
|
||||
proc match(s, pattern: string, start: int = 0): bool =
|
||||
return matchOrFind(s, rawCompile(pattern, PCRE.ANCHORED), start) >= 0'i32
|
||||
|
||||
proc find(s, pattern: string, start: int = 0): bool =
|
||||
return matchOrFind(s, rawCompile(pattern, PCRE.MULTILINE), start) >= 0'i32
|
||||
|
||||
template `=~` *(s, pattern: expr): expr =
|
||||
## This calls ``match`` with an implicit declared ``matches`` array that
|
||||
## can be used in the scope of the ``=~`` call:
|
||||
##
|
||||
## .. code-block:: nimrod
|
||||
##
|
||||
## if line =~ r"\s*(\w+)\s*\=\s*(\w+)":
|
||||
## # matches a key=value pair:
|
||||
## echo("Key: ", matches[1])
|
||||
## echo("Value: ", matches[2])
|
||||
## elif line =~ r"\s*(\#.*)":
|
||||
## # matches a comment
|
||||
## # note that the implicit ``matches`` array is different from the
|
||||
## # ``matches`` array of the first branch
|
||||
## echo("comment: ", matches[1])
|
||||
## else:
|
||||
## echo("syntax error")
|
||||
##
|
||||
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
|
||||
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
|
||||
reBinary* = r"\b0[bB][01]+\b" ## describes a binary number (example: 0b11101)
|
||||
reOctal* = r"\b0[oO][0-7]+\b" ## describes an octal number (example: 0o777)
|
||||
reFloat* = r"\b[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?\b"
|
||||
## describes a floating point number
|
||||
reEmail* = r"\b[a-zA-Z0-9!#$%&'*+/=?^_`{|}~\-]+(?:\.[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+)" &
|
||||
r"*@(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\.)+(?:[a-zA-Z]{2}|com|org|" &
|
||||
r"net|gov|mil|biz|info|mobi|name|aero|jobs|museum)\b"
|
||||
## describes a common email address
|
||||
reURL* = r"\b(http(s)?|ftp|gopher|telnet|file|notes|ms\-help):" &
|
||||
r"((//)|(\\\\))+[\w\d:#@%/;$()~_?\+\-\=\\\.\&]*\b"
|
||||
## describes an URL
|
||||
|
||||
proc verbose*(pattern: string): string {.noSideEffect.} =
|
||||
## deletes whitespace from a pattern that is not escaped or in a character
|
||||
## class. This is modelled after Perl's ``/x`` modifier.
|
||||
result = ""
|
||||
var i = 0
|
||||
while i < pattern.len:
|
||||
case pattern[i]
|
||||
of ' ', '\t':
|
||||
inc i
|
||||
of '\\':
|
||||
add result, '\\'
|
||||
add result, pattern[i+1]
|
||||
inc i, 2
|
||||
of '[':
|
||||
while pattern[i] != ']' and pattern[i] != '\0':
|
||||
add result, pattern[i]
|
||||
inc i
|
||||
else:
|
||||
add result, pattern[i]
|
||||
inc i
|
||||
|
||||
|
|
@ -480,40 +480,40 @@ proc align*(s: string, count: int): string {.
|
|||
for i in spaces..count-1: result[i] = s[i-spaces]
|
||||
else:
|
||||
result = s
|
||||
|
||||
iterator tokenize*(s: string, seps: set[char] = Whitespace): tuple[
|
||||
token: string, isSep: bool] =
|
||||
## Tokenizes the string `s` into substrings.
|
||||
##
|
||||
## Substrings are separated by a substring containing only `seps`.
|
||||
## Examples:
|
||||
##
|
||||
## .. code-block:: nimrod
|
||||
## for word in tokenize(" this is an example "):
|
||||
## writeln(stdout, word)
|
||||
##
|
||||
## Results in:
|
||||
##
|
||||
## .. code-block:: nimrod
|
||||
## (" ", true)
|
||||
## ("this", false)
|
||||
## (" ", true)
|
||||
## ("is", false)
|
||||
## (" ", true)
|
||||
## ("an", false)
|
||||
## (" ", true)
|
||||
## ("example", false)
|
||||
## (" ", true)
|
||||
var i = 0
|
||||
while true:
|
||||
var j = i
|
||||
var isSep = s[j] in seps
|
||||
while j < s.len and (s[j] in seps) == isSep: inc(j)
|
||||
if j > i:
|
||||
yield (substr(s, i, j-1), isSep)
|
||||
else:
|
||||
break
|
||||
i = j
|
||||
|
||||
iterator tokenize*(s: string, seps: set[char] = Whitespace): tuple[
|
||||
token: string, isSep: bool] =
|
||||
## Tokenizes the string `s` into substrings.
|
||||
##
|
||||
## Substrings are separated by a substring containing only `seps`.
|
||||
## Examples:
|
||||
##
|
||||
## .. code-block:: nimrod
|
||||
## for word in tokenize(" this is an example "):
|
||||
## writeln(stdout, word)
|
||||
##
|
||||
## Results in:
|
||||
##
|
||||
## .. code-block:: nimrod
|
||||
## (" ", true)
|
||||
## ("this", false)
|
||||
## (" ", true)
|
||||
## ("is", false)
|
||||
## (" ", true)
|
||||
## ("an", false)
|
||||
## (" ", true)
|
||||
## ("example", false)
|
||||
## (" ", true)
|
||||
var i = 0
|
||||
while true:
|
||||
var j = i
|
||||
var isSep = s[j] in seps
|
||||
while j < s.len and (s[j] in seps) == isSep: inc(j)
|
||||
if j > i:
|
||||
yield (substr(s, i, j-1), isSep)
|
||||
else:
|
||||
break
|
||||
i = j
|
||||
|
||||
proc wordWrap*(s: string, maxLineWidth = 80,
|
||||
splitLongWords = true,
|
||||
|
|
@ -544,6 +544,33 @@ proc wordWrap*(s: string, maxLineWidth = 80,
|
|||
SpaceLeft = SpaceLeft - len(Word)
|
||||
result.add(word)
|
||||
|
||||
proc unindent*(s: string, eatAllIndent = false): string {.
|
||||
noSideEffect, rtl, extern: "nsuUnindent".} =
|
||||
## unindents `s`.
|
||||
result = newStringOfCap(s.len)
|
||||
var i = 0
|
||||
var pattern = true
|
||||
var indent = 0
|
||||
while s[i] == ' ': inc i
|
||||
var level = if i == 0: -1 else: i
|
||||
while i < s.len:
|
||||
if s[i] == ' ':
|
||||
if i > 0 and s[i-1] in {'\l', '\c'}:
|
||||
pattern = true
|
||||
indent = 0
|
||||
if pattern:
|
||||
inc(indent)
|
||||
if indent > level and not eatAllIndent:
|
||||
result.add(s[i])
|
||||
if level < 0: level = indent
|
||||
else:
|
||||
# a space somewhere: do not delete
|
||||
result.add(s[i])
|
||||
else:
|
||||
pattern = false
|
||||
result.add(s[i])
|
||||
inc i
|
||||
|
||||
proc startsWith*(s, prefix: string): bool {.noSideEffect,
|
||||
rtl, extern: "nsuStartsWith".} =
|
||||
## Returns true iff ``s`` starts with ``prefix``.
|
||||
|
|
@ -827,34 +854,6 @@ proc escape*(s: string, prefix = "\"", suffix = "\""): string {.noSideEffect,
|
|||
of '\"': add(result, "\\\"")
|
||||
else: add(result, c)
|
||||
add(result, suffix)
|
||||
|
||||
proc validEmailAddress*(s: string): bool {.noSideEffect,
|
||||
rtl, extern: "nsuValidEmailAddress".} =
|
||||
## returns true if `s` seems to be a valid e-mail address.
|
||||
## The checking also uses a domain list.
|
||||
## Note: This will be moved to another module soon.
|
||||
const
|
||||
chars = Letters + Digits + {'!','#','$','%','&',
|
||||
'\'','*','+','/','=','?','^','_','`','{','}','|','~','-','.'}
|
||||
var i = 0
|
||||
if s[i] notin chars or s[i] == '.': return false
|
||||
while s[i] in chars:
|
||||
if s[i] == '.' and s[i+1] == '.': return false
|
||||
inc(i)
|
||||
if s[i] != '@': return false
|
||||
var j = len(s)-1
|
||||
if s[j] notin letters: return false
|
||||
while j >= i and s[j] in letters: dec(j)
|
||||
inc(i) # skip '@'
|
||||
while s[i] in {'0'..'9', 'a'..'z', '-', '.'}: inc(i)
|
||||
if s[i] != '\0': return false
|
||||
|
||||
var x = substr(s, j+1)
|
||||
if len(x) == 2 and x[0] in Letters and x[1] in Letters: return true
|
||||
case toLower(x)
|
||||
of "com", "org", "net", "gov", "mil", "biz", "info", "mobi", "name",
|
||||
"aero", "jobs", "museum": return true
|
||||
return false
|
||||
|
||||
proc validIdentifier*(s: string): bool {.noSideEffect,
|
||||
rtl, extern: "nsuValidIdentifier".} =
|
||||
|
|
|
|||
|
|
@ -254,7 +254,7 @@ type
|
|||
## that should not be part of a message! Use
|
||||
## a ``TThreadId`` for that.
|
||||
emptyFn: proc ()
|
||||
dataFn: proc (p: TMsg)
|
||||
dataFn: proc (m: TMsg)
|
||||
data: TMsg
|
||||
TThreadId*[TMsg] = ptr TThread[TMsg] ## the current implementation uses
|
||||
## a pointer as a thread ID.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue