Merge branch 'master' of github.com:Araq/Nimrod into upstream

This commit is contained in:
Zahary Karadjov 2012-04-10 22:39:00 +03:00
commit c1ad05c4c5
32 changed files with 12023 additions and 459 deletions

47
lib/pure/endians.nim Normal file
View file

@ -0,0 +1,47 @@
#
#
# Nimrod's Runtime Library
# (c) Copyright 2012 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## This module contains helpers that deal with different byte orders
## (`endian`:idx:).
proc swapEndian64*(outp, inp: pointer) =
## copies `inp` to `outp` swapping bytes. Both buffers are supposed to
## contain at least 8 bytes.
var i = cast[cstring](inp)
var o = cast[cstring](outp)
o[0] = i[7]
o[1] = i[6]
o[2] = i[5]
o[3] = i[4]
o[4] = i[3]
o[5] = i[2]
o[6] = i[1]
o[7] = i[0]
proc swapEndian32*(outp, inp: pointer) =
## copies `inp` to `outp` swapping bytes. Both buffers are supposed to
## contain at least 4 bytes.
var i = cast[cstring](inp)
var o = cast[cstring](outp)
o[0] = i[3]
o[1] = i[2]
o[2] = i[1]
o[3] = i[0]
when system.cpuEndian == bigEndian:
proc littleEndian64*(outp, inp: pointer) {.inline.} = swapEndian64(outp, inp)
proc littleEndian32*(outp, inp: pointer) {.inline.} = swapEndian32(outp, inp)
proc bigEndian64*(outp, inp: pointer) {.inline.} = copyMem(outp, inp, 8)
proc bigEndian32*(outp, inp: pointer) {.inline.} = copyMem(outp, inp, 4)
else:
proc littleEndian64*(outp, inp: pointer) {.inline.} = copyMem(outp, inp, 8)
proc littleEndian32*(outp, inp: pointer) {.inline.} = copyMem(outp, inp, 4)
proc bigEndian64*(outp, inp: pointer) {.inline.} = swapEndian64(outp, inp)
proc bigEndian32*(outp, inp: pointer) {.inline.} = swapEndian32(outp, inp)

View file

@ -495,16 +495,16 @@ type
JArray
PJsonNode* = ref TJsonNode ## JSON node
TJsonNode* {.final, pure.} = object
TJsonNode* {.final, pure, acyclic.} = object
case kind*: TJsonNodeKind
of JString:
str*: String
str*: string
of JInt:
num*: biggestInt
of JFloat:
fnum: Float
fnum*: float
of JBool:
bval*: Bool
bval*: bool
of JNull:
nil
of JObject:
@ -558,6 +558,45 @@ proc newJArray*(): PJsonNode =
result.kind = JArray
result.elems = @[]
proc `%`*(s: string): PJsonNode =
## Generic constructor for JSON data. Creates a new `JString PJsonNode`.
new(result)
result.kind = JString
result.str = s
proc `%`*(n: biggestInt): PJsonNode =
## Generic constructor for JSON data. Creates a new `JInt PJsonNode`.
new(result)
result.kind = JInt
result.num = n
proc `%`*(n: float): PJsonNode =
## Generic constructor for JSON data. Creates a new `JFloat PJsonNode`.
new(result)
result.kind = JFloat
result.fnum = n
proc `%`*(b: bool): PJsonNode =
## Generic constructor for JSON data. Creates a new `JBool PJsonNode`.
new(result)
result.kind = JBool
result.bval = b
proc `%`*(keyVals: openArray[tuple[key: string, val: PJsonNode]]): PJsonNode =
## Generic constructor for JSON data. Creates a new `JObject PJsonNode`
new(result)
result.kind = JObject
newSeq(result.fields, keyVals.len)
for i, p in pairs(keyVals): result.fields[i] = p
proc `%`*(elements: openArray[PJSonNode]): PJsonNode =
## Generic constructor for JSON data. Creates a new `JArray PJsonNode`
new(result)
result.kind = JArray
newSeq(result.elems, elements.len)
for i, p in pairs(elements): result.elems[i] = p
proc len*(n: PJsonNode): int =
## If `n` is a `JArray`, it returns the number of elements.
## If `n` is a `JObject`, it returns the number of pairs.

86
lib/pure/oids.nim Normal file
View file

@ -0,0 +1,86 @@
#
#
# Nimrod's Runtime Library
# (c) Copyright 2012 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## Nimrod OID support. An OID is a global ID that consists of a timestamp,
## a unique counter and a random value. This combination should suffice to
## produce a globally distributed unique ID. This implementation was extracted
## from the Mongodb interface and it thus binary compatible with a Mongo OID.
##
## This implementation calls ``math.randomize()`` for the first call of
## ``genOid``.
import times, endians
type
Toid* {.pure, final.} = object ## an OID
time: int32 ##
fuzz: int32 ##
count: int32 ##
proc hexbyte*(hex: char): int =
case hex
of '0'..'9': result = (ord(hex) - ord('0'))
of 'a'..'f': result = (ord(hex) - ord('a') + 10)
of 'A'..'F': result = (ord(hex) - ord('A') + 10)
else: nil
proc parseOid*(str: cstring): TOid =
## parses an OID.
var bytes = cast[cstring](addr(result.time))
var i = 0
while i < 12:
bytes[i] = chr((hexbyte(str[2 * i]) shl 4) or hexbyte(str[2 * i + 1]))
inc(i)
proc oidToString*(oid: TOid, str: cstring) =
const hex = "0123456789abcdef"
# work around a compiler bug:
var str = str
var o = oid
var bytes = cast[cstring](addr(o))
var i = 0
while i < 12:
let b = bytes[i].ord
str[2 * i] = hex[(b and 0xF0) shr 4]
str[2 * i + 1] = hex[b and 0xF]
inc(i)
str[24] = '\0'
var
incr, fuzz: int
proc genOid*(): TOid =
## generates a new OID.
proc rand(): cint {.importc: "rand", nodecl.}
proc gettime(dummy: ptr cint): cint {.importc: "time", header: "<time.h>".}
proc srand(seed: cint) {.importc: "srand", nodecl.}
var t = gettime(nil)
var i = int32(incr)
atomicInc(incr)
if fuzz == 0:
# racy, but fine semantically:
srand(t)
fuzz = rand()
bigEndian32(addr result.time, addr(t))
result.fuzz = fuzz
bigEndian32(addr result.count, addr(i))
proc generatedTime*(oid: TOid): TTime =
## returns the generated timestamp of the OID.
var tmp: int32
var dummy = oid.time
bigEndian32(addr(tmp), addr(dummy))
result = TTime(tmp)
when isMainModule:
let xo = genOID()
echo xo.generatedTime

View file

@ -151,7 +151,7 @@ else: # UNIX-like operating system
ScriptExt* = ""
DynlibFormat* = "lib$1.so"
when defined(macosx):
when defined(macosx) or defined(bsd):
var
pathMax {.importc: "PATH_MAX", header: "<stdlib.h>".}: cint
@ -580,7 +580,7 @@ proc expandFilename*(filename: string): string {.rtl, extern: "nos$1".} =
var L = GetFullPathNameA(filename, bufsize, result, unused)
if L <= 0'i32 or L >= bufsize: OSError()
setLen(result, L)
elif defined(macosx):
elif defined(macosx) or defined(bsd):
# On Mac OS X 10.5, realpath does not allocate the buffer on its own
var pathBuffer: cstring = newString(pathMax)
var resultBuffer = realpath(filename, pathBuffer)
@ -1355,6 +1355,7 @@ when defined(macosx):
proc getAppFilename*(): string {.rtl, extern: "nos$1".} =
## Returns the filename of the application's executable.
## **Note**: This does not work reliably on BSD.
# Linux: /proc/<pid>/exe
# Solaris:
@ -1410,6 +1411,7 @@ proc getApplicationDir*(): string {.rtl, extern: "nos$1", deprecated.} =
proc getAppDir*(): string {.rtl, extern: "nos$1".} =
## Returns the directory of the application's executable.
## **Note**: This does not work reliably on BSD.
result = splitFile(getAppFilename()).dir
proc sleep*(milsecs: int) {.rtl, extern: "nos$1".} =

View file

@ -1486,10 +1486,10 @@ proc primary(p: var TPegParser): TPeg =
return !primary(p)
of tkAt:
getTok(p)
return @primary(p)
return @(primary(p))
of tkCurlyAt:
getTok(p)
return @@primary(p).token(p)
return @@(primary(p).token(p))
else: nil
case p.tok.kind
of tkIdentifier:

View file

@ -378,6 +378,22 @@ proc parseBool*(s: string): bool =
of "y", "yes", "true", "1", "on": result = true
of "n", "no", "false", "0", "off": result = false
else: raise newException(EInvalidValue, "cannot interpret as a bool: " & s)
proc parseEnum*[T: enum](s: string): T =
## parses an enum ``T``. Raises ``EInvalidValue`` for an invalid value in
## `s`. The comparison is done in a style insensitive way.
for e in low(T)..high(T):
if cmpIgnoreStyle(s, $e) == 0:
return e
raise newException(EInvalidValue, "invalid enum value: " & s)
proc parseEnum*[T: enum](s: string, default: T): T =
## parses an enum ``T``. Uses `default` for an invalid value in
## `s`. The comparison is done in a style insensitive way.
for e in low(T)..high(T):
if cmpIgnoreStyle(s, $e) == 0:
return e
result = default
proc repeatChar*(count: int, c: Char = ' '): string {.noSideEffect,
rtl, extern: "nsuRepeatChar".} =
@ -1105,5 +1121,8 @@ when isMainModule:
doAssert "-ld a-ldz -ld".replaceWord("-ld") == " a-ldz "
doAssert "-lda-ldz -ld abc".replaceWord("-ld") == "-lda-ldz abc"
type TMyEnum = enum enA, enB, enC, enuD, enE
doAssert parseEnum[TMyEnum]("enu_D") == enuD
doAssert parseEnum("invalid enum value", enC) == enC

View file

@ -1,7 +1,7 @@
#
#
# Nimrod's Runtime Library
# (c) Copyright 2009 Andreas Rumpf
# (c) Copyright 2012 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
@ -307,6 +307,17 @@ proc setBackgroundColor*(bg: TBackgroundColor, bright=false) =
gBG = ord(bg)
if bright: inc(gBG, 60)
stdout.write("\e[" & $gBG & 'm')
proc isatty*(f: TFile): bool =
## returns true if `f` is associated with a terminal device.
when defined(posix):
proc isatty(fildes: TFileHandle): cint {.
importc: "isatty", header: "<unistd.h>".}
else:
proc isatty(fildes: TFileHandle): cint {.
importc: "_isatty", header: "<io.h>".}
result = isatty(fileHandle(f)) != 0'i32
# XXX:
# These should be private, but there is no yet
@ -317,7 +328,7 @@ proc styledEchoProcessArg*(style: set[TStyle]) = setStyle style
proc styledEchoProcessArg*(color: TForegroundColor) = setForeGroundColor color
proc styledEchoProcessArg*(color: TBackgroundColor) = setBackGroundColor color
macro styledEcho*(m: stmt): stmt =
macro styledEcho*(m: stmt): stmt =
result = newNimNode(nnkStmtList)
for i in countup(1, m.len - 1):