Merge branch 'devel' of https://github.com/Araq/Nimrod into devel
This commit is contained in:
commit
12247b3f56
13 changed files with 616 additions and 515 deletions
|
|
@ -34,25 +34,36 @@ Options:
|
||||||
--skipcomments do not copy comments
|
--skipcomments do not copy comments
|
||||||
--ignoreRValueRefs translate C++'s ``T&&`` to ``T`` instead ``of var T``
|
--ignoreRValueRefs translate C++'s ``T&&`` to ``T`` instead ``of var T``
|
||||||
--keepBodies keep C++'s method bodies
|
--keepBodies keep C++'s method bodies
|
||||||
|
--spliceHeader parse and emit header before source file
|
||||||
-v, --version write c2nim's version
|
-v, --version write c2nim's version
|
||||||
-h, --help show this help
|
-h, --help show this help
|
||||||
"""
|
"""
|
||||||
|
|
||||||
proc main(infile, outfile: string, options: PParserOptions) =
|
proc parse(infile: string, options: PParserOptions): PNode =
|
||||||
var start = getTime()
|
|
||||||
var stream = llStreamOpen(infile, fmRead)
|
var stream = llStreamOpen(infile, fmRead)
|
||||||
if stream == nil: rawMessage(errCannotOpenFile, infile)
|
if stream == nil: rawMessage(errCannotOpenFile, infile)
|
||||||
var p: TParser
|
var p: TParser
|
||||||
openParser(p, infile, stream, options)
|
openParser(p, infile, stream, options)
|
||||||
var module = parseUnit(p)
|
result = parseUnit(p)
|
||||||
closeParser(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),
|
rawMessage(hintSuccessX, [$gLinesCompiled, $(getTime() - start),
|
||||||
formatSize(getTotalMem())])
|
formatSize(getTotalMem())])
|
||||||
|
|
||||||
var
|
var
|
||||||
infile = ""
|
infile = ""
|
||||||
outfile = ""
|
outfile = ""
|
||||||
|
spliceHeader = false
|
||||||
parserOptions = newParserOptions()
|
parserOptions = newParserOptions()
|
||||||
for kind, key, val in getopt():
|
for kind, key, val in getopt():
|
||||||
case kind
|
case kind
|
||||||
|
|
@ -66,6 +77,7 @@ for kind, key, val in getopt():
|
||||||
stdout.write(Version & "\n")
|
stdout.write(Version & "\n")
|
||||||
quit(0)
|
quit(0)
|
||||||
of "o", "out": outfile = val
|
of "o", "out": outfile = val
|
||||||
|
of "spliceheader": spliceHeader = true
|
||||||
else:
|
else:
|
||||||
if not parserOptions.setOption(key, val):
|
if not parserOptions.setOption(key, val):
|
||||||
stdout.writeln("[Error] unknown option: " & key)
|
stdout.writeln("[Error] unknown option: " & key)
|
||||||
|
|
@ -77,4 +89,4 @@ else:
|
||||||
if outfile.len == 0:
|
if outfile.len == 0:
|
||||||
outfile = changeFileExt(infile, "nim")
|
outfile = changeFileExt(infile, "nim")
|
||||||
infile = addFileExt(infile, "h")
|
infile = addFileExt(infile, "h")
|
||||||
main(infile, outfile, parserOptions)
|
main(infile, outfile, parserOptions, spliceHeader)
|
||||||
|
|
|
||||||
|
|
@ -315,13 +315,28 @@ proc getNumber16(L: var TLexer, tok: var TToken) =
|
||||||
else: tok.xkind = pxIntLit
|
else: tok.xkind = pxIntLit
|
||||||
L.bufpos = pos
|
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) =
|
proc getNumber(L: var TLexer, tok: var TToken) =
|
||||||
tok.base = base10
|
tok.base = base10
|
||||||
matchUnderscoreChars(L, tok, {'0'..'9'})
|
if L.buf[L.bufpos] == '.':
|
||||||
if (L.buf[L.bufpos] == '.') and (L.buf[L.bufpos + 1] in {'0'..'9'}):
|
add(tok.s, "0.")
|
||||||
add(tok.s, '.')
|
|
||||||
inc(L.bufpos)
|
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:
|
try:
|
||||||
if isFloatLiteral(tok.s):
|
if isFloatLiteral(tok.s):
|
||||||
tok.fnumber = parseFloat(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'))
|
xi = (xi shl 3) or (ord(L.buf[L.bufpos]) - ord('0'))
|
||||||
inc(L.bufpos)
|
inc(L.bufpos)
|
||||||
add(tok.s, chr(xi))
|
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:
|
elif not allowEmpty:
|
||||||
lexMessage(L, errInvalidCharacterConstant)
|
lexMessage(L, errInvalidCharacterConstant)
|
||||||
|
|
||||||
|
|
@ -559,7 +591,7 @@ proc getTok(L: var TLexer, tok: var TToken) =
|
||||||
of 'b', 'B': getNumber2(L, tok)
|
of 'b', 'B': getNumber2(L, tok)
|
||||||
of '1'..'7': getNumber8(L, tok)
|
of '1'..'7': getNumber8(L, tok)
|
||||||
else: getNumber(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)
|
getNumber(L, tok)
|
||||||
else:
|
else:
|
||||||
case c
|
case c
|
||||||
|
|
|
||||||
|
|
@ -61,6 +61,8 @@ type
|
||||||
|
|
||||||
TReplaceTuple* = array[0..1, string]
|
TReplaceTuple* = array[0..1, string]
|
||||||
|
|
||||||
|
ERetryParsing = object of ESynch
|
||||||
|
|
||||||
proc newParserOptions*(): PParserOptions =
|
proc newParserOptions*(): PParserOptions =
|
||||||
new(result)
|
new(result)
|
||||||
result.prefixes = @[]
|
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
|
# avoids to build a symbol table, which can't be done reliably anyway for our
|
||||||
# purposes.
|
# purposes.
|
||||||
|
|
||||||
proc expression(p: var TParser): PNode
|
proc expression(p: var TParser, rbp: int = 0): PNode
|
||||||
proc constantExpression(p: var TParser): PNode
|
proc constantExpression(p: var TParser): PNode = expression(p, 40)
|
||||||
proc assignmentExpression(p: var TParser): PNode
|
proc assignmentExpression(p: var TParser): PNode = expression(p, 30)
|
||||||
proc compoundStatement(p: var TParser): PNode
|
proc compoundStatement(p: var TParser): PNode
|
||||||
proc statement(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 =
|
proc typeDesc(p: var TParser): PNode =
|
||||||
result = pointer(p, typeAtom(p))
|
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 =
|
proc parseField(p: var TParser, kind: TNodeKind): PNode =
|
||||||
if p.tok.xkind == pxParLe:
|
if p.tok.xkind == pxParLe:
|
||||||
getTok(p, nil)
|
getTok(p, nil)
|
||||||
|
|
@ -716,18 +734,36 @@ proc parseStruct(p: var TParser, isUnion: bool): PNode =
|
||||||
else:
|
else:
|
||||||
addSon(result, newNodeP(nkRecList, p))
|
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) =
|
proc parseParam(p: var TParser, params: PNode) =
|
||||||
var typ = typeDesc(p)
|
var typ = typeDesc(p)
|
||||||
# support for ``(void)`` parameter list:
|
# support for ``(void)`` parameter list:
|
||||||
if typ.kind == nkNilLit and p.tok.xkind == pxParRi: return
|
if typ.kind == nkNilLit and p.tok.xkind == pxParRi: return
|
||||||
var name: PNode
|
var name: PNode
|
||||||
if p.tok.xkind == pxSymbol:
|
typ = declarator(p, typ, addr name)
|
||||||
name = skipIdent(p)
|
if name == nil:
|
||||||
else:
|
|
||||||
# generate a name for the formal parameter:
|
|
||||||
var idx = sonsLen(params)+1
|
var idx = sonsLen(params)+1
|
||||||
name = newIdentNodeP("a" & $idx, p)
|
name = newIdentNodeP("a" & $idx, p)
|
||||||
typ = parseTypeSuffix(p, typ)
|
|
||||||
var x = newNodeP(nkIdentDefs, p)
|
var x = newNodeP(nkIdentDefs, p)
|
||||||
addSon(x, name, typ)
|
addSon(x, name, typ)
|
||||||
if p.tok.xkind == pxAsgn:
|
if p.tok.xkind == pxAsgn:
|
||||||
|
|
@ -1134,224 +1170,27 @@ proc setBaseFlags(n: PNode, base: TNumericalBase) =
|
||||||
of base8: incl(n.flags, nfBase8)
|
of base8: incl(n.flags, nfBase8)
|
||||||
of base16: incl(n.flags, nfBase16)
|
of base16: incl(n.flags, nfBase16)
|
||||||
|
|
||||||
proc unaryExpression(p: var TParser): PNode
|
proc startExpression(p : var TParser, tok : TToken) : PNode =
|
||||||
|
#echo "nud ", $tok
|
||||||
proc isDefinitelyAType(p: var TParser): bool =
|
case tok.xkind:
|
||||||
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")
|
|
||||||
of pxSymbol:
|
of pxSymbol:
|
||||||
if p.tok.s == "sizeof":
|
if tok.s == "NULL":
|
||||||
|
result = newNodeP(nkNilLit, p)
|
||||||
|
elif tok.s == "sizeof":
|
||||||
result = newNodeP(nkCall, p)
|
result = newNodeP(nkCall, p)
|
||||||
addSon(result, newIdentNodeP("sizeof", p))
|
addSon(result, newIdentNodeP("sizeof", p))
|
||||||
getTok(p, result)
|
saveContext(p)
|
||||||
if p.tok.xkind == pxParLe:
|
try:
|
||||||
getTok(p, result)
|
addSon(result, expression(p, 139))
|
||||||
addSon(result, typeDesc(p))
|
closeContext(p)
|
||||||
eat(p, pxParRi, result)
|
except ERetryParsing:
|
||||||
else:
|
backtrackContext(p)
|
||||||
addSon(result, unaryExpression(p))
|
eat(p, pxParLe)
|
||||||
elif p.tok.s == "new" or p.tok.s == "delete" and pfCpp in p.options.flags:
|
addSon(result, typeName(p))
|
||||||
var opr = p.tok.s
|
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)
|
result = newNodeP(nkCall, p)
|
||||||
getTok(p, result)
|
|
||||||
if p.tok.xkind == pxBracketLe:
|
if p.tok.xkind == pxBracketLe:
|
||||||
getTok(p)
|
getTok(p)
|
||||||
eat(p, pxBracketRi)
|
eat(p, pxBracketRi)
|
||||||
|
|
@ -1362,148 +1201,269 @@ proc unaryExpression(p: var TParser): PNode =
|
||||||
addSon(result, typeDesc(p))
|
addSon(result, typeDesc(p))
|
||||||
eat(p, pxParRi, result)
|
eat(p, pxParRi, result)
|
||||||
else:
|
else:
|
||||||
addSon(result, unaryExpression(p))
|
addSon(result, expression(p, 139))
|
||||||
else:
|
else:
|
||||||
result = postfixExpression(p)
|
result = mangledIdent(tok.s, p)
|
||||||
else: result = postfixExpression(p)
|
result = optScope(p, result)
|
||||||
|
result = optAngle(p, result)
|
||||||
proc expression(p: var TParser): PNode =
|
of pxIntLit:
|
||||||
# we cannot support C's ``,`` operator
|
result = newIntNodeP(nkIntLit, tok.iNumber, p)
|
||||||
result = assignmentExpression(p)
|
setBaseFlags(result, tok.base)
|
||||||
if p.tok.xkind == pxComma:
|
of pxInt64Lit:
|
||||||
getTok(p, result)
|
result = newIntNodeP(nkInt64Lit, tok.iNumber, p)
|
||||||
parMessage(p, errOperatorExpected, ",")
|
setBaseFlags(result, tok.base)
|
||||||
|
of pxFloatLit:
|
||||||
proc conditionalExpression(p: var TParser): PNode
|
result = newFloatNodeP(nkFloatLit, tok.fNumber, p)
|
||||||
|
setBaseFlags(result, tok.base)
|
||||||
proc constantExpression(p: var TParser): PNode =
|
of pxStrLit:
|
||||||
result = conditionalExpression(p)
|
result = newStrNodeP(nkStrLit, tok.s, p)
|
||||||
|
while p.tok.xkind == pxStrLit:
|
||||||
proc lvalue(p: var TParser): PNode =
|
add(result.strVal, p.tok.s)
|
||||||
result = unaryExpression(p)
|
getTok(p, result)
|
||||||
|
of pxCharLit:
|
||||||
proc asgnExpr(p: var TParser, opr: string, a: PNode): PNode =
|
result = newIntNodeP(nkCharLit, ord(tok.s[0]), p)
|
||||||
closeContext(p)
|
of pxParLe:
|
||||||
getTok(p, a)
|
try:
|
||||||
var b = assignmentExpression(p)
|
saveContext(p)
|
||||||
result = newNodeP(nkAsgn, p)
|
result = newNodeP(nkPar, p)
|
||||||
addSon(result, a, newBinary(opr, copyTree(a), b, p))
|
addSon(result, expression(p, 0))
|
||||||
|
if p.tok.xkind != pxParRi:
|
||||||
proc incdec(p: var TParser, opr: string, a: PNode): PNode =
|
raise newException(ERetryParsing, "expected a ')'")
|
||||||
closeContext(p)
|
getTok(p, result)
|
||||||
getTok(p, a)
|
if p.tok.xkind in {pxSymbol, pxIntLit, pxFloatLit, pxStrLit, pxCharLit}:
|
||||||
var b = assignmentExpression(p)
|
raise newException(ERetryParsing, "expected a non literal token")
|
||||||
result = newNodeP(nkCall, p)
|
closeContext(p)
|
||||||
addSon(result, newIdentNodeP(getIdent(opr), p), a, b)
|
except ERetryParsing:
|
||||||
|
backtrackContext(p)
|
||||||
proc assignmentExpression(p: var TParser): PNode =
|
result = newNodeP(nkCast, p)
|
||||||
saveContext(p)
|
addSon(result, typeName(p))
|
||||||
var a = lvalue(p)
|
eat(p, pxParRi, result)
|
||||||
case p.tok.xkind
|
addSon(result, expression(p, 139))
|
||||||
of pxAsgn:
|
of pxPlusPlus:
|
||||||
closeContext(p)
|
result = newNodeP(nkCall, p)
|
||||||
getTok(p, a)
|
addSon(result, newIdentNodeP("inc", p))
|
||||||
var b = assignmentExpression(p)
|
addSon(result, expression(p, 139))
|
||||||
result = newNodeP(nkAsgn, p)
|
of pxMinusMinus:
|
||||||
addSon(result, a, b)
|
result = newNodeP(nkCall, p)
|
||||||
of pxPlusAsgn: result = incdec(p, "inc", a)
|
addSon(result, newIdentNodeP("dec", p))
|
||||||
of pxMinusAsgn: result = incdec(p, "dec", a)
|
addSon(result, expression(p, 139))
|
||||||
of pxStarAsgn: result = asgnExpr(p, "*", a)
|
of pxAmp:
|
||||||
of pxSlashAsgn: result = asgnExpr(p, "/", a)
|
result = newNodeP(nkAddr, p)
|
||||||
of pxModAsgn: result = asgnExpr(p, "mod", a)
|
addSon(result, expression(p, 139))
|
||||||
of pxShlAsgn: result = asgnExpr(p, "shl", a)
|
of pxStar:
|
||||||
of pxShrAsgn: result = asgnExpr(p, "shr", a)
|
result = newNodeP(nkBracketExpr, p)
|
||||||
of pxAmpAsgn: result = asgnExpr(p, "and", a)
|
addSon(result, expression(p, 139))
|
||||||
of pxHatAsgn: result = asgnExpr(p, "xor", a)
|
of pxPlus:
|
||||||
of pxBarAsgn: result = asgnExpr(p, "or", a)
|
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:
|
else:
|
||||||
backtrackContext(p)
|
# probably from a failed sub expression attempt, try a type cast
|
||||||
result = conditionalExpression(p)
|
raise newException(ERetryParsing, "did not expect " & $tok)
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
proc relationalExpression(p: var TParser): PNode =
|
proc leftBindingPower(p : var TParser, tok : ref TToken) : int =
|
||||||
result = shiftExpression(p)
|
#echo "lbp ", $tok[]
|
||||||
# Nimrod uses ``<`` and ``<=``, etc. too:
|
case tok.xkind:
|
||||||
while p.tok.xkind in {pxLt, pxLe, pxGt, pxGe}:
|
of pxComma:
|
||||||
var op = tokKindToStr(p.tok.xkind)
|
return 10
|
||||||
getTok(p, result)
|
# throw == 20
|
||||||
var a = result
|
of pxAsgn, pxPlusAsgn, pxMinusAsgn, pxStarAsgn, pxSlashAsgn, pxModAsgn, pxShlAsgn, pxShrAsgn, pxAmpAsgn, pxHatAsgn, pxBarAsgn:
|
||||||
var b = shiftExpression(p)
|
return 30
|
||||||
result = newBinary(op, a, b, p)
|
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 =
|
proc buildStmtList(a: PNode): 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 andExpression(p: var TParser): PNode =
|
proc leftExpression(p : var TParser, tok : TToken, left : PNode) : PNode =
|
||||||
result = equalityExpression(p)
|
#echo "led ", $tok
|
||||||
while p.tok.xkind == pxAmp:
|
case tok.xkind:
|
||||||
getTok(p, result)
|
of pxComma: # 10
|
||||||
var a = result
|
# not supported as an expression, turns into a statement list
|
||||||
var b = equalityExpression(p)
|
result = buildStmtList(left)
|
||||||
result = newBinary("and", a, b, p)
|
addSon(result, expression(p, 0))
|
||||||
|
# throw == 20
|
||||||
proc exclusiveOrExpression(p: var TParser): PNode =
|
of pxAsgn: # 30
|
||||||
result = andExpression(p)
|
result = newNodeP(nkAsgn, p)
|
||||||
while p.tok.xkind == pxHat:
|
addSon(result, left, expression(p, 29))
|
||||||
getTok(p, result)
|
of pxPlusAsgn: # 30
|
||||||
var a = result
|
result = newNodeP(nkCall, p)
|
||||||
var b = andExpression(p)
|
addSon(result, newIdentNodeP(getIdent("inc"), p), left, expression(p, 29))
|
||||||
result = newBinary("^", a, b, p)
|
of pxMinusAsgn: # 30
|
||||||
|
result = newNodeP(nkCall, p)
|
||||||
proc inclusiveOrExpression(p: var TParser): PNode =
|
addSon(result, newIdentNodeP(getIdent("dec"), p), left, expression(p, 29))
|
||||||
result = exclusiveOrExpression(p)
|
of pxStarAsgn: # 30
|
||||||
while p.tok.xkind == pxBar:
|
result = newNodeP(nkAsgn, p)
|
||||||
getTok(p, result)
|
var right = expression(p, 29)
|
||||||
var a = result
|
addSon(result, left, newBinary("*", copyTree(left), right, p))
|
||||||
var b = exclusiveOrExpression(p)
|
of pxSlashAsgn: # 30
|
||||||
result = newBinary("or", a, b, p)
|
result = newNodeP(nkAsgn, p)
|
||||||
|
var right = expression(p, 29)
|
||||||
proc logicalAndExpression(p: var TParser): PNode =
|
addSon(result, left, newBinary("/", copyTree(left), right, p))
|
||||||
result = inclusiveOrExpression(p)
|
of pxModAsgn: # 30
|
||||||
while p.tok.xkind == pxAmpAmp:
|
result = newNodeP(nkAsgn, p)
|
||||||
getTok(p, result)
|
var right = expression(p, 29)
|
||||||
var a = result
|
addSon(result, left, newBinary("mod", copyTree(left), right, p))
|
||||||
var b = inclusiveOrExpression(p)
|
of pxShlAsgn: # 30
|
||||||
result = newBinary("and", a, b, p)
|
result = newNodeP(nkAsgn, p)
|
||||||
|
var right = expression(p, 29)
|
||||||
proc logicalOrExpression(p: var TParser): PNode =
|
addSon(result, left, newBinary("shl", copyTree(left), right, p))
|
||||||
result = logicalAndExpression(p)
|
of pxShrAsgn: # 30
|
||||||
while p.tok.xkind == pxBarBar:
|
result = newNodeP(nkAsgn, p)
|
||||||
getTok(p, result)
|
var right = expression(p, 29)
|
||||||
var a = result
|
addSon(result, left, newBinary("shr", copyTree(left), right, p))
|
||||||
var b = logicalAndExpression(p)
|
of pxAmpAsgn: # 30
|
||||||
result = newBinary("or", a, b, p)
|
result = newNodeP(nkAsgn, p)
|
||||||
|
var right = expression(p, 29)
|
||||||
proc conditionalExpression(p: var TParser): PNode =
|
addSon(result, left, newBinary("and", copyTree(left), right, p))
|
||||||
result = logicalOrExpression(p)
|
of pxHatAsgn: # 30
|
||||||
if p.tok.xkind == pxConditional:
|
result = newNodeP(nkAsgn, p)
|
||||||
getTok(p, result) # skip '?'
|
var right = expression(p, 29)
|
||||||
var a = result
|
addSon(result, left, newBinary("xor", copyTree(left), right, p))
|
||||||
var b = expression(p)
|
of pxBarAsgn: # 30
|
||||||
eat(p, pxColon, b)
|
result = newNodeP(nkAsgn, p)
|
||||||
var c = conditionalExpression(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)
|
result = newNodeP(nkIfExpr, p)
|
||||||
var branch = newNodeP(nkElifExpr, p)
|
var branch = newNodeP(nkElifExpr, p)
|
||||||
addSon(branch, a, b)
|
addSon(branch, left, a)
|
||||||
addSon(result, branch)
|
addSon(result, branch)
|
||||||
branch = newNodeP(nkElseExpr, p)
|
branch = newNodeP(nkElseExpr, p)
|
||||||
addSon(branch, c)
|
addSon(branch, b)
|
||||||
addSon(result, branch)
|
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
|
# Statements
|
||||||
|
|
||||||
|
|
@ -1549,12 +1509,12 @@ proc parseIf(p: var TParser): PNode =
|
||||||
while true:
|
while true:
|
||||||
getTok(p) # skip ``if``
|
getTok(p) # skip ``if``
|
||||||
var branch = newNodeP(nkElifBranch, p)
|
var branch = newNodeP(nkElifBranch, p)
|
||||||
skipCom(p, branch)
|
|
||||||
eat(p, pxParLe, branch)
|
eat(p, pxParLe, branch)
|
||||||
addSon(branch, expression(p))
|
addSon(branch, expression(p))
|
||||||
eat(p, pxParRi, branch)
|
eat(p, pxParRi, branch)
|
||||||
addSon(branch, nestedStatement(p))
|
addSon(branch, nestedStatement(p))
|
||||||
addSon(result, branch)
|
addSon(result, branch)
|
||||||
|
skipCom(p, branch)
|
||||||
if p.tok.s == "else":
|
if p.tok.s == "else":
|
||||||
getTok(p, result)
|
getTok(p, result)
|
||||||
if p.tok.s != "if":
|
if p.tok.s != "if":
|
||||||
|
|
@ -1574,19 +1534,51 @@ proc parseWhile(p: var TParser): PNode =
|
||||||
eat(p, pxParRi, result)
|
eat(p, pxParRi, result)
|
||||||
addSon(result, nestedStatement(p))
|
addSon(result, nestedStatement(p))
|
||||||
|
|
||||||
|
proc embedStmts(sl, a: PNode)
|
||||||
|
|
||||||
proc parseDoWhile(p: var TParser): PNode =
|
proc parseDoWhile(p: var TParser): PNode =
|
||||||
# we only support ``do stmt while (0)`` as an idiom for
|
# parsing
|
||||||
# ``block: stmt``
|
result = newNodeP(nkWhileStmt, p)
|
||||||
result = newNodeP(nkBlockStmt, p)
|
getTok(p, result)
|
||||||
getTok(p, result) # skip "do"
|
var stm = nestedStatement(p)
|
||||||
addSon(result, ast.emptyNode, nestedStatement(p))
|
|
||||||
eat(p, "while", result)
|
eat(p, "while", result)
|
||||||
eat(p, pxParLe, result)
|
eat(p, pxParLe, result)
|
||||||
if p.tok.xkind == pxIntLit and p.tok.iNumber == 0: getTok(p, result)
|
var exp = expression(p)
|
||||||
else: parMessage(p, errTokenExpected, "0")
|
|
||||||
eat(p, pxParRi, result)
|
eat(p, pxParRi, result)
|
||||||
if p.tok.xkind == pxSemicolon: getTok(p)
|
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 =
|
proc declarationOrStatement(p: var TParser): PNode =
|
||||||
if p.tok.xkind != pxSymbol:
|
if p.tok.xkind != pxSymbol:
|
||||||
result = expressionStatement(p)
|
result = expressionStatement(p)
|
||||||
|
|
@ -1666,7 +1658,7 @@ proc parseFor(p: var TParser, result: PNode) =
|
||||||
eat(p, pxParLe, result)
|
eat(p, pxParLe, result)
|
||||||
var initStmt = declarationOrStatement(p)
|
var initStmt = declarationOrStatement(p)
|
||||||
if initStmt.kind != nkEmpty:
|
if initStmt.kind != nkEmpty:
|
||||||
addSon(result, initStmt)
|
embedStmts(result, initStmt)
|
||||||
var w = newNodeP(nkWhileStmt, p)
|
var w = newNodeP(nkWhileStmt, p)
|
||||||
var condition = expressionStatement(p)
|
var condition = expressionStatement(p)
|
||||||
if condition.kind == nkEmpty: condition = newIdentNodeP("true", p)
|
if condition.kind == nkEmpty: condition = newIdentNodeP("true", p)
|
||||||
|
|
@ -1676,7 +1668,7 @@ proc parseFor(p: var TParser, result: PNode) =
|
||||||
var loopBody = nestedStatement(p)
|
var loopBody = nestedStatement(p)
|
||||||
if step.kind != nkEmpty:
|
if step.kind != nkEmpty:
|
||||||
loopBody = buildStmtList(loopBody)
|
loopBody = buildStmtList(loopBody)
|
||||||
addSon(loopBody, step)
|
embedStmts(loopBody, step)
|
||||||
addSon(w, loopBody)
|
addSon(w, loopBody)
|
||||||
addSon(result, w)
|
addSon(result, w)
|
||||||
|
|
||||||
|
|
@ -2048,6 +2040,10 @@ proc parseStandaloneClass(p: var TParser, isStruct: bool): PNode =
|
||||||
result = declaration(p)
|
result = declaration(p)
|
||||||
p.currentClass = oldClass
|
p.currentClass = oldClass
|
||||||
|
|
||||||
|
proc unwrap(a: PNode): PNode =
|
||||||
|
if a.kind == nkPar:
|
||||||
|
return a.sons[0]
|
||||||
|
return a
|
||||||
|
|
||||||
include cpp
|
include cpp
|
||||||
|
|
||||||
|
|
@ -2082,16 +2078,10 @@ proc statement(p: var TParser): PNode =
|
||||||
of "return":
|
of "return":
|
||||||
result = newNodeP(nkReturnStmt, p)
|
result = newNodeP(nkReturnStmt, p)
|
||||||
getTok(p)
|
getTok(p)
|
||||||
# special case for ``return (expr)`` because I hate the redundant
|
if p.tok.xkind == pxSemicolon:
|
||||||
# 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:
|
|
||||||
addSon(result, ast.emptyNode)
|
addSon(result, ast.emptyNode)
|
||||||
|
else:
|
||||||
|
addSon(result, unwrap(expression(p)))
|
||||||
eat(p, pxSemicolon)
|
eat(p, pxSemicolon)
|
||||||
of "enum": result = enumSpecifier(p)
|
of "enum": result = enumSpecifier(p)
|
||||||
of "typedef": result = parseTypeDef(p)
|
of "typedef": result = parseTypeDef(p)
|
||||||
|
|
@ -2140,9 +2130,12 @@ proc statement(p: var TParser): PNode =
|
||||||
assert result != nil
|
assert result != nil
|
||||||
|
|
||||||
proc parseUnit(p: var TParser): PNode =
|
proc parseUnit(p: var TParser): PNode =
|
||||||
result = newNodeP(nkStmtList, p)
|
try:
|
||||||
getTok(p) # read first token
|
result = newNodeP(nkStmtList, p)
|
||||||
while p.tok.xkind != pxEof:
|
getTok(p) # read first token
|
||||||
var s = statement(p)
|
while p.tok.xkind != pxEof:
|
||||||
if s.kind != nkEmpty: embedStmts(result, s)
|
var s = statement(p)
|
||||||
|
if s.kind != nkEmpty: embedStmts(result, s)
|
||||||
|
except ERetryParsing:
|
||||||
|
parMessage(p, errGenerated, "Uncaught parsing exception raised")
|
||||||
|
|
||||||
|
|
|
||||||
33
compiler/c2nim/tests/vincent.c
Normal file
33
compiler/c2nim/tests/vincent.c
Normal 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';
|
||||||
|
}
|
||||||
3
compiler/c2nim/tests/vincent.h
Normal file
3
compiler/c2nim/tests/vincent.h
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
struct foo {
|
||||||
|
int x,y,z;
|
||||||
|
};
|
||||||
114
doc/lib.txt
114
doc/lib.txt
|
|
@ -227,7 +227,12 @@ Parsers
|
||||||
-------
|
-------
|
||||||
|
|
||||||
* `parseopt <parseopt.html>`_
|
* `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
|
supports long and short command options with optional values and command line
|
||||||
arguments.
|
arguments.
|
||||||
|
|
||||||
|
|
@ -381,9 +386,6 @@ Database support
|
||||||
* `db_mongo <db_mongo.html>`_
|
* `db_mongo <db_mongo.html>`_
|
||||||
A higher level **mongodb** wrapper.
|
A higher level **mongodb** wrapper.
|
||||||
|
|
||||||
* `mongodb <mongo.html>`_
|
|
||||||
Lower level wrapper for the **mongodb** client C library.
|
|
||||||
|
|
||||||
|
|
||||||
Other
|
Other
|
||||||
-----
|
-----
|
||||||
|
|
@ -446,45 +448,6 @@ UNIX specific
|
||||||
|
|
||||||
* `posix <posix.html>`_
|
* `posix <posix.html>`_
|
||||||
Contains a wrapper for the POSIX standard.
|
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>`_
|
* `readline <readline.html>`_
|
||||||
Part of the wrapper for the GNU readline library.
|
Part of the wrapper for the GNU readline library.
|
||||||
* `history <history.html>`_
|
* `history <history.html>`_
|
||||||
|
|
@ -505,15 +468,6 @@ Regular expressions
|
||||||
Graphics libraries
|
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>`_
|
* `sdl <sdl.html>`_
|
||||||
Part of the wrapper for SDL.
|
Part of the wrapper for SDL.
|
||||||
* `sdl_gfx <sdl_gfx.html>`_
|
* `sdl_gfx <sdl_gfx.html>`_
|
||||||
|
|
@ -529,47 +483,10 @@ Graphics libraries
|
||||||
* `smpeg <smpeg.html>`_
|
* `smpeg <smpeg.html>`_
|
||||||
Part of the wrapper for SDL.
|
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
|
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>`_
|
* `iup <iup.html>`_
|
||||||
Wrapper of the IUP GUI library.
|
Wrapper of the IUP GUI library.
|
||||||
|
|
||||||
|
|
@ -583,6 +500,8 @@ Database support
|
||||||
Contains a wrapper for the mySQL API.
|
Contains a wrapper for the mySQL API.
|
||||||
* `sqlite3 <sqlite3.html>`_
|
* `sqlite3 <sqlite3.html>`_
|
||||||
Contains a wrapper for SQLite 3 API.
|
Contains a wrapper for SQLite 3 API.
|
||||||
|
* `mongodb <mongo.html>`_
|
||||||
|
Lower level wrapper for the **mongodb** client C library.
|
||||||
* `odbcsql <odbcsql.html>`_
|
* `odbcsql <odbcsql.html>`_
|
||||||
interface to the ODBC driver.
|
interface to the ODBC driver.
|
||||||
* `sphinx <sphinx.html>`_
|
* `sphinx <sphinx.html>`_
|
||||||
|
|
@ -612,21 +531,6 @@ Network Programming and Internet Protocols
|
||||||
Wrapper for OpenSSL.
|
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
|
Data Compression and Archiving
|
||||||
------------------------------
|
------------------------------
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -312,14 +312,39 @@ Character literals
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
Character literals are enclosed in single quotes ``''`` and can contain the
|
Character literals are enclosed in single quotes ``''`` and can contain the
|
||||||
same escape sequences as strings - with one exception: ``\n`` is not allowed
|
same escape sequences as strings - with one exception: `newline`:idx: (``\n``)
|
||||||
as it may be wider than one character (often it is the pair CR/LF for example).
|
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
|
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
|
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
|
programs will still handle UTF-8 properly as UTF-8 was specially designed for
|
||||||
this.
|
this. Another reason is that Nimrod can thus support ``array[char, int]`` or
|
||||||
Another reason is that Nimrod can thus support ``array[char, int]`` or
|
``set[char]`` efficiently as many algorithms rely on this feature. The `TRune`
|
||||||
``set[char]`` efficiently as many algorithms rely on this feature.
|
type is used for Unicode characters, it can represent any Unicode character.
|
||||||
|
``TRune`` is declared in the `unicode module <unicode.html>`_.
|
||||||
|
|
||||||
|
|
||||||
Numerical constants
|
Numerical constants
|
||||||
|
|
@ -750,7 +775,8 @@ designed for this.
|
||||||
Another reason is that Nimrod can support ``array[char, int]`` or
|
Another reason is that Nimrod can support ``array[char, int]`` or
|
||||||
``set[char]`` efficiently as many algorithms rely on this feature. The
|
``set[char]`` efficiently as many algorithms rely on this feature. The
|
||||||
`TRune` type is used for Unicode characters, it can represent any Unicode
|
`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
|
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
|
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
|
bytes. The index operation ``s[i]`` means the i-th *char* of ``s``, not the
|
||||||
i-th *unichar*. The iterator ``runes`` from the ``unicode``
|
i-th *unichar*. The iterator ``runes`` from the `unicode module
|
||||||
module can be used for iteration over all Unicode characters.
|
<unicode.html>`_ can be used for iteration over all Unicode characters.
|
||||||
|
|
||||||
|
|
||||||
CString type
|
CString type
|
||||||
|
|
@ -2206,12 +2232,12 @@ Instead of:
|
||||||
Using statement
|
Using statement
|
||||||
---------------
|
---------------
|
||||||
|
|
||||||
The using statement provides syntactic convenience for procs that heavily use a
|
The `using statement`:idx: provides syntactic convenience for procs that
|
||||||
single contextual parameter. When applied to a variable or a constant, it will
|
heavily use a single contextual parameter. When applied to a variable or a
|
||||||
instruct Nimrod to automatically consider the used symbol as a hidden leading
|
constant, it will instruct Nimrod to automatically consider the used symbol as
|
||||||
parameter for any procedure calls, following the using statement in the current
|
a hidden leading parameter for any procedure calls, following the using
|
||||||
scope. Thus, it behaves much like the hidden `this` parameter available in some
|
statement in the current scope. Thus, it behaves much like the hidden `this`
|
||||||
object-oriented programming languages.
|
parameter available in some object-oriented programming languages.
|
||||||
|
|
||||||
.. code-block:: nimrod
|
.. code-block:: nimrod
|
||||||
|
|
||||||
|
|
@ -2234,6 +2260,24 @@ from different modules having the same name.
|
||||||
import windows, sdl
|
import windows, sdl
|
||||||
using sdl.SetTimer
|
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
|
If expression
|
||||||
-------------
|
-------------
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,9 @@ Thanks to its conditional construct ``$[0|1|2|else]`` it supports
|
||||||
Notation meaning
|
Notation meaning
|
||||||
===================== =====================================================
|
===================== =====================================================
|
||||||
``$#`` use first or next argument
|
``$#`` 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 first argument
|
||||||
``$-1`` use last argument
|
``$-1`` use last argument
|
||||||
``${1..3}`` use arguments 1 to 3
|
``${1..3}`` use arguments 1 to 3
|
||||||
|
|
|
||||||
47
doc/tut1.txt
47
doc/tut1.txt
|
|
@ -202,6 +202,12 @@ statement and all the variables will have the same value:
|
||||||
echo "x ", x # outputs "x 42"
|
echo "x ", x # outputs "x 42"
|
||||||
echo "y ", y # outputs "y 3"
|
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
|
Constants
|
||||||
=========
|
=========
|
||||||
|
|
@ -807,7 +813,11 @@ important differences:
|
||||||
|
|
||||||
However, you can also use a ``closure`` iterator to get a different set of
|
However, you can also use a ``closure`` iterator to get a different set of
|
||||||
restrictions. See `first class iterators <manual.html#first-class-iterators>`_
|
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
|
Basic types
|
||||||
|
|
@ -1582,6 +1592,17 @@ rules apply:
|
||||||
write(stdout, x(3)) # ambiguous: which `x` is to call?
|
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
|
From statement
|
||||||
--------------
|
--------------
|
||||||
|
|
||||||
|
|
@ -1592,6 +1613,30 @@ exported symbols. An alternative that only imports listed symbols is the
|
||||||
.. code-block:: nimrod
|
.. code-block:: nimrod
|
||||||
from mymodule import x, y, z
|
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
|
Include statement
|
||||||
-----------------
|
-----------------
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@ type
|
||||||
splitAfter*: int # split too long entries in the TOC
|
splitAfter*: int # split too long entries in the TOC
|
||||||
tocPart*: seq[TTocEntry]
|
tocPart*: seq[TTocEntry]
|
||||||
hasToc*: bool
|
hasToc*: bool
|
||||||
theIndex: string
|
theIndex: string # Contents of the index file to be dumped at the end.
|
||||||
options*: TRstParseOptions
|
options*: TRstParseOptions
|
||||||
findFile*: TFindFileHandler
|
findFile*: TFindFileHandler
|
||||||
msgHandler*: TMsgHandler
|
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] = ""
|
for i in low(g.meta)..high(g.meta): g.meta[i] = ""
|
||||||
|
|
||||||
proc writeIndexFile*(g: var TRstGenerator, outfile: string) =
|
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)
|
if g.theIndex.len > 0: writeFile(outfile, g.theIndex)
|
||||||
|
|
||||||
proc addXmlChar(dest: var string, c: char) =
|
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 --------------------------------------------
|
# ---------------- index handling --------------------------------------------
|
||||||
|
|
||||||
proc setIndexTerm*(d: var TRstGenerator, id, term: string) =
|
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(term)
|
||||||
d.theIndex.add('\t')
|
d.theIndex.add('\t')
|
||||||
let htmlFile = changeFileExt(extractFilename(d.filename), HtmlExt)
|
let htmlFile = changeFileExt(extractFilename(d.filename), HtmlExt)
|
||||||
|
|
|
||||||
|
|
@ -11,8 +11,8 @@
|
||||||
## It supports one convenience iterator over all command line options and some
|
## It supports one convenience iterator over all command line options and some
|
||||||
## lower-level features.
|
## lower-level features.
|
||||||
##
|
##
|
||||||
## DEPRECATED. Use parseopt2 instead as this version has issues with spaces
|
## **Deprecated since version 0.9.3:** Use the `parseopt2 <parseopt2.html>`_
|
||||||
## in arguments.
|
## module instead as this version has issues with spaces in arguments.
|
||||||
{.deprecated.}
|
{.deprecated.}
|
||||||
{.push debugger: off.}
|
{.push debugger: off.}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2236,8 +2236,19 @@ when not defined(JS): #and not defined(NimrodVM):
|
||||||
|
|
||||||
when hostOS != "standalone":
|
when hostOS != "standalone":
|
||||||
iterator lines*(filename: string): TaintedString {.tags: [FReadIO].} =
|
iterator lines*(filename: string): TaintedString {.tags: [FReadIO].} =
|
||||||
## Iterate over any line in the file named `filename`.
|
## Iterates over any line in the file named `filename`.
|
||||||
## If the file does not exist `EIO` is raised.
|
##
|
||||||
|
## 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 f = open(filename)
|
||||||
var res = TaintedString(newStringOfCap(80))
|
var res = TaintedString(newStringOfCap(80))
|
||||||
while f.readLine(res): yield res
|
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].} =
|
iterator lines*(f: TFile): TaintedString {.tags: [FReadIO].} =
|
||||||
## Iterate over any line in the file `f`.
|
## 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))
|
var res = TaintedString(newStringOfCap(80))
|
||||||
while f.readLine(res): yield res
|
while f.readLine(res): yield res
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,7 @@ srcdoc2: "impure/re;pure/sockets"
|
||||||
srcdoc: "system/threads.nim;system/channels.nim;js/dom"
|
srcdoc: "system/threads.nim;system/channels.nim;js/dom"
|
||||||
srcdoc2: "pure/os;pure/strutils;pure/math;pure/matchers;pure/algorithm"
|
srcdoc2: "pure/os;pure/strutils;pure/math;pure/matchers;pure/algorithm"
|
||||||
srcdoc2: "pure/complex;pure/times;pure/osproc;pure/pegs;pure/dynlib"
|
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/parsecfg;pure/parsexml;pure/parsecsv;pure/parsesql"
|
||||||
srcdoc2: "pure/streams;pure/terminal;pure/cgi;impure/web;pure/unicode"
|
srcdoc2: "pure/streams;pure/terminal;pure/cgi;impure/web;pure/unicode"
|
||||||
srcdoc2: "impure/zipfiles;pure/htmlgen;pure/parseutils;pure/browsers"
|
srcdoc2: "impure/zipfiles;pure/htmlgen;pure/parseutils;pure/browsers"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue