Merge branch 'devel' into gcbugfix
This commit is contained in:
commit
373a79b28a
127 changed files with 1341 additions and 612 deletions
|
|
@ -1,7 +1,7 @@
|
|||
#
|
||||
#
|
||||
# Nim's Runtime Library
|
||||
# (c) Copyright 2012 Andreas Rumpf
|
||||
# (c) Copyright 2015 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
|
|
@ -13,6 +13,8 @@
|
|||
## is used. This suffices because Windows' console already provides the
|
||||
## wanted functionality.
|
||||
|
||||
{.deadCodeElim: on.}
|
||||
|
||||
when defined(Windows):
|
||||
proc readLineFromStdin*(prompt: string): TaintedString {.
|
||||
tags: [ReadIOEffect, WriteIOEffect].} =
|
||||
|
|
@ -31,9 +33,27 @@ when defined(Windows):
|
|||
stdout.write(prompt)
|
||||
result = readLine(stdin, line)
|
||||
|
||||
proc readPasswordFromStdin*(prompt: string, password: var TaintedString) =
|
||||
## Reads a `password` from stdin without printing it. `password` must not
|
||||
## be ``nil``!
|
||||
proc getch(): cint {.header: "<conio.h>", importc: "_getch".}
|
||||
|
||||
password.setLen(0)
|
||||
var c: char
|
||||
echo prompt
|
||||
while true:
|
||||
c = getch().char
|
||||
case c
|
||||
of '\r', chr(0xA):
|
||||
break
|
||||
of '\b':
|
||||
password.setLen(password.len - 1)
|
||||
else:
|
||||
password.add(c)
|
||||
|
||||
else:
|
||||
import readline, history
|
||||
|
||||
import readline, history, termios, unsigned
|
||||
|
||||
proc readLineFromStdin*(prompt: string): TaintedString {.
|
||||
tags: [ReadIOEffect, WriteIOEffect].} =
|
||||
var buffer = readline.readLine(prompt)
|
||||
|
|
@ -55,8 +75,24 @@ else:
|
|||
result = true
|
||||
|
||||
# initialization:
|
||||
# disable auto-complete:
|
||||
# disable auto-complete:
|
||||
proc doNothing(a, b: cint): cint {.cdecl, procvar.} = discard
|
||||
|
||||
|
||||
discard readline.bind_key('\t'.ord, doNothing)
|
||||
|
||||
proc readPasswordFromStdin*(prompt: string, password: var TaintedString) =
|
||||
password.setLen(0)
|
||||
let fd = stdin.getFileHandle()
|
||||
var cur, old: Termios
|
||||
discard fd.tcgetattr(cur.addr)
|
||||
old = cur
|
||||
cur.lflag = cur.lflag and not Tcflag(ECHO)
|
||||
discard fd.tcsetattr(TCSADRAIN, cur.addr)
|
||||
stdout.write prompt
|
||||
discard stdin.readLine(password)
|
||||
discard fd.tcsetattr(TCSADRAIN, old.addr)
|
||||
|
||||
proc readPasswordFromStdin*(prompt: string): TaintedString =
|
||||
## Reads a password from stdin without printing it.
|
||||
result = TaintedString("")
|
||||
readPasswordFromStdin(prompt, result)
|
||||
|
|
|
|||
|
|
@ -379,7 +379,7 @@ static inline void GCGuard (void *ptr) { asm volatile ("" :: "X" (ptr)); }
|
|||
# define GC_GUARD
|
||||
#endif
|
||||
|
||||
/* Test to see if nimrod and the C compiler agree on the size of a pointer.
|
||||
/* Test to see if Nim and the C compiler agree on the size of a pointer.
|
||||
On disagreement, your C compiler will say something like:
|
||||
"error: 'assert_numbits' declared as an array with a negative size" */
|
||||
typedef int assert_numbits[sizeof(NI) == sizeof(void*) && NIM_INTBITS == sizeof(NI)*8 ? 1 : -1];
|
||||
|
|
@ -390,3 +390,12 @@ typedef int assert_numbits[sizeof(NI) == sizeof(void*) && NIM_INTBITS == sizeof(
|
|||
#else
|
||||
# define NIM_EXTERNC
|
||||
#endif
|
||||
|
||||
/* ---------------- platform specific includes ----------------------- */
|
||||
|
||||
/* VxWorks related includes */
|
||||
#if defined(__VXWORKS__)
|
||||
# include <sys/types.h>
|
||||
# include <types/vxWind.h>
|
||||
# include <tool/gnu/toolMacros.h>
|
||||
#endif
|
||||
|
|
|
|||
264
lib/posix/termios.nim
Normal file
264
lib/posix/termios.nim
Normal file
|
|
@ -0,0 +1,264 @@
|
|||
#
|
||||
#
|
||||
# Nim's Runtime Library
|
||||
# (c) Copyright 2015 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
{.deadCodeElim: on.}
|
||||
import posix
|
||||
|
||||
type
|
||||
Speed* = cuint
|
||||
Tcflag* = cuint
|
||||
|
||||
const
|
||||
NCCS* = 32
|
||||
|
||||
type
|
||||
Termios* = object {.importc: "struct termios", header: "<termios.h>", final, pure.}
|
||||
iflag*: Tcflag # input mode flags
|
||||
oflag*: Tcflag # output mode flags
|
||||
cflag*: Tcflag # control mode flags
|
||||
lflag*: Tcflag # local mode flags
|
||||
line*: cuchar # line discipline
|
||||
cc*: array[NCCS, cuchar] # control characters
|
||||
ispeed*: Speed # input speed
|
||||
ospeed*: Speed # output speed
|
||||
|
||||
|
||||
# cc characters
|
||||
|
||||
const
|
||||
VINTR* = 0
|
||||
VQUIT* = 1
|
||||
VERASE* = 2
|
||||
VKILL* = 3
|
||||
VEOF* = 4
|
||||
VTIME* = 5
|
||||
VMIN* = 6
|
||||
VSWTC* = 7
|
||||
VSTART* = 8
|
||||
VSTOP* = 9
|
||||
VSUSP* = 10
|
||||
VEOL* = 11
|
||||
VREPRINT* = 12
|
||||
VDISCARD* = 13
|
||||
VWERASE* = 14
|
||||
VLNEXT* = 15
|
||||
VEOL2* = 16
|
||||
|
||||
# iflag bits
|
||||
|
||||
const
|
||||
IGNBRK* = 1
|
||||
BRKINT* = 2
|
||||
IGNPAR* = 4
|
||||
PARMRK* = 10
|
||||
INPCK* = 20
|
||||
ISTRIP* = 40
|
||||
INLCR* = 100
|
||||
IGNCR* = 200
|
||||
ICRNL* = 400
|
||||
IUCLC* = 1000
|
||||
IXON* = 2000
|
||||
IXANY* = 4000
|
||||
IXOFF* = 10000
|
||||
IMAXBEL* = 20000
|
||||
IUTF8* = 40000
|
||||
|
||||
# oflag bits
|
||||
|
||||
const
|
||||
OPOST* = 1
|
||||
OLCUC* = 2
|
||||
ONLCR* = 4
|
||||
OCRNL* = 10
|
||||
ONOCR* = 20
|
||||
ONLRET* = 40
|
||||
OFILL* = 100
|
||||
OFDEL* = 200
|
||||
NLDLY* = 400
|
||||
NL0* = 0
|
||||
NL1* = 400
|
||||
CRDLY* = 3000
|
||||
CR0* = 0
|
||||
CR1* = 1000
|
||||
CR2* = 2000
|
||||
CR3* = 3000
|
||||
TABDLY* = 14000
|
||||
TAB0* = 0
|
||||
TAB1* = 4000
|
||||
TAB2* = 10000
|
||||
TAB3* = 14000
|
||||
BSDLY* = 20000
|
||||
BS0* = 0
|
||||
BS1* = 20000
|
||||
FFDLY* = 0o000000100000
|
||||
FF0* = 0
|
||||
FF1* = 0o000000100000
|
||||
VTDLY* = 40000
|
||||
VT0* = 0
|
||||
VT1* = 40000
|
||||
XTABS* = 14000
|
||||
|
||||
# cflag bit meaning
|
||||
|
||||
const
|
||||
CBAUD* = 10017
|
||||
B0* = 0
|
||||
B50* = 1
|
||||
B75* = 2
|
||||
B110* = 3
|
||||
B134* = 4
|
||||
B150* = 5
|
||||
B200* = 6
|
||||
B300* = 7
|
||||
B600* = 10
|
||||
B1200* = 11
|
||||
B1800* = 12
|
||||
B2400* = 13
|
||||
B4800* = 14
|
||||
B9600* = 15
|
||||
B19200* = 16
|
||||
B38400* = 17
|
||||
EXTA* = B19200
|
||||
EXTB* = B38400
|
||||
CSIZE* = 60
|
||||
CS5* = 0
|
||||
CS6* = 20
|
||||
CS7* = 40
|
||||
CS8* = 60
|
||||
CSTOPB* = 100
|
||||
CREAD* = 200
|
||||
PARENB* = 400
|
||||
PARODD* = 1000
|
||||
HUPCL* = 2000
|
||||
CLOCAL* = 4000
|
||||
CBAUDEX* = 10000
|
||||
B57600* = 10001
|
||||
B115200* = 10002
|
||||
B230400* = 10003
|
||||
B460800* = 10004
|
||||
B500000* = 10005
|
||||
B576000* = 10006
|
||||
B921600* = 10007
|
||||
B1000000* = 10010
|
||||
B1152000* = 10011
|
||||
B1500000* = 10012
|
||||
B2000000* = 10013
|
||||
B2500000* = 10014
|
||||
B3000000* = 10015
|
||||
B3500000* = 10016
|
||||
B4000000* = 10017
|
||||
MAX_BAUD* = B4000000
|
||||
CIBAUD* = 2003600000
|
||||
CMSPAR* = 0o010000000000
|
||||
CRTSCTS* = 0o020000000000
|
||||
|
||||
# lflag bits
|
||||
|
||||
const
|
||||
ISIG* = 1
|
||||
ICANON* = 2
|
||||
XCASE* = 4
|
||||
ECHO* = 10
|
||||
ECHOE* = 20
|
||||
ECHOK* = 40
|
||||
ECHONL* = 100
|
||||
NOFLSH* = 200
|
||||
TOSTOP* = 400
|
||||
ECHOCTL* = 1000
|
||||
ECHOPRT* = 2000
|
||||
ECHOKE* = 4000
|
||||
FLUSHO* = 10000
|
||||
PENDIN* = 40000
|
||||
IEXTEN* = 0o000000100000
|
||||
EXTPROC* = 0o000000200000
|
||||
|
||||
# tcflow() and TCXONC use these
|
||||
|
||||
const
|
||||
TCOOFF* = 0
|
||||
TCOON* = 1
|
||||
TCIOFF* = 2
|
||||
TCION* = 3
|
||||
|
||||
# tcflush() and TCFLSH use these
|
||||
|
||||
const
|
||||
TCIFLUSH* = 0
|
||||
TCOFLUSH* = 1
|
||||
TCIOFLUSH* = 2
|
||||
|
||||
# tcsetattr uses these
|
||||
|
||||
const
|
||||
TCSANOW* = 0
|
||||
TCSADRAIN* = 1
|
||||
TCSAFLUSH* = 2
|
||||
|
||||
# Compare a character C to a value VAL from the `cc' array in a
|
||||
# `struct termios'. If VAL is _POSIX_VDISABLE, no character can match it.
|
||||
|
||||
template cceq*(val, c: expr): expr =
|
||||
c == val and val != POSIX_VDISABLE
|
||||
|
||||
# Return the output baud rate stored in *TERMIOS_P.
|
||||
|
||||
proc cfGetOspeed*(termios: ptr Termios): Speed {.importc: "cfgetospeed",
|
||||
header: "<termios.h>".}
|
||||
# Return the input baud rate stored in *TERMIOS_P.
|
||||
|
||||
proc cfGetIspeed*(termios: ptr Termios): Speed {.importc: "cfgetispeed",
|
||||
header: "<termios.h>".}
|
||||
# Set the output baud rate stored in *TERMIOS_P to SPEED.
|
||||
|
||||
proc cfSetOspeed*(termios: ptr Termios; speed: Speed): cint {.
|
||||
importc: "cfsetospeed", header: "<termios.h>".}
|
||||
# Set the input baud rate stored in *TERMIOS_P to SPEED.
|
||||
|
||||
proc cfSetIspeed*(termios: ptr Termios; speed: Speed): cint {.
|
||||
importc: "cfsetispeed", header: "<termios.h>".}
|
||||
# Set both the input and output baud rates in *TERMIOS_OP to SPEED.
|
||||
|
||||
proc cfSetSpeed*(termios: ptr Termios; speed: Speed): cint {.
|
||||
importc: "cfsetspeed", header: "<termios.h>".}
|
||||
# Put the state of FD into *TERMIOS_P.
|
||||
|
||||
proc tcGetAttr*(fd: cint; termios: ptr Termios): cint {.
|
||||
importc: "tcgetattr", header: "<termios.h>".}
|
||||
# Set the state of FD to *TERMIOS_P.
|
||||
# Values for OPTIONAL_ACTIONS (TCSA*) are in <bits/termios.h>.
|
||||
|
||||
proc tcSetAttr*(fd: cint; optional_actions: cint; termios: ptr Termios): cint {.
|
||||
importc: "tcsetattr", header: "<termios.h>".}
|
||||
# Set *TERMIOS_P to indicate raw mode.
|
||||
|
||||
proc cfMakeRaw*(termios: ptr Termios) {.importc: "cfmakeraw",
|
||||
header: "<termios.h>".}
|
||||
# Send zero bits on FD.
|
||||
|
||||
proc tcSendBreak*(fd: cint; duration: cint): cint {.importc: "tcsendbreak",
|
||||
header: "<termios.h>".}
|
||||
# Wait for pending output to be written on FD.
|
||||
#
|
||||
# This function is a cancellation point and therefore not marked with
|
||||
# .
|
||||
|
||||
proc tcDrain*(fd: cint): cint {.importc: "tcdrain", header: "<termios.h>".}
|
||||
# Flush pending data on FD.
|
||||
# Values for QUEUE_SELECTOR (TC{I,O,IO}FLUSH) are in <bits/termios.h>.
|
||||
|
||||
proc tcFlush*(fd: cint; queue_selector: cint): cint {.importc: "tcflush",
|
||||
header: "<termios.h>".}
|
||||
# Suspend or restart transmission on FD.
|
||||
# Values for ACTION (TC[IO]{OFF,ON}) are in <bits/termios.h>.
|
||||
|
||||
proc tcFlow*(fd: cint; action: cint): cint {.importc: "tcflow",
|
||||
header: "<termios.h>".}
|
||||
# Get process group ID for session leader for controlling terminal FD.
|
||||
|
||||
proc tcGetSid*(fd: cint): TPid {.importc: "tcgetsid", header: "<termios.h>".}
|
||||
|
|
@ -220,3 +220,62 @@ proc product*[T](x: openArray[seq[T]]): seq[seq[T]] =
|
|||
result.add(res)
|
||||
index = 0
|
||||
indexes[index] -=1
|
||||
|
||||
proc nextPermutation*[T](x: var openarray[T]): bool {.discardable.} =
|
||||
## Calculates the next lexicographic permutation, directly modifying ``x``.
|
||||
## The result is whether a permutation happened, otherwise we have reached
|
||||
## the last-ordered permutation.
|
||||
##
|
||||
## .. code-block:: nim
|
||||
##
|
||||
## var v = @[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
|
||||
## v.nextPermutation()
|
||||
## echo v
|
||||
if x.len < 2:
|
||||
return false
|
||||
|
||||
var i = x.high
|
||||
while i > 0 and x[i-1] >= x[i]:
|
||||
dec i
|
||||
|
||||
if i == 0:
|
||||
return false
|
||||
|
||||
var j = x.high
|
||||
while j >= i and x[j] <= x[i-1]:
|
||||
dec j
|
||||
|
||||
swap x[j], x[i-1]
|
||||
x.reverse(i, x.high)
|
||||
|
||||
result = true
|
||||
|
||||
proc prevPermutation*[T](x: var openarray[T]): bool {.discardable.} =
|
||||
## Calculates the previous lexicographic permutation, directly modifying
|
||||
## ``x``. The result is whether a permutation happened, otherwise we have
|
||||
## reached the first-ordered permutation.
|
||||
##
|
||||
## .. code-block:: nim
|
||||
##
|
||||
## var v = @[0, 1, 2, 3, 4, 5, 6, 7, 9, 8]
|
||||
## v.prevPermutation()
|
||||
## echo v
|
||||
if x.len < 2:
|
||||
return false
|
||||
|
||||
var i = x.high
|
||||
while i > 0 and x[i-1] <= x[i]:
|
||||
dec i
|
||||
|
||||
if i == 0:
|
||||
return false
|
||||
|
||||
x.reverse(i, x.high)
|
||||
|
||||
var j = x.high
|
||||
while j >= i and x[j-1] < x[i-1]:
|
||||
dec j
|
||||
|
||||
swap x[i-1], x[j]
|
||||
|
||||
result = true
|
||||
|
|
|
|||
|
|
@ -1064,6 +1064,17 @@ proc accept*(socket: TAsyncFD,
|
|||
|
||||
# -- Await Macro
|
||||
|
||||
proc skipUntilStmtList(node: PNimrodNode): PNimrodNode {.compileTime.} =
|
||||
# Skips a nest of StmtList's.
|
||||
result = node
|
||||
if node[0].kind == nnkStmtList:
|
||||
result = skipUntilStmtList(node[0])
|
||||
|
||||
proc skipStmtList(node: PNimrodNode): PNimrodNode {.compileTime.} =
|
||||
result = node
|
||||
if node[0].kind == nnkStmtList:
|
||||
result = node[0]
|
||||
|
||||
template createCb(retFutureSym, iteratorNameSym,
|
||||
name: expr): stmt {.immediate.} =
|
||||
var nameIterVar = iteratorNameSym
|
||||
|
|
@ -1211,26 +1222,53 @@ proc processBody(node, retFutureSym: PNimrodNode,
|
|||
of nnkTryStmt:
|
||||
# try: await x; except: ...
|
||||
result = newNimNode(nnkStmtList, node)
|
||||
template wrapInTry(n, tryBody: PNimrodNode) =
|
||||
var temp = n
|
||||
n[0] = tryBody
|
||||
tryBody = temp
|
||||
|
||||
# Transform ``except`` body.
|
||||
# TODO: Could we perform some ``await`` transformation here to get it
|
||||
# working in ``except``?
|
||||
tryBody[1] = processBody(n[1], retFutureSym, subTypeIsVoid, nil)
|
||||
|
||||
proc processForTry(n: PNimrodNode, i: var int,
|
||||
res: PNimrodNode): bool {.compileTime.} =
|
||||
## Transforms the body of the tryStmt. Does not transform the
|
||||
## body in ``except``.
|
||||
## Returns true if the tryStmt node was transformed into an ifStmt.
|
||||
result = false
|
||||
while i < n[0].len:
|
||||
var processed = processBody(n[0][i], retFutureSym, subTypeIsVoid, n)
|
||||
if processed.kind != n[0][i].kind or processed.len != n[0][i].len:
|
||||
var skipped = n.skipStmtList()
|
||||
while i < skipped.len:
|
||||
var processed = processBody(skipped[i], retFutureSym,
|
||||
subTypeIsVoid, n)
|
||||
|
||||
# Check if we transformed the node into an exception check.
|
||||
# This suggests skipped[i] contains ``await``.
|
||||
if processed.kind != skipped[i].kind or processed.len != skipped[i].len:
|
||||
processed = processed.skipUntilStmtList()
|
||||
expectKind(processed, nnkStmtList)
|
||||
expectKind(processed[2][1], nnkElse)
|
||||
i.inc
|
||||
discard processForTry(n, i, processed[2][1][0])
|
||||
|
||||
if not processForTry(n, i, processed[2][1][0]):
|
||||
# We need to wrap the nnkElse nodes back into a tryStmt.
|
||||
# As they are executed if an exception does not happen
|
||||
# inside the awaited future.
|
||||
# The following code will wrap the nodes inside the
|
||||
# original tryStmt.
|
||||
wrapInTry(n, processed[2][1][0])
|
||||
|
||||
res.add processed
|
||||
result = true
|
||||
else:
|
||||
res.add n[0][i]
|
||||
res.add skipped[i]
|
||||
i.inc
|
||||
var i = 0
|
||||
if not processForTry(node, i, result):
|
||||
var temp = node
|
||||
temp[0] = result
|
||||
result = temp
|
||||
# If the tryStmt hasn't been transformed we can just put the body
|
||||
# back into it.
|
||||
wrapInTry(node, result)
|
||||
return
|
||||
else: discard
|
||||
|
||||
|
|
@ -1329,8 +1367,8 @@ macro async*(prc: stmt): stmt {.immediate.} =
|
|||
result[6] = outerProcBody
|
||||
|
||||
#echo(treeRepr(result))
|
||||
#if prc[0].getName == "catch":
|
||||
# echo(toStrLit(result))
|
||||
if prc[0].getName == "test3":
|
||||
echo(toStrLit(result))
|
||||
|
||||
proc recvLine*(socket: TAsyncFD): Future[string] {.async.} =
|
||||
## Reads a line of data from ``socket``. Returned future will complete once
|
||||
|
|
|
|||
|
|
@ -30,9 +30,28 @@
|
|||
##
|
||||
## 1.3000000000000000e+00
|
||||
## true
|
||||
##
|
||||
## This module can also be used to comfortably create JSON using the `%*`
|
||||
## operator:
|
||||
##
|
||||
## .. code-block:: nim
|
||||
##
|
||||
## var hisName = "John"
|
||||
## let herAge = 31
|
||||
## var j = %*
|
||||
## [
|
||||
## {
|
||||
## "name": hisName,
|
||||
## "age": 30
|
||||
## },
|
||||
## {
|
||||
## "name": "Susan",
|
||||
## "age": herAge
|
||||
## }
|
||||
## ]
|
||||
|
||||
import
|
||||
hashes, strutils, lexbase, streams, unicode
|
||||
hashes, strutils, lexbase, streams, unicode, macros
|
||||
|
||||
type
|
||||
JsonEventKind* = enum ## enumeration of all events that may occur when parsing
|
||||
|
|
@ -625,6 +644,29 @@ proc `%`*(elements: openArray[JsonNode]): JsonNode =
|
|||
newSeq(result.elems, elements.len)
|
||||
for i, p in pairs(elements): result.elems[i] = p
|
||||
|
||||
proc toJson(x: PNimrodNode): PNimrodNode {.compiletime.} =
|
||||
case x.kind
|
||||
of nnkBracket:
|
||||
result = newNimNode(nnkBracket)
|
||||
for i in 0 .. <x.len:
|
||||
result.add(toJson(x[i]))
|
||||
|
||||
of nnkTableConstr:
|
||||
result = newNimNode(nnkTableConstr)
|
||||
for i in 0 .. <x.len:
|
||||
assert x[i].kind == nnkExprColonExpr
|
||||
result.add(newNimNode(nnkExprColonExpr).add(x[i][0]).add(toJson(x[i][1])))
|
||||
|
||||
else:
|
||||
result = x
|
||||
|
||||
result = prefix(result, "%")
|
||||
|
||||
macro `%*`*(x: expr): expr =
|
||||
## Convert an expression to a JsonNode directly, without having to specify
|
||||
## `%` for every element.
|
||||
result = toJson(x)
|
||||
|
||||
proc `==`* (a,b: JsonNode): bool =
|
||||
## Check two nodes for equality
|
||||
if a.isNil:
|
||||
|
|
@ -864,7 +906,7 @@ proc pretty*(node: JsonNode, indent = 2): string =
|
|||
proc `$`*(node: JsonNode): string =
|
||||
## Converts `node` to its JSON Representation on one line.
|
||||
result = ""
|
||||
toPretty(result, node, 1, false)
|
||||
toPretty(result, node, 0, false)
|
||||
|
||||
iterator items*(node: JsonNode): JsonNode =
|
||||
## Iterator for the items of `node`. `node` has to be a JArray.
|
||||
|
|
@ -1101,6 +1143,37 @@ when isMainModule:
|
|||
except:
|
||||
assert(false, "EInvalidIndex thrown for valid index")
|
||||
|
||||
# Generator:
|
||||
var j = %* [{"name": "John", "age": 30}, {"name": "Susan", "age": 31}]
|
||||
assert j == %[%{"name": %"John", "age": %30}, %{"name": %"Susan", "age": %31}]
|
||||
|
||||
var j2 = %*
|
||||
[
|
||||
{
|
||||
"name": "John",
|
||||
"age": 30
|
||||
},
|
||||
{
|
||||
"name": "Susan",
|
||||
"age": 31
|
||||
}
|
||||
]
|
||||
assert j2 == %[%{"name": %"John", "age": %30}, %{"name": %"Susan", "age": %31}]
|
||||
|
||||
var name = "John"
|
||||
let herAge = 30
|
||||
const hisAge = 31
|
||||
|
||||
var j3 = %*
|
||||
[ { "name": "John"
|
||||
, "age": herAge
|
||||
}
|
||||
, { "name": "Susan"
|
||||
, "age": hisAge
|
||||
}
|
||||
]
|
||||
assert j3 == %[%{"name": %"John", "age": %30}, %{"name": %"Susan", "age": %31}]
|
||||
|
||||
discard """
|
||||
while true:
|
||||
var json = stdin.readLine()
|
||||
|
|
|
|||
|
|
@ -186,7 +186,7 @@ proc newRollingFileLogger*(filename = defaultFilename(),
|
|||
## a new log file will be started and the old will be renamed.
|
||||
new(result)
|
||||
result.levelThreshold = levelThreshold
|
||||
result.fmtStr = defaultFmtStr
|
||||
result.fmtStr = fmtStr
|
||||
result.maxLines = maxLines
|
||||
result.f = open(filename, mode)
|
||||
result.curLine = 0
|
||||
|
|
|
|||
|
|
@ -1074,8 +1074,12 @@ when defined(windows):
|
|||
# because we support Windows GUI applications, things get really
|
||||
# messy here...
|
||||
when useWinUnicode:
|
||||
proc strEnd(cstr: WideCString, c = 0'i32): WideCString {.
|
||||
importc: "wcschr", header: "<string.h>".}
|
||||
when defined(cpp):
|
||||
proc strEnd(cstr: WideCString, c = 0'i32): WideCString {.
|
||||
importcpp: "(NI16*)wcschr((const wchar_t *)#, #)", header: "<string.h>".}
|
||||
else:
|
||||
proc strEnd(cstr: WideCString, c = 0'i32): WideCString {.
|
||||
importc: "wcschr", header: "<string.h>".}
|
||||
else:
|
||||
proc strEnd(cstr: cstring, c = 0'i32): cstring {.
|
||||
importc: "strchr", header: "<string.h>".}
|
||||
|
|
|
|||
|
|
@ -112,7 +112,7 @@ proc `[]`*(t: StringTableRef, key: string): string {.rtl, extern: "nstGet".} =
|
|||
proc mget*(t: StringTableRef, key: string): var string {.
|
||||
rtl, extern: "nstTake".} =
|
||||
## retrieves the location at ``t[key]``. If `key` is not in `t`, the
|
||||
## ``EInvalidKey`` exception is raised.
|
||||
## ``KeyError`` exception is raised.
|
||||
var index = rawGet(t, key)
|
||||
if index >= 0: result = t.data[index].val
|
||||
else: raise newException(KeyError, "key does not exist: " & key)
|
||||
|
|
@ -158,7 +158,7 @@ proc getValue(t: StringTableRef, flags: set[FormatFlag], key: string): string =
|
|||
else: result = ""
|
||||
if result.len == 0:
|
||||
if useKey in flags: result = '$' & key
|
||||
elif not (useEmpty in flags): raiseFormatException(key)
|
||||
elif useEmpty notin flags: raiseFormatException(key)
|
||||
|
||||
proc newStringTable*(mode: StringTableMode): StringTableRef {.
|
||||
rtl, extern: "nst$1".} =
|
||||
|
|
|
|||
|
|
@ -45,6 +45,21 @@ when defined(windows):
|
|||
var
|
||||
oldAttr = getAttributes()
|
||||
|
||||
proc winGetch(): cint {.header: "<conio.h>", importc: "_getch".}
|
||||
else:
|
||||
import termios, unsigned
|
||||
|
||||
proc setRaw(fd: FileHandle, time: cint = TCSAFLUSH) =
|
||||
var mode: Termios
|
||||
discard fd.tcgetattr(addr mode)
|
||||
mode.iflag = mode.iflag and not Tcflag(BRKINT or ICRNL or INPCK or ISTRIP or IXON)
|
||||
mode.oflag = mode.oflag and not Tcflag(OPOST)
|
||||
mode.cflag = (mode.cflag and not Tcflag(CSIZE or PARENB)) or CS8
|
||||
mode.lflag = mode.lflag and not Tcflag(ECHO or ICANON or IEXTEN or ISIG)
|
||||
mode.cc[VMIN] = 1.cuchar
|
||||
mode.cc[VTIME] = 0.cuchar
|
||||
discard fd.tcsetattr(time, addr mode)
|
||||
|
||||
proc setCursorPos*(x, y: int) =
|
||||
## sets the terminal's cursor to the (x,y) position. (0,0) is the
|
||||
## upper left of the screen.
|
||||
|
|
@ -349,6 +364,19 @@ macro styledEcho*(m: varargs[expr]): stmt =
|
|||
result.add(newCall(bindSym"write", bindSym"stdout", newStrLitNode("\n")))
|
||||
result.add(newCall(bindSym"resetAttributes"))
|
||||
|
||||
proc getch*(): char =
|
||||
## Read a single character from the terminal, blocking until it is entered.
|
||||
## The character is not printed to the terminal.
|
||||
when defined(windows):
|
||||
result = winGetch().char
|
||||
else:
|
||||
let fd = getFileHandle(stdin)
|
||||
var oldMode: Termios
|
||||
discard fd.tcgetattr(addr oldMode)
|
||||
fd.setRaw()
|
||||
result = stdin.readChar()
|
||||
discard fd.tcsetattr(TCSADRAIN, addr oldMode)
|
||||
|
||||
when isMainModule:
|
||||
system.addQuitProc(resetAttributes)
|
||||
write(stdout, "never mind")
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ when declared(stdout):
|
|||
|
||||
when not defined(ECMAScript):
|
||||
import terminal
|
||||
system.addQuitProc(resetAttributes)
|
||||
|
||||
type
|
||||
TestStatus* = enum OK, FAILED
|
||||
|
|
@ -234,5 +235,3 @@ if envOutLvl.len > 0:
|
|||
if $opt == envOutLvl:
|
||||
outputLevel = opt
|
||||
break
|
||||
|
||||
system.addQuitProc(resetAttributes)
|
||||
|
|
|
|||
|
|
@ -343,10 +343,10 @@ type
|
|||
##
|
||||
## Each exception has to inherit from `Exception`. See the full `exception
|
||||
## hierarchy`_.
|
||||
parent: ref Exception ## parent exception (can be used as a stack)
|
||||
name: cstring ## The exception's name is its Nim identifier.
|
||||
## This field is filled automatically in the
|
||||
## ``raise`` statement.
|
||||
parent*: ref Exception ## parent exception (can be used as a stack)
|
||||
name: cstring ## The exception's name is its Nim identifier.
|
||||
## This field is filled automatically in the
|
||||
## ``raise`` statement.
|
||||
msg* {.exportc: "message".}: string ## the exception's message. Not
|
||||
## providing an exception message
|
||||
## is bad style.
|
||||
|
|
@ -3161,7 +3161,7 @@ when hostOS != "standalone":
|
|||
x[j+i] = item[j]
|
||||
inc(j)
|
||||
|
||||
proc compiles*(x): bool {.magic: "Compiles", noSideEffect.} =
|
||||
proc compiles*(x: expr): bool {.magic: "Compiles", noSideEffect.} =
|
||||
## Special compile-time procedure that checks whether `x` can be compiled
|
||||
## without any semantic error.
|
||||
## This can be used to check whether a type supports some operation:
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ proc genericAssignAux(dest, src: pointer, n: ptr TNimNode,
|
|||
var m = selectBranch(src, n)
|
||||
# reset if different branches are in use; note different branches also
|
||||
# imply that's not self-assignment (``x = x``)!
|
||||
if m != dd and dd != nil:
|
||||
if m != dd and dd != nil:
|
||||
genericResetAux(dest, dd)
|
||||
copyMem(cast[pointer](d +% n.offset), cast[pointer](s +% n.offset),
|
||||
n.typ.size)
|
||||
|
|
@ -205,9 +205,13 @@ proc genericReset(dest: pointer, mt: PNimType) =
|
|||
case mt.kind
|
||||
of tyString, tyRef, tySequence:
|
||||
unsureAsgnRef(cast[PPointer](dest), nil)
|
||||
of tyObject, tyTuple:
|
||||
# we don't need to reset m_type field for tyObject
|
||||
of tyTuple:
|
||||
genericResetAux(dest, mt.node)
|
||||
of tyObject:
|
||||
genericResetAux(dest, mt.node)
|
||||
# also reset the type field for tyObject, for correct branch switching!
|
||||
var pint = cast[ptr PNimType](dest)
|
||||
pint[] = nil
|
||||
of tyArray, tyArrayConstr:
|
||||
for i in 0..(mt.size div mt.base.size)-1:
|
||||
genericReset(cast[pointer](d +% i*% mt.base.size), mt.base)
|
||||
|
|
|
|||
|
|
@ -84,16 +84,18 @@ elif defined(windows) or defined(dos):
|
|||
type
|
||||
THINSTANCE {.importc: "HINSTANCE".} = object
|
||||
x: pointer
|
||||
proc getProcAddress(lib: THINSTANCE, name: cstring): TProcAddr {.
|
||||
importcpp: "(void*)GetProcAddress(@)", header: "<windows.h>", stdcall.}
|
||||
else:
|
||||
type
|
||||
THINSTANCE {.importc: "HINSTANCE".} = pointer
|
||||
proc getProcAddress(lib: THINSTANCE, name: cstring): TProcAddr {.
|
||||
importc: "GetProcAddress", header: "<windows.h>", stdcall.}
|
||||
|
||||
proc freeLibrary(lib: THINSTANCE) {.
|
||||
importc: "FreeLibrary", header: "<windows.h>", stdcall.}
|
||||
proc winLoadLibrary(path: cstring): THINSTANCE {.
|
||||
importc: "LoadLibraryA", header: "<windows.h>", stdcall.}
|
||||
proc getProcAddress(lib: THINSTANCE, name: cstring): TProcAddr {.
|
||||
importc: "GetProcAddress", header: "<windows.h>", stdcall.}
|
||||
|
||||
proc nimUnloadLibrary(lib: TLibHandle) =
|
||||
freeLibrary(cast[THINSTANCE](lib))
|
||||
|
|
|
|||
|
|
@ -183,11 +183,17 @@ proc rawEchoNL() {.inline, compilerproc.} = write(stdout, "\n")
|
|||
when (defined(windows) and not defined(useWinAnsi)) or defined(nimdoc):
|
||||
include "system/widestrs"
|
||||
|
||||
when defined(windows) and not defined(useWinAnsi):
|
||||
proc wfopen(filename, mode: WideCString): pointer {.
|
||||
importc: "_wfopen", nodecl.}
|
||||
proc wfreopen(filename, mode: WideCString, stream: File): File {.
|
||||
importc: "_wfreopen", nodecl.}
|
||||
when defined(windows) and not defined(useWinAnsi):
|
||||
when defined(cpp):
|
||||
proc wfopen(filename, mode: WideCString): pointer {.
|
||||
importcpp: "_wfopen((const wchar_t*)#, (const wchar_t*)#)", nodecl.}
|
||||
proc wfreopen(filename, mode: WideCString, stream: File): File {.
|
||||
importc: "_wfreopen((const wchar_t*)#, (const wchar_t*)#)", nodecl.}
|
||||
else:
|
||||
proc wfopen(filename, mode: WideCString): pointer {.
|
||||
importc: "_wfopen", nodecl.}
|
||||
proc wfreopen(filename, mode: WideCString, stream: File): File {.
|
||||
importc: "_wfreopen", nodecl.}
|
||||
|
||||
proc fopen(filename, mode: cstring): pointer =
|
||||
var f = newWideCString(filename)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue