mirror of
https://github.com/nim-lang/Nim.git
synced 2026-04-18 21:40:32 +00:00
Merge branch 'devel' of https://github.com/Araq/Nimrod into new_spawn
Conflicts: lib/system.nim
This commit is contained in:
@@ -511,6 +511,7 @@ const
|
||||
tfUncheckedArray* = tfVarargs
|
||||
tfUnion* = tfNoSideEffect
|
||||
tfGcSafe* = tfThread
|
||||
tfObjHasKids* = tfEnumHasHoles
|
||||
skError* = skUnknown
|
||||
|
||||
# type flags that are essential for type equality:
|
||||
|
||||
@@ -1144,6 +1144,24 @@ proc genNewFinalize(p: BProc, e: PNode) =
|
||||
genObjectInit(p, cpsStmts, bt, a, false)
|
||||
gcUsage(e)
|
||||
|
||||
proc genOfHelper(p: BProc; dest: PType; a: PRope): PRope =
|
||||
# unfortunately 'genTypeInfo' sets tfObjHasKids as a side effect, so we
|
||||
# have to call it here first:
|
||||
let ti = genTypeInfo(p.module, dest)
|
||||
if tfFinal in dest.flags or (p.module.objHasKidsValid and
|
||||
tfObjHasKids notin dest.flags):
|
||||
result = ropef("$1.m_type == $2", a, ti)
|
||||
else:
|
||||
discard cgsym(p.module, "TNimType")
|
||||
inc p.module.labels
|
||||
let cache = con("Nim_OfCheck_CACHE", p.module.labels.toRope)
|
||||
appf(p.module.s[cfsVars], "static TNimType* $#[2];$n", cache)
|
||||
result = rfmt(p.module, "#isObjWithCache($#.m_type, $#, $#)", a, ti, cache)
|
||||
when false:
|
||||
# former version:
|
||||
result = rfmt(p.module, "#isObj($1.m_type, $2)",
|
||||
a, genTypeInfo(p.module, dest))
|
||||
|
||||
proc genOf(p: BProc, x: PNode, typ: PType, d: var TLoc) =
|
||||
var a: TLoc
|
||||
initLocExpr(p, x, a)
|
||||
@@ -1163,11 +1181,9 @@ proc genOf(p: BProc, x: PNode, typ: PType, d: var TLoc) =
|
||||
globalError(x.info, errGenerated,
|
||||
"no 'of' operator available for pure objects")
|
||||
if nilCheck != nil:
|
||||
r = rfmt(p.module, "(($1) && #isObj($2.m_type, $3))",
|
||||
nilCheck, r, genTypeInfo(p.module, dest))
|
||||
r = rfmt(p.module, "(($1) && ($2))", nilCheck, genOfHelper(p, dest, r))
|
||||
else:
|
||||
r = rfmt(p.module, "#isObj($1.m_type, $2)",
|
||||
r, genTypeInfo(p.module, dest))
|
||||
r = rfmt(p.module, "($1)", genOfHelper(p, dest, r))
|
||||
putIntoDest(p, d, getSysType(tyBool), r)
|
||||
|
||||
proc genOf(p: BProc, n: PNode, d: var TLoc) =
|
||||
|
||||
@@ -796,6 +796,11 @@ proc genObjectInfo(m: BModule, typ: PType, name: PRope) =
|
||||
var tmp = getNimNode(m)
|
||||
genObjectFields(m, typ, typ.n, tmp)
|
||||
appf(m.s[cfsTypeInit3], "$1.node = &$2;$n", [name, tmp])
|
||||
var t = typ.sons[0]
|
||||
while t != nil:
|
||||
t = t.skipTypes(abstractInst)
|
||||
t.flags.incl tfObjHasKids
|
||||
t = t.sons[0]
|
||||
|
||||
proc genTupleInfo(m: BModule, typ: PType, name: PRope) =
|
||||
genTypeInfoAuxBase(m, typ, name, toRope("0"))
|
||||
|
||||
@@ -1384,6 +1384,7 @@ proc myClose(b: PPassContext, n: PNode): PNode =
|
||||
registerModuleToMain(m.module)
|
||||
|
||||
if sfMainModule in m.module.flags:
|
||||
m.objHasKidsValid = true
|
||||
var disp = generateMethodDispatchers()
|
||||
for i in 0..sonsLen(disp)-1: genProcAux(m, disp.sons[i].sym)
|
||||
genMainProc(m)
|
||||
|
||||
@@ -96,6 +96,7 @@ type
|
||||
# a frame var twice in an init proc
|
||||
isHeaderFile*: bool # C source file is the header file
|
||||
includesStringh*: bool # C source file already includes ``<string.h>``
|
||||
objHasKidsValid*: bool # whether we can rely on tfObjHasKids
|
||||
cfilename*: string # filename of the module (including path,
|
||||
# without extension)
|
||||
typeCache*: TIdTable # cache the generated types
|
||||
|
||||
@@ -625,7 +625,7 @@ proc factImplies(fact, prop: PNode): TImplication =
|
||||
# == not a or not b == not (a and b)
|
||||
let arg = fact.sons[1]
|
||||
case arg.getMagic
|
||||
of mIsNil:
|
||||
of mIsNil, mEqRef:
|
||||
return ~factImplies(arg, prop)
|
||||
of mAnd:
|
||||
# not (a and b) means not a or not b:
|
||||
|
||||
@@ -82,6 +82,9 @@ when not defined(readLineFromStdin):
|
||||
proc readLineFromStdin(prompt: string, line: var string): bool =
|
||||
stdout.write(prompt)
|
||||
result = readLine(stdin, line)
|
||||
if not result:
|
||||
stdout.write("\n")
|
||||
quit(0)
|
||||
|
||||
proc endsWith*(x: string, s: set[char]): bool =
|
||||
var i = x.len-1
|
||||
|
||||
@@ -147,8 +147,10 @@ proc expectIdent(p: TParser) =
|
||||
proc eat(p: var TParser, tokType: TTokType) =
|
||||
## Move the parser to the next token if the current token is of type
|
||||
## `tokType`, otherwise error.
|
||||
if p.tok.tokType == tokType: getTok(p)
|
||||
else: lexMessage(p.lex, errTokenExpected, TokTypeToStr[tokType])
|
||||
if p.tok.tokType == tokType:
|
||||
getTok(p)
|
||||
else:
|
||||
lexMessage(p.lex, errTokenExpected, TokTypeToStr[tokType])
|
||||
|
||||
proc parLineInfo(p: TParser): TLineInfo =
|
||||
## Retrieve the line information associated with the parser's current state.
|
||||
@@ -285,7 +287,7 @@ proc colcom(p: var TParser, n: PNode) =
|
||||
skipComment(p, n)
|
||||
|
||||
proc parseSymbol(p: var TParser, allowNil = false): PNode =
|
||||
#| symbol = '`' (KEYW|IDENT|operator|'(' ')'|'[' ']'|'{' '}'|'='|literal)+ '`'
|
||||
#| symbol = '`' (KEYW|IDENT|literal|(operator|'('|')'|'['|']'|'{'|'}'|'=')+)+ '`'
|
||||
#| | IDENT
|
||||
case p.tok.tokType
|
||||
of tkSymbol:
|
||||
@@ -296,31 +298,22 @@ proc parseSymbol(p: var TParser, allowNil = false): PNode =
|
||||
getTok(p)
|
||||
while true:
|
||||
case p.tok.tokType
|
||||
of tkBracketLe:
|
||||
add(result, newIdentNodeP(getIdent"[]", p))
|
||||
getTok(p)
|
||||
eat(p, tkBracketRi)
|
||||
of tkEquals:
|
||||
add(result, newIdentNodeP(getIdent"=", p))
|
||||
getTok(p)
|
||||
of tkParLe:
|
||||
add(result, newIdentNodeP(getIdent"()", p))
|
||||
getTok(p)
|
||||
eat(p, tkParRi)
|
||||
of tkCurlyLe:
|
||||
add(result, newIdentNodeP(getIdent"{}", p))
|
||||
getTok(p)
|
||||
eat(p, tkCurlyRi)
|
||||
of tokKeywordLow..tokKeywordHigh, tkSymbol, tkOpr, tkDot, tkDotDot:
|
||||
add(result, newIdentNodeP(p.tok.ident, p))
|
||||
getTok(p)
|
||||
of tkIntLit..tkCharLit:
|
||||
add(result, newIdentNodeP(getIdent(tokToStr(p.tok)), p))
|
||||
getTok(p)
|
||||
else:
|
||||
of tkAccent:
|
||||
if result.len == 0:
|
||||
parMessage(p, errIdentifierExpected, p.tok)
|
||||
break
|
||||
of tkOpr, tkDot, tkDotDot, tkEquals, tkParLe..tkParDotRi:
|
||||
var accm = ""
|
||||
while p.tok.tokType in {tkOpr, tkDot, tkDotDot, tkEquals,
|
||||
tkParLe..tkParDotRi}:
|
||||
accm.add(tokToStr(p.tok))
|
||||
getTok(p)
|
||||
result.add(newIdentNodeP(getIdent(accm), p))
|
||||
of tokKeywordLow..tokKeywordHigh, tkSymbol, tkIntLit..tkCharLit:
|
||||
result.add(newIdentNodeP(getIdent(tokToStr(p.tok)), p))
|
||||
getTok(p)
|
||||
else:
|
||||
parMessage(p, errIdentifierExpected, p.tok)
|
||||
eat(p, tkAccent)
|
||||
else:
|
||||
if allowNil and p.tok.tokType == tkNil:
|
||||
@@ -993,6 +986,7 @@ proc parseSymbolList(p: var TParser, result: PNode, allowNil = false) =
|
||||
|
||||
proc parseTypeDescKAux(p: var TParser, kind: TNodeKind,
|
||||
mode: TPrimaryMode): PNode =
|
||||
#| distinct = 'distinct' optInd typeDesc
|
||||
result = newNodeP(kind, p)
|
||||
getTok(p)
|
||||
optInd(p, result)
|
||||
|
||||
@@ -269,11 +269,15 @@ include hlo, seminst, semcall
|
||||
|
||||
proc semAfterMacroCall(c: PContext, n: PNode, s: PSym,
|
||||
flags: TExprFlags): PNode =
|
||||
## Semantically check the output of a macro.
|
||||
## This involves processes such as re-checking the macro output for type
|
||||
## coherence, making sure that variables declared with 'let' aren't
|
||||
## reassigned, and binding the unbound identifiers that the macro output
|
||||
## contains.
|
||||
inc(evalTemplateCounter)
|
||||
if evalTemplateCounter > 100:
|
||||
globalError(s.info, errTemplateInstantiationTooNested)
|
||||
let oldFriend = c.friendModule
|
||||
c.friendModule = s.owner.getModule
|
||||
c.friendModules.add(s.owner.getModule)
|
||||
|
||||
result = n
|
||||
if s.typ.sons[0] == nil:
|
||||
@@ -297,7 +301,7 @@ proc semAfterMacroCall(c: PContext, n: PNode, s: PSym,
|
||||
result = fitNode(c, s.typ.sons[0], result)
|
||||
#GlobalError(s.info, errInvalidParamKindX, typeToString(s.typ.sons[0]))
|
||||
dec(evalTemplateCounter)
|
||||
c.friendModule = oldFriend
|
||||
discard c.friendModules.pop()
|
||||
|
||||
proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym,
|
||||
flags: TExprFlags = {}): PNode =
|
||||
|
||||
@@ -52,7 +52,7 @@ type
|
||||
importTable*: PScope # scope for all imported symbols
|
||||
topLevelScope*: PScope # scope for all top-level symbols
|
||||
p*: PProcCon # procedure context
|
||||
friendModule*: PSym # current friend module; may access private data;
|
||||
friendModules*: seq[PSym] # friend modules; may access private data;
|
||||
# this is used so that generic instantiations
|
||||
# can access private object fields
|
||||
instCounter*: int # to prevent endless instantiations
|
||||
@@ -169,7 +169,7 @@ proc newContext(module: PSym): PContext =
|
||||
initLinkedList(result.libs)
|
||||
append(result.optionStack, newOptionEntry())
|
||||
result.module = module
|
||||
result.friendModule = module
|
||||
result.friendModules = @[module]
|
||||
result.converters = @[]
|
||||
result.patterns = @[]
|
||||
result.includedFiles = initIntSet()
|
||||
|
||||
@@ -190,6 +190,9 @@ proc instantiateProcType(c: PContext, pt: TIdTable,
|
||||
|
||||
proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
|
||||
info: TLineInfo): PSym =
|
||||
## Generates a new instance of a generic procedure.
|
||||
## The `pt` parameter is a type-unsafe mapping table used to link generic
|
||||
## parameters to their concrete types within the generic instance.
|
||||
# no need to instantiate generic templates/macros:
|
||||
if fn.kind in {skTemplate, skMacro}: return fn
|
||||
# generates an instantiated proc
|
||||
@@ -199,8 +202,7 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
|
||||
var n = copyTree(fn.ast)
|
||||
# NOTE: for access of private fields within generics from a different module
|
||||
# we set the friend module:
|
||||
var oldFriend = c.friendModule
|
||||
c.friendModule = getModule(fn)
|
||||
c.friendModules.add(getModule(fn))
|
||||
#let oldScope = c.currentScope
|
||||
#c.currentScope = fn.scope
|
||||
result = copySym(fn, false)
|
||||
@@ -236,6 +238,6 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
|
||||
closeScope(c) # close scope for parameters
|
||||
popOwner()
|
||||
#c.currentScope = oldScope
|
||||
c.friendModule = oldFriend
|
||||
discard c.friendModules.pop()
|
||||
dec(c.instCounter)
|
||||
if result.kind == skMethod: finishMethod(c, result)
|
||||
|
||||
@@ -66,10 +66,16 @@ proc toCover(t: PType): BiggestInt =
|
||||
result = lengthOrd(skipTypes(t, abstractVar-{tyTypeDesc}))
|
||||
|
||||
proc performProcvarCheck(c: PContext, n: PNode, s: PSym) =
|
||||
## Checks that the given symbol is a proper procedure variable, meaning
|
||||
## that it
|
||||
var smoduleId = getModule(s).id
|
||||
if sfProcvar notin s.flags and s.typ.callConv == ccDefault and
|
||||
smoduleId != c.module.id and smoduleId != c.friendModule.id:
|
||||
localError(n.info, errXCannotBePassedToProcVar, s.name.s)
|
||||
smoduleId != c.module.id:
|
||||
block outer:
|
||||
for module in c.friendModules:
|
||||
if smoduleId == module.id:
|
||||
break outer
|
||||
localError(n.info, errXCannotBePassedToProcVar, s.name.s)
|
||||
|
||||
proc semProcvarCheck(c: PContext, n: PNode) =
|
||||
let n = n.skipConv
|
||||
|
||||
@@ -70,9 +70,10 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType =
|
||||
counter = x
|
||||
of nkSym:
|
||||
e = n.sons[i].sym
|
||||
of nkIdent:
|
||||
of nkIdent, nkAccQuoted:
|
||||
e = newSymS(skEnumField, n.sons[i], c)
|
||||
else: illFormedAst(n)
|
||||
else:
|
||||
illFormedAst(n[i])
|
||||
e.typ = result
|
||||
e.position = int(counter)
|
||||
if e.position == 0: hasNull = true
|
||||
|
||||
@@ -63,8 +63,11 @@ proc filterSym(s: PSym): bool {.inline.} =
|
||||
|
||||
proc fieldVisible*(c: PContext, f: PSym): bool {.inline.} =
|
||||
let fmoduleId = getModule(f).id
|
||||
result = sfExported in f.flags or fmoduleId == c.module.id or
|
||||
fmoduleId == c.friendModule.id
|
||||
result = sfExported in f.flags or fmoduleId == c.module.id
|
||||
for module in c.friendModules:
|
||||
if fmoduleId == module.id:
|
||||
result = true
|
||||
break
|
||||
|
||||
proc suggestField(c: PContext, s: PSym, outputs: var int) =
|
||||
if filterSym(s) and fieldVisible(c, s):
|
||||
@@ -319,7 +322,7 @@ proc suggestSym*(n: PNode, s: PSym) {.inline.} =
|
||||
findUsages(n, s)
|
||||
if optDef in gGlobalOptions:
|
||||
findDefinition(n, s)
|
||||
if isServing:
|
||||
if isServing and not n.isNil:
|
||||
addToSourceMap(s, n.info)
|
||||
|
||||
proc markUsed(n: PNode, s: PSym) =
|
||||
|
||||
@@ -15,6 +15,8 @@ proc readOutput(p: PProcess): string =
|
||||
discard p.waitForExit
|
||||
while not output.atEnd:
|
||||
result.add(output.readLine)
|
||||
result.add("\n")
|
||||
result.setLen(result.len - "\n".len)
|
||||
|
||||
proc opGorge*(cmd, input: string): string =
|
||||
var p = startCmd(cmd)
|
||||
|
||||
@@ -24,7 +24,7 @@ ampExpr = plusExpr (OP6 optInd plusExpr)*
|
||||
plusExpr = mulExpr (OP7 optInd mulExpr)*
|
||||
mulExpr = dollarExpr (OP8 optInd dollarExpr)*
|
||||
dollarExpr = primary (OP9 optInd primary)*
|
||||
symbol = '`' (KEYW|IDENT|operator|'(' ')'|'[' ']'|'{' '}'|'='|literal)+ '`'
|
||||
symbol = '`' (KEYW|IDENT|literal|(operator|'('|')'|'['|']'|'{'|'}'|'=')+)+ '`'
|
||||
| IDENT
|
||||
indexExpr = expr
|
||||
indexExprList = indexExpr ^+ comma
|
||||
@@ -82,6 +82,7 @@ paramListColon = paramList? (':' optInd typeDesc)?
|
||||
doBlock = 'do' paramListArrow pragmas? colcom stmt
|
||||
doBlocks = doBlock ^* IND{=}
|
||||
procExpr = 'proc' paramListColon pragmas? ('=' COMMENT? stmt)?
|
||||
distinct = 'distinct' optInd typeDesc
|
||||
expr = (ifExpr
|
||||
| whenExpr
|
||||
| caseExpr
|
||||
@@ -166,7 +167,6 @@ object = 'object' pragma? ('of' typeDesc)? COMMENT? objectPart
|
||||
typeClassParam = ('var')? symbol
|
||||
typeClass = typeClassParam ^* ',' (pragma)? ('of' typeDesc ^* ',')?
|
||||
&IND{>} stmt
|
||||
distinct = 'distinct' optInd typeDesc
|
||||
typeDef = identWithPragma genericParamList? '=' optInd typeDefAux
|
||||
indAndComment?
|
||||
varTuple = '(' optInd identWithPragma ^+ comma optPar ')' '=' optInd expr
|
||||
|
||||
@@ -5485,7 +5485,7 @@ the argument is missing, the C name is the Nimrod identifier *exactly as
|
||||
spelled*:
|
||||
|
||||
.. code-block::
|
||||
proc printf(formatstr: cstring) {.importc: "printf", varargs.}
|
||||
proc printf(formatstr: cstring) {.header: "<stdio.h>", importc: "printf", varargs.}
|
||||
|
||||
Note that this pragma is somewhat of a misnomer: Other backends will provide
|
||||
the same feature under the same name.
|
||||
|
||||
@@ -87,6 +87,18 @@ Level Description
|
||||
for compiler developers.
|
||||
===== ============================================
|
||||
|
||||
|
||||
Compile time symbols
|
||||
--------------------
|
||||
|
||||
Through the ``-d:x`` or ``--define:x`` switch you can define compile time
|
||||
symbols for conditional compilation. The defined switches can be checked in
|
||||
source code with the `when statement <manual.html#when-statement>`_ and
|
||||
`defined proc <system.html#defined>`_. The typical use of this switch is to
|
||||
enable builds in release mode (``-d:release``) where certain safety checks are
|
||||
omitted for better performance. Another common use is the ``-d:ssl`` switch to
|
||||
activate `SSL sockets <sockets.html>`_.
|
||||
|
||||
|
||||
Configuration files
|
||||
-------------------
|
||||
|
||||
@@ -1385,8 +1385,8 @@ Tuples
|
||||
A tuple type defines various named *fields* and an *order* of the fields.
|
||||
The constructor ``()`` can be used to construct tuples. The order of the
|
||||
fields in the constructor must match the order in the tuple's definition.
|
||||
Different tuple-types are *equivalent* if they specify the same fields of
|
||||
the same type in the same order.
|
||||
Different tuple-types are *equivalent* if they specify fields of
|
||||
the same type and of the same name in the same order.
|
||||
|
||||
The assignment operator for tuples copies each component. The notation
|
||||
``t.field`` is used to access a tuple's field. Another notation is
|
||||
|
||||
@@ -501,7 +501,7 @@ with the file and line where the uncaught exception is being raised, which may
|
||||
help you locate the offending code which has changed.
|
||||
|
||||
If you want to add the ``{.raises.}`` pragma to existing code, the compiler can
|
||||
also help you. You can add the ``{.effect.}`` pragma statement to your proc and
|
||||
also help you. You can add the ``{.effects.}`` pragma statement to your proc and
|
||||
the compiler will output all inferred effects up to that point (exception
|
||||
tracking is part of Nimrod's effect system). Another more roundabout way to
|
||||
find out the list of exceptions raised by a proc is to use the Nimrod ``doc2``
|
||||
|
||||
@@ -150,6 +150,15 @@ proc sort*[T](a: var openArray[T],
|
||||
## # overload:
|
||||
## sort(myStrArray, system.cmp)
|
||||
##
|
||||
## You can inline adhoc comparison procs with the `do notation
|
||||
## <manual.html#do-notation>`_. Example:
|
||||
##
|
||||
## .. code-block:: nimrod
|
||||
##
|
||||
## people.sort do (x, y: Person) -> int:
|
||||
## result = cmp(x.surname, y.surname)
|
||||
## if result == 0:
|
||||
## result = cmp(x.name, y.name)
|
||||
var n = a.len
|
||||
var b: seq[T]
|
||||
newSeq(b, n div 2)
|
||||
|
||||
@@ -27,9 +27,11 @@ export TPort
|
||||
|
||||
|
||||
# TODO: Discarded void PFutures need to checked for exception.
|
||||
# TODO: Exceptions are currently uncatchable due to the limitation that
|
||||
# you cannot have yield in a try stmt. Perhaps I can get the macro to put
|
||||
# a user's try except around ``future.read``.
|
||||
# TODO: ``except`` statement (without `try`) does not work.
|
||||
# TODO: Multiple exception names in a ``except`` don't work.
|
||||
# TODO: The effect system (raises: []) has trouble with my try transformation.
|
||||
# TODO: Can't await in a 'except' body
|
||||
|
||||
|
||||
# -- Futures
|
||||
|
||||
@@ -922,14 +924,17 @@ proc getName(node: PNimrodNode): string {.compileTime.} =
|
||||
return $node[1].ident
|
||||
of nnkIdent:
|
||||
return $node.ident
|
||||
of nnkEmpty:
|
||||
return "anonymous"
|
||||
else:
|
||||
assert false
|
||||
error("Unknown name.")
|
||||
|
||||
macro async*(prc: stmt): stmt {.immediate.} =
|
||||
## Macro which processes async procedures into the appropriate
|
||||
## iterators and yield statements.
|
||||
|
||||
expectKind(prc, nnkProcDef)
|
||||
if prc.kind notin {nnkProcDef, nnkLambda}:
|
||||
error("Cannot transform this node kind into an async proc." &
|
||||
" Proc definition or lambda node expected.")
|
||||
|
||||
hint("Processing " & prc[0].getName & " as an async proc.")
|
||||
|
||||
@@ -941,7 +946,9 @@ macro async*(prc: stmt): stmt {.immediate.} =
|
||||
if $returnType[0] != "PFuture":
|
||||
error("Expected return type of 'PFuture' got '" & $returnType[0] & "'")
|
||||
|
||||
let subtypeIsVoid = returnType.kind == nnkEmpty
|
||||
let subtypeIsVoid = returnType.kind == nnkEmpty or
|
||||
(returnType.kind == nnkBracketExpr and
|
||||
returnType[1].kind == nnkIdent and returnType[1].ident == !"void")
|
||||
|
||||
var outerProcBody = newNimNode(nnkStmtList)
|
||||
|
||||
@@ -990,17 +997,19 @@ macro async*(prc: stmt): stmt {.immediate.} =
|
||||
|
||||
# Remove the 'async' pragma.
|
||||
for i in 0 .. <result[4].len:
|
||||
if result[4][i].ident == !"async":
|
||||
if result[4][i].kind == nnkIdent and result[4][i].ident == !"async":
|
||||
result[4].del(i)
|
||||
if subtypeIsVoid:
|
||||
# Add discardable pragma.
|
||||
result[4].add(newIdentNode("discardable"))
|
||||
if prc.kind == nnkProcDef: # TODO: This is a workaround for #1287
|
||||
result[4].add(newIdentNode("discardable"))
|
||||
if returnType.kind == nnkEmpty:
|
||||
# Add PFuture[void]
|
||||
result[3][0] = parseExpr("PFuture[void]")
|
||||
|
||||
result[6] = outerProcBody
|
||||
|
||||
#echo(treeRepr(result))
|
||||
#echo(toStrLit(result))
|
||||
|
||||
proc recvLine*(socket: TAsyncFD): PFuture[string] {.async.} =
|
||||
|
||||
@@ -14,12 +14,13 @@
|
||||
import strtabs, asyncnet, asyncdispatch, parseutils, parseurl, strutils
|
||||
type
|
||||
TRequest* = object
|
||||
client: PAsyncSocket # TODO: Separate this into a Response object?
|
||||
client*: PAsyncSocket # TODO: Separate this into a Response object?
|
||||
reqMethod*: string
|
||||
headers*: PStringTable
|
||||
protocol*: tuple[orig: string, major, minor: int]
|
||||
url*: TURL
|
||||
hostname*: string ## The hostname of the client that made the request.
|
||||
body*: string # TODO
|
||||
|
||||
PAsyncHttpServer* = ref object
|
||||
socket: PAsyncSocket
|
||||
@@ -169,6 +170,10 @@ proc serve*(server: PAsyncHttpServer, port: TPort,
|
||||
var fut = await server.socket.acceptAddr()
|
||||
processClient(fut.client, fut.address, callback)
|
||||
|
||||
proc close*(server: PAsyncHttpServer) =
|
||||
## Terminates the async http server instance.
|
||||
server.socket.close()
|
||||
|
||||
when isMainModule:
|
||||
var server = newAsyncHttpServer()
|
||||
proc cb(req: TRequest) {.async.} =
|
||||
|
||||
@@ -59,7 +59,7 @@ proc enqueue*[T](q: var TQueue[T], item: T) =
|
||||
|
||||
proc dequeue*[T](q: var TQueue[T]): T =
|
||||
## removes and returns the first element of the queue `q`.
|
||||
assert q.len > 0
|
||||
assert q.count > 0
|
||||
dec q.count
|
||||
result = q.data[q.rd]
|
||||
q.rd = (q.rd + 1) and q.mask
|
||||
|
||||
@@ -37,7 +37,8 @@
|
||||
## ## Piggyback on the already available string hash proc.
|
||||
## ##
|
||||
## ## Without this proc nothing works!
|
||||
## result = hash(x.firstName & x.lastName)
|
||||
## result = x.firstName.hash !& x.lastName.hash
|
||||
## result = !$result
|
||||
##
|
||||
## var
|
||||
## salaries = initTable[Person, int]()
|
||||
@@ -145,6 +146,14 @@ proc mget*[A, B](t: var TTable[A, B], key: A): var B =
|
||||
if index >= 0: result = t.data[index].val
|
||||
else: raise newException(EInvalidKey, "key not found: " & $key)
|
||||
|
||||
iterator allValues*[A, B](t: TTable[A, B]; key: A): B =
|
||||
## iterates over any value in the table `t` that belongs to the given `key`.
|
||||
var h: THash = hash(key) and high(t.data)
|
||||
while t.data[h].slot != seEmpty:
|
||||
if t.data[h].key == key and t.data[h].slot == seFilled:
|
||||
yield t.data[h].val
|
||||
h = nextTry(h, high(t.data))
|
||||
|
||||
proc hasKey*[A, B](t: TTable[A, B], key: A): bool =
|
||||
## returns true iff `key` is in the table `t`.
|
||||
result = rawGet(t, key) >= 0
|
||||
@@ -313,8 +322,7 @@ proc newTable*[A, B](initialSize=64): PTable[A, B] =
|
||||
new(result)
|
||||
result[] = initTable[A, B](initialSize)
|
||||
|
||||
proc newTable*[A, B](pairs: openArray[tuple[key: A,
|
||||
val: B]]): PTable[A, B] =
|
||||
proc newTable*[A, B](pairs: openArray[tuple[key: A, val: B]]): PTable[A, B] =
|
||||
## creates a new hash table that contains the given `pairs`.
|
||||
new(result)
|
||||
result[] = toTable[A, B](pairs)
|
||||
@@ -841,7 +849,8 @@ when isMainModule:
|
||||
## Piggyback on the already available string hash proc.
|
||||
##
|
||||
## Without this proc nothing works!
|
||||
result = hash(x.firstName & x.lastName)
|
||||
result = x.firstName.hash !& x.lastName.hash
|
||||
result = !$result
|
||||
|
||||
var
|
||||
salaries = initTable[Person, int]()
|
||||
|
||||
@@ -119,8 +119,8 @@ proc getEvent(m: PFSMonitor, fd: cint): seq[TMonitorEvent] =
|
||||
var mev: TMonitorEvent
|
||||
mev.wd = event.wd
|
||||
if event.len.int != 0:
|
||||
mev.name = newString(event.len.int)
|
||||
copyMem(addr(mev.name[0]), addr event.name, event.len.int-1)
|
||||
let cstr = event.name.addr.cstring
|
||||
mev.name = $cstr
|
||||
else:
|
||||
mev.name = ""
|
||||
|
||||
@@ -211,4 +211,4 @@ when isMainModule:
|
||||
|
||||
while true:
|
||||
if not disp.poll(): break
|
||||
|
||||
|
||||
|
||||
@@ -8,7 +8,34 @@
|
||||
#
|
||||
|
||||
## This module implements efficient computations of hash values for diverse
|
||||
## Nimrod types.
|
||||
## Nimrod types. All the procs are based on these two building blocks: the `!&
|
||||
## proc <#!&>`_ used to start or mix a hash value, and the `!$ proc <#!$>`_
|
||||
## used to *finish* the hash value. If you want to implement hash procs for
|
||||
## your custom types you will end up writing the following kind of skeleton of
|
||||
## code:
|
||||
##
|
||||
## .. code-block:: nimrod
|
||||
## proc hash(x: Something): THash =
|
||||
## ## Computes a THash from `x`.
|
||||
## var h: THash = 0
|
||||
## # Iterate over parts of `x`.
|
||||
## for xAtom in x:
|
||||
## # Mix the atom with the partial hash.
|
||||
## h = h !& xAtom
|
||||
## # Finish the hash.
|
||||
## result = !$h
|
||||
##
|
||||
## If your custom types contain fields for which there already is a hash proc,
|
||||
## like for example objects made up of ``strings``, you can simply hash
|
||||
## together the hash value of the individual fields:
|
||||
##
|
||||
## .. code-block:: nimrod
|
||||
## proc hash(x: Something): THash =
|
||||
## ## Computes a THash from `x`.
|
||||
## var h: THash = 0
|
||||
## h = h &! hash(x.foo)
|
||||
## h = h &! hash(x.bar)
|
||||
## result = !$h
|
||||
|
||||
import
|
||||
strutils
|
||||
|
||||
@@ -619,6 +619,44 @@ proc `%`*(elements: openArray[PJsonNode]): PJsonNode =
|
||||
newSeq(result.elems, elements.len)
|
||||
for i, p in pairs(elements): result.elems[i] = p
|
||||
|
||||
proc `==`* (a,b: PJsonNode): bool =
|
||||
## Check two nodes for equality
|
||||
if a.kind != b.kind: false
|
||||
else:
|
||||
case a.kind
|
||||
of JString:
|
||||
a.str == b.str
|
||||
of JInt:
|
||||
a.num == b.num
|
||||
of JFloat:
|
||||
a.fnum == b.fnum
|
||||
of JBool:
|
||||
a.bval == b.bval
|
||||
of JNull:
|
||||
true
|
||||
of JArray:
|
||||
a.elems == b.elems
|
||||
of JObject:
|
||||
a.fields == b.fields
|
||||
|
||||
proc hash* (n:PJsonNode): THash =
|
||||
## Compute the hash for a JSON node
|
||||
case n.kind
|
||||
of JArray:
|
||||
result = hash(n.elems)
|
||||
of JObject:
|
||||
result = hash(n.fields)
|
||||
of JInt:
|
||||
result = hash(n.num)
|
||||
of JFloat:
|
||||
result = hash(n.fnum)
|
||||
of JBool:
|
||||
result = hash(n.bval.int)
|
||||
of JString:
|
||||
result = hash(n.str)
|
||||
of JNull:
|
||||
result = hash(0)
|
||||
|
||||
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.
|
||||
@@ -631,7 +669,7 @@ proc len*(n: PJsonNode): int =
|
||||
proc `[]`*(node: PJsonNode, name: string): PJsonNode =
|
||||
## Gets a field from a `JObject`, which must not be nil.
|
||||
## If the value at `name` does not exist, returns nil
|
||||
assert(node != nil)
|
||||
assert(not isNil(node))
|
||||
assert(node.kind == JObject)
|
||||
for key, item in items(node.fields):
|
||||
if key == name:
|
||||
@@ -641,8 +679,8 @@ proc `[]`*(node: PJsonNode, name: string): PJsonNode =
|
||||
proc `[]`*(node: PJsonNode, index: int): PJsonNode =
|
||||
## Gets the node at `index` in an Array. Result is undefined if `index`
|
||||
## is out of bounds
|
||||
assert(not isNil(node))
|
||||
assert(node.kind == JArray)
|
||||
assert(node != nil)
|
||||
return node.elems[index]
|
||||
|
||||
proc hasKey*(node: PJsonNode, key: string): bool =
|
||||
@@ -675,14 +713,12 @@ proc `[]=`*(obj: PJsonNode, key: string, val: PJsonNode) =
|
||||
return
|
||||
obj.fields.add((key, val))
|
||||
|
||||
proc `{}`*(node: PJsonNode, names: varargs[string]): PJsonNode =
|
||||
proc `{}`*(node: PJsonNode, key: string): PJsonNode =
|
||||
## Transverses the node and gets the given value. If any of the
|
||||
## names does not exist, returns nil
|
||||
result = node
|
||||
for name in names:
|
||||
result = result[name]
|
||||
if isNil(result):
|
||||
return nil
|
||||
if isNil(node): return nil
|
||||
result = result[key]
|
||||
|
||||
proc `{}=`*(node: PJsonNode, names: varargs[string], value: PJsonNode) =
|
||||
## Transverses the node and tries to set the value at the given location
|
||||
@@ -1021,7 +1057,7 @@ when isMainModule:
|
||||
|
||||
let testJson = parseJson"""{ "a": [1, 2, 3, 4], "b": "asd" }"""
|
||||
# nil passthrough
|
||||
assert(testJson{"doesnt_exist", "anything"} == nil)
|
||||
assert(testJson{"doesnt_exist"}{"anything"}.isNil)
|
||||
testJson{["c", "d"]} = %true
|
||||
assert(testJson["c"]["d"].bval)
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
{.deadCodeElim: on.}
|
||||
import rawsockets, os, strutils, unsigned, parseutils, times
|
||||
export TPort
|
||||
export TPort, `$`
|
||||
|
||||
const useWinVersion = defined(Windows) or defined(nimdoc)
|
||||
|
||||
|
||||
@@ -39,7 +39,6 @@ export
|
||||
MSG_PEEK
|
||||
|
||||
type
|
||||
|
||||
TPort* = distinct uint16 ## port type
|
||||
|
||||
TDomain* = enum ## domain, which specifies the protocol family of the
|
||||
|
||||
@@ -90,6 +90,15 @@ proc defined*(x: expr): bool {.magic: "Defined", noSideEffect.}
|
||||
## when not defined(strutils.toUpper):
|
||||
## # provide our own toUpper proc here, because strutils is
|
||||
## # missing it.
|
||||
##
|
||||
## You can also check external symbols introduced through the compiler's
|
||||
## `-d:x switch <nimrodc.html#compile-time-symbols>`_ to enable build time
|
||||
## conditionals:
|
||||
##
|
||||
## .. code-block:: Nimrod
|
||||
## when not defined(release):
|
||||
## # Do here programmer friendly expensive sanity checks.
|
||||
## # Put here the normal code
|
||||
|
||||
when defined(useNimRtl):
|
||||
{.deadCodeElim: on.}
|
||||
@@ -1769,9 +1778,38 @@ iterator fields*[S:tuple|object, T:tuple|object](x: S, y: T): tuple[a,b: expr] {
|
||||
## in the loop body.
|
||||
iterator fieldPairs*[T: tuple|object](x: T): TObject {.
|
||||
magic: "FieldPairs", noSideEffect.}
|
||||
## iterates over every field of `x`. Warning: This really transforms
|
||||
## the 'for' and unrolls the loop. The current implementation also has a bug
|
||||
## that affects symbol binding in the loop body.
|
||||
## Iterates over every field of `x` returning their name and value.
|
||||
##
|
||||
## When you iterate over objects with different field types you have to use
|
||||
## the compile time ``when`` instead of a runtime ``if`` to select the code
|
||||
## you want to run for each type. To perform the comparison use the `is
|
||||
## operator <manual.html#is-operator>`_. Example:
|
||||
##
|
||||
## .. code-block:: Nimrod
|
||||
##
|
||||
## type
|
||||
## Custom = object
|
||||
## foo: string
|
||||
## bar: bool
|
||||
##
|
||||
## proc `$`(x: Custom): string =
|
||||
## result = "Custom:"
|
||||
## for name, value in x.fieldPairs:
|
||||
## when value is bool:
|
||||
## result.add("\n\t" & name & " is " & $value)
|
||||
## else:
|
||||
## if value.isNil:
|
||||
## result.add("\n\t" & name & " (nil)")
|
||||
## else:
|
||||
## result.add("\n\t" & name & " '" & value & "'")
|
||||
##
|
||||
## Another way to do the same without ``when`` is to leave the task of
|
||||
## picking the appropriate code to a secondary proc which you overload for
|
||||
## each field type and pass the `value` to.
|
||||
##
|
||||
## Warning: This really transforms the 'for' and unrolls the loop. The
|
||||
## current implementation also has a bug that affects symbol binding in the
|
||||
## loop body.
|
||||
iterator fieldPairs*[S: tuple|object, T: tuple|object](x: S, y: T): tuple[
|
||||
a, b: expr] {.
|
||||
magic: "FieldPairs", noSideEffect.}
|
||||
@@ -2785,10 +2823,15 @@ when true:
|
||||
THide(raiseAssert)(msg)
|
||||
|
||||
template assert*(cond: bool, msg = "") =
|
||||
## provides a means to implement `programming by contracts`:idx: in Nimrod.
|
||||
## Raises ``EAssertionFailure`` with `msg` if `cond` is false.
|
||||
##
|
||||
## Provides a means to implement `programming by contracts`:idx: in Nimrod.
|
||||
## ``assert`` evaluates expression ``cond`` and if ``cond`` is false, it
|
||||
## raises an ``EAssertionFailure`` exception. However, the compiler may
|
||||
## not generate any code at all for ``assert`` if it is advised to do so.
|
||||
## raises an ``EAssertionFailure`` exception. However, the compiler may not
|
||||
## generate any code at all for ``assert`` if it is advised to do so through
|
||||
## the ``-d:release`` or ``--assertions:off`` `command line switches
|
||||
## <nimrodc.html#command-line-switches>`_.
|
||||
##
|
||||
## Use ``assert`` for debugging purposes only.
|
||||
bind instantiationInfo
|
||||
mixin failedAssertImpl
|
||||
|
||||
@@ -67,6 +67,28 @@ proc chckObjAsgn(a, b: PNimType) {.compilerproc, inline.} =
|
||||
if a != b:
|
||||
sysFatal(EInvalidObjectAssignment, "invalid object assignment")
|
||||
|
||||
type ObjCheckCache = array[0..1, PNimType]
|
||||
|
||||
proc isObjSlowPath(obj, subclass: PNimType;
|
||||
cache: var ObjCheckCache): bool {.noinline.} =
|
||||
# checks if obj is of type subclass:
|
||||
var x = obj.base
|
||||
while x != subclass:
|
||||
if x == nil:
|
||||
cache[0] = obj
|
||||
return false
|
||||
x = x.base
|
||||
cache[1] = obj
|
||||
return true
|
||||
|
||||
proc isObjWithCache(obj, subclass: PNimType;
|
||||
cache: var ObjCheckCache): bool {.compilerProc, inline.} =
|
||||
if obj == subclass: return true
|
||||
if obj.base == subclass: return true
|
||||
if cache[0] == obj: return false
|
||||
if cache[1] == obj: return true
|
||||
return isObjSlowPath(obj, subclass, cache)
|
||||
|
||||
proc isObj(obj, subclass: PNimType): bool {.compilerproc.} =
|
||||
# checks if obj is of type subclass:
|
||||
var x = obj
|
||||
|
||||
14
tests/misc/tbug1217bracketquotes.nim
Normal file
14
tests/misc/tbug1217bracketquotes.nim
Normal file
@@ -0,0 +1,14 @@
|
||||
discard """
|
||||
output: "13{(.{}}{*4&*$**()&*@1235"
|
||||
"""
|
||||
|
||||
type
|
||||
Test = enum
|
||||
`1`, `3`, `{`, `(.`, `{}}{`, `*4&*$**()&*@`
|
||||
|
||||
let `.}` = 1
|
||||
let `(}` = 2
|
||||
let `[` = 3
|
||||
let `]` = 5
|
||||
|
||||
echo `1`, `3`, `{`, `(.`, `{}}{`, `*4&*$**()&*@`, `.}`, `(}`, `[`, `]`
|
||||
14
tests/notnil/tnotnil4.nim
Normal file
14
tests/notnil/tnotnil4.nim
Normal file
@@ -0,0 +1,14 @@
|
||||
discard ""
|
||||
type
|
||||
TObj = ref object
|
||||
|
||||
proc check(a: TObj not nil) =
|
||||
echo repr(a)
|
||||
|
||||
proc doit() =
|
||||
var x : array[0..1, TObj]
|
||||
|
||||
if x[0] != nil:
|
||||
check(x[0])
|
||||
|
||||
doit()
|
||||
3
tests/osproc/ta.nim
Normal file
3
tests/osproc/ta.nim
Normal file
@@ -0,0 +1,3 @@
|
||||
import strutils
|
||||
let x = stdin.readLine()
|
||||
echo x.parseInt + 5
|
||||
16
tests/osproc/tstdin.nim
Normal file
16
tests/osproc/tstdin.nim
Normal file
@@ -0,0 +1,16 @@
|
||||
discard """
|
||||
file: "tstdin.nim"
|
||||
output: "10"
|
||||
"""
|
||||
import osproc, os, streams
|
||||
|
||||
doAssert fileExists(getCurrentDir() / "tests" / "osproc" / "ta.exe")
|
||||
|
||||
var p = startProcess("ta.exe", getCurrentDir() / "tests" / "osproc")
|
||||
p.inputStream.write("5\n")
|
||||
while true:
|
||||
let line = p.outputStream.readLine()
|
||||
if line != "":
|
||||
echo line
|
||||
else:
|
||||
break
|
||||
@@ -86,6 +86,10 @@ proc doProcCommand(session: var TNimrodSession, command: string): string =
|
||||
|
||||
proc doCommand(session: var TNimrodSession, command: string) =
|
||||
if session.mode == CaasRun:
|
||||
if not session.nim.running:
|
||||
session.lastOutput = "FAILED TO EXECUTE: " & command & "\n" &
|
||||
"Exit code " & $session.nim.peekExitCode
|
||||
return
|
||||
session.lastOutput = doCaasCommand(session,
|
||||
command & " " & session.filename)
|
||||
else:
|
||||
@@ -102,7 +106,7 @@ proc close(session: var TNimrodSession) {.destructor.} =
|
||||
if session.mode == CaasRun:
|
||||
session.nim.close
|
||||
|
||||
proc doScenario(script: string, output: PStream, mode: TRunMode): bool =
|
||||
proc doScenario(script: string, output: PStream, mode: TRunMode, verbose: bool): bool =
|
||||
result = true
|
||||
|
||||
var f = open(script)
|
||||
@@ -134,7 +138,7 @@ proc doScenario(script: string, output: PStream, mode: TRunMode): bool =
|
||||
continue
|
||||
elif line.startsWith(">"):
|
||||
s.doCommand(line.substr(1).strip)
|
||||
output.writeln line, "\n", s.lastOutput
|
||||
output.writeln line, "\n", if verbose: s.lastOutput else: ""
|
||||
else:
|
||||
var expectMatch = true
|
||||
var pattern = s.replaceVars(line)
|
||||
@@ -151,13 +155,14 @@ proc doScenario(script: string, output: PStream, mode: TRunMode): bool =
|
||||
output.writeln "FAILURE ", line
|
||||
result = false
|
||||
|
||||
iterator caasTestsRunner*(filter = ""): tuple[test, output: string,
|
||||
status: bool, mode: TRunMode] =
|
||||
iterator caasTestsRunner*(filter = "", verbose = false): tuple[test,
|
||||
output: string, status: bool,
|
||||
mode: TRunMode] =
|
||||
for scenario in os.walkFiles(TesterDir / "caas/*.txt"):
|
||||
if filter.len > 0 and find(scenario, filter) == -1: continue
|
||||
for mode in modes:
|
||||
var outStream = newStringStream()
|
||||
let r = doScenario(scenario, outStream, mode)
|
||||
let r = doScenario(scenario, outStream, mode, verbose)
|
||||
yield (scenario, outStream.data, r, mode)
|
||||
|
||||
when isMainModule:
|
||||
@@ -175,9 +180,12 @@ when isMainModule:
|
||||
if verbose and len(filter) > 0:
|
||||
echo "Running only test cases matching filter '$1'" % [filter]
|
||||
|
||||
for test, output, result, mode in caasTestsRunner(filter):
|
||||
for test, output, result, mode in caasTestsRunner(filter, verbose):
|
||||
if not result or verbose:
|
||||
echo test, "\n", output, "-> ", $mode, ":", $result, "\n-----"
|
||||
echo "Mode ", $mode, " (", if result: "succeeded)" else: "failed)"
|
||||
echo test
|
||||
echo output
|
||||
echo "---------\n"
|
||||
if not result:
|
||||
failures += 1
|
||||
|
||||
|
||||
@@ -282,26 +282,33 @@ proc testBabelPackages(r: var TResults, cat: Category, filter: PackageFilter) =
|
||||
echo("[Warning] - Cannot run babel tests: Babel update failed.")
|
||||
return
|
||||
|
||||
for name, url in listPackages(filter):
|
||||
var test = makeTest(name, "", cat)
|
||||
echo(url)
|
||||
let
|
||||
installProcess = startProcess(babelExe, "", ["install", "-y", name])
|
||||
installStatus = waitForExitEx(installProcess)
|
||||
installProcess.close
|
||||
if installStatus != quitSuccess:
|
||||
r.addResult(test, "", "", reInstallFailed)
|
||||
continue
|
||||
let packageFileTest = makeTest("PackageFileParsed", "", cat)
|
||||
try:
|
||||
for name, url in listPackages(filter):
|
||||
var test = makeTest(name, "", cat)
|
||||
echo(url)
|
||||
let
|
||||
installProcess = startProcess(babelExe, "", ["install", "-y", name])
|
||||
installStatus = waitForExitEx(installProcess)
|
||||
installProcess.close
|
||||
if installStatus != quitSuccess:
|
||||
r.addResult(test, "", "", reInstallFailed)
|
||||
continue
|
||||
|
||||
let
|
||||
buildPath = getPackageDir(name)[0.. -3]
|
||||
let
|
||||
buildProcess = startProcess(babelExe, buildPath, ["build"])
|
||||
buildStatus = waitForExitEx(buildProcess)
|
||||
buildProcess.close
|
||||
if buildStatus != quitSuccess:
|
||||
r.addResult(test, "", "", reBuildFailed)
|
||||
r.addResult(test, "", "", reSuccess)
|
||||
r.addResult(packageFileTest, "", "", reSuccess)
|
||||
except EJsonParsingError:
|
||||
echo("[Warning] - Cannot run babel tests: Invalid package file.")
|
||||
r.addResult(packageFileTest, "", "", reBuildFailed)
|
||||
|
||||
let
|
||||
buildPath = getPackageDir(name)[0.. -3]
|
||||
let
|
||||
buildProcess = startProcess(babelExe, buildPath, ["build"])
|
||||
buildStatus = waitForExitEx(buildProcess)
|
||||
buildProcess.close
|
||||
if buildStatus != quitSuccess:
|
||||
r.addResult(test, "", "", reBuildFailed)
|
||||
r.addResult(test, "", "", reSuccess)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
|
||||
1
todo.txt
1
todo.txt
@@ -155,7 +155,6 @@ Not essential for 1.0.0
|
||||
- implement the "snoopResult" pragma; no, make a strutils with string append
|
||||
semantics instead ...
|
||||
- implement "closure tuple consists of a single 'ref'" optimization
|
||||
- optimize method dispatchers
|
||||
- new feature: ``distinct T with operations``
|
||||
- arglist as a type (iterator chaining); variable length type lists for generics
|
||||
- implement marker procs for message passing
|
||||
|
||||
@@ -93,7 +93,7 @@ html, body {
|
||||
border-left:10px solid #8f9698;
|
||||
background:#f3f6f8;
|
||||
font-size:15px;
|
||||
font-family:courier;
|
||||
font-family:courier, monospace;
|
||||
letter-spacing:0;
|
||||
line-height:17px;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user