405 changes: 405 additions & 0 deletions .gitignore

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions bin/empty.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
This file keeps several tools from deleting this subdirectory.
200 changes: 0 additions & 200 deletions build.bat

This file was deleted.

1 change: 1 addition & 0 deletions build/empty.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
This file keeps several tools from deleting this subdirectory.
200 changes: 0 additions & 200 deletions build64.bat

This file was deleted.

14 changes: 7 additions & 7 deletions compiler/aliases.nim
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ proc isPartOfAux(n: PNode, b: PType, marker: var TIntSet): TAnalysisResult =
proc isPartOfAux(a, b: PType, marker: var TIntSet): TAnalysisResult =
result = arNo
if a == nil or b == nil: return
if ContainsOrIncl(marker, a.id): return
if containsOrIncl(marker, a.id): return
if compareTypes(a, b, dcEqIgnoreDistinct): return arYes
case a.kind
of tyObject:
Expand All @@ -54,11 +54,11 @@ proc isPartOfAux(a, b: PType, marker: var TIntSet): TAnalysisResult =
for i in countup(0, sonsLen(a) - 1):
result = isPartOfAux(a.sons[i], b, marker)
if result == arYes: return
else: nil
else: discard

proc isPartOf(a, b: PType): TAnalysisResult =
## checks iff 'a' can be part of 'b'. Iterates over VALUE types!
var marker = InitIntSet()
var marker = initIntSet()
# watch out: parameters reversed because I'm too lazy to change the code...
result = isPartOfAux(b, a, marker)

Expand Down Expand Up @@ -115,7 +115,7 @@ proc isPartOf*(a, b: PNode): TAnalysisResult =
var x = if a[1].kind == nkHiddenStdConv: a[1][1] else: a[1]
var y = if b[1].kind == nkHiddenStdConv: b[1][1] else: b[1]

if SameValue(x, y): result = arYes
if sameValue(x, y): result = arYes
else: result = arNo
# else: maybe and no are accurate
else:
Expand All @@ -140,7 +140,7 @@ proc isPartOf*(a, b: PNode): TAnalysisResult =
result = isPartOf(a[1], b[1])
of nkObjUpConv, nkObjDownConv, nkCheckedFieldExpr:
result = isPartOf(a[0], b[0])
else: nil
else: discard
# Calls return a new location, so a default of ``arNo`` is fine.
else:
# go down recursively; this is quite demanding:
Expand Down Expand Up @@ -177,6 +177,6 @@ proc isPartOf*(a, b: PNode): TAnalysisResult =
if isPartOf(a.typ, b.typ) != arNo:
result = isPartOf(a[0], b)
if result == arNo: result = arMaybe
else: nil
else: nil
else: discard
else: discard

402 changes: 313 additions & 89 deletions compiler/ast.nim

Large diffs are not rendered by default.

341 changes: 185 additions & 156 deletions compiler/astalgo.nim

Large diffs are not rendered by default.

10 changes: 5 additions & 5 deletions compiler/babelcmd.nim
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import parseutils, strutils, strtabs, os, options, msgs, lists

proc addPath*(path: string, info: TLineInfo) =
if not contains(options.searchPaths, path):
lists.PrependStr(options.searchPaths, path)
lists.prependStr(options.searchPaths, path)

proc versionSplitPos(s: string): int =
result = s.len-2
Expand Down Expand Up @@ -45,9 +45,9 @@ proc `<.`(a, b: string): bool =

proc addPackage(packages: PStringTable, p: string) =
let x = versionSplitPos(p)
let name = p.subStr(0, x-1)
let name = p.substr(0, x-1)
if x < p.len:
let version = p.subStr(x+1)
let version = p.substr(x+1)
if packages[name] <. version:
packages[name] = version
else:
Expand All @@ -60,8 +60,8 @@ iterator chosen(packages: PStringTable): string =

proc addBabelPath(p: string, info: TLineInfo) =
if not contains(options.searchPaths, p):
if gVerbosity >= 1: Message(info, hintPath, p)
lists.PrependStr(options.lazyPaths, p)
if gVerbosity >= 1: message(info, hintPath, p)
lists.prependStr(options.lazyPaths, p)

proc addPathWithNimFiles(p: string, info: TLineInfo) =
proc hasNimFile(dir: string): bool =
Expand Down
40 changes: 20 additions & 20 deletions compiler/bitsets.nim
Original file line number Diff line number Diff line change
Expand Up @@ -18,53 +18,53 @@ type
const
ElemSize* = sizeof(int8) * 8

proc BitSetInit*(b: var TBitSet, length: int)
proc BitSetUnion*(x: var TBitSet, y: TBitSet)
proc BitSetDiff*(x: var TBitSet, y: TBitSet)
proc BitSetSymDiff*(x: var TBitSet, y: TBitSet)
proc BitSetIntersect*(x: var TBitSet, y: TBitSet)
proc BitSetIncl*(x: var TBitSet, elem: BiggestInt)
proc BitSetExcl*(x: var TBitSet, elem: BiggestInt)
proc BitSetIn*(x: TBitSet, e: BiggestInt): bool
proc BitSetEquals*(x, y: TBitSet): bool
proc BitSetContains*(x, y: TBitSet): bool
proc bitSetInit*(b: var TBitSet, length: int)
proc bitSetUnion*(x: var TBitSet, y: TBitSet)
proc bitSetDiff*(x: var TBitSet, y: TBitSet)
proc bitSetSymDiff*(x: var TBitSet, y: TBitSet)
proc bitSetIntersect*(x: var TBitSet, y: TBitSet)
proc bitSetIncl*(x: var TBitSet, elem: BiggestInt)
proc bitSetExcl*(x: var TBitSet, elem: BiggestInt)
proc bitSetIn*(x: TBitSet, e: BiggestInt): bool
proc bitSetEquals*(x, y: TBitSet): bool
proc bitSetContains*(x, y: TBitSet): bool
# implementation

proc BitSetIn(x: TBitSet, e: BiggestInt): bool =
proc bitSetIn(x: TBitSet, e: BiggestInt): bool =
result = (x[int(e div ElemSize)] and toU8(int(1 shl (e mod ElemSize)))) !=
toU8(0)

proc BitSetIncl(x: var TBitSet, elem: BiggestInt) =
proc bitSetIncl(x: var TBitSet, elem: BiggestInt) =
assert(elem >= 0)
x[int(elem div ElemSize)] = x[int(elem div ElemSize)] or
toU8(int(1 shl (elem mod ElemSize)))

proc BitSetExcl(x: var TBitSet, elem: BiggestInt) =
proc bitSetExcl(x: var TBitSet, elem: BiggestInt) =
x[int(elem div ElemSize)] = x[int(elem div ElemSize)] and
not toU8(int(1 shl (elem mod ElemSize)))

proc BitSetInit(b: var TBitSet, length: int) =
proc bitSetInit(b: var TBitSet, length: int) =
newSeq(b, length)

proc BitSetUnion(x: var TBitSet, y: TBitSet) =
proc bitSetUnion(x: var TBitSet, y: TBitSet) =
for i in countup(0, high(x)): x[i] = x[i] or y[i]

proc BitSetDiff(x: var TBitSet, y: TBitSet) =
proc bitSetDiff(x: var TBitSet, y: TBitSet) =
for i in countup(0, high(x)): x[i] = x[i] and not y[i]

proc BitSetSymDiff(x: var TBitSet, y: TBitSet) =
proc bitSetSymDiff(x: var TBitSet, y: TBitSet) =
for i in countup(0, high(x)): x[i] = x[i] xor y[i]

proc BitSetIntersect(x: var TBitSet, y: TBitSet) =
proc bitSetIntersect(x: var TBitSet, y: TBitSet) =
for i in countup(0, high(x)): x[i] = x[i] and y[i]

proc BitSetEquals(x, y: TBitSet): bool =
proc bitSetEquals(x, y: TBitSet): bool =
for i in countup(0, high(x)):
if x[i] != y[i]:
return false
result = true

proc BitSetContains(x, y: TBitSet): bool =
proc bitSetContains(x, y: TBitSet): bool =
for i in countup(0, high(x)):
if (x[i] and not y[i]) != int8(0):
return false
Expand Down
27 changes: 21 additions & 6 deletions compiler/c2nim/c2nim.nim
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ c2nim - C to Nimrod source converter
Usage: c2nim [options] inputfile [options]
Options:
-o, --out:FILE set output filename
--cpp process C++ input file
--dynlib:SYMBOL import from dynlib: SYMBOL will be used for the import
--header:HEADER_FILE import from a HEADER_FILE (discouraged!)
--cdecl annotate procs with ``{.cdecl.}``
Expand All @@ -31,25 +32,38 @@ Options:
--skipinclude do not convert ``#include`` to ``import``
--typeprefixes generate ``T`` and ``P`` type prefixes
--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()
var stream = LLStreamOpen(infile, fmRead)
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
Expand All @@ -63,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)
Expand All @@ -74,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)
103 changes: 69 additions & 34 deletions compiler/c2nim/clex.nim
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@ type
pxParLe, pxBracketLe, pxCurlyLe, # this order is important
pxParRi, pxBracketRi, pxCurlyRi, # for macro argument parsing!
pxComma, pxSemiColon, pxColon,
pxAngleRi # '>' but determined to be the end of a
# template's angle bracket
TTokKinds* = set[TTokKind]

type
Expand All @@ -101,7 +103,7 @@ type
inDirective: bool

proc getTok*(L: var TLexer, tok: var TToken)
proc PrintTok*(tok: TToken)
proc printTok*(tok: TToken)
proc `$`*(tok: TToken): string
# implementation

Expand Down Expand Up @@ -136,7 +138,7 @@ proc lexMessagePos(L: var TLexer, msg: TMsgKind, pos: int, arg = "") =
var info = newLineInfo(L.fileIdx, L.linenumber, pos - L.lineStart)
msgs.GlobalError(info, msg, arg)

proc TokKindToStr*(k: TTokKind): string =
proc tokKindToStr*(k: TTokKind): string =
case k
of pxEof: result = "[EOF]"
of pxInvalid: result = "[invalid]"
Expand Down Expand Up @@ -202,15 +204,16 @@ proc TokKindToStr*(k: TTokKind): string =
of pxColon: result = ":"
of pxCurlyLe: result = "{"
of pxCurlyRi: result = "}"
of pxAngleRi: result = "> [end of template]"

proc `$`(tok: TToken): string =
case tok.xkind
of pxSymbol, pxInvalid, pxStarComment, pxLineComment, pxStrLit: result = tok.s
of pxIntLit, pxInt64Lit: result = $tok.iNumber
of pxFloatLit: result = $tok.fNumber
else: result = TokKindToStr(tok.xkind)
else: result = tokKindToStr(tok.xkind)

proc PrintTok(tok: TToken) =
proc printTok(tok: TToken) =
writeln(stdout, $tok)

proc matchUnderscoreChars(L: var TLexer, tok: var TToken, chars: TCharSet) =
Expand All @@ -220,12 +223,12 @@ proc matchUnderscoreChars(L: var TLexer, tok: var TToken, chars: TCharSet) =
while true:
if buf[pos] in chars:
add(tok.s, buf[pos])
Inc(pos)
inc(pos)
else:
break
if buf[pos] == '_':
add(tok.s, '_')
Inc(pos)
inc(pos)
L.bufPos = pos

proc isFloatLiteral(s: string): bool =
Expand All @@ -236,7 +239,7 @@ proc isFloatLiteral(s: string): bool =
proc getNumber2(L: var TLexer, tok: var TToken) =
var pos = L.bufpos + 2 # skip 0b
tok.base = base2
var xi: biggestInt = 0
var xi: BiggestInt = 0
var bits = 0
while true:
case L.buf[pos]
Expand All @@ -261,7 +264,7 @@ proc getNumber2(L: var TLexer, tok: var TToken) =
proc getNumber8(L: var TLexer, tok: var TToken) =
var pos = L.bufpos + 1 # skip 0
tok.base = base8
var xi: biggestInt = 0
var xi: BiggestInt = 0
var bits = 0
while true:
case L.buf[pos]
Expand All @@ -286,7 +289,7 @@ proc getNumber8(L: var TLexer, tok: var TToken) =
proc getNumber16(L: var TLexer, tok: var TToken) =
var pos = L.bufpos + 2 # skip 0x
tok.base = base16
var xi: biggestInt = 0
var xi: BiggestInt = 0
var bits = 0
while true:
case L.buf[pos]
Expand All @@ -312,19 +315,34 @@ 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)
tok.xkind = pxFloatLit
else:
tok.iNumber = ParseInt(tok.s)
tok.iNumber = parseInt(tok.s)
if (tok.iNumber < low(int32)) or (tok.iNumber > high(int32)):
tok.xkind = pxInt64Lit
else:
Expand All @@ -336,10 +354,10 @@ proc getNumber(L: var TLexer, tok: var TToken) =
# ignore type suffix:
while L.buf[L.bufpos] in {'A'..'Z', 'a'..'z'}: inc(L.bufpos)

proc HandleCRLF(L: var TLexer, pos: int): int =
proc handleCRLF(L: var TLexer, pos: int): int =
case L.buf[pos]
of CR: result = nimlexbase.HandleCR(L, pos)
of LF: result = nimlexbase.HandleLF(L, pos)
of CR: result = nimlexbase.handleCR(L, pos)
of LF: result = nimlexbase.handleLF(L, pos)
else: result = pos

proc escape(L: var TLexer, tok: var TToken, allowEmpty=false) =
Expand Down Expand Up @@ -379,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)

Expand All @@ -402,7 +437,7 @@ proc getString(L: var TLexer, tok: var TToken) =
while true:
case buf[pos]
of '\"':
Inc(pos)
inc(pos)
break
of CR:
pos = nimlexbase.HandleCR(L, pos)
Expand All @@ -424,7 +459,7 @@ proc getString(L: var TLexer, tok: var TToken) =
pos = L.bufpos
else:
add(tok.s, buf[pos])
Inc(pos)
inc(pos)
L.bufpos = pos
tok.xkind = pxStrLit

Expand All @@ -435,7 +470,7 @@ proc getSymbol(L: var TLexer, tok: var TToken) =
var c = buf[pos]
if c notin SymChars: break
add(tok.s, c)
Inc(pos)
inc(pos)
L.bufpos = pos
tok.xkind = pxSymbol

Expand Down Expand Up @@ -472,7 +507,7 @@ proc scanStarComment(L: var TLexer, tok: var TToken) =
while true:
case buf[pos]
of CR, LF:
pos = HandleCRLF(L, pos)
pos = handleCRLF(L, pos)
buf = L.buf
add(tok.s, "\n#")
# skip annoying stars as line prefix: (eg.
Expand Down Expand Up @@ -508,12 +543,12 @@ proc skip(L: var TLexer, tok: var TToken) =
if L.inDirective:
while buf[pos] in {' ', '\t'}: inc(pos)
if buf[pos] in {CR, LF}:
pos = HandleCRLF(L, pos)
pos = handleCRLF(L, pos)
buf = L.buf
of ' ', Tabulator:
Inc(pos) # newline is special:
inc(pos) # newline is special:
of CR, LF:
pos = HandleCRLF(L, pos)
pos = handleCRLF(L, pos)
buf = L.buf
if L.inDirective:
tok.xkind = pxNewLine
Expand Down Expand Up @@ -556,13 +591,13 @@ 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
of ';':
tok.xkind = pxSemicolon
Inc(L.bufpos)
inc(L.bufpos)
of '/':
if L.buf[L.bufpos + 1] == '/':
scanLineComment(L, tok)
Expand All @@ -577,9 +612,9 @@ proc getTok(L: var TLexer, tok: var TToken) =
inc(L.bufpos)
of ',':
tok.xkind = pxComma
Inc(L.bufpos)
inc(L.bufpos)
of '(':
Inc(L.bufpos)
inc(L.bufpos)
tok.xkind = pxParLe
of '*':
inc(L.bufpos)
Expand All @@ -589,13 +624,13 @@ proc getTok(L: var TLexer, tok: var TToken) =
else:
tok.xkind = pxStar
of ')':
Inc(L.bufpos)
inc(L.bufpos)
tok.xkind = pxParRi
of '[':
Inc(L.bufpos)
inc(L.bufpos)
tok.xkind = pxBracketLe
of ']':
Inc(L.bufpos)
inc(L.bufpos)
tok.xkind = pxBracketRi
of '.':
inc(L.bufpos)
Expand All @@ -605,10 +640,10 @@ proc getTok(L: var TLexer, tok: var TToken) =
else:
tok.xkind = pxDot
of '{':
Inc(L.bufpos)
inc(L.bufpos)
tok.xkind = pxCurlyLe
of '}':
Inc(L.bufpos)
inc(L.bufpos)
tok.xkind = pxCurlyRi
of '+':
inc(L.bufpos)
Expand Down Expand Up @@ -749,4 +784,4 @@ proc getTok(L: var TLexer, tok: var TToken) =
tok.s = $c
tok.xkind = pxInvalid
lexMessage(L, errInvalidToken, c & " (\\" & $(ord(c)) & ')')
Inc(L.bufpos)
inc(L.bufpos)
1,330 changes: 880 additions & 450 deletions compiler/c2nim/cparse.nim

Large diffs are not rendered by default.

20 changes: 10 additions & 10 deletions compiler/c2nim/cpp.nim
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ proc skipLine(p: var TParser) =
proc parseDefineBody(p: var TParser, tmplDef: PNode): string =
if p.tok.xkind == pxCurlyLe or
(p.tok.xkind == pxSymbol and (
declKeyword(p.tok.s) or stmtKeyword(p.tok.s))):
declKeyword(p, p.tok.s) or stmtKeyword(p.tok.s))):
addSon(tmplDef, statement(p))
result = "stmt"
elif p.tok.xkind in {pxLineComment, pxNewLine}:
Expand Down Expand Up @@ -103,7 +103,7 @@ proc parseDefBody(p: var TParser, m: var TMacro, params: seq[string]) =
m.body.add(tok)
of pxDirConc:
# just ignore this token: this implements token merging correctly
nil
discard
else:
m.body.add(p.tok)
# we do not want macro expansion here:
Expand Down Expand Up @@ -166,7 +166,7 @@ proc parseStmtList(p: var TParser): PNode =
of pxDirectiveParLe, pxDirective:
case p.tok.s
of "else", "endif", "elif": break
else: nil
else: discard
addSon(result, statement(p))

proc eatEndif(p: var TParser) =
Expand Down Expand Up @@ -226,7 +226,7 @@ proc skipUntilElifElseEndif(p: var TParser): TEndifMarker =

proc parseIfdef(p: var TParser): PNode =
getTok(p) # skip #ifdef
ExpectIdent(p)
expectIdent(p)
case p.tok.s
of "__cplusplus":
skipUntilEndif(p)
Expand All @@ -245,7 +245,7 @@ proc parseIfdef(p: var TParser): PNode =
proc parseIfndef(p: var TParser): PNode =
result = ast.emptyNode
getTok(p) # skip #ifndef
ExpectIdent(p)
expectIdent(p)
if p.tok.s == c2nimSymbol:
skipLine(p)
case skipUntilElifElseEndif(p)
Expand Down Expand Up @@ -282,11 +282,11 @@ proc parseIfDir(p: var TParser): PNode =
proc parsePegLit(p: var TParser): TPeg =
var col = getColumn(p.lex) + 2
getTok(p)
if p.tok.xkind != pxStrLit: ExpectIdent(p)
if p.tok.xkind != pxStrLit: expectIdent(p)
try:
result = parsePeg(
pattern = if p.tok.xkind == pxStrLit: p.tok.s else: escapePeg(p.tok.s),
filename = p.lex.fileIdx.ToFilename,
filename = p.lex.fileIdx.toFilename,
line = p.lex.linenumber,
col = col)
getTok(p)
Expand All @@ -295,7 +295,7 @@ proc parsePegLit(p: var TParser): TPeg =

proc parseMangleDir(p: var TParser) =
var pattern = parsePegLit(p)
if p.tok.xkind != pxStrLit: ExpectIdent(p)
if p.tok.xkind != pxStrLit: expectIdent(p)
p.options.mangleRules.add((pattern, p.tok.s))
getTok(p)
eatNewLine(p, nil)
Expand Down Expand Up @@ -323,10 +323,10 @@ proc parseDir(p: var TParser): PNode =
discard setOption(p.options, p.tok.s)
getTok(p)
eatNewLine(p, nil)
of "dynlib", "header", "prefix", "suffix":
of "dynlib", "header", "prefix", "suffix", "class":
var key = p.tok.s
getTok(p)
if p.tok.xkind != pxStrLit: ExpectIdent(p)
if p.tok.xkind != pxStrLit: expectIdent(p)
discard setOption(p.options, key, p.tok.s)
getTok(p)
eatNewLine(p, nil)
Expand Down
240 changes: 240 additions & 0 deletions compiler/c2nim/tests/matrix.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,240 @@
/////////////////////////////////////////////////////////////////////////////
// Name: wx/matrix.h
// Purpose: wxTransformMatrix class. NOT YET USED
// Author: Chris Breeze, Julian Smart
// Modified by: Klaas Holwerda
// Created: 01/02/97
// RCS-ID: $Id$
// Copyright: (c) Julian Smart, Chris Breeze
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////

#ifndef _WX_MATRIXH__
#define _WX_MATRIXH__

//! headerfiles="matrix.h wx/object.h"
#include "wx/object.h"
#include "wx/math.h"

//! codefiles="matrix.cpp"

// A simple 3x3 matrix. This may be replaced by a more general matrix
// class some day.
//
// Note: this is intended to be used in wxDC at some point to replace
// the current system of scaling/translation. It is not yet used.

#def WXDLLIMPEXP_CORE
#header "wxmatrix.h"

//:definition
// A 3x3 matrix to do 2D transformations.
// It can be used to map data to window coordinates,
// and also for manipulating your own data.
// For example drawing a picture (composed of several primitives)
// at a certain coordinate and angle within another parent picture.
// At all times m_isIdentity is set if the matrix itself is an Identity matrix.
// It is used where possible to optimize calculations.
class WXDLLIMPEXP_CORE wxTransformMatrix: public wxObject<string, string<ubyte>>
{
public:
wxTransformMatrix(void);
wxTransformMatrix(const wxTransformMatrix& mat);

~wxTransformMatrix(void);

//get the value in the matrix at col,row
//rows are horizontal (second index of m_matrix member)
//columns are vertical (first index of m_matrix member)
double GetValue(int col, int row) const;

//set the value in the matrix at col,row
//rows are horizontal (second index of m_matrix member)
//columns are vertical (first index of m_matrix member)
void SetValue(int col, int row, double value);

void operator = (const wxTransformMatrix& mat);
bool operator == (const wxTransformMatrix& mat) const;
bool operator != (const module::gah::wxTransformMatrix& mat) const;

//multiply every element by t
wxTransformMatrix& operator*=(const double& t);
//divide every element by t
wxTransformMatrix& operator/=(const double& t);
//add matrix m to this t
wxTransformMatrix& operator+=(const wxTransformMatrix& m);
//subtract matrix m from this
wxTransformMatrix& operator-=(const wxTransformMatrix& m);
//multiply matrix m with this
wxTransformMatrix& operator*=(const wxTransformMatrix& m);

// constant operators

//multiply every element by t and return result
wxTransformMatrix operator*(const double& t) const;
//divide this matrix by t and return result
wxTransformMatrix operator/(const double& t) const;
//add matrix m to this and return result
wxTransformMatrix operator+(const wxTransformMatrix& m) const;
//subtract matrix m from this and return result
wxTransformMatrix operator-(const wxTransformMatrix& m) const;
//multiply this by matrix m and return result
wxTransformMatrix operator*(const wxTransformMatrix& m) const;
wxTransformMatrix operator-() const;

//rows are horizontal (second index of m_matrix member)
//columns are vertical (first index of m_matrix member)
double& operator()(int col, int row);

//rows are horizontal (second index of m_matrix member)
//columns are vertical (first index of m_matrix member)
double operator()(int col, int row) const;

// Invert matrix
bool Invert(void);

// Make into identity matrix
bool Identity(void);

// Is the matrix the identity matrix?
// Only returns a flag, which is set whenever an operation
// is done.
inline bool IsIdentity(void) const { return m_isIdentity; }

// This does an actual check.
inline bool IsIdentity1(void) const ;

//Scale by scale (isotropic scaling i.e. the same in x and y):
//!ex:
//!code: | scale 0 0 |
//!code: matrix' = | 0 scale 0 | x matrix
//!code: | 0 0 scale |
bool Scale(double scale);

//Scale with center point and x/y scale
//
//!ex:
//!code: | xs 0 xc(1-xs) |
//!code: matrix' = | 0 ys yc(1-ys) | x matrix
//!code: | 0 0 1 |
wxTransformMatrix& Scale(const double &xs, const double &ys,const double &xc, const double &yc);

// mirror a matrix in x, y
//!ex:
//!code: | -1 0 0 |
//!code: matrix' = | 0 -1 0 | x matrix
//!code: | 0 0 1 |
wxTransformMatrix<float>& Mirror(bool x=true, bool y=false);
// Translate by dx, dy:
//!ex:
//!code: | 1 0 dx |
//!code: matrix' = | 0 1 dy | x matrix
//!code: | 0 0 1 |
bool Translate(double x, double y);

// Rotate clockwise by the given number of degrees:
//!ex:
//!code: | cos sin 0 |
//!code: matrix' = | -sin cos 0 | x matrix
//!code: | 0 0 1 |
bool Rotate(double angle);

//Rotate counter clockwise with point of rotation
//
//!ex:
//!code: | cos(r) -sin(r) x(1-cos(r))+y(sin(r)|
//!code: matrix' = | sin(r) cos(r) y(1-cos(r))-x(sin(r)| x matrix
//!code: | 0 0 1 |
wxTransformMatrix& Rotate(const double &r, const double &x, const double &y);

// Transform X value from logical to device
inline double TransformX(double x) const;

// Transform Y value from logical to device
inline double TransformY(double y) const;

// Transform a point from logical to device coordinates
bool TransformPoint(double x, double y, double& tx, double& ty) const;

// Transform a point from device to logical coordinates.
// Example of use:
// wxTransformMatrix mat = dc.GetTransformation();
// mat.Invert();
// mat.InverseTransformPoint(x, y, x1, y1);
// OR (shorthand:)
// dc.LogicalToDevice(x, y, x1, y1);
// The latter is slightly less efficient if we're doing several
// conversions, since the matrix is inverted several times.
// N.B. 'this' matrix is the inverse at this point
bool InverseTransformPoint(double x, double y, double& tx, double& ty) const;

double Get_scaleX();
double Get_scaleY();
double GetRotation();
void SetRotation(double rotation);


public:
double m_matrix[3][3];
bool m_isIdentity;
};


/*
Chris Breeze reported, that
some functions of wxTransformMatrix cannot work because it is not
known if he matrix has been inverted. Be careful when using it.
*/

// Transform X value from logical to device
// warning: this function can only be used for this purpose
// because no rotation is involved when mapping logical to device coordinates
// mirror and scaling for x and y will be part of the matrix
// if you have a matrix that is rotated, eg a shape containing a matrix to place
// it in the logical coordinate system, use TransformPoint
inline double wxTransformMatrix::TransformX(double x) const
{
//normally like this, but since no rotation is involved (only mirror and scale)
//we can do without Y -> m_matrix[1]{0] is -sin(rotation angle) and therefore zero
//(x * m_matrix[0][0] + y * m_matrix[1][0] + m_matrix[2][0]))
return (m_isIdentity ? x : (x * m_matrix[0][0] + m_matrix[2][0]));
}

// Transform Y value from logical to device
// warning: this function can only be used for this purpose
// because no rotation is involved when mapping logical to device coordinates
// mirror and scaling for x and y will be part of the matrix
// if you have a matrix that is rotated, eg a shape containing a matrix to place
// it in the logical coordinate system, use TransformPoint
inline double wxTransformMatrix::TransformY(double y) const
{
//normally like this, but since no rotation is involved (only mirror and scale)
//we can do without X -> m_matrix[0]{1] is sin(rotation angle) and therefore zero
//(x * m_matrix[0][1] + y * m_matrix[1][1] + m_matrix[2][1]))
return (m_isIdentity ? y : (y * m_matrix[1][1] + m_matrix[2][1]));
}


// Is the matrix the identity matrix?
// Each operation checks whether the result is still the identity matrix and sets a flag.
inline bool wxTransformMatrix::IsIdentity1(void) const
{
return
( wxIsSameDouble(m_matrix[0][0], 1.0) &&
wxIsSameDouble(m_matrix[1][1], 1.0) &&
wxIsSameDouble(m_matrix[2][2], 1.0) &&
wxIsSameDouble(m_matrix[1][0], 0.0) &&
wxIsSameDouble(m_matrix[2][0], 0.0) &&
wxIsSameDouble(m_matrix[0][1], 0.0) &&
wxIsSameDouble(m_matrix[2][1], 0.0) &&
wxIsSameDouble(m_matrix[0][2], 0.0) &&
wxIsSameDouble(m_matrix[1][2], 0.0) );
}

// Calculates the determinant of a 2 x 2 matrix
inline double wxCalculateDet(double a11, double a21, double a12, double a22)
{
return a11 * a22 - a12 * a21;
}

#endif // _WX_MATRIXH__
33 changes: 33 additions & 0 deletions compiler/c2nim/tests/vincent.c
Original file line number Diff line number Diff line change
@@ -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 changes: 3 additions & 0 deletions compiler/c2nim/tests/vincent.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
struct foo {
int x,y,z;
};
416 changes: 416 additions & 0 deletions compiler/canonicalizer.nim

Large diffs are not rendered by default.

16 changes: 10 additions & 6 deletions compiler/ccgcalls.nim
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ proc isInCurrentFrame(p: BProc, n: PNode): bool =
result = false
of nkObjUpConv, nkObjDownConv, nkCheckedFieldExpr:
result = isInCurrentFrame(p, n.sons[0])
else: nil
else: discard

proc openArrayLoc(p: BProc, n: PNode): PRope =
var a: TLoc
Expand All @@ -88,7 +88,7 @@ proc openArrayLoc(p: BProc, n: PNode): PRope =
result = ropef("$1->data, $1->$2", [a.rdLoc, lenField()])
of tyArray, tyArrayConstr:
result = ropef("$1, $2", [rdLoc(a), toRope(lengthOrd(a.t))])
else: InternalError("openArrayLoc: " & typeToString(a.t))
else: internalError("openArrayLoc: " & typeToString(a.t))

proc genArgStringToCString(p: BProc,
n: PNode): PRope {.inline.} =
Expand Down Expand Up @@ -146,7 +146,8 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
proc addComma(r: PRope): PRope =
result = if r == nil: r else: con(r, ~", ")

const CallPattern = "$1.ClEnv? $1.ClPrc($3$1.ClEnv) : (($4)($1.ClPrc))($2)"
const PatProc = "$1.ClEnv? $1.ClPrc($3$1.ClEnv):(($4)($1.ClPrc))($2)"
const PatIter = "$1.ClPrc($3$1.ClEnv)" # we know the env exists
var op: TLoc
initLocExpr(p, ri.sons[0], op)
var pl: PRope
Expand All @@ -164,9 +165,10 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
if i < length - 1: app(pl, ~", ")

template genCallPattern {.dirty.} =
lineF(p, cpsStmts, CallPattern & ";$n", op.r, pl, pl.addComma, rawProc)
lineF(p, cpsStmts, callPattern & ";$n", op.r, pl, pl.addComma, rawProc)

let rawProc = getRawProcType(p, typ)
let callPattern = if tfIterator in typ.flags: PatIter else: PatProc
if typ.sons[0] != nil:
if isInvalidReturnType(typ.sons[0]):
if sonsLen(ri) > 1: app(pl, ~", ")
Expand All @@ -190,7 +192,7 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
assert(d.t != nil) # generate an assignment to d:
var list: TLoc
initLoc(list, locCall, d.t, OnUnknown)
list.r = ropef(CallPattern, op.r, pl, pl.addComma, rawProc)
list.r = ropef(callPattern, op.r, pl, pl.addComma, rawProc)
genAssignment(p, d, list, {}) # no need for deep copying
else:
genCallPattern()
Expand Down Expand Up @@ -243,7 +245,7 @@ proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) =
for i in countup(3, length-1):
assert(sonsLen(typ) == sonsLen(typ.n))
if i >= sonsLen(typ):
InternalError(ri.info, "varargs for objective C method?")
internalError(ri.info, "varargs for objective C method?")
assert(typ.n.sons[i].kind == nkSym)
var param = typ.n.sons[i].sym
app(pl, ~" ")
Expand Down Expand Up @@ -290,6 +292,7 @@ proc genCall(p: BProc, e: PNode, d: var TLoc) =
genNamedParamCall(p, e, d)
else:
genPrefixCall(p, nil, e, d)
postStmtActions(p)
when false:
if d.s == onStack and containsGarbageCollectedRef(d.t): keepAlive(p, d)

Expand All @@ -303,6 +306,7 @@ proc genAsgnCall(p: BProc, le, ri: PNode, d: var TLoc) =
genNamedParamCall(p, ri, d)
else:
genPrefixCall(p, le, ri, d)
postStmtActions(p)
when false:
if d.s == onStack and containsGarbageCollectedRef(d.t): keepAlive(p, d)

413 changes: 236 additions & 177 deletions compiler/ccgexprs.nim

Large diffs are not rendered by default.

60 changes: 16 additions & 44 deletions compiler/ccgmerge.nim
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ proc genMergeInfo*(m: BModule): PRope =
s.add("labels:")
encodeVInt(m.labels, s)
s.add(" hasframe:")
encodeVInt(ord(m.FrameDeclared), s)
encodeVInt(ord(m.frameDeclared), s)
s.add(tnl)
s.add("*/")
result = s.toRope
Expand All @@ -119,8 +119,8 @@ proc skipWhite(L: var TBaseLexer) =
var pos = L.bufpos
while true:
case ^pos
of CR: pos = nimlexbase.HandleCR(L, pos)
of LF: pos = nimlexbase.HandleLF(L, pos)
of CR: pos = nimlexbase.handleCR(L, pos)
of LF: pos = nimlexbase.handleLF(L, pos)
of ' ': inc pos
else: break
L.bufpos = pos
Expand All @@ -129,8 +129,8 @@ proc skipUntilCmd(L: var TBaseLexer) =
var pos = L.bufpos
while true:
case ^pos
of CR: pos = nimlexbase.HandleCR(L, pos)
of LF: pos = nimlexbase.HandleLF(L, pos)
of CR: pos = nimlexbase.handleCR(L, pos)
of LF: pos = nimlexbase.handleLF(L, pos)
of '\0': break
of '/':
if ^(pos+1) == '*' and ^(pos+2) == '\t':
Expand All @@ -145,49 +145,22 @@ proc atEndMark(buf: cstring, pos: int): bool =
while s < NimMergeEndMark.len and buf[pos+s] == NimMergeEndMark[s]: inc s
result = s == NimMergeEndMark.len

when false:
proc readVerbatimSection(L: var TBaseLexer): PRope =
var pos = L.bufpos
var buf = L.buf
result = newMutableRope(30_000)
while true:
case buf[pos]
of CR:
pos = nimlexbase.HandleCR(L, pos)
buf = L.buf
result.data.add(tnl)
of LF:
pos = nimlexbase.HandleLF(L, pos)
buf = L.buf
result.data.add(tnl)
of '\0':
InternalError("ccgmerge: expected: " & NimMergeEndMark)
break
else:
if atEndMark(buf, pos):
inc pos, NimMergeEndMark.len
break
result.data.add(buf[pos])
inc pos
L.bufpos = pos
freezeMutableRope(result)

proc readVerbatimSection(L: var TBaseLexer): PRope =
var pos = L.bufpos
var buf = L.buf
var r = newStringOfCap(30_000)
while true:
case buf[pos]
of CR:
pos = nimlexbase.HandleCR(L, pos)
pos = nimlexbase.handleCR(L, pos)
buf = L.buf
r.add(tnl)
of LF:
pos = nimlexbase.HandleLF(L, pos)
pos = nimlexbase.handleLF(L, pos)
buf = L.buf
r.add(tnl)
of '\0':
InternalError("ccgmerge: expected: " & NimMergeEndMark)
internalError("ccgmerge: expected: " & NimMergeEndMark)
break
else:
if atEndMark(buf, pos):
Expand All @@ -208,7 +181,7 @@ proc readKey(L: var TBaseLexer, result: var string) =
if buf[pos] != ':': internalError("ccgmerge: ':' expected")
L.bufpos = pos + 1 # skip ':'

proc NewFakeType(id: int): PType =
proc newFakeType(id: int): PType =
new(result)
result.id = id

Expand All @@ -224,7 +197,7 @@ proc readTypeCache(L: var TBaseLexer, result: var TIdTable) =
# XXX little hack: we create a "fake" type object with the correct Id
# better would be to adapt the data structure to not even store the
# object as key, but only the Id
IdTablePut(result, newFakeType(key), value.toRope)
idTablePut(result, newFakeType(key), value.toRope)
inc L.bufpos

proc readIntSet(L: var TBaseLexer, result: var TIntSet) =
Expand All @@ -249,14 +222,14 @@ proc processMergeInfo(L: var TBaseLexer, m: BModule) =
of "declared": readIntSet(L, m.declaredThings)
of "typeInfo": readIntSet(L, m.typeInfoMarker)
of "labels": m.labels = decodeVInt(L.buf, L.bufpos)
of "hasframe": m.FrameDeclared = decodeVInt(L.buf, L.bufpos) != 0
else: InternalError("ccgmerge: unkown key: " & k)
of "hasframe": m.frameDeclared = decodeVInt(L.buf, L.bufpos) != 0
else: internalError("ccgmerge: unkown key: " & k)

when not defined(nimhygiene):
{.pragma: inject.}

template withCFile(cfilename: string, body: stmt) {.immediate.} =
var s = LLStreamOpen(cfilename, fmRead)
var s = llStreamOpen(cfilename, fmRead)
if s == nil: return
var L {.inject.}: TBaseLexer
openBaseLexer(L, s)
Expand Down Expand Up @@ -285,7 +258,7 @@ proc readMergeSections(cfilename: string, m: var TMergeSections) =
withCFile(cfilename):
readKey(L, k)
if k == "NIM_merge_INFO":
nil
discard
elif ^L.bufpos == '*' and ^(L.bufpos+1) == '/':
inc(L.bufpos, 2)
# read back into section
Expand All @@ -300,9 +273,9 @@ proc readMergeSections(cfilename: string, m: var TMergeSections) =
if sectionB >= 0 and sectionB <= high(TCProcSection).int:
m.p[TCProcSection(sectionB)] = verbatim
else:
InternalError("ccgmerge: unknown section: " & k)
internalError("ccgmerge: unknown section: " & k)
else:
InternalError("ccgmerge: '*/' expected")
internalError("ccgmerge: '*/' expected")

proc mergeRequired*(m: BModule): bool =
for i in cfsHeaders..cfsProcs:
Expand All @@ -323,4 +296,3 @@ proc mergeFiles*(cfilename: string, m: BModule) =
m.s[i] = con(old.f[i], m.s[i])
for i in low(TCProcSection)..high(TCProcSection):
m.initProc.s(i) = con(old.p[i], m.initProc.s(i))

279 changes: 204 additions & 75 deletions compiler/ccgstmts.nim

Large diffs are not rendered by default.

10 changes: 5 additions & 5 deletions compiler/ccgthreadvars.nim
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@

# included from cgen.nim

proc emulatedThreadVars(): bool {.inline.} =
proc emulatedThreadVars(): bool =
result = {optThreads, optTlsEmulation} <= gGlobalOptions

proc AccessThreadLocalVar(p: BProc, s: PSym) =
if emulatedThreadVars() and not p.ThreadVarAccessed:
p.ThreadVarAccessed = true
proc accessThreadLocalVar(p: BProc, s: PSym) =
if emulatedThreadVars() and not p.threadVarAccessed:
p.threadVarAccessed = true
p.module.usesThreadVars = true
appf(p.procSec(cpsLocals), "\tNimThreadVars* NimTV;$n")
app(p.procSec(cpsInit),
Expand Down Expand Up @@ -55,7 +55,7 @@ proc generateThreadLocalStorage(m: BModule) =
for t in items(nimtvDeps): discard getTypeDesc(m, t)
appf(m.s[cfsSeqTypes], "typedef struct {$1} NimThreadVars;$n", [nimtv])

proc GenerateThreadVarsSize(m: BModule) =
proc generateThreadVarsSize(m: BModule) =
if nimtv != nil:
app(m.s[cfsProcs],
"NI NimThreadVarsSize(){return (NI)sizeof(NimThreadVars);}" & tnl)
Expand Down
16 changes: 10 additions & 6 deletions compiler/ccgtrav.nim
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ proc genTraverseProc(c: var TTraversalClosure, accessor: PRope, n: PNode) =
for i in countup(0, sonsLen(n) - 1):
genTraverseProc(c, accessor, n.sons[i])
of nkRecCase:
if (n.sons[0].kind != nkSym): InternalError(n.info, "genTraverseProc")
if (n.sons[0].kind != nkSym): internalError(n.info, "genTraverseProc")
var p = c.p
let disc = n.sons[0].sym
lineF(p, cpsStmts, "switch ($1.$2) {$n", accessor, disc.loc.r)
Expand Down Expand Up @@ -74,7 +74,7 @@ proc genTraverseProc(c: var TTraversalClosure, accessor: PRope, typ: PType) =
genTraverseProc(c, accessor.parentObj, typ.sons[i])
if typ.n != nil: genTraverseProc(c, accessor, typ.n)
of tyTuple:
let typ = GetUniqueType(typ)
let typ = getUniqueType(typ)
for i in countup(0, sonsLen(typ) - 1):
genTraverseProc(c, rfmt(nil, "$1.Field$2", accessor, i.toRope), typ.sons[i])
of tyRef, tyString, tySequence:
Expand All @@ -83,7 +83,7 @@ proc genTraverseProc(c: var TTraversalClosure, accessor: PRope, typ: PType) =
if typ.callConv == ccClosure:
lineCg(p, cpsStmts, c.visitorFrmt, rfmt(nil, "$1.ClEnv", accessor))
else:
nil
discard

proc genTraverseProcSeq(c: var TTraversalClosure, accessor: PRope, typ: PType) =
var p = c.p
Expand Down Expand Up @@ -111,7 +111,7 @@ proc genTraverseProc(m: BModule, typ: PType, reason: TTypeInfoReason): PRope =
lineF(p, cpsInit, "a = ($1)p;$n", t)

c.p = p
assert typ.kind != tyTypedesc
assert typ.kind != tyTypeDesc
if typ.kind == tySequence:
genTraverseProcSeq(c, "a".toRope, typ)
else:
Expand All @@ -127,18 +127,22 @@ proc genTraverseProc(m: BModule, typ: PType, reason: TTypeInfoReason): PRope =
m.s[cfsProcHeaders].appf("$1;$n", header)
m.s[cfsProcs].app(generatedProc)


proc genTraverseProcForGlobal(m: BModule, s: PSym): PRope =
discard genTypeInfo(m, s.loc.t)

var c: TTraversalClosure
var p = newProc(nil, m)
var sLoc = s.loc.r
result = getGlobalTempName()

if sfThread in s.flags and emulatedThreadVars():
accessThreadLocalVar(p, s)
sLoc = con("NimTV->", sLoc)

c.visitorFrmt = "#nimGCvisit((void*)$1, 0);$n"
c.p = p
let header = ropef("N_NIMCALL(void, $1)()", result)
genTraverseProc(c, s.loc.r, s.loc.t)
genTraverseProc(c, sLoc, s.loc.t)

let generatedProc = ropef("$1 {$n$2$3$4}$n",
[header, p.s(cpsLocals), p.s(cpsInit), p.s(cpsStmts)])
Expand Down
192 changes: 110 additions & 82 deletions compiler/ccgtypes.nim

Large diffs are not rendered by default.

53 changes: 26 additions & 27 deletions compiler/ccgutils.nim
Original file line number Diff line number Diff line change
Expand Up @@ -22,19 +22,19 @@ proc getPragmaStmt*(n: PNode, w: TSpecialWord): PNode =
of nkPragma:
for i in 0 .. < n.len:
if whichPragma(n[i]) == w: return n[i]
else: nil
else: discard

proc stmtsContainPragma*(n: PNode, w: TSpecialWord): bool =
result = getPragmaStmt(n, w) != nil

proc hashString*(s: string): biggestInt =
proc hashString*(s: string): BiggestInt =
# has to be the same algorithm as system.hashString!
if CPU[targetCPU].bit == 64:
# we have to use the same bitwidth
# as the target CPU
var b = 0'i64
for i in countup(0, len(s) - 1):
b = b +% Ord(s[i])
b = b +% ord(s[i])
b = b +% `shl`(b, 10)
b = b xor `shr`(b, 6)
b = b +% `shl`(b, 3)
Expand All @@ -44,7 +44,7 @@ proc hashString*(s: string): biggestInt =
else:
var a = 0'i32
for i in countup(0, len(s) - 1):
a = a +% Ord(s[i]).int32
a = a +% ord(s[i]).int32
a = a +% `shl`(a, 10'i32)
a = a xor `shr`(a, 6'i32)
a = a +% `shl`(a, 3'i32)
Expand All @@ -57,7 +57,7 @@ var
gCanonicalTypes: array[TTypeKind, PType]

proc initTypeTables() =
for i in countup(low(TTypeKind), high(TTypeKind)): InitIdTable(gTypeTable[i])
for i in countup(low(TTypeKind), high(TTypeKind)): initIdTable(gTypeTable[i])

proc resetCaches* =
## XXX: fix that more properly
Expand All @@ -70,7 +70,7 @@ when false:
for i in countup(low(TTypeKind), high(TTypeKind)):
echo i, " ", gTypeTable[i].counter

proc GetUniqueType*(key: PType): PType =
proc getUniqueType*(key: PType): PType =
# this is a hotspot in the compiler!
if key == nil: return
var k = key.kind
Expand All @@ -86,12 +86,12 @@ proc GetUniqueType*(key: PType): PType =
if result == nil:
gCanonicalTypes[k] = key
result = key
of tyTypeDesc, tyTypeClass:
InternalError("value expected, but got a type")
of tyGenericParam:
InternalError("GetUniqueType")
of tyGenericInst, tyDistinct, tyOrdinal, tyMutable, tyConst, tyIter:
result = GetUniqueType(lastSon(key))
of tyTypeDesc, tyTypeClasses, tyGenericParam,
tyFromExpr, tyFieldAccessor:
internalError("GetUniqueType")
of tyGenericInst, tyDistinct, tyOrdinal, tyMutable,
tyConst, tyIter, tyStatic:
result = getUniqueType(lastSon(key))
of tyArrayConstr, tyGenericInvokation, tyGenericBody,
tyOpenArray, tyArray, tySet, tyRange, tyTuple,
tyPtr, tyRef, tySequence, tyForward, tyVarargs, tyProxy, tyVar:
Expand All @@ -102,51 +102,50 @@ proc GetUniqueType*(key: PType): PType =

# we have to do a slow linear search because types may need
# to be compared by their structure:
if IdTableHasObjectAsKey(gTypeTable[k], key): return key
if idTableHasObjectAsKey(gTypeTable[k], key): return key
for h in countup(0, high(gTypeTable[k].data)):
var t = PType(gTypeTable[k].data[h].key)
if t != nil and sameBackendType(t, key):
return t
IdTablePut(gTypeTable[k], key, key)
idTablePut(gTypeTable[k], key, key)
result = key
of tyObject:
if tfFromGeneric notin key.flags:
# fast case; lookup per id suffices:
result = PType(IdTableGet(gTypeTable[k], key))
result = PType(idTableGet(gTypeTable[k], key))
if result == nil:
IdTablePut(gTypeTable[k], key, key)
idTablePut(gTypeTable[k], key, key)
result = key
else:
# ugly slow case: need to compare by structure
if IdTableHasObjectAsKey(gTypeTable[k], key): return key
if idTableHasObjectAsKey(gTypeTable[k], key): return key
for h in countup(0, high(gTypeTable[k].data)):
var t = PType(gTypeTable[k].data[h].key)
if t != nil and sameType(t, key):
return t
IdTablePut(gTypeTable[k], key, key)
idTablePut(gTypeTable[k], key, key)
result = key
of tyEnum:
result = PType(IdTableGet(gTypeTable[k], key))
result = PType(idTableGet(gTypeTable[k], key))
if result == nil:
IdTablePut(gTypeTable[k], key, key)
idTablePut(gTypeTable[k], key, key)
result = key
of tyProc:
# tyVar is not 100% correct, but would speeds things up a little:
if key.callConv != ccClosure:
result = key
else:
# ugh, we need the canon here:
if IdTableHasObjectAsKey(gTypeTable[k], key): return key
if idTableHasObjectAsKey(gTypeTable[k], key): return key
for h in countup(0, high(gTypeTable[k].data)):
var t = PType(gTypeTable[k].data[h].key)
if t != nil and sameBackendType(t, key):
return t
IdTablePut(gTypeTable[k], key, key)
idTablePut(gTypeTable[k], key, key)
result = key

proc TableGetType*(tab: TIdTable, key: PType): PObject =
proc tableGetType*(tab: TIdTable, key: PType): PObject =
# returns nil if we need to declare this type
result = IdTableGet(tab, key)
result = idTableGet(tab, key)
if (result == nil) and (tab.counter > 0):
# we have to do a slow linear search because types may need
# to be compared by their structure:
Expand All @@ -169,7 +168,7 @@ proc makeLLVMString*(s: string): PRope =
for i in countup(0, len(s) - 1):
if (i + 1) mod MaxLineLength == 0:
app(result, toRope(res))
setlen(res, 0)
setLen(res, 0)
case s[i]
of '\0'..'\x1F', '\x80'..'\xFF', '\"', '\\':
add(res, '\\')
Expand All @@ -178,4 +177,4 @@ proc makeLLVMString*(s: string): PRope =
add(res, "\\00\"")
app(result, toRope(res))

InitTypeTables()
initTypeTables()
431 changes: 258 additions & 173 deletions compiler/cgen.nim

Large diffs are not rendered by default.

34 changes: 20 additions & 14 deletions compiler/cgendata.nim
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ type
ctInt, ctInt8, ctInt16, ctInt32, ctInt64,
ctFloat, ctFloat32, ctFloat64, ctFloat128,
ctUInt, ctUInt8, ctUInt16, ctUInt32, ctUInt64,
ctArray, ctStruct, ctPtr, ctNimStr, ctNimSeq, ctProc, ctCString
ctArray, ctPtrToArray, ctStruct, ctPtr, ctNimStr, ctNimSeq, ctProc,
ctCString
TCFileSections* = array[TCFileSection, PRope] # represents a generated C file
TCProcSection* = enum # the sections a generated C proc consists of
cpsLocals, # section of local variables for C proc
Expand All @@ -57,17 +58,20 @@ type
sections*: TCProcSections # the code beloging
isLoop*: bool # whether block is a loop
nestedTryStmts*: int16 # how many try statements is it nested into
nestedExceptStmts*: int16 # how many except statements is it nested into
frameLen*: int16

TCProc{.final.} = object # represents C proc that is currently generated
prc*: PSym # the Nimrod proc that this C proc belongs to
BeforeRetNeeded*: bool # true iff 'BeforeRet' label for proc is needed
ThreadVarAccessed*: bool # true if the proc already accessed some threadvar
nestedTryStmts*: seq[PNode] # in how many nested try statements we are
# (the vars must be volatile then)
beforeRetNeeded*: bool # true iff 'BeforeRet' label for proc is needed
threadVarAccessed*: bool # true if the proc already accessed some threadvar
nestedTryStmts*: seq[PNode] # in how many nested try statements we are
# (the vars must be volatile then)
inExceptBlock*: int # are we currently inside an except block?
# leaving such scopes by raise or by return must
# execute any applicable finally blocks
finallySafePoints*: seq[PRope] # For correctly cleaning up exceptions when
# using return in finally statements
labels*: Natural # for generating unique labels in the C proc
blocks*: seq[TBlock] # nested blocks
breakIdx*: int # the block that will be exited
Expand All @@ -78,19 +82,20 @@ type
maxFrameLen*: int # max length of frame descriptor
module*: BModule # used to prevent excessive parameter passing
withinLoop*: int # > 0 if we are within a loop
gcFrameId*: natural # for the GC stack marking
gcFrameId*: Natural # for the GC stack marking
gcFrameType*: PRope # the struct {} we put the GC markers into

TTypeSeq* = seq[PType]
TCGen = object of TPassContext # represents a C source file
module*: PSym
filename*: string
s*: TCFileSections # sections of the C file
PreventStackTrace*: bool # true if stack traces need to be prevented
preventStackTrace*: bool # true if stack traces need to be prevented
usesThreadVars*: bool # true if the module uses a thread var
FrameDeclared*: bool # hack for ROD support so that we don't declare
frameDeclared*: bool # hack for ROD support so that we don't declare
# a frame var twice in an init proc
isHeaderFile*: bool # C source file is the header file
includesStringh*: bool # C source file already includes ``<string.h>``
cfilename*: string # filename of the module (including path,
# without extension)
typeCache*: TIdTable # cache the generated types
Expand All @@ -100,21 +105,21 @@ type
headerFiles*: TLinkedList # needed headers to include
typeInfoMarker*: TIntSet # needed for generating type information
initProc*: BProc # code for init procedure
postInitProc*: BProc # code to be executed after the init proc
preInitProc*: BProc # code executed before the init proc
# used for initialization code for
# .global. variables
# (or instantiated generic variables)
typeStack*: TTypeSeq # used for type generation
dataCache*: TNodeTable
forwardedProcs*: TSymSeq # keep forwarded procs here
typeNodes*, nimTypes*: int # used for type info generation
typeNodesName*, nimTypesName*: PRope # used for type info generation
labels*: natural # for generating unique module-scope names
labels*: Natural # for generating unique module-scope names
extensionLoaders*: array['0'..'9', PRope] # special procs for the
# OpenGL wrapper
injectStmt*: PRope

var
mainModProcs*, mainModInit*, mainDatInit*: PRope # parts of the main module
mainModProcs*, mainModInit*, otherModsInit*, mainDatInit*: PRope
# varuious parts of the main module
gMapping*: PRope # the generated mapping file (if requested)
gModules*: seq[BModule] = @[] # list of all compiled modules
gForwardedProcsCounter*: int = 0
Expand All @@ -139,8 +144,9 @@ proc newProc*(prc: PSym, module: BModule): BProc =
else: result.options = gOptions
newSeq(result.blocks, 1)
result.nestedTryStmts = @[]
result.finallySafePoints = @[]

iterator cgenModules*: var BModule =
iterator cgenModules*: BModule =
for i in 0..high(gModules):
# ultimately, we are iterating over the file ids here.
# some "files" won't have an associated cgen module (like stdin)
Expand Down
28 changes: 14 additions & 14 deletions compiler/cgmeth.nim
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,16 @@ proc genConv(n: PNode, d: PType, downcast: bool): PNode =
var source = skipTypes(n.typ, abstractPtrs)
if (source.kind == tyObject) and (dest.kind == tyObject):
var diff = inheritanceDiff(dest, source)
if diff == high(int): InternalError(n.info, "cgmeth.genConv")
if diff == high(int): internalError(n.info, "cgmeth.genConv")
if diff < 0:
result = newNodeIT(nkObjUpConv, n.info, d)
addSon(result, n)
if downCast: InternalError(n.info, "cgmeth.genConv: no upcast allowed")
if downcast: internalError(n.info, "cgmeth.genConv: no upcast allowed")
elif diff > 0:
result = newNodeIT(nkObjDownConv, n.info, d)
addSon(result, n)
if not downCast:
InternalError(n.info, "cgmeth.genConv: no downcast allowed")
if not downcast:
internalError(n.info, "cgmeth.genConv: no downcast allowed")
else:
result = n
else:
Expand Down Expand Up @@ -59,14 +59,14 @@ proc sameMethodBucket(a, b: PSym): bool =
aa = skipTypes(aa, {tyGenericInst})
bb = skipTypes(bb, {tyGenericInst})
if (aa.kind == bb.kind) and (aa.kind in {tyVar, tyPtr, tyRef}):
aa = aa.sons[0]
bb = bb.sons[0]
aa = aa.lastSon
bb = bb.lastSon
else:
break
if sameType(aa, bb) or
(aa.kind == tyObject) and (bb.kind == tyObject) and
(inheritanceDiff(bb, aa) < 0):
nil
discard
else:
return
result = true
Expand Down Expand Up @@ -112,12 +112,12 @@ proc relevantCol(methods: TSymSeq, col: int): bool =
if t.kind == tyObject:
for i in countup(1, high(methods)):
let t2 = skipTypes(methods[i].typ.sons[col], skipPtrs)
if not SameType(t2, t):
if not sameType(t2, t):
return true

proc cmpSignatures(a, b: PSym, relevantCols: TIntSet): int =
for col in countup(1, sonsLen(a.typ) - 1):
if Contains(relevantCols, col):
if contains(relevantCols, col):
var aa = skipTypes(a.typ.sons[col], skipPtrs)
var bb = skipTypes(b.typ.sons[col], skipPtrs)
var d = inheritanceDiff(aa, bb)
Expand All @@ -126,14 +126,14 @@ proc cmpSignatures(a, b: PSym, relevantCols: TIntSet): int =

proc sortBucket(a: var TSymSeq, relevantCols: TIntSet) =
# we use shellsort here; fast and simple
var N = len(a)
var n = len(a)
var h = 1
while true:
h = 3 * h + 1
if h > N: break
if h > n: break
while true:
h = h div 3
for i in countup(h, N - 1):
for i in countup(h, n - 1):
var v = a[i]
var j = i
while cmpSignatures(a[j - h], v, relevantCols) >= 0:
Expand All @@ -154,7 +154,7 @@ proc genDispatcher(methods: TSymSeq, relevantCols: TIntSet): PSym =
var curr = methods[meth] # generate condition:
var cond: PNode = nil
for col in countup(1, paramLen - 1):
if Contains(relevantCols, col):
if contains(relevantCols, col):
var isn = newNodeIT(nkCall, base.info, getSysType(tyBool))
addSon(isn, newSymNode(iss))
addSon(isn, newSymNode(base.typ.n.sons[col].sym))
Expand Down Expand Up @@ -195,7 +195,7 @@ proc generateMethodDispatchers*(): PNode =
for bucket in countup(0, len(gMethods) - 1):
var relevantCols = initIntSet()
for col in countup(1, sonsLen(gMethods[bucket][0].typ) - 1):
if relevantCol(gMethods[bucket], col): Incl(relevantCols, col)
if relevantCol(gMethods[bucket], col): incl(relevantCols, col)
sortBucket(gMethods[bucket], relevantCols)
addSon(result, newSymNode(genDispatcher(gMethods[bucket], relevantCols)))

49 changes: 0 additions & 49 deletions compiler/charsets.nim

This file was deleted.

219 changes: 116 additions & 103 deletions compiler/commands.nim

Large diffs are not rendered by default.

129 changes: 59 additions & 70 deletions compiler/condsyms.nim
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#
#
# The Nimrod Compiler
# (c) Copyright 2012 Andreas Rumpf
# (c) Copyright 2014 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
Expand All @@ -10,93 +10,82 @@
# This module handles the conditional symbols.

import
ast, astalgo, hashes, platform, strutils, idents
strtabs, platform, strutils, idents

var gSymbols*: TStrTable
# We need to use a PStringTable here as defined symbols are always guaranteed
# to be style insensitive. Otherwise hell would break lose.
var gSymbols: PStringTable

proc DefineSymbol*(symbol: string) =
var i = getIdent(symbol)
var sym = StrTableGet(gSymbols, i)
if sym == nil:
new(sym) # circumvent the ID mechanism
sym.kind = skConditional
sym.name = i
StrTableAdd(gSymbols, sym)
sym.position = 1
proc defineSymbol*(symbol: string) =
gSymbols[symbol] = "true"

proc UndefSymbol*(symbol: string) =
var sym = StrTableGet(gSymbols, getIdent(symbol))
if sym != nil: sym.position = 0

proc isDefined*(symbol: PIdent): bool =
var sym = StrTableGet(gSymbols, symbol)
result = sym != nil and sym.position == 1
proc undefSymbol*(symbol: string) =
gSymbols[symbol] = "false"

proc isDefined*(symbol: string): bool =
result = isDefined(getIdent(symbol))
if gSymbols.hasKey(symbol):
result = gSymbols[symbol] == "true"

proc isDefined*(symbol: PIdent): bool = isDefined(symbol.s)

iterator definedSymbolNames*: string =
var it: TTabIter
var s = InitTabIter(it, gSymbols)
while s != nil:
if s.position == 1: yield s.name.s
s = nextIter(it, gSymbols)
for key, val in pairs(gSymbols):
if val == "true": yield key

proc countDefinedSymbols*(): int =
var it: TTabIter
var s = InitTabIter(it, gSymbols)
result = 0
while s != nil:
if s.position == 1: inc(result)
s = nextIter(it, gSymbols)
for key, val in pairs(gSymbols):
if val == "true": inc(result)

proc InitDefines*() =
initStrTable(gSymbols)
DefineSymbol("nimrod") # 'nimrod' is always defined
proc initDefines*() =
gSymbols = newStringTable(modeStyleInsensitive)
defineSymbol("nimrod") # 'nimrod' is always defined
# for bootstrapping purposes and old code:
DefineSymbol("nimhygiene")
DefineSymbol("niminheritable")
DefineSymbol("nimmixin")
DefineSymbol("nimeffects")
DefineSymbol("nimbabel")
defineSymbol("nimhygiene")
defineSymbol("niminheritable")
defineSymbol("nimmixin")
defineSymbol("nimeffects")
defineSymbol("nimbabel")
defineSymbol("nimcomputedgoto")
defineSymbol("nimunion")
defineSymbol("nimnewshared")
defineSymbol("nimrequiresnimframe")

# add platform specific symbols:
case targetCPU
of cpuI386: DefineSymbol("x86")
of cpuIa64: DefineSymbol("itanium")
of cpuAmd64: DefineSymbol("x8664")
else: nil
of cpuI386: defineSymbol("x86")
of cpuIa64: defineSymbol("itanium")
of cpuAmd64: defineSymbol("x8664")
else: discard
case targetOS
of osDOS:
DefineSymbol("msdos")
of osDos:
defineSymbol("msdos")
of osWindows:
DefineSymbol("mswindows")
DefineSymbol("win32")
of osLinux, osMorphOS, osSkyOS, osIrix, osPalmOS, osQNX, osAtari, osAix,
defineSymbol("mswindows")
defineSymbol("win32")
of osLinux, osMorphos, osSkyos, osIrix, osPalmos, osQnx, osAtari, osAix,
osHaiku:
# these are all 'unix-like'
DefineSymbol("unix")
DefineSymbol("posix")
defineSymbol("unix")
defineSymbol("posix")
of osSolaris:
DefineSymbol("sunos")
DefineSymbol("unix")
DefineSymbol("posix")
of osNetBSD, osFreeBSD, osOpenBSD:
DefineSymbol("unix")
DefineSymbol("bsd")
DefineSymbol("posix")
of osMacOS:
DefineSymbol("macintosh")
of osMacOSX:
DefineSymbol("macintosh")
DefineSymbol("unix")
DefineSymbol("posix")
else: nil
DefineSymbol("cpu" & $cpu[targetCPU].bit)
DefineSymbol(normalize(endianToStr[cpu[targetCPU].endian]))
DefineSymbol(cpu[targetCPU].name)
DefineSymbol(platform.os[targetOS].name)
defineSymbol("sunos")
defineSymbol("unix")
defineSymbol("posix")
of osNetbsd, osFreebsd, osOpenbsd:
defineSymbol("unix")
defineSymbol("bsd")
defineSymbol("posix")
of osMacos:
defineSymbol("macintosh")
of osMacosx:
defineSymbol("macintosh")
defineSymbol("unix")
defineSymbol("posix")
else: discard
defineSymbol("cpu" & $CPU[targetCPU].bit)
defineSymbol(normalize(EndianToStr[CPU[targetCPU].endian]))
defineSymbol(CPU[targetCPU].name)
defineSymbol(platform.OS[targetOS].name)
if platform.OS[targetOS].props.contains(ospLacksThreadVars):
DefineSymbol("emulatedthreadvars")


defineSymbol("emulatedthreadvars")
14 changes: 7 additions & 7 deletions compiler/crc.nim
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ const
InitAdler32* = int32(1)

proc updateCrc32*(val: int8, crc: TCrc32): TCrc32 {.inline.}
proc updateCrc32*(val: Char, crc: TCrc32): TCrc32 {.inline.}
proc crcFromBuf*(buf: Pointer, length: int): TCrc32
proc updateCrc32*(val: char, crc: TCrc32): TCrc32 {.inline.}
proc crcFromBuf*(buf: pointer, length: int): TCrc32
proc strCrc32*(s: string): TCrc32
proc crcFromFile*(filename: string): TCrc32
proc updateAdler32*(adler: int32, buf: pointer, length: int): int32
Expand Down Expand Up @@ -75,10 +75,10 @@ const
755167117]

proc updateCrc32(val: int8, crc: TCrc32): TCrc32 =
result = TCrc32(crc32Table[(int(crc) xor (int(val) and 0x000000FF)) and
result = TCrc32(crc32table[(int(crc) xor (int(val) and 0x000000FF)) and
0x000000FF]) xor (crc shr TCrc32(8))

proc updateCrc32(val: Char, crc: TCrc32): TCrc32 =
proc updateCrc32(val: char, crc: TCrc32): TCrc32 =
result = updateCrc32(toU8(ord(val)), crc)

proc strCrc32(s: string): TCrc32 =
Expand All @@ -93,7 +93,7 @@ type
TByteArray = array[0..10000000, int8]
PByteArray = ref TByteArray

proc crcFromBuf(buf: Pointer, length: int): TCrc32 =
proc crcFromBuf(buf: pointer, length: int): TCrc32 =
var p = cast[PByteArray](buf)
result = InitCrc32
for i in countup(0, length - 1): result = updateCrc32(p[i], result)
Expand All @@ -102,11 +102,11 @@ proc crcFromFile(filename: string): TCrc32 =
const
bufSize = 8000 # don't use 8K for the memory allocator!
var
bin: tfile
bin: TFile
result = InitCrc32
if not open(bin, filename):
return # not equal if file does not exist
var buf = alloc(BufSize)
var buf = alloc(bufSize)
var p = cast[PByteArray](buf)
while true:
var readBytes = readBuffer(bin, buf, bufSize)
Expand Down
4 changes: 2 additions & 2 deletions compiler/depends.nim
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,11 @@ proc addDotDependency(c: PPassContext, n: PNode): PNode =
of nkStmtList, nkBlockStmt, nkStmtListExpr, nkBlockExpr:
for i in countup(0, sonsLen(n) - 1): discard addDotDependency(c, n.sons[i])
else:
nil
discard

proc generateDot(project: string) =
writeRope(ropef("digraph $1 {$n$2}$n", [
toRope(changeFileExt(extractFileName(project), "")), gDotGraph]),
toRope(changeFileExt(extractFilename(project), "")), gDotGraph]),
changeFileExt(project, "dot"))

proc myOpen(module: PSym): PPassContext =
Expand Down
494 changes: 361 additions & 133 deletions compiler/docgen.nim

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions compiler/docgen2.nim
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ proc close(p: PPassContext, n: PNode): PNode =
try:
generateIndex(g.doc)
except EIO:
nil
discard

proc processNode(c: PPassContext, n: PNode): PNode =
result = n
Expand All @@ -46,4 +46,4 @@ proc myOpen(module: PSym): PPassContext =
const docgen2Pass* = makePass(open = myOpen, process = processNode, close = close)

proc finishDoc2Pass*(project: string) =
nil
discard
146 changes: 99 additions & 47 deletions compiler/evalffi.nim
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
#
#
# The Nimrod Compiler
# (c) Copyright 2012 Andreas Rumpf
# (c) Copyright 2014 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#

## This file implements the FFI part of the evaluator for Nimrod code.

import ast, astalgo, ropes, types, options, tables, dynlib, libffi, msgs
import ast, astalgo, ropes, types, options, tables, dynlib, libffi, msgs, os

when defined(windows):
const libcDll = "msvcrt.dll"
Expand All @@ -20,23 +20,29 @@ type
TDllCache = tables.TTable[string, TLibHandle]
var
gDllCache = initTable[string, TLibHandle]()
gExeHandle = LoadLib()

when defined(windows):
var gExeHandle = loadLib(os.getAppFilename())
else:
var gExeHandle = loadLib()

proc getDll(cache: var TDllCache; dll: string; info: TLineInfo): pointer =
result = cache[dll]
if result.isNil:
var libs: seq[string] = @[]
libCandidates(dll, libs)
for c in libs:
result = LoadLib(c)
result = loadLib(c)
if not result.isNil: break
if result.isNil:
GlobalError(info, "cannot load: " & dll)
globalError(info, "cannot load: " & dll)
cache[dll] = result

const
nkPtrLit = nkIntLit # hopefully we can get rid of this hack soon

var myerrno {.importc: "errno", header: "<errno.h>".}: cint ## error variable

proc importcSymbol*(sym: PSym): PNode =
let name = ropeToStr(sym.loc.r)

Expand All @@ -47,21 +53,24 @@ proc importcSymbol*(sym: PSym): PNode =
of "stdin": result.intVal = cast[TAddress](system.stdin)
of "stdout": result.intVal = cast[TAddress](system.stdout)
of "stderr": result.intVal = cast[TAddress](system.stderr)
of "vmErrnoWrapper": result.intVal = cast[TAddress](myerrno)
else:
let lib = sym.annex
if lib != nil and lib.path.kind notin {nkStrLit..nkTripleStrLit}:
GlobalError(sym.info, "dynlib needs to be a string lit for the REPL")
globalError(sym.info, "dynlib needs to be a string lit for the REPL")
var theAddr: pointer
if lib.isNil and not gExehandle.isNil:
# first try this exe itself:
theAddr = gExehandle.symAddr(name)
# then try libc:
if theAddr.isNil:
let dllhandle = gDllCache.getDll(libcDll, sym.info)
theAddr = dllhandle.checkedSymAddr(name)
else:
let dllhandle = gDllCache.getDll(lib.path.strVal, sym.info)
theAddr = dllhandle.checkedSymAddr(name)
theAddr = dllhandle.symAddr(name)
elif not lib.isNil:
let dllhandle = gDllCache.getDll(if lib.kind == libHeader: libcDll
else: lib.path.strVal, sym.info)
theAddr = dllhandle.symAddr(name)
if theAddr.isNil: globalError(sym.info, "cannot import: " & sym.name.s)
result.intVal = cast[TAddress](theAddr)

proc mapType(t: ast.PType): ptr libffi.TType =
Expand All @@ -78,7 +87,7 @@ proc mapType(t: ast.PType): ptr libffi.TType =
of tyFloat, tyFloat64: result = addr libffi.type_double
of tyFloat32: result = addr libffi.type_float
of tyVar, tyPointer, tyPtr, tyRef, tyCString, tySequence, tyString, tyExpr,
tyStmt, tyTypeDesc, tyProc, tyArray, tyArrayConstr, tyNil:
tyStmt, tyTypeDesc, tyProc, tyArray, tyArrayConstr, tyStatic, tyNil:
result = addr libffi.type_pointer
of tyDistinct:
result = mapType(t.sons[0])
Expand All @@ -93,7 +102,7 @@ proc mapCallConv(cc: TCallingConvention, info: TLineInfo): TABI =
of ccStdCall: result = when defined(windows): STDCALL else: DEFAULT_ABI
of ccCDecl: result = DEFAULT_ABI
else:
GlobalError(info, "cannot map calling convention to FFI")
globalError(info, "cannot map calling convention to FFI")

template rd(T, p: expr): expr {.immediate.} = (cast[ptr T](p))[]
template wr(T, p, v: expr) {.immediate.} = (cast[ptr T](p))[] = v
Expand All @@ -107,7 +116,7 @@ proc packSize(v: PNode, typ: PType): int =
if v.kind in {nkNilLit, nkPtrLit}:
result = sizeof(pointer)
else:
result = sizeof(pointer) + packSize(v.sons[0], typ.sons[0])
result = sizeof(pointer) + packSize(v.sons[0], typ.lastSon)
of tyDistinct, tyGenericInst:
result = packSize(v, typ.sons[0])
of tyArray, tyArrayConstr:
Expand Down Expand Up @@ -139,10 +148,10 @@ proc getField(n: PNode; position: int): PSym =
else: internalError(n.info, "getField(record case branch)")
of nkSym:
if n.sym.position == position: result = n.sym
else: nil
else: discard

proc packObject(x: PNode, typ: PType, res: pointer) =
InternalAssert x.kind in {nkObjConstr, nkPar}
internalAssert x.kind in {nkObjConstr, nkPar}
# compute the field's offsets:
discard typ.getSize
for i in countup(ord(x.kind == nkObjConstr), sonsLen(x) - 1):
Expand All @@ -155,7 +164,7 @@ proc packObject(x: PNode, typ: PType, res: pointer) =
let field = getField(typ.n, i)
pack(it, field.typ, res +! field.offset)
else:
GlobalError(x.info, "cannot pack unnamed tuple")
globalError(x.info, "cannot pack unnamed tuple")

const maxPackDepth = 20
var packRecCheck = 0
Expand Down Expand Up @@ -184,33 +193,33 @@ proc pack(v: PNode, typ: PType, res: pointer) =
of 4: awr(int32, v.intVal.int32)
of 8: awr(int64, v.intVal.int64)
else:
GlobalError(v.info, "cannot map value to FFI (tyEnum, tySet)")
globalError(v.info, "cannot map value to FFI (tyEnum, tySet)")
of tyFloat: awr(float, v.floatVal)
of tyFloat32: awr(float32, v.floatVal)
of tyFloat64: awr(float64, v.floatVal)

of tyPointer, tyProc, tyCString, tyString:
if v.kind == nkNilLit:
# nothing to do since the memory is 0 initialized anyway
nil
discard
elif v.kind == nkPtrLit:
awr(pointer, cast[pointer](v.intVal))
elif v.kind in {nkStrLit..nkTripleStrLit}:
awr(cstring, cstring(v.strVal))
else:
GlobalError(v.info, "cannot map pointer/proc value to FFI")
globalError(v.info, "cannot map pointer/proc value to FFI")
of tyPtr, tyRef, tyVar:
if v.kind == nkNilLit:
# nothing to do since the memory is 0 initialized anyway
nil
discard
elif v.kind == nkPtrLit:
awr(pointer, cast[pointer](v.intVal))
else:
if packRecCheck > maxPackDepth:
packRecCheck = 0
GlobalError(v.info, "cannot map value to FFI " & typeToString(v.typ))
globalError(v.info, "cannot map value to FFI " & typeToString(v.typ))
inc packRecCheck
pack(v.sons[0], typ.sons[0], res +! sizeof(pointer))
pack(v.sons[0], typ.lastSon, res +! sizeof(pointer))
dec packRecCheck
awr(pointer, res +! sizeof(pointer))
of tyArray, tyArrayConstr:
Expand All @@ -220,11 +229,11 @@ proc pack(v: PNode, typ: PType, res: pointer) =
of tyObject, tyTuple:
packObject(v, typ, res)
of tyNil:
nil
discard
of tyDistinct, tyGenericInst:
pack(v, typ.sons[0], res)
else:
GlobalError(v.info, "cannot map value to FFI " & typeToString(v.typ))
globalError(v.info, "cannot map value to FFI " & typeToString(v.typ))

proc unpack(x: pointer, typ: PType, n: PNode): PNode

Expand All @@ -234,14 +243,14 @@ proc unpackObjectAdd(x: pointer, n, result: PNode) =
for i in countup(0, sonsLen(n) - 1):
unpackObjectAdd(x, n.sons[i], result)
of nkRecCase:
GlobalError(result.info, "case objects cannot be unpacked")
globalError(result.info, "case objects cannot be unpacked")
of nkSym:
var pair = newNodeI(nkExprColonExpr, result.info, 2)
pair.sons[0] = n
pair.sons[1] = unpack(x +! n.sym.offset, n.sym.typ, nil)
#echo "offset: ", n.sym.name.s, " ", n.sym.offset
result.add pair
else: nil
else: discard

proc unpackObject(x: pointer, typ: PType, n: PNode): PNode =
# compute the field's offsets:
Expand All @@ -253,14 +262,14 @@ proc unpackObject(x: pointer, typ: PType, n: PNode): PNode =
result = newNode(nkPar)
result.typ = typ
if typ.n.isNil:
InternalError("cannot unpack unnamed tuple")
internalError("cannot unpack unnamed tuple")
unpackObjectAdd(x, typ.n, result)
else:
result = n
if result.kind notin {nkObjConstr, nkPar}:
GlobalError(n.info, "cannot map value from FFI")
globalError(n.info, "cannot map value from FFI")
if typ.n.isNil:
GlobalError(n.info, "cannot unpack unnamed tuple")
globalError(n.info, "cannot unpack unnamed tuple")
for i in countup(ord(n.kind == nkObjConstr), sonsLen(n) - 1):
var it = n.sons[i]
if it.kind == nkExprColonExpr:
Expand All @@ -279,7 +288,7 @@ proc unpackArray(x: pointer, typ: PType, n: PNode): PNode =
else:
result = n
if result.kind != nkBracket:
GlobalError(n.info, "cannot map value from FFI")
globalError(n.info, "cannot map value from FFI")
let baseSize = typ.sons[1].getSize
for i in 0 .. < result.len:
result.sons[i] = unpack(x +! i * baseSize, typ.sons[1], result.sons[i])
Expand All @@ -303,7 +312,7 @@ proc unpack(x: pointer, typ: PType, n: PNode): PNode =
#echo "expected ", k, " but got ", result.kind
#debug result
return newNodeI(nkExceptBranch, n.info)
#GlobalError(n.info, "cannot map value from FFI")
#globalError(n.info, "cannot map value from FFI")
result.field = v

template setNil() =
Expand All @@ -328,19 +337,19 @@ proc unpack(x: pointer, typ: PType, n: PNode): PNode =
of tyInt16: awi(nkInt16Lit, rd(int16, x))
of tyInt32: awi(nkInt32Lit, rd(int32, x))
of tyInt64: awi(nkInt64Lit, rd(int64, x))
of tyUInt: awi(nkUIntLit, rd(uint, x).biggestInt)
of tyUInt8: awi(nkUInt8Lit, rd(uint8, x).biggestInt)
of tyUInt16: awi(nkUInt16Lit, rd(uint16, x).biggestInt)
of tyUInt32: awi(nkUInt32Lit, rd(uint32, x).biggestInt)
of tyUInt64: awi(nkUInt64Lit, rd(uint64, x).biggestInt)
of tyUInt: awi(nkUIntLit, rd(uint, x).BiggestInt)
of tyUInt8: awi(nkUInt8Lit, rd(uint8, x).BiggestInt)
of tyUInt16: awi(nkUInt16Lit, rd(uint16, x).BiggestInt)
of tyUInt32: awi(nkUInt32Lit, rd(uint32, x).BiggestInt)
of tyUInt64: awi(nkUInt64Lit, rd(uint64, x).BiggestInt)
of tyEnum:
case typ.getSize
of 1: awi(nkIntLit, rd(uint8, x).biggestInt)
of 2: awi(nkIntLit, rd(uint16, x).biggestInt)
of 4: awi(nkIntLit, rd(int32, x).biggestInt)
of 8: awi(nkIntLit, rd(int64, x).biggestInt)
of 1: awi(nkIntLit, rd(uint8, x).BiggestInt)
of 2: awi(nkIntLit, rd(uint16, x).BiggestInt)
of 4: awi(nkIntLit, rd(int32, x).BiggestInt)
of 8: awi(nkIntLit, rd(int64, x).BiggestInt)
else:
GlobalError(n.info, "cannot map value from FFI (tyEnum, tySet)")
globalError(n.info, "cannot map value from FFI (tyEnum, tySet)")
of tyFloat: awf(nkFloatLit, rd(float, x))
of tyFloat32: awf(nkFloat32Lit, rd(float32, x))
of tyFloat64: awf(nkFloat64Lit, rd(float64, x))
Expand All @@ -362,10 +371,10 @@ proc unpack(x: pointer, typ: PType, n: PNode): PNode =
awi(nkPtrLit, cast[TAddress](p))
elif n != nil and n.len == 1:
internalAssert n.kind == nkRefTy
n.sons[0] = unpack(p, typ.sons[0], n.sons[0])
n.sons[0] = unpack(p, typ.lastSon, n.sons[0])
result = n
else:
GlobalError(n.info, "cannot map value from FFI " & typeToString(typ))
globalError(n.info, "cannot map value from FFI " & typeToString(typ))
of tyObject, tyTuple:
result = unpackObject(x, typ, n)
of tyArray, tyArrayConstr:
Expand All @@ -382,7 +391,7 @@ proc unpack(x: pointer, typ: PType, n: PNode): PNode =
result = unpack(x, typ.sons[0], n)
else:
# XXX what to do with 'array' here?
GlobalError(n.info, "cannot map value from FFI " & typeToString(typ))
globalError(n.info, "cannot map value from FFI " & typeToString(typ))

proc fficast*(x: PNode, destTyp: PType): PNode =
if x.kind == nkPtrLit and x.typ.kind in {tyPtr, tyRef, tyVar, tyPointer,
Expand All @@ -405,20 +414,20 @@ proc fficast*(x: PNode, destTyp: PType): PNode =
dealloc a

proc callForeignFunction*(call: PNode): PNode =
InternalAssert call.sons[0].kind == nkPtrLit
internalAssert call.sons[0].kind == nkPtrLit

var cif: TCif
var sig: TParamList
# use the arguments' types for varargs support:
for i in 1..call.len-1:
sig[i-1] = mapType(call.sons[i].typ)
if sig[i-1].isNil:
GlobalError(call.info, "cannot map FFI type")
globalError(call.info, "cannot map FFI type")

let typ = call.sons[0].typ
if prep_cif(cif, mapCallConv(typ.callConv, call.info), cuint(call.len-1),
mapType(typ.sons[0]), sig) != OK:
GlobalError(call.info, "error in FFI call")
globalError(call.info, "error in FFI call")

var args: TArgList
let fn = cast[pointer](call.sons[0].intVal)
Expand All @@ -441,3 +450,46 @@ proc callForeignFunction*(call: PNode): PNode =
for i in 1 .. call.len-1:
call.sons[i] = unpack(args[i-1], typ.sons[i], call[i])
dealloc args[i-1]

proc callForeignFunction*(fn: PNode, fntyp: PType,
args: var TNodeSeq, start, len: int,
info: TLineInfo): PNode =
internalAssert fn.kind == nkPtrLit

var cif: TCif
var sig: TParamList
for i in 0..len-1:
var aTyp = args[i+start].typ
if aTyp.isNil:
internalAssert i+1 < fntyp.len
aTyp = fntyp.sons[i+1]
args[i+start].typ = aTyp
sig[i] = mapType(aTyp)
if sig[i].isNil: globalError(info, "cannot map FFI type")

if prep_cif(cif, mapCallConv(fntyp.callConv, info), cuint(len),
mapType(fntyp.sons[0]), sig) != OK:
globalError(info, "error in FFI call")

var cargs: TArgList
let fn = cast[pointer](fn.intVal)
for i in 0 .. len-1:
let t = args[i+start].typ
cargs[i] = alloc0(packSize(args[i+start], t))
pack(args[i+start], t, cargs[i])
let retVal = if isEmptyType(fntyp.sons[0]): pointer(nil)
else: alloc(fntyp.sons[0].getSize.int)

libffi.call(cif, fn, retVal, cargs)

if retVal.isNil:
result = emptyNode
else:
result = unpack(retVal, fntyp.sons[0], nil)
result.info = info

if retVal != nil: dealloc retVal
for i in 0 .. len-1:
let t = args[i+start].typ
args[i+start] = unpack(cargs[i], t, args[i+start])
dealloc cargs[i]
504 changes: 238 additions & 266 deletions compiler/evals.nim

Large diffs are not rendered by default.

59 changes: 20 additions & 39 deletions compiler/evaltempl.nim
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#
#
# The Nimrod Compiler
# (c) Copyright 2012 Andreas Rumpf
# (c) Copyright 2013 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
Expand All @@ -16,9 +16,14 @@ import
type
TemplCtx {.pure, final.} = object
owner, genSymOwner: PSym
instLines: bool # use the instantiation lines numbers
mapping: TIdTable # every gensym'ed symbol needs to be mapped to some
# new symbol

proc copyNode(ctx: TemplCtx, a, b: PNode): PNode =
result = copyNode(a)
if ctx.instLines: result.info = b.info

proc evalTemplateAux(templ, actual: PNode, c: var TemplCtx, result: PNode) =
case templ.kind
of nkSym:
Expand All @@ -31,49 +36,23 @@ proc evalTemplateAux(templ, actual: PNode, c: var TemplCtx, result: PNode) =
else:
result.add copyTree(x)
else:
InternalAssert sfGenSym in s.flags
var x = PSym(IdTableGet(c.mapping, s))
internalAssert sfGenSym in s.flags
var x = PSym(idTableGet(c.mapping, s))
if x == nil:
x = copySym(s, false)
x.owner = c.genSymOwner
IdTablePut(c.mapping, s, x)
result.add newSymNode(x, templ.info)
idTablePut(c.mapping, s, x)
result.add newSymNode(x, if c.instLines: actual.info else: templ.info)
else:
result.add copyNode(templ)
result.add copyNode(c, templ, actual)
of nkNone..nkIdent, nkType..nkNilLit: # atom
result.add copyNode(templ)
result.add copyNode(c, templ, actual)
else:
var res = copyNode(templ)
var res = copyNode(c, templ, actual)
for i in countup(0, sonsLen(templ) - 1):
evalTemplateAux(templ.sons[i], actual, c, res)
result.add res

when false:
proc evalTemplateAux(templ, actual: PNode, c: var TemplCtx): PNode =
case templ.kind
of nkSym:
var s = templ.sym
if s.owner.id == c.owner.id:
if s.kind == skParam:
result = copyTree(actual.sons[s.position])
else:
InternalAssert sfGenSym in s.flags
var x = PSym(IdTableGet(c.mapping, s))
if x == nil:
x = copySym(s, false)
x.owner = c.genSymOwner
IdTablePut(c.mapping, s, x)
result = newSymNode(x, templ.info)
else:
result = copyNode(templ)
of nkNone..nkIdent, nkType..nkNilLit: # atom
result = copyNode(templ)
else:
result = copyNode(templ)
newSons(result, sonsLen(templ))
for i in countup(0, sonsLen(templ) - 1):
result.sons[i] = evalTemplateAux(templ.sons[i], actual, c)

proc evalTemplateArgs(n: PNode, s: PSym): PNode =
# if the template has zero arguments, it can be called without ``()``
# `n` is then a nkSym or something similar
Expand All @@ -83,13 +62,13 @@ proc evalTemplateArgs(n: PNode, s: PSym): PNode =
a = sonsLen(n)
else: a = 0
var f = s.typ.sonsLen
if a > f: GlobalError(n.info, errWrongNumberOfArguments)
if a > f: globalError(n.info, errWrongNumberOfArguments)

result = newNodeI(nkArgList, n.info)
for i in countup(1, f - 1):
var arg = if i < a: n.sons[i] else: copyTree(s.typ.n.sons[i].sym.ast)
if arg == nil or arg.kind == nkEmpty:
LocalError(n.info, errWrongNumberOfArguments)
localError(n.info, errWrongNumberOfArguments)
addSon(result, arg)

var evalTemplateCounter* = 0
Expand All @@ -98,7 +77,7 @@ var evalTemplateCounter* = 0
proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym): PNode =
inc(evalTemplateCounter)
if evalTemplateCounter > 100:
GlobalError(n.info, errTemplateInstantiationTooNested)
globalError(n.info, errTemplateInstantiationTooNested)
result = n

# replace each param by the corresponding node:
Expand All @@ -114,11 +93,13 @@ proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym): PNode =
evalTemplateAux(body, args, ctx, result)
if result.len == 1: result = result.sons[0]
else:
GlobalError(result.info, errIllFormedAstX,
globalError(result.info, errIllFormedAstX,
renderTree(result, {renderNoComments}))
else:
result = copyNode(body)
#evalTemplateAux(body, args, ctx, result)
ctx.instLines = body.kind notin {nkStmtList, nkStmtListExpr,
nkBlockStmt, nkBlockExpr}
if ctx.instLines: result.info = n.info
for i in countup(0, safeLen(body) - 1):
evalTemplateAux(body.sons[i], args, ctx, result)

Expand Down
235 changes: 134 additions & 101 deletions compiler/extccomp.nim

Large diffs are not rendered by default.

112 changes: 56 additions & 56 deletions compiler/filter_tmpl.nim
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ type
indent, emitPar: int
x: string # the current input line
outp: PLLStream # the ouput will be parsed by pnimsyn
subsChar, NimDirective: Char
subsChar, nimDirective: char
emit, conc, toStr: string
curly, bracket, par: int
pendingExprLine: bool
Expand All @@ -37,11 +37,11 @@ const
PatternChars = {'a'..'z', 'A'..'Z', '0'..'9', '\x80'..'\xFF', '.', '_'}

proc newLine(p: var TTmplParser) =
LLStreamWrite(p.outp, repeatChar(p.emitPar, ')'))
llStreamWrite(p.outp, repeatChar(p.emitPar, ')'))
p.emitPar = 0
if p.info.line > int16(1): LLStreamWrite(p.outp, "\n")
if p.info.line > int16(1): llStreamWrite(p.outp, "\n")
if p.pendingExprLine:
LLStreamWrite(p.outp, repeatChar(2))
llStreamWrite(p.outp, repeatChar(2))
p.pendingExprLine = false

proc scanPar(p: var TTmplParser, d: int) =
Expand All @@ -55,7 +55,7 @@ proc scanPar(p: var TTmplParser, d: int) =
of ']': dec(p.bracket)
of '{': inc(p.curly)
of '}': dec(p.curly)
else: nil
else: discard
inc(i)

proc withInExpr(p: TTmplParser): bool {.inline.} =
Expand All @@ -67,9 +67,9 @@ proc parseLine(p: var TTmplParser) =
keyw: string
j = 0
while p.x[j] == ' ': inc(j)
if (p.x[0] == p.NimDirective) and (p.x[0 + 1] == '!'):
if (p.x[0] == p.nimDirective) and (p.x[0 + 1] == '!'):
newLine(p)
elif (p.x[j] == p.NimDirective):
elif (p.x[j] == p.nimDirective):
newLine(p)
inc(j)
while p.x[j] == ' ': inc(j)
Expand All @@ -87,26 +87,26 @@ proc parseLine(p: var TTmplParser) =
dec(p.indent, 2)
else:
p.info.col = int16(j)
LocalError(p.info, errXNotAllowedHere, "end")
LLStreamWrite(p.outp, repeatChar(p.indent))
LLStreamWrite(p.outp, "#end")
localError(p.info, errXNotAllowedHere, "end")
llStreamWrite(p.outp, repeatChar(p.indent))
llStreamWrite(p.outp, "#end")
of wIf, wWhen, wTry, wWhile, wFor, wBlock, wCase, wProc, wIterator,
wConverter, wMacro, wTemplate, wMethod:
LLStreamWrite(p.outp, repeatChar(p.indent))
LLStreamWrite(p.outp, substr(p.x, d))
llStreamWrite(p.outp, repeatChar(p.indent))
llStreamWrite(p.outp, substr(p.x, d))
inc(p.indent, 2)
of wElif, wOf, wElse, wExcept, wFinally:
LLStreamWrite(p.outp, repeatChar(p.indent - 2))
LLStreamWrite(p.outp, substr(p.x, d))
llStreamWrite(p.outp, repeatChar(p.indent - 2))
llStreamWrite(p.outp, substr(p.x, d))
of wLet, wVar, wConst, wType:
LLStreamWrite(p.outp, repeatChar(p.indent))
LLStreamWrite(p.outp, substr(p.x, d))
llStreamWrite(p.outp, repeatChar(p.indent))
llStreamWrite(p.outp, substr(p.x, d))
if not p.x.contains({':', '='}):
# no inline element --> treat as block:
inc(p.indent, 2)
else:
LLStreamWrite(p.outp, repeatChar(p.indent))
LLStreamWrite(p.outp, substr(p.x, d))
llStreamWrite(p.outp, repeatChar(p.indent))
llStreamWrite(p.outp, substr(p.x, d))
p.state = psDirective
else:
# data line
Expand All @@ -118,33 +118,33 @@ proc parseLine(p: var TTmplParser) =
case p.state
of psTempl:
# next line of string literal:
LLStreamWrite(p.outp, p.conc)
LLStreamWrite(p.outp, "\n")
LLStreamWrite(p.outp, repeatChar(p.indent + 2))
LLStreamWrite(p.outp, "\"")
llStreamWrite(p.outp, p.conc)
llStreamWrite(p.outp, "\n")
llStreamWrite(p.outp, repeatChar(p.indent + 2))
llStreamWrite(p.outp, "\"")
of psDirective:
newLine(p)
LLStreamWrite(p.outp, repeatChar(p.indent))
LLStreamWrite(p.outp, p.emit)
LLStreamWrite(p.outp, "(\"")
llStreamWrite(p.outp, repeatChar(p.indent))
llStreamWrite(p.outp, p.emit)
llStreamWrite(p.outp, "(\"")
inc(p.emitPar)
p.state = psTempl
while true:
case p.x[j]
of '\0':
break
of '\x01'..'\x1F', '\x80'..'\xFF':
LLStreamWrite(p.outp, "\\x")
LLStreamWrite(p.outp, toHex(ord(p.x[j]), 2))
llStreamWrite(p.outp, "\\x")
llStreamWrite(p.outp, toHex(ord(p.x[j]), 2))
inc(j)
of '\\':
LLStreamWrite(p.outp, "\\\\")
llStreamWrite(p.outp, "\\\\")
inc(j)
of '\'':
LLStreamWrite(p.outp, "\\\'")
llStreamWrite(p.outp, "\\\'")
inc(j)
of '\"':
LLStreamWrite(p.outp, "\\\"")
llStreamWrite(p.outp, "\\\"")
inc(j)
else:
if p.x[j] == p.subsChar:
Expand All @@ -153,69 +153,69 @@ proc parseLine(p: var TTmplParser) =
case p.x[j]
of '{':
p.info.col = int16(j)
LLStreamWrite(p.outp, '\"')
LLStreamWrite(p.outp, p.conc)
LLStreamWrite(p.outp, p.toStr)
LLStreamWrite(p.outp, '(')
llStreamWrite(p.outp, '\"')
llStreamWrite(p.outp, p.conc)
llStreamWrite(p.outp, p.toStr)
llStreamWrite(p.outp, '(')
inc(j)
curly = 0
while true:
case p.x[j]
of '\0':
LocalError(p.info, errXExpected, "}")
localError(p.info, errXExpected, "}")
break
of '{':
inc(j)
inc(curly)
LLStreamWrite(p.outp, '{')
llStreamWrite(p.outp, '{')
of '}':
inc(j)
if curly == 0: break
if curly > 0: dec(curly)
LLStreamWrite(p.outp, '}')
llStreamWrite(p.outp, '}')
else:
LLStreamWrite(p.outp, p.x[j])
llStreamWrite(p.outp, p.x[j])
inc(j)
LLStreamWrite(p.outp, ')')
LLStreamWrite(p.outp, p.conc)
LLStreamWrite(p.outp, '\"')
llStreamWrite(p.outp, ')')
llStreamWrite(p.outp, p.conc)
llStreamWrite(p.outp, '\"')
of 'a'..'z', 'A'..'Z', '\x80'..'\xFF':
LLStreamWrite(p.outp, '\"')
LLStreamWrite(p.outp, p.conc)
LLStreamWrite(p.outp, p.toStr)
LLStreamWrite(p.outp, '(')
llStreamWrite(p.outp, '\"')
llStreamWrite(p.outp, p.conc)
llStreamWrite(p.outp, p.toStr)
llStreamWrite(p.outp, '(')
while p.x[j] in PatternChars:
LLStreamWrite(p.outp, p.x[j])
llStreamWrite(p.outp, p.x[j])
inc(j)
LLStreamWrite(p.outp, ')')
LLStreamWrite(p.outp, p.conc)
LLStreamWrite(p.outp, '\"')
llStreamWrite(p.outp, ')')
llStreamWrite(p.outp, p.conc)
llStreamWrite(p.outp, '\"')
else:
if p.x[j] == p.subsChar:
LLStreamWrite(p.outp, p.subsChar)
llStreamWrite(p.outp, p.subsChar)
inc(j)
else:
p.info.col = int16(j)
LocalError(p.info, errInvalidExpression, "$")
localError(p.info, errInvalidExpression, "$")
else:
LLStreamWrite(p.outp, p.x[j])
llStreamWrite(p.outp, p.x[j])
inc(j)
LLStreamWrite(p.outp, "\\n\"")
llStreamWrite(p.outp, "\\n\"")

proc filterTmpl(stdin: PLLStream, filename: string, call: PNode): PLLStream =
var p: TTmplParser
p.info = newLineInfo(filename, 0, 0)
p.outp = LLStreamOpen("")
p.outp = llStreamOpen("")
p.inp = stdin
p.subsChar = charArg(call, "subschar", 1, '$')
p.nimDirective = charArg(call, "metachar", 2, '#')
p.emit = strArg(call, "emit", 3, "result.add")
p.conc = strArg(call, "conc", 4, " & ")
p.toStr = strArg(call, "tostring", 5, "$")
p.x = newStringOfCap(120)
while LLStreamReadLine(p.inp, p.x):
while llStreamReadLine(p.inp, p.x):
p.info.line = p.info.line + int16(1)
parseLine(p)
newLine(p)
result = p.outp
LLStreamClose(p.inp)
llStreamClose(p.inp)
30 changes: 15 additions & 15 deletions compiler/filters.nim
Original file line number Diff line number Diff line change
Expand Up @@ -16,26 +16,26 @@ import
proc filterReplace*(stdin: PLLStream, filename: string, call: PNode): PLLStream
proc filterStrip*(stdin: PLLStream, filename: string, call: PNode): PLLStream
# helpers to retrieve arguments:
proc charArg*(n: PNode, name: string, pos: int, default: Char): Char
proc charArg*(n: PNode, name: string, pos: int, default: char): char
proc strArg*(n: PNode, name: string, pos: int, default: string): string
proc boolArg*(n: PNode, name: string, pos: int, default: bool): bool
# implementation

proc invalidPragma(n: PNode) =
LocalError(n.info, errXNotAllowedHere, renderTree(n, {renderNoComments}))
localError(n.info, errXNotAllowedHere, renderTree(n, {renderNoComments}))

proc getArg(n: PNode, name: string, pos: int): PNode =
result = nil
if n.kind in {nkEmpty..nkNilLit}: return
for i in countup(1, sonsLen(n) - 1):
if n.sons[i].kind == nkExprEqExpr:
if n.sons[i].sons[0].kind != nkIdent: invalidPragma(n)
if IdentEq(n.sons[i].sons[0].ident, name):
if identEq(n.sons[i].sons[0].ident, name):
return n.sons[i].sons[1]
elif i == pos:
return n.sons[i]

proc charArg(n: PNode, name: string, pos: int, default: Char): Char =
proc charArg(n: PNode, name: string, pos: int, default: char): char =
var x = getArg(n, name, pos)
if x == nil: result = default
elif x.kind == nkCharLit: result = chr(int(x.intVal))
Expand All @@ -50,30 +50,30 @@ proc strArg(n: PNode, name: string, pos: int, default: string): string =
proc boolArg(n: PNode, name: string, pos: int, default: bool): bool =
var x = getArg(n, name, pos)
if x == nil: result = default
elif (x.kind == nkIdent) and IdentEq(x.ident, "true"): result = true
elif (x.kind == nkIdent) and IdentEq(x.ident, "false"): result = false
elif (x.kind == nkIdent) and identEq(x.ident, "true"): result = true
elif (x.kind == nkIdent) and identEq(x.ident, "false"): result = false
else: invalidPragma(n)

proc filterStrip(stdin: PLLStream, filename: string, call: PNode): PLLStream =
var pattern = strArg(call, "startswith", 1, "")
var leading = boolArg(call, "leading", 2, true)
var trailing = boolArg(call, "trailing", 3, true)
result = LLStreamOpen("")
result = llStreamOpen("")
var line = newStringOfCap(80)
while LLStreamReadLine(stdin, line):
while llStreamReadLine(stdin, line):
var stripped = strip(line, leading, trailing)
if (len(pattern) == 0) or startsWith(stripped, pattern):
LLStreamWriteln(result, stripped)
llStreamWriteln(result, stripped)
else:
LLStreamWriteln(result, line)
LLStreamClose(stdin)
llStreamWriteln(result, line)
llStreamClose(stdin)

proc filterReplace(stdin: PLLStream, filename: string, call: PNode): PLLStream =
var sub = strArg(call, "sub", 1, "")
if len(sub) == 0: invalidPragma(call)
var by = strArg(call, "by", 2, "")
result = LLStreamOpen("")
result = llStreamOpen("")
var line = newStringOfCap(80)
while LLStreamReadLine(stdin, line):
LLStreamWriteln(result, replace(line, sub, by))
LLStreamClose(stdin)
while llStreamReadLine(stdin, line):
llStreamWriteln(result, replace(line, sub, by))
llStreamClose(stdin)
Loading