Merge branch 'devel' of https://github.com/Araq/Nimrod into devel

This commit is contained in:
Araq
2014-01-17 01:19:18 +01:00
13 changed files with 616 additions and 515 deletions

View File

@@ -34,25 +34,36 @@ Options:
--skipcomments do not copy comments
--ignoreRValueRefs translate C++'s ``T&&`` to ``T`` instead ``of var T``
--keepBodies keep C++'s method bodies
--spliceHeader parse and emit header before source file
-v, --version write c2nim's version
-h, --help show this help
"""
proc main(infile, outfile: string, options: PParserOptions) =
var start = getTime()
proc parse(infile: string, options: PParserOptions): PNode =
var stream = llStreamOpen(infile, fmRead)
if stream == nil: rawMessage(errCannotOpenFile, infile)
var p: TParser
openParser(p, infile, stream, options)
var module = parseUnit(p)
result = parseUnit(p)
closeParser(p)
renderModule(module, outfile)
proc main(infile, outfile: string, options: PParserOptions, spliceHeader: bool) =
var start = getTime()
if spliceHeader and infile.splitFile.ext == ".c" and existsFile(infile.changeFileExt(".h")):
var header_module = parse(infile.changeFileExt(".h"), options)
var source_module = parse(infile, options)
for n in source_module:
addson(header_module, n)
renderModule(header_module, outfile)
else:
renderModule(parse(infile, options), outfile)
rawMessage(hintSuccessX, [$gLinesCompiled, $(getTime() - start),
formatSize(getTotalMem())])
var
infile = ""
outfile = ""
spliceHeader = false
parserOptions = newParserOptions()
for kind, key, val in getopt():
case kind
@@ -66,6 +77,7 @@ for kind, key, val in getopt():
stdout.write(Version & "\n")
quit(0)
of "o", "out": outfile = val
of "spliceheader": spliceHeader = true
else:
if not parserOptions.setOption(key, val):
stdout.writeln("[Error] unknown option: " & key)
@@ -77,4 +89,4 @@ else:
if outfile.len == 0:
outfile = changeFileExt(infile, "nim")
infile = addFileExt(infile, "h")
main(infile, outfile, parserOptions)
main(infile, outfile, parserOptions, spliceHeader)

View File

@@ -315,13 +315,28 @@ proc getNumber16(L: var TLexer, tok: var TToken) =
else: tok.xkind = pxIntLit
L.bufpos = pos
proc getFloating(L: var TLexer, tok: var TToken) =
matchUnderscoreChars(L, tok, {'0'..'9'})
if L.buf[L.bufpos] in {'e', 'E'}:
add(tok.s, L.buf[L.bufpos])
inc(L.bufpos)
if L.buf[L.bufpos] in {'+', '-'}:
add(tok.s, L.buf[L.bufpos])
inc(L.bufpos)
matchUnderscoreChars(L, tok, {'0'..'9'})
proc getNumber(L: var TLexer, tok: var TToken) =
tok.base = base10
matchUnderscoreChars(L, tok, {'0'..'9'})
if (L.buf[L.bufpos] == '.') and (L.buf[L.bufpos + 1] in {'0'..'9'}):
add(tok.s, '.')
if L.buf[L.bufpos] == '.':
add(tok.s, "0.")
inc(L.bufpos)
matchUnderscoreChars(L, tok, {'e', 'E', '+', '-', '0'..'9'})
getFloating(L, tok)
else:
matchUnderscoreChars(L, tok, {'0'..'9'})
if L.buf[L.bufpos] == '.':
add(tok.s, '.')
inc(L.bufpos)
getFloating(L, tok)
try:
if isFloatLiteral(tok.s):
tok.fnumber = parseFloat(tok.s)
@@ -382,6 +397,23 @@ proc escape(L: var TLexer, tok: var TToken, allowEmpty=false) =
xi = (xi shl 3) or (ord(L.buf[L.bufpos]) - ord('0'))
inc(L.bufpos)
add(tok.s, chr(xi))
of 'x':
var xi = 0
inc(L.bufpos)
while true:
case L.buf[L.bufpos]
of '0'..'9':
xi = `shl`(xi, 4) or (ord(L.buf[L.bufpos]) - ord('0'))
inc(L.bufpos)
of 'a'..'f':
xi = `shl`(xi, 4) or (ord(L.buf[L.bufpos]) - ord('a') + 10)
inc(L.bufpos)
of 'A'..'F':
xi = `shl`(xi, 4) or (ord(L.buf[L.bufpos]) - ord('A') + 10)
inc(L.bufpos)
else:
break
add(tok.s, chr(xi))
elif not allowEmpty:
lexMessage(L, errInvalidCharacterConstant)
@@ -559,7 +591,7 @@ proc getTok(L: var TLexer, tok: var TToken) =
of 'b', 'B': getNumber2(L, tok)
of '1'..'7': getNumber8(L, tok)
else: getNumber(L, tok)
elif c in {'1'..'9'}:
elif c in {'1'..'9'} or (c == '.' and L.buf[L.bufpos+1] in {'0'..'9'}):
getNumber(L, tok)
else:
case c

View File

@@ -61,6 +61,8 @@ type
TReplaceTuple* = array[0..1, string]
ERetryParsing = object of ESynch
proc newParserOptions*(): PParserOptions =
new(result)
result.prefixes = @[]
@@ -420,9 +422,9 @@ proc markTypeIdent(p: var TParser, typ: PNode) =
# avoids to build a symbol table, which can't be done reliably anyway for our
# purposes.
proc expression(p: var TParser): PNode
proc constantExpression(p: var TParser): PNode
proc assignmentExpression(p: var TParser): PNode
proc expression(p: var TParser, rbp: int = 0): PNode
proc constantExpression(p: var TParser): PNode = expression(p, 40)
proc assignmentExpression(p: var TParser): PNode = expression(p, 30)
proc compoundStatement(p: var TParser): PNode
proc statement(p: var TParser): PNode
@@ -651,6 +653,22 @@ proc parseTypeSuffix(p: var TParser, typ: PNode): PNode =
proc typeDesc(p: var TParser): PNode =
result = pointer(p, typeAtom(p))
proc abstractDeclarator(p: var TParser, a: PNode): PNode
proc directAbstractDeclarator(p: var TParser, a: PNode): PNode =
if p.tok.xkind == pxParLe:
getTok(p, a)
if p.tok.xkind in {pxStar, pxAmp, pxAmpAmp}:
result = abstractDeclarator(p, a)
eat(p, pxParRi, result)
return parseTypeSuffix(p, a)
proc abstractDeclarator(p: var TParser, a: PNode): PNode =
return directAbstractDeclarator(p, pointer(p, a))
proc typeName(p: var TParser): PNode =
return abstractDeclarator(p, typeAtom(p))
proc parseField(p: var TParser, kind: TNodeKind): PNode =
if p.tok.xkind == pxParLe:
getTok(p, nil)
@@ -716,18 +734,36 @@ proc parseStruct(p: var TParser, isUnion: bool): PNode =
else:
addSon(result, newNodeP(nkRecList, p))
proc declarator(p: var TParser, a: PNode, ident: ptr PNode): PNode
proc directDeclarator(p: var TParser, a: PNode, ident: ptr PNode): PNode =
case p.tok.xkind
of pxSymbol:
ident[] = skipIdent(p)
of pxParLe:
getTok(p, a)
if p.tok.xkind in {pxStar, pxAmp, pxAmpAmp, pxSymbol}:
result = declarator(p, a, ident)
eat(p, pxParRi, result)
else:
nil
return parseTypeSuffix(p, a)
proc declarator(p: var TParser, a: PNode, ident: ptr PNode): PNode =
return directDeclarator(p, pointer(p, a), ident)
# parameter-declaration
# declaration-specifiers declarator
# declaration-specifiers asbtract-declarator(opt)
proc parseParam(p: var TParser, params: PNode) =
var typ = typeDesc(p)
# support for ``(void)`` parameter list:
if typ.kind == nkNilLit and p.tok.xkind == pxParRi: return
var name: PNode
if p.tok.xkind == pxSymbol:
name = skipIdent(p)
else:
# generate a name for the formal parameter:
typ = declarator(p, typ, addr name)
if name == nil:
var idx = sonsLen(params)+1
name = newIdentNodeP("a" & $idx, p)
typ = parseTypeSuffix(p, typ)
var x = newNodeP(nkIdentDefs, p)
addSon(x, name, typ)
if p.tok.xkind == pxAsgn:
@@ -1134,224 +1170,27 @@ proc setBaseFlags(n: PNode, base: TNumericalBase) =
of base8: incl(n.flags, nfBase8)
of base16: incl(n.flags, nfBase16)
proc unaryExpression(p: var TParser): PNode
proc isDefinitelyAType(p: var TParser): bool =
var starFound = false
var words = 0
while true:
case p.tok.xkind
of pxSymbol:
if declKeyword(p, p.tok.s): return true
elif starFound: return false
else: inc(words)
of pxStar, pxAmp, pxAmpAmp:
starFound = true
of pxParRi: return words == 0 or words > 1 or starFound
else: return false
getTok(p, nil)
proc castExpression(p: var TParser): PNode =
if p.tok.xkind == pxParLe:
saveContext(p)
result = newNodeP(nkCast, p)
getTok(p, result)
var t = isDefinitelyAType(p)
backtrackContext(p)
if t:
eat(p, pxParLe, result)
var a = typeDesc(p)
eat(p, pxParRi, result)
addSon(result, a)
addSon(result, castExpression(p))
else:
# else it is just an expression in ():
result = newNodeP(nkPar, p)
eat(p, pxParLe, result)
addSon(result, expression(p))
if p.tok.xkind != pxParRi:
# ugh, it is a cast, even though it does not look like one:
result.kind = nkCast
addSon(result, castExpression(p))
eat(p, pxParRi, result)
#result = unaryExpression(p)
else:
result = unaryExpression(p)
proc primaryExpression(p: var TParser): PNode =
case p.tok.xkind
of pxSymbol:
if p.tok.s == "NULL":
result = newNodeP(nkNilLit, p)
else:
result = mangledIdent(p.tok.s, p)
getTok(p, result)
result = optScope(p, result)
of pxIntLit:
result = newIntNodeP(nkIntLit, p.tok.iNumber, p)
setBaseFlags(result, p.tok.base)
getTok(p, result)
of pxInt64Lit:
result = newIntNodeP(nkInt64Lit, p.tok.iNumber, p)
setBaseFlags(result, p.tok.base)
getTok(p, result)
of pxFloatLit:
result = newFloatNodeP(nkFloatLit, p.tok.fNumber, p)
setBaseFlags(result, p.tok.base)
getTok(p, result)
of pxStrLit:
# Ansi C allows implicit string literal concatenations:
result = newStrNodeP(nkStrLit, p.tok.s, p)
getTok(p, result)
while p.tok.xkind == pxStrLit:
add(result.strVal, p.tok.s)
getTok(p, result)
of pxCharLit:
result = newIntNodeP(nkCharLit, ord(p.tok.s[0]), p)
getTok(p, result)
of pxParLe:
result = castExpression(p)
else:
result = ast.emptyNode
proc multiplicativeExpression(p: var TParser): PNode =
result = castExpression(p)
while true:
case p.tok.xkind
of pxStar:
var a = result
result = newNodeP(nkInfix, p)
addSon(result, newIdentNodeP("*", p), a)
getTok(p, result)
var b = castExpression(p)
addSon(result, b)
of pxSlash:
var a = result
result = newNodeP(nkInfix, p)
addSon(result, newIdentNodeP("div", p), a)
getTok(p, result)
var b = castExpression(p)
addSon(result, b)
of pxMod:
var a = result
result = newNodeP(nkInfix, p)
addSon(result, newIdentNodeP("mod", p), a)
getTok(p, result)
var b = castExpression(p)
addSon(result, b)
else: break
proc additiveExpression(p: var TParser): PNode =
result = multiplicativeExpression(p)
while true:
case p.tok.xkind
of pxPlus:
var a = result
result = newNodeP(nkInfix, p)
addSon(result, newIdentNodeP("+", p), a)
getTok(p, result)
var b = multiplicativeExpression(p)
addSon(result, b)
of pxMinus:
var a = result
result = newNodeP(nkInfix, p)
addSon(result, newIdentNodeP("-", p), a)
getTok(p, result)
var b = multiplicativeExpression(p)
addSon(result, b)
else: break
proc incdec(p: var TParser, opr: string): PNode =
result = newNodeP(nkCall, p)
addSon(result, newIdentNodeP(opr, p))
getTok(p, result)
addSon(result, unaryExpression(p))
proc unaryOp(p: var TParser, kind: TNodeKind): PNode =
result = newNodeP(kind, p)
getTok(p, result)
addSon(result, castExpression(p))
proc prefixCall(p: var TParser, opr: string): PNode =
result = newNodeP(nkPrefix, p)
addSon(result, newIdentNodeP(opr, p))
getTok(p, result)
addSon(result, castExpression(p))
proc postfixExpression(p: var TParser): PNode =
result = primaryExpression(p)
while true:
case p.tok.xkind
of pxBracketLe:
var a = result
result = newNodeP(nkBracketExpr, p)
addSon(result, a)
getTok(p, result)
var b = expression(p)
addSon(result, b)
eat(p, pxBracketRi, result)
of pxParLe:
var a = result
result = newNodeP(nkCall, p)
addSon(result, a)
getTok(p, result)
if p.tok.xkind != pxParRi:
a = assignmentExpression(p)
addSon(result, a)
while p.tok.xkind == pxComma:
getTok(p, a)
a = assignmentExpression(p)
addSon(result, a)
eat(p, pxParRi, result)
of pxDot, pxArrow:
var a = result
result = newNodeP(nkDotExpr, p)
addSon(result, a)
getTok(p, result)
addSon(result, skipIdent(p))
of pxPlusPlus:
var a = result
result = newNodeP(nkCall, p)
addSon(result, newIdentNodeP("inc", p))
getTok(p, result)
addSon(result, a)
of pxMinusMinus:
var a = result
result = newNodeP(nkCall, p)
addSon(result, newIdentNodeP("dec", p))
getTok(p, result)
addSon(result, a)
of pxLt:
if isTemplateAngleBracket(p):
result = optAngle(p, result)
else: break
else: break
proc unaryExpression(p: var TParser): PNode =
case p.tok.xkind
of pxPlusPlus: result = incdec(p, "inc")
of pxMinusMinus: result = incdec(p, "dec")
of pxAmp: result = unaryOp(p, nkAddr)
of pxStar: result = unaryOp(p, nkBracketExpr)
of pxPlus: result = prefixCall(p, "+")
of pxMinus: result = prefixCall(p, "-")
of pxTilde: result = prefixCall(p, "not")
of pxNot: result = prefixCall(p, "not")
proc startExpression(p : var TParser, tok : TToken) : PNode =
#echo "nud ", $tok
case tok.xkind:
of pxSymbol:
if p.tok.s == "sizeof":
if tok.s == "NULL":
result = newNodeP(nkNilLit, p)
elif tok.s == "sizeof":
result = newNodeP(nkCall, p)
addSon(result, newIdentNodeP("sizeof", p))
getTok(p, result)
if p.tok.xkind == pxParLe:
getTok(p, result)
addSon(result, typeDesc(p))
eat(p, pxParRi, result)
else:
addSon(result, unaryExpression(p))
elif p.tok.s == "new" or p.tok.s == "delete" and pfCpp in p.options.flags:
var opr = p.tok.s
saveContext(p)
try:
addSon(result, expression(p, 139))
closeContext(p)
except ERetryParsing:
backtrackContext(p)
eat(p, pxParLe)
addSon(result, typeName(p))
eat(p, pxParRi)
elif (tok.s == "new" or tok.s == "delete") and pfCpp in p.options.flags:
var opr = tok.s
result = newNodeP(nkCall, p)
getTok(p, result)
if p.tok.xkind == pxBracketLe:
getTok(p)
eat(p, pxBracketRi)
@@ -1362,148 +1201,269 @@ proc unaryExpression(p: var TParser): PNode =
addSon(result, typeDesc(p))
eat(p, pxParRi, result)
else:
addSon(result, unaryExpression(p))
addSon(result, expression(p, 139))
else:
result = postfixExpression(p)
else: result = postfixExpression(p)
proc expression(p: var TParser): PNode =
# we cannot support C's ``,`` operator
result = assignmentExpression(p)
if p.tok.xkind == pxComma:
getTok(p, result)
parMessage(p, errOperatorExpected, ",")
proc conditionalExpression(p: var TParser): PNode
proc constantExpression(p: var TParser): PNode =
result = conditionalExpression(p)
proc lvalue(p: var TParser): PNode =
result = unaryExpression(p)
proc asgnExpr(p: var TParser, opr: string, a: PNode): PNode =
closeContext(p)
getTok(p, a)
var b = assignmentExpression(p)
result = newNodeP(nkAsgn, p)
addSon(result, a, newBinary(opr, copyTree(a), b, p))
proc incdec(p: var TParser, opr: string, a: PNode): PNode =
closeContext(p)
getTok(p, a)
var b = assignmentExpression(p)
result = newNodeP(nkCall, p)
addSon(result, newIdentNodeP(getIdent(opr), p), a, b)
proc assignmentExpression(p: var TParser): PNode =
saveContext(p)
var a = lvalue(p)
case p.tok.xkind
of pxAsgn:
closeContext(p)
getTok(p, a)
var b = assignmentExpression(p)
result = newNodeP(nkAsgn, p)
addSon(result, a, b)
of pxPlusAsgn: result = incdec(p, "inc", a)
of pxMinusAsgn: result = incdec(p, "dec", a)
of pxStarAsgn: result = asgnExpr(p, "*", a)
of pxSlashAsgn: result = asgnExpr(p, "/", a)
of pxModAsgn: result = asgnExpr(p, "mod", a)
of pxShlAsgn: result = asgnExpr(p, "shl", a)
of pxShrAsgn: result = asgnExpr(p, "shr", a)
of pxAmpAsgn: result = asgnExpr(p, "and", a)
of pxHatAsgn: result = asgnExpr(p, "xor", a)
of pxBarAsgn: result = asgnExpr(p, "or", a)
result = mangledIdent(tok.s, p)
result = optScope(p, result)
result = optAngle(p, result)
of pxIntLit:
result = newIntNodeP(nkIntLit, tok.iNumber, p)
setBaseFlags(result, tok.base)
of pxInt64Lit:
result = newIntNodeP(nkInt64Lit, tok.iNumber, p)
setBaseFlags(result, tok.base)
of pxFloatLit:
result = newFloatNodeP(nkFloatLit, tok.fNumber, p)
setBaseFlags(result, tok.base)
of pxStrLit:
result = newStrNodeP(nkStrLit, tok.s, p)
while p.tok.xkind == pxStrLit:
add(result.strVal, p.tok.s)
getTok(p, result)
of pxCharLit:
result = newIntNodeP(nkCharLit, ord(tok.s[0]), p)
of pxParLe:
try:
saveContext(p)
result = newNodeP(nkPar, p)
addSon(result, expression(p, 0))
if p.tok.xkind != pxParRi:
raise newException(ERetryParsing, "expected a ')'")
getTok(p, result)
if p.tok.xkind in {pxSymbol, pxIntLit, pxFloatLit, pxStrLit, pxCharLit}:
raise newException(ERetryParsing, "expected a non literal token")
closeContext(p)
except ERetryParsing:
backtrackContext(p)
result = newNodeP(nkCast, p)
addSon(result, typeName(p))
eat(p, pxParRi, result)
addSon(result, expression(p, 139))
of pxPlusPlus:
result = newNodeP(nkCall, p)
addSon(result, newIdentNodeP("inc", p))
addSon(result, expression(p, 139))
of pxMinusMinus:
result = newNodeP(nkCall, p)
addSon(result, newIdentNodeP("dec", p))
addSon(result, expression(p, 139))
of pxAmp:
result = newNodeP(nkAddr, p)
addSon(result, expression(p, 139))
of pxStar:
result = newNodeP(nkBracketExpr, p)
addSon(result, expression(p, 139))
of pxPlus:
result = newNodeP(nkPrefix, p)
addSon(result, newIdentNodeP("+", p))
addSon(result, expression(p, 139))
of pxMinus:
result = newNodeP(nkPrefix, p)
addSon(result, newIdentNodeP("-", p))
addSon(result, expression(p, 139))
of pxTilde:
result = newNodeP(nkPrefix, p)
addSon(result, newIdentNodeP("not", p))
addSon(result, expression(p, 139))
of pxNot:
result = newNodeP(nkPrefix, p)
addSon(result, newIdentNodeP("not", p))
addSon(result, expression(p, 139))
else:
backtrackContext(p)
result = conditionalExpression(p)
proc shiftExpression(p: var TParser): PNode =
result = additiveExpression(p)
while p.tok.xkind in {pxShl, pxShr}:
var op = if p.tok.xkind == pxShl: "shl" else: "shr"
getTok(p, result)
var a = result
var b = additiveExpression(p)
result = newBinary(op, a, b, p)
# probably from a failed sub expression attempt, try a type cast
raise newException(ERetryParsing, "did not expect " & $tok)
proc relationalExpression(p: var TParser): PNode =
result = shiftExpression(p)
# Nimrod uses ``<`` and ``<=``, etc. too:
while p.tok.xkind in {pxLt, pxLe, pxGt, pxGe}:
var op = tokKindToStr(p.tok.xkind)
getTok(p, result)
var a = result
var b = shiftExpression(p)
result = newBinary(op, a, b, p)
proc leftBindingPower(p : var TParser, tok : ref TToken) : int =
#echo "lbp ", $tok[]
case tok.xkind:
of pxComma:
return 10
# throw == 20
of pxAsgn, pxPlusAsgn, pxMinusAsgn, pxStarAsgn, pxSlashAsgn, pxModAsgn, pxShlAsgn, pxShrAsgn, pxAmpAsgn, pxHatAsgn, pxBarAsgn:
return 30
of pxConditional:
return 40
of pxBarBar:
return 50
of pxAmpAmp:
return 60
of pxBar:
return 70
of pxHat:
return 80
of pxAmp:
return 90
of pxEquals, pxNeq:
return 100
of pxLt, pxLe, pxGt, pxGe:
return 110
of pxShl, pxShr:
return 120
of pxPlus, pxMinus:
return 130
of pxStar, pxSlash, pxMod:
return 140
# .* ->* == 150
of pxPlusPlus, pxMinusMinus, pxParLe, pxDot, pxArrow, pxBracketLe:
return 160
# :: == 170
else:
return 0
proc equalityExpression(p: var TParser): PNode =
result = relationalExpression(p)
# Nimrod uses ``==`` and ``!=`` too:
while p.tok.xkind in {pxEquals, pxNeq}:
var op = tokKindToStr(p.tok.xkind)
getTok(p, result)
var a = result
var b = relationalExpression(p)
result = newBinary(op, a, b, p)
proc buildStmtList(a: PNode): PNode
proc andExpression(p: var TParser): PNode =
result = equalityExpression(p)
while p.tok.xkind == pxAmp:
getTok(p, result)
var a = result
var b = equalityExpression(p)
result = newBinary("and", a, b, p)
proc exclusiveOrExpression(p: var TParser): PNode =
result = andExpression(p)
while p.tok.xkind == pxHat:
getTok(p, result)
var a = result
var b = andExpression(p)
result = newBinary("^", a, b, p)
proc inclusiveOrExpression(p: var TParser): PNode =
result = exclusiveOrExpression(p)
while p.tok.xkind == pxBar:
getTok(p, result)
var a = result
var b = exclusiveOrExpression(p)
result = newBinary("or", a, b, p)
proc logicalAndExpression(p: var TParser): PNode =
result = inclusiveOrExpression(p)
while p.tok.xkind == pxAmpAmp:
getTok(p, result)
var a = result
var b = inclusiveOrExpression(p)
result = newBinary("and", a, b, p)
proc logicalOrExpression(p: var TParser): PNode =
result = logicalAndExpression(p)
while p.tok.xkind == pxBarBar:
getTok(p, result)
var a = result
var b = logicalAndExpression(p)
result = newBinary("or", a, b, p)
proc conditionalExpression(p: var TParser): PNode =
result = logicalOrExpression(p)
if p.tok.xkind == pxConditional:
getTok(p, result) # skip '?'
var a = result
var b = expression(p)
eat(p, pxColon, b)
var c = conditionalExpression(p)
proc leftExpression(p : var TParser, tok : TToken, left : PNode) : PNode =
#echo "led ", $tok
case tok.xkind:
of pxComma: # 10
# not supported as an expression, turns into a statement list
result = buildStmtList(left)
addSon(result, expression(p, 0))
# throw == 20
of pxAsgn: # 30
result = newNodeP(nkAsgn, p)
addSon(result, left, expression(p, 29))
of pxPlusAsgn: # 30
result = newNodeP(nkCall, p)
addSon(result, newIdentNodeP(getIdent("inc"), p), left, expression(p, 29))
of pxMinusAsgn: # 30
result = newNodeP(nkCall, p)
addSon(result, newIdentNodeP(getIdent("dec"), p), left, expression(p, 29))
of pxStarAsgn: # 30
result = newNodeP(nkAsgn, p)
var right = expression(p, 29)
addSon(result, left, newBinary("*", copyTree(left), right, p))
of pxSlashAsgn: # 30
result = newNodeP(nkAsgn, p)
var right = expression(p, 29)
addSon(result, left, newBinary("/", copyTree(left), right, p))
of pxModAsgn: # 30
result = newNodeP(nkAsgn, p)
var right = expression(p, 29)
addSon(result, left, newBinary("mod", copyTree(left), right, p))
of pxShlAsgn: # 30
result = newNodeP(nkAsgn, p)
var right = expression(p, 29)
addSon(result, left, newBinary("shl", copyTree(left), right, p))
of pxShrAsgn: # 30
result = newNodeP(nkAsgn, p)
var right = expression(p, 29)
addSon(result, left, newBinary("shr", copyTree(left), right, p))
of pxAmpAsgn: # 30
result = newNodeP(nkAsgn, p)
var right = expression(p, 29)
addSon(result, left, newBinary("and", copyTree(left), right, p))
of pxHatAsgn: # 30
result = newNodeP(nkAsgn, p)
var right = expression(p, 29)
addSon(result, left, newBinary("xor", copyTree(left), right, p))
of pxBarAsgn: # 30
result = newNodeP(nkAsgn, p)
var right = expression(p, 29)
addSon(result, left, newBinary("or", copyTree(left), right, p))
of pxConditional: # 40
var a = expression(p, 0)
eat(p, pxColon, a)
var b = expression(p, 39)
result = newNodeP(nkIfExpr, p)
var branch = newNodeP(nkElifExpr, p)
addSon(branch, a, b)
addSon(branch, left, a)
addSon(result, branch)
branch = newNodeP(nkElseExpr, p)
addSon(branch, c)
addSon(branch, b)
addSon(result, branch)
of pxBarBar: # 50
result = newBinary("or", left, expression(p, 50), p)
of pxAmpAmp: # 60
result = newBinary("and", left, expression(p, 60), p)
of pxBar: # 70
result = newBinary("or", left, expression(p, 70), p)
of pxHat: # 80
result = newBinary("^", left, expression(p, 80), p)
of pxAmp: # 90
result = newBinary("and", left, expression(p, 90), p)
of pxEquals: # 100
result = newBinary("==", left, expression(p, 100), p)
of pxNeq: # 100
result = newBinary("!=", left, expression(p, 100), p)
of pxLt: # 110
result = newBinary("<", left, expression(p, 110), p)
of pxLe: # 110
result = newBinary("<=", left, expression(p, 110), p)
of pxGt: # 110
result = newBinary(">", left, expression(p, 110), p)
of pxGe: # 110
result = newBinary(">=", left, expression(p, 110), p)
of pxShl: # 120
result = newBinary("shl", left, expression(p, 120), p)
of pxShr: # 120
result = newBinary("shr", left, expression(p, 120), p)
of pxPlus: # 130
result = newNodeP(nkInfix, p)
addSon(result, newIdentNodeP("+", p), left)
addSon(result, expression(p, 130))
of pxMinus: # 130
result = newNodeP(nkInfix, p)
addSon(result, newIdentNodeP("+", p), left)
addSon(result, expression(p, 130))
of pxStar: # 140
result = newNodeP(nkInfix, p)
addSon(result, newIdentNodeP("*", p), left)
addSon(result, expression(p, 140))
of pxSlash: # 140
result = newNodeP(nkInfix, p)
addSon(result, newIdentNodeP("div", p), left)
addSon(result, expression(p, 140))
of pxMod: # 140
result = newNodeP(nkInfix, p)
addSon(result, newIdentNodeP("mod", p), left)
addSon(result, expression(p, 140))
# .* ->* == 150
of pxPlusPlus: # 160
result = newNodeP(nkCall, p)
addSon(result, newIdentNodeP("inc", p), left)
of pxMinusMinus: # 160
result = newNodeP(nkCall, p)
addSon(result, newIdentNodeP("dec", p), left)
of pxParLe: # 160
result = newNodeP(nkCall, p)
addSon(result, left)
while p.tok.xkind != pxParRi:
var a = expression(p, 29)
addSon(result, a)
while p.tok.xkind == pxComma:
getTok(p, a)
a = expression(p, 29)
addSon(result, a)
eat(p, pxParRi, result)
of pxDot: # 160
result = newNodeP(nkDotExpr, p)
addSon(result, left)
addSon(result, skipIdent(p))
of pxArrow: # 160
result = newNodeP(nkDotExpr, p)
addSon(result, left)
addSon(result, skipIdent(p))
of pxBracketLe: # 160
result = newNodeP(nkBracketExpr, p)
addSon(result, left, expression(p))
eat(p, pxBracketRi, result)
# :: == 170
else:
result = left
proc expression*(p : var TParser, rbp : int = 0) : PNode =
var tok : TToken
tok = p.tok[]
getTok(p, result)
result = startExpression(p, tok)
while rbp < leftBindingPower(p, p.tok):
tok = p.tok[]
getTok(p, result)
result = leftExpression(p, tok, result)
# Statements
@@ -1549,12 +1509,12 @@ proc parseIf(p: var TParser): PNode =
while true:
getTok(p) # skip ``if``
var branch = newNodeP(nkElifBranch, p)
skipCom(p, branch)
eat(p, pxParLe, branch)
addSon(branch, expression(p))
eat(p, pxParRi, branch)
addSon(branch, nestedStatement(p))
addSon(result, branch)
skipCom(p, branch)
if p.tok.s == "else":
getTok(p, result)
if p.tok.s != "if":
@@ -1574,19 +1534,51 @@ proc parseWhile(p: var TParser): PNode =
eat(p, pxParRi, result)
addSon(result, nestedStatement(p))
proc embedStmts(sl, a: PNode)
proc parseDoWhile(p: var TParser): PNode =
# we only support ``do stmt while (0)`` as an idiom for
# ``block: stmt``
result = newNodeP(nkBlockStmt, p)
getTok(p, result) # skip "do"
addSon(result, ast.emptyNode, nestedStatement(p))
# parsing
result = newNodeP(nkWhileStmt, p)
getTok(p, result)
var stm = nestedStatement(p)
eat(p, "while", result)
eat(p, pxParLe, result)
if p.tok.xkind == pxIntLit and p.tok.iNumber == 0: getTok(p, result)
else: parMessage(p, errTokenExpected, "0")
var exp = expression(p)
eat(p, pxParRi, result)
if p.tok.xkind == pxSemicolon: getTok(p)
# while true:
# stmt
# if not expr:
# break
addSon(result, newIdentNodeP("true", p))
stm = buildStmtList(stm)
# get the last exp if it is a stmtlist
var cleanedExp = exp
if exp.kind == nkStmtList:
cleanedExp = exp.sons[exp.len-1]
exp.sons = exp.sons[0..exp.len-2]
embedStmts(stm, exp)
var notExp = newNodeP(nkPrefix, p)
addSon(notExp, newIdentNodeP("not", p))
addSon(notExp, cleanedExp)
var brkStm = newNodeP(nkBreakStmt, p)
addSon(brkStm, ast.emptyNode)
var ifStm = newNodeP(nkIfStmt, p)
var ifBranch = newNodeP(nkElifBranch, p)
addSon(ifBranch, notExp)
addSon(ifBranch, brkStm)
addSon(ifStm, ifBranch)
embedStmts(stm, ifStm)
addSon(result, stm)
proc declarationOrStatement(p: var TParser): PNode =
if p.tok.xkind != pxSymbol:
result = expressionStatement(p)
@@ -1666,7 +1658,7 @@ proc parseFor(p: var TParser, result: PNode) =
eat(p, pxParLe, result)
var initStmt = declarationOrStatement(p)
if initStmt.kind != nkEmpty:
addSon(result, initStmt)
embedStmts(result, initStmt)
var w = newNodeP(nkWhileStmt, p)
var condition = expressionStatement(p)
if condition.kind == nkEmpty: condition = newIdentNodeP("true", p)
@@ -1676,7 +1668,7 @@ proc parseFor(p: var TParser, result: PNode) =
var loopBody = nestedStatement(p)
if step.kind != nkEmpty:
loopBody = buildStmtList(loopBody)
addSon(loopBody, step)
embedStmts(loopBody, step)
addSon(w, loopBody)
addSon(result, w)
@@ -2048,6 +2040,10 @@ proc parseStandaloneClass(p: var TParser, isStruct: bool): PNode =
result = declaration(p)
p.currentClass = oldClass
proc unwrap(a: PNode): PNode =
if a.kind == nkPar:
return a.sons[0]
return a
include cpp
@@ -2082,16 +2078,10 @@ proc statement(p: var TParser): PNode =
of "return":
result = newNodeP(nkReturnStmt, p)
getTok(p)
# special case for ``return (expr)`` because I hate the redundant
# parenthesis ;-)
if p.tok.xkind == pxParLe:
getTok(p, result)
addSon(result, expression(p))
eat(p, pxParRi, result)
elif p.tok.xkind != pxSemicolon:
addSon(result, expression(p))
else:
if p.tok.xkind == pxSemicolon:
addSon(result, ast.emptyNode)
else:
addSon(result, unwrap(expression(p)))
eat(p, pxSemicolon)
of "enum": result = enumSpecifier(p)
of "typedef": result = parseTypeDef(p)
@@ -2140,9 +2130,12 @@ proc statement(p: var TParser): PNode =
assert result != nil
proc parseUnit(p: var TParser): PNode =
result = newNodeP(nkStmtList, p)
getTok(p) # read first token
while p.tok.xkind != pxEof:
var s = statement(p)
if s.kind != nkEmpty: embedStmts(result, s)
try:
result = newNodeP(nkStmtList, p)
getTok(p) # read first token
while p.tok.xkind != pxEof:
var s = statement(p)
if s.kind != nkEmpty: embedStmts(result, s)
except ERetryParsing:
parMessage(p, errGenerated, "Uncaught parsing exception raised")

View File

@@ -0,0 +1,33 @@
#include <stdlib.h>
#include <stdio.h>
int rand(void);
int id2(void) {
return (int *)1;
}
int id(void (*f)(void)) {
f();
((void (*)(int))f)(10);
return 10;
return (20+1);
return (int *)id;
}
int main() {
float f = .2,
g = 2.,
h = 1.0+rand(),
i = 1.0e+3;
int j, a;
for(j = 0, a = 10; j < 0; j++, a++) ;
do {
printf("howdy");
} while(--i, 0);
if(1)
printf("1"); // error from this comment
else
printf("2");
return '\x00';
}

View File

@@ -0,0 +1,3 @@
struct foo {
int x,y,z;
};

View File

@@ -227,7 +227,12 @@ Parsers
-------
* `parseopt <parseopt.html>`_
The ``parseopt`` module implements a command line option parser. This
The ``parseopt`` module implements a command line option parser.
**Deprecated since version 0.9.3:** Use the `parseopt2
<parseopt2.html>`_ module instead.
* `parseopt2 <parseopt2.html>`_
The ``parseopt2`` module implements a command line option parser. This
supports long and short command options with optional values and command line
arguments.
@@ -381,9 +386,6 @@ Database support
* `db_mongo <db_mongo.html>`_
A higher level **mongodb** wrapper.
* `mongodb <mongo.html>`_
Lower level wrapper for the **mongodb** client C library.
Other
-----
@@ -446,45 +448,6 @@ UNIX specific
* `posix <posix.html>`_
Contains a wrapper for the POSIX standard.
* `cursorfont <cursorfont.html>`_
Part of the wrapper for X11.
* `keysym <keysym.html>`_
Part of the wrapper for X11.
* `x <x.html>`_
Part of the wrapper for X11.
* `xatom <xatom.html>`_
Part of the wrapper for X11.
* `xcms <xcms.html>`_
Part of the wrapper for X11.
* `xf86dga <xf86dga.html>`_
Part of the wrapper for X11.
* `xf86vmode <xf86vmode.html>`_
Part of the wrapper for X11.
* `xi <xi.html>`_
Part of the wrapper for X11.
* `xinerama <xinerama.html>`_
Part of the wrapper for X11.
* `xkb <xkb.html>`_
Part of the wrapper for X11.
* `xkblib <xkblib.html>`_
Part of the wrapper for X11.
* `xlib <xlib.html>`_
Part of the wrapper for X11.
* `xrandr <xrandr.html>`_
Part of the wrapper for X11.
* `xrender <xrender.html>`_
Part of the wrapper for X11.
* `xresource <xresource.html>`_
Part of the wrapper for X11.
* `xshm <xshm.html>`_
Part of the wrapper for X11.
* `xutil <xutil.html>`_
Part of the wrapper for X11.
* `xv <xv.html>`_
Part of the wrapper for X11.
* `xvlib <xvlib.html>`_
Part of the wrapper for X11.
* `readline <readline.html>`_
Part of the wrapper for the GNU readline library.
* `history <history.html>`_
@@ -505,15 +468,6 @@ Regular expressions
Graphics libraries
------------------
* `cairo <cairo.html>`_
Wrapper for the cairo library.
* `cairoft <cairoft.html>`_
Wrapper for the cairoft library.
* `cairowin32 <cairowin32.html>`_
Wrapper for the cairowin32 library.
* `cairoxlib <cairoxlib.html>`_
Wrapper for the cairoxlib library.
* `sdl <sdl.html>`_
Part of the wrapper for SDL.
* `sdl_gfx <sdl_gfx.html>`_
@@ -529,47 +483,10 @@ Graphics libraries
* `smpeg <smpeg.html>`_
Part of the wrapper for SDL.
* `gl <gl.html>`_
Part of the wrapper for OpenGL.
* `glext <glext.html>`_
Part of the wrapper for OpenGL.
* `glu <glu.html>`_
Part of the wrapper for OpenGL.
* `glut <glut.html>`_
Part of the wrapper for OpenGL.
* `glx <glx.html>`_
Part of the wrapper for OpenGL.
* `wingl <wingl.html>`_
Part of the wrapper for OpenGL.
* `opengl <opengl.html>`_
New wrapper for OpenGL supporting up to version 4.2.
GUI libraries
-------------
* `atk <atk.html>`_
Wrapper for the atk library.
* `gdk2 <gdk2.html>`_
Wrapper for the gdk2 library.
* `gdk2pixbuf <gdk2pixbuf.html>`_
Wrapper for the gdk2pixbuf library.
* `gdkglext <gdkglext.html>`_
Wrapper for the gdkglext library.
* `glib2 <glib2.html>`_
Wrapper for the glib2 library.
* `gtk2 <gtk2.html>`_
Wrapper for the gtk2 library.
* `gtkglext <gtkglext.html>`_
Wrapper for the gtkglext library.
* `gtkhtml <gtkhtml.html>`_
Wrapper for the gtkhtml library.
* `libglade2 <libglade2.html>`_
Wrapper for the libglade2 library.
* `pango <pango.html>`_
Wrapper for the pango library.
* `pangoutils <pangoutils.html>`_
Wrapper for the pangoutils library.
* `iup <iup.html>`_
Wrapper of the IUP GUI library.
@@ -583,6 +500,8 @@ Database support
Contains a wrapper for the mySQL API.
* `sqlite3 <sqlite3.html>`_
Contains a wrapper for SQLite 3 API.
* `mongodb <mongo.html>`_
Lower level wrapper for the **mongodb** client C library.
* `odbcsql <odbcsql.html>`_
interface to the ODBC driver.
* `sphinx <sphinx.html>`_
@@ -612,21 +531,6 @@ Network Programming and Internet Protocols
Wrapper for OpenSSL.
Scripting languages
-------------------
* `lua <lua.html>`_
Part of the wrapper for Lua.
* `lualib <lualib.html>`_
Part of the wrapper for Lua.
* `lauxlib <lauxlib.html>`_
Part of the wrapper for Lua.
* `tcl <tcl.html>`_
Wrapper for the TCL programming language.
* `python <python.html>`_
Wrapper for the Python programming language.
Data Compression and Archiving
------------------------------

View File

@@ -312,14 +312,39 @@ Character literals
------------------
Character literals are enclosed in single quotes ``''`` and can contain the
same escape sequences as strings - with one exception: ``\n`` is not allowed
as it may be wider than one character (often it is the pair CR/LF for example).
same escape sequences as strings - with one exception: `newline`:idx: (``\n``)
is not allowed as it may be wider than one character (often it is the pair
CR/LF for example). Here are the valid `escape sequences`:idx: for character
literals:
================== ===================================================
Escape sequence Meaning
================== ===================================================
``\r``, ``\c`` `carriage return`:idx:
``\l`` `line feed`:idx:
``\f`` `form feed`:idx:
``\t`` `tabulator`:idx:
``\v`` `vertical tabulator`:idx:
``\\`` `backslash`:idx:
``\"`` `quotation mark`:idx:
``\'`` `apostrophe`:idx:
``\`` '0'..'9'+ `character with decimal value d`:idx:;
all decimal digits directly
following are used for the character
``\a`` `alert`:idx:
``\b`` `backspace`:idx:
``\e`` `escape`:idx: `[ESC]`:idx:
``\x`` HH `character with hex value HH`:idx:;
exactly two hex digits are allowed
================== ===================================================
A character is not an Unicode character but a single byte. The reason for this
is efficiency: for the overwhelming majority of use-cases, the resulting
programs will still handle UTF-8 properly as UTF-8 was specially designed for
this.
Another reason is that Nimrod can thus support ``array[char, int]`` or
``set[char]`` efficiently as many algorithms rely on this feature.
this. Another reason is that Nimrod can thus support ``array[char, int]`` or
``set[char]`` efficiently as many algorithms rely on this feature. The `TRune`
type is used for Unicode characters, it can represent any Unicode character.
``TRune`` is declared in the `unicode module <unicode.html>`_.
Numerical constants
@@ -750,7 +775,8 @@ designed for this.
Another reason is that Nimrod can support ``array[char, int]`` or
``set[char]`` efficiently as many algorithms rely on this feature. The
`TRune` type is used for Unicode characters, it can represent any Unicode
character. ``TRune`` is declared in the ``unicode`` module.
character. ``TRune`` is declared in the `unicode module <unicode.html>`_.
@@ -847,8 +873,8 @@ arrays, they can be used in case statements:
Per convention, all strings are UTF-8 strings, but this is not enforced. For
example, when reading strings from binary files, they are merely a sequence of
bytes. The index operation ``s[i]`` means the i-th *char* of ``s``, not the
i-th *unichar*. The iterator ``runes`` from the ``unicode``
module can be used for iteration over all Unicode characters.
i-th *unichar*. The iterator ``runes`` from the `unicode module
<unicode.html>`_ can be used for iteration over all Unicode characters.
CString type
@@ -2206,12 +2232,12 @@ Instead of:
Using statement
---------------
The using statement provides syntactic convenience for procs that heavily use a
single contextual parameter. When applied to a variable or a constant, it will
instruct Nimrod to automatically consider the used symbol as a hidden leading
parameter for any procedure calls, following the using statement in the current
scope. Thus, it behaves much like the hidden `this` parameter available in some
object-oriented programming languages.
The `using statement`:idx: provides syntactic convenience for procs that
heavily use a single contextual parameter. When applied to a variable or a
constant, it will instruct Nimrod to automatically consider the used symbol as
a hidden leading parameter for any procedure calls, following the using
statement in the current scope. Thus, it behaves much like the hidden `this`
parameter available in some object-oriented programming languages.
.. code-block:: nimrod
@@ -2234,6 +2260,24 @@ from different modules having the same name.
import windows, sdl
using sdl.SetTimer
Note that ``using`` only *adds* to the current context, it doesn't remove or
replace, **neither** does it create a new scope. What this means is that if you
apply this to multiple variables the compiler will find conflicts in what
variable to use:
.. code-block:: nimrod
var a, b = "kill it"
using a
add(" with fire")
using b
add(" with water")
echo a
echo b
When the compiler reaches the second ``add`` call, both ``a`` and ``b`` could
be used with the proc, so you get ``Error: expression '(a|b)' has no type (or
is ambiguous)``. To solve this you would need to nest ``using`` with a
``block`` statement so as to control the reach of the ``using`` statement.
If expression
-------------

View File

@@ -14,7 +14,9 @@ Thanks to its conditional construct ``$[0|1|2|else]`` it supports
Notation meaning
===================== =====================================================
``$#`` use first or next argument
``$name`` use named argument
``$name`` use named argument, you can wrap the named argument
in curly braces (eg. ``${name}``) to separate it from
the next characters.
``$1`` use first argument
``$-1`` use last argument
``${1..3}`` use arguments 1 to 3

View File

@@ -202,6 +202,12 @@ statement and all the variables will have the same value:
echo "x ", x # outputs "x 42"
echo "y ", y # outputs "y 3"
Note that declaring multiple variables with a single assignment which calls a
procedure can have unexpected results: the compiler will *unroll* the
assignments and end up calling the procedure several times. If the result of
the procedure depends on side effects, your variables may end up having
different values! For safety use only constant values.
Constants
=========
@@ -807,7 +813,11 @@ important differences:
However, you can also use a ``closure`` iterator to get a different set of
restrictions. See `first class iterators <manual.html#first-class-iterators>`_
for details.
for details. Iterators can have the same name and parameters as a proc,
essentially they have their own namespace. Therefore it is common practice to
wrap iterators in procs of the same name which accumulate the result of the
iterator and return it as a sequence, like ``split`` from the `strutils module
<strutils.html>`_.
Basic types
@@ -1582,6 +1592,17 @@ rules apply:
write(stdout, x(3)) # ambiguous: which `x` is to call?
Excluding symbols
-----------------
The normal ``import`` statement will bring in all exported symbols.
These can be limited by naming symbols which should be excluded with
the ``except`` qualifier.
.. code-block:: nimrod
import mymodule except y
From statement
--------------
@@ -1592,6 +1613,30 @@ exported symbols. An alternative that only imports listed symbols is the
.. code-block:: nimrod
from mymodule import x, y, z
The ``from`` statement can also force namespace qualification on
symbols, thereby making symbols available, but needing to be qualified
to be used.
.. code-block:: nimrod
from mymodule import x, y, z
x() # use x without any qualification
.. code-block:: nimrod
from mymodule import nil
mymodule.x() # must qualify x with the module name as prefix
x() # using x here without qualification is a compile error
Since module names are generally long to be descriptive, you can also
define a shorter alias to use when qualifying symbols.
.. code-block:: nimrod
from mymodule as m import nil
m.x() # m is aliasing mymodule
Include statement
-----------------

View File

@@ -44,7 +44,7 @@ type
splitAfter*: int # split too long entries in the TOC
tocPart*: seq[TTocEntry]
hasToc*: bool
theIndex: string
theIndex: string # Contents of the index file to be dumped at the end.
options*: TRstParseOptions
findFile*: TFindFileHandler
msgHandler*: TMsgHandler
@@ -111,6 +111,10 @@ proc initRstGenerator*(g: var TRstGenerator, target: TOutputTarget,
for i in low(g.meta)..high(g.meta): g.meta[i] = ""
proc writeIndexFile*(g: var TRstGenerator, outfile: string) =
## Writes the current index buffer to the specified output file.
##
## You previously need to add entries to the index with the ``setIndexTerm``
## proc. If the index is empty the file won't be created.
if g.theIndex.len > 0: writeFile(outfile, g.theIndex)
proc addXmlChar(dest: var string, c: char) =
@@ -224,6 +228,13 @@ proc renderAux(d: PDoc, n: PRstNode, frmtA, frmtB: string, result: var string) =
# ---------------- index handling --------------------------------------------
proc setIndexTerm*(d: var TRstGenerator, id, term: string) =
## Adds a `term` to the index using the specified hyperlink identifier.
##
## The ``d.theIndex`` string will be used to append the term in the format
## ``term<tab>file#id``. The anchor will be the based on the name of the file
## currently being parsed plus the `id`, which will be appended after a hash.
##
## The index won't be written to disk unless you call ``writeIndexFile``.
d.theIndex.add(term)
d.theIndex.add('\t')
let htmlFile = changeFileExt(extractFilename(d.filename), HtmlExt)

View File

@@ -11,8 +11,8 @@
## It supports one convenience iterator over all command line options and some
## lower-level features.
##
## DEPRECATED. Use parseopt2 instead as this version has issues with spaces
## in arguments.
## **Deprecated since version 0.9.3:** Use the `parseopt2 <parseopt2.html>`_
## module instead as this version has issues with spaces in arguments.
{.deprecated.}
{.push debugger: off.}

View File

@@ -2236,8 +2236,19 @@ when not defined(JS): #and not defined(NimrodVM):
when hostOS != "standalone":
iterator lines*(filename: string): TaintedString {.tags: [FReadIO].} =
## Iterate over any line in the file named `filename`.
## If the file does not exist `EIO` is raised.
## Iterates over any line in the file named `filename`.
##
## If the file does not exist `EIO` is raised. The trailing newline
## character(s) are removed from the iterated lines. Example:
##
## .. code-block:: nimrod
## import strutils
##
## proc transformLetters(filename: string) =
## var buffer = ""
## for line in filename.lines:
## buffer.add(line.replace("a", "0") & '\x0A')
## writeFile(filename, buffer)
var f = open(filename)
var res = TaintedString(newStringOfCap(80))
while f.readLine(res): yield res
@@ -2245,6 +2256,17 @@ when not defined(JS): #and not defined(NimrodVM):
iterator lines*(f: TFile): TaintedString {.tags: [FReadIO].} =
## Iterate over any line in the file `f`.
##
## The trailing newline character(s) are removed from the iterated lines.
## Example:
##
## .. code-block:: nimrod
## proc countZeros(filename: TFile): tuple[lines, zeros: int] =
## for line in filename.lines:
## for letter in line:
## if letter == '0':
## result.zeros += 1
## result.lines += 1
var res = TaintedString(newStringOfCap(80))
while f.readLine(res): yield res

View File

@@ -45,7 +45,7 @@ srcdoc2: "impure/re;pure/sockets"
srcdoc: "system/threads.nim;system/channels.nim;js/dom"
srcdoc2: "pure/os;pure/strutils;pure/math;pure/matchers;pure/algorithm"
srcdoc2: "pure/complex;pure/times;pure/osproc;pure/pegs;pure/dynlib"
srcdoc2: "pure/parseopt;pure/hashes;pure/strtabs;pure/lexbase"
srcdoc2: "pure/parseopt;pure/parseopt2;pure/hashes;pure/strtabs;pure/lexbase"
srcdoc2: "pure/parsecfg;pure/parsexml;pure/parsecsv;pure/parsesql"
srcdoc2: "pure/streams;pure/terminal;pure/cgi;impure/web;pure/unicode"
srcdoc2: "impure/zipfiles;pure/htmlgen;pure/parseutils;pure/browsers"