588 changes: 588 additions & 0 deletions compiler/guards.nim

Large diffs are not rendered by default.

30 changes: 21 additions & 9 deletions compiler/hlo.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 @@ -12,7 +12,7 @@
proc hlo(c: PContext, n: PNode): PNode

proc evalPattern(c: PContext, n, orig: PNode): PNode =
InternalAssert n.kind == nkCall and n.sons[0].kind == nkSym
internalAssert n.kind == nkCall and n.sons[0].kind == nkSym
# we need to ensure that the resulting AST is semchecked. However, it's
# aweful to semcheck before macro invocation, so we don't and treat
# templates and macros as immediate in this context.
Expand All @@ -28,10 +28,8 @@ proc evalPattern(c: PContext, n, orig: PNode): PNode =
else:
result = semDirectOp(c, n, {})
if optHints in gOptions and hintPattern in gNotes:
Message(orig.info, hintPattern, rule & " --> '" &
message(orig.info, hintPattern, rule & " --> '" &
renderTree(result, {renderNoComments}) & "'")
# check the resulting AST for optimization rules again:
result = hlo(c, result)

proc applyPatterns(c: PContext, n: PNode): PNode =
result = n
Expand All @@ -44,9 +42,10 @@ proc applyPatterns(c: PContext, n: PNode): PNode =
let x = applyRule(c, pattern, result)
if not isNil(x):
assert x.kind in {nkStmtList, nkCall}
# better be safe than sorry, so check evalTemplateCounter too:
inc(evalTemplateCounter)
if evalTemplateCounter > 100:
GlobalError(n.info, errTemplateInstantiationTooNested)
globalError(n.info, errTemplateInstantiationTooNested)
# deactivate this pattern:
c.patterns[i] = nil
if x.kind == nkStmtList:
Expand All @@ -60,11 +59,19 @@ proc applyPatterns(c: PContext, n: PNode): PNode =
c.patterns[i] = pattern

proc hlo(c: PContext, n: PNode): PNode =
inc(c.hloLoopDetector)
# simply stop and do not perform any further transformations:
if c.hloLoopDetector > 300: return n
case n.kind
of nkMacroDef, nkTemplateDef, procDefs:
# already processed (special cases in semstmts.nim)
result = n
else:
if n.kind in {nkFastAsgn, nkAsgn, nkIdentDefs, nkVarTuple} and
n.sons[0].kind == nkSym and
{sfGlobal, sfPure} * n.sons[0].sym.flags == {sfGlobal, sfPure}:
# do not optimize 'var g {.global} = re(...)' again!
return n
result = applyPatterns(c, n)
if result == n:
# no optimization applied, try subtrees:
Expand All @@ -74,18 +81,23 @@ proc hlo(c: PContext, n: PNode): PNode =
if h != a: result.sons[i] = h
else:
# perform type checking, so that the replacement still fits:
if n.typ == nil and (result.typ == nil or
result.typ.kind in {tyStmt, tyEmpty}):
nil
if isEmptyType(n.typ) and isEmptyType(result.typ):
discard
else:
result = fitNode(c, n.typ, result)
# optimization has been applied so check again:
result = commonOptimizations(c.module, result)
result = hlo(c, result)
result = commonOptimizations(c.module, result)

proc hloBody(c: PContext, n: PNode): PNode =
# fast exit:
if c.patterns.len == 0 or optPatterns notin gOptions: return n
c.hloLoopDetector = 0
result = hlo(c, n)

proc hloStmt(c: PContext, n: PNode): PNode =
# fast exit:
if c.patterns.len == 0 or optPatterns notin gOptions: return n
c.hloLoopDetector = 0
result = hlo(c, n)
8 changes: 6 additions & 2 deletions compiler/idents.nim
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,13 @@ type
s*: string
next*: PIdent # for hash-table chaining
h*: THash # hash value of s


var firstCharIsCS*: bool
var buckets*: array[0..4096 * 2 - 1, PIdent]

proc cmpIgnoreStyle(a, b: cstring, blen: int): int =
if firstCharIsCS:
if a[0] != b[0]: return 1
var i = 0
var j = 0
result = 1
Expand Down Expand Up @@ -99,8 +102,9 @@ proc getIdent*(identifier: string): PIdent =
proc getIdent*(identifier: string, h: THash): PIdent =
result = getIdent(cstring(identifier), len(identifier), h)

proc IdentEq*(id: PIdent, name: string): bool =
proc identEq*(id: PIdent, name: string): bool =
result = id.id == getIdent(name).id

var idAnon* = getIdent":anonymous"
let idDelegator* = getIdent":delegator"

16 changes: 8 additions & 8 deletions compiler/idgen.nim
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,12 @@ const
when debugIds:
import intsets

var usedIds = InitIntSet()
var usedIds = initIntSet()

proc registerID*(id: PIdObj) =
when debugIDs:
if id.id == -1 or ContainsOrIncl(usedIds, id.id):
InternalError("ID already used: " & $id.id)
when debugIds:
if id.id == -1 or containsOrIncl(usedIds, id.id):
internalError("ID already used: " & $id.id)

proc getID*(): int {.inline.} =
result = gFrontEndId
Expand All @@ -37,8 +37,8 @@ proc backendId*(): int {.inline.} =
proc setId*(id: int) {.inline.} =
gFrontEndId = max(gFrontEndId, id + 1)

proc IDsynchronizationPoint*(idRange: int) =
gFrontEndId = (gFrontEndId div IdRange + 1) * IdRange + 1
proc idSynchronizationPoint*(idRange: int) =
gFrontEndId = (gFrontEndId div idRange + 1) * idRange + 1

proc toGid(f: string): string =
# we used to use ``f.addFileExt("gid")`` (aka ``$project.gid``), but this
Expand All @@ -49,7 +49,7 @@ proc toGid(f: string): string =
proc saveMaxIds*(project: string) =
var f = open(project.toGid, fmWrite)
f.writeln($gFrontEndId)
f.writeln($gBackEndId)
f.writeln($gBackendId)
f.close()

proc loadMaxIds*(project: string) =
Expand All @@ -61,5 +61,5 @@ proc loadMaxIds*(project: string) =
if f.readLine(line):
var backEndId = parseInt(line)
gFrontEndId = max(gFrontEndId, frontEndId)
gBackEndId = max(gBackEndId, backEndId)
gBackendId = max(gBackendId, backEndId)
f.close()
104 changes: 63 additions & 41 deletions compiler/importer.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 @@ -22,24 +22,35 @@ proc getModuleName*(n: PNode): string =
# The proc won't perform any checks that the path is actually valid
case n.kind
of nkStrLit, nkRStrLit, nkTripleStrLit:
result = UnixToNativePath(n.strVal)
result = unixToNativePath(n.strVal)
of nkIdent:
result = n.ident.s
of nkSym:
result = n.sym.name.s
else:
of nkInfix:
if n.sons[0].kind == nkIdent and n.sons[0].ident.id == getIdent("as").id:
# XXX hack ahead:
n.kind = nkImportAs
n.sons[0] = n.sons[1]
n.sons[1] = n.sons[2]
n.sons.setLen(2)
return getModuleName(n.sons[0])
# hacky way to implement 'x / y /../ z':
result = renderTree(n, {renderNoComments}).replace(" ")
#localError(n.info, errGenerated,
# "invalide module name: '$1'" % renderTree(n))
#result = ""
of nkDotExpr:
result = renderTree(n, {renderNoComments}).replace(".", "/")
of nkImportAs:
result = getModuleName(n.sons[0])
else:
localError(n.info, errGenerated, "invalid module name: '$1'" % n.renderTree)
result = ""

proc checkModuleName*(n: PNode): int32 =
# This returns the full canonical path for a given module import
let modulename = n.getModuleName
let fullPath = findModule(modulename)
let fullPath = findModule(modulename, n.info.toFullPath)
if fullPath.len == 0:
LocalError(n.info, errCannotOpenFile, modulename)
localError(n.info, errCannotOpenFile, modulename)
result = InvalidFileIDX
else:
result = fullPath.fileInfoIdx
Expand All @@ -48,32 +59,32 @@ proc rawImportSymbol(c: PContext, s: PSym) =
# This does not handle stubs, because otherwise loading on demand would be
# pointless in practice. So importing stubs is fine here!
# check if we have already a symbol of the same name:
var check = StrTableGet(c.importTable.symbols, s.name)
var check = strTableGet(c.importTable.symbols, s.name)
if check != nil and check.id != s.id:
if s.kind notin OverloadableSyms:
# s and check need to be qualified:
Incl(c.AmbiguousSymbols, s.id)
Incl(c.AmbiguousSymbols, check.id)
incl(c.ambiguousSymbols, s.id)
incl(c.ambiguousSymbols, check.id)
# thanks to 'export' feature, it could be we import the same symbol from
# multiple sources, so we need to call 'StrTableAdd' here:
StrTableAdd(c.importTable.symbols, s)
strTableAdd(c.importTable.symbols, s)
if s.kind == skType:
var etyp = s.typ
if etyp.kind in {tyBool, tyEnum} and sfPure notin s.flags:
for j in countup(0, sonsLen(etyp.n) - 1):
var e = etyp.n.sons[j].sym
if e.Kind != skEnumField:
InternalError(s.info, "rawImportSymbol")
if e.kind != skEnumField:
internalError(s.info, "rawImportSymbol")
# BUGFIX: because of aliases for enums the symbol may already
# have been put into the symbol table
# BUGFIX: but only iff they are the same symbols!
var it: TIdentIter
check = InitIdentIter(it, c.importTable.symbols, e.name)
check = initIdentIter(it, c.importTable.symbols, e.name)
while check != nil:
if check.id == e.id:
e = nil
break
check = NextIdentIter(it, c.importTable.symbols)
check = nextIdentIter(it, c.importTable.symbols)
if e != nil:
rawImportSymbol(c, e)
else:
Expand All @@ -83,36 +94,36 @@ proc rawImportSymbol(c: PContext, s: PSym) =

proc importSymbol(c: PContext, n: PNode, fromMod: PSym) =
let ident = lookups.considerAcc(n)
let s = StrTableGet(fromMod.tab, ident)
let s = strTableGet(fromMod.tab, ident)
if s == nil:
LocalError(n.info, errUndeclaredIdentifier, ident.s)
localError(n.info, errUndeclaredIdentifier, ident.s)
else:
if s.kind == skStub: loadStub(s)
if s.Kind notin ExportableSymKinds:
InternalError(n.info, "importSymbol: 2")
if s.kind notin ExportableSymKinds:
internalError(n.info, "importSymbol: 2")
# for an enumeration we have to add all identifiers
case s.Kind
of skProc, skMethod, skIterator, skMacro, skTemplate, skConverter:
case s.kind
of skProcKinds:
# for a overloadable syms add all overloaded routines
var it: TIdentIter
var e = InitIdentIter(it, fromMod.tab, s.name)
var e = initIdentIter(it, fromMod.tab, s.name)
while e != nil:
if e.name.id != s.Name.id: InternalError(n.info, "importSymbol: 3")
if e.name.id != s.name.id: internalError(n.info, "importSymbol: 3")
rawImportSymbol(c, e)
e = NextIdentIter(it, fromMod.tab)
e = nextIdentIter(it, fromMod.tab)
else: rawImportSymbol(c, s)

proc importAllSymbolsExcept(c: PContext, fromMod: PSym, exceptSet: TIntSet) =
var i: TTabIter
var s = InitTabIter(i, fromMod.tab)
var s = initTabIter(i, fromMod.tab)
while s != nil:
if s.kind != skModule:
if s.kind != skEnumField:
if s.Kind notin ExportableSymKinds:
InternalError(s.info, "importAllSymbols: " & $s.kind)
if s.kind notin ExportableSymKinds:
internalError(s.info, "importAllSymbols: " & $s.kind)
if exceptSet.empty or s.name.id notin exceptSet:
rawImportSymbol(c, s)
s = NextIter(i, fromMod.tab)
s = nextIter(i, fromMod.tab)

proc importAllSymbols*(c: PContext, fromMod: PSym) =
var exceptSet: TIntSet
Expand All @@ -135,15 +146,28 @@ proc importForwarded(c: PContext, n: PNode, exceptSet: TIntSet) =
for i in 0 ..safeLen(n)-1:
importForwarded(c, n.sons[i], exceptSet)

proc importModuleAs(n: PNode, realModule: PSym): PSym =
result = realModule
if n.kind != nkImportAs: discard
elif n.len != 2 or n.sons[1].kind != nkIdent:
localError(n.info, errGenerated, "module alias must be an identifier")
elif n.sons[1].ident.id != realModule.name.id:
# some misguided guy will write 'import abc.foo as foo' ...
result = createModuleAlias(realModule, n.sons[1].ident, n.sons[1].info)

proc myImportModule(c: PContext, n: PNode): PSym =
var f = checkModuleName(n)
if f != InvalidFileIDX:
result = importModuleAs(n, gImportModule(c.module, f))
if sfDeprecated in result.flags:
message(n.info, warnDeprecated, result.name.s)

proc evalImport(c: PContext, n: PNode): PNode =
result = n
var emptySet: TIntSet
for i in countup(0, sonsLen(n) - 1):
var f = checkModuleName(n.sons[i])
if f != InvalidFileIDX:
var m = gImportModule(c.module, f)
if sfDeprecated in m.flags:
Message(n.sons[i].info, warnDeprecated, m.name.s)
var m = myImportModule(c, n.sons[i])
if m != nil:
# ``addDecl`` needs to be done before ``importAllSymbols``!
addDecl(c, m) # add symbol to symbol table of module
importAllSymbolsExcept(c, m, emptySet)
Expand All @@ -152,21 +176,19 @@ proc evalImport(c: PContext, n: PNode): PNode =
proc evalFrom(c: PContext, n: PNode): PNode =
result = n
checkMinSonsLen(n, 2)
var f = checkModuleName(n.sons[0])
if f != InvalidFileIDX:
var m = gImportModule(c.module, f)
var m = myImportModule(c, n.sons[0])
if m != nil:
n.sons[0] = newSymNode(m)
addDecl(c, m) # add symbol to symbol table of module
for i in countup(1, sonsLen(n) - 1):
for i in countup(1, sonsLen(n) - 1):
if n.sons[i].kind != nkNilLit:
importSymbol(c, n.sons[i], m)

proc evalImportExcept*(c: PContext, n: PNode): PNode =
result = n
checkMinSonsLen(n, 2)
var f = checkModuleName(n.sons[0])
if f != InvalidFileIDX:
var m = gImportModule(c.module, f)
var m = myImportModule(c, n.sons[0])
if m != nil:
n.sons[0] = newSymNode(m)
addDecl(c, m) # add symbol to symbol table of module
var exceptSet = initIntSet()
Expand Down
591 changes: 395 additions & 196 deletions compiler/jsgen.nim

Large diffs are not rendered by default.

10 changes: 5 additions & 5 deletions compiler/jstypes.nim
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ proc genObjectFields(p: PProc, typ: PType, n: PNode): PRope =
[mangleName(field), s, makeJSString(field.name.s)])
of nkRecCase:
length = sonsLen(n)
if (n.sons[0].kind != nkSym): InternalError(n.info, "genObjectFields")
if (n.sons[0].kind != nkSym): internalError(n.info, "genObjectFields")
field = n.sons[0].sym
s = genTypeInfo(p, field.typ)
for i in countup(1, length - 1):
Expand Down Expand Up @@ -98,7 +98,7 @@ proc genEnumInfo(p: PProc, typ: PType, name: PRope) =
let length = sonsLen(typ.n)
var s: PRope = nil
for i in countup(0, length - 1):
if (typ.n.sons[i].kind != nkSym): InternalError(typ.n.info, "genEnumInfo")
if (typ.n.sons[i].kind != nkSym): internalError(typ.n.info, "genEnumInfo")
let field = typ.n.sons[i].sym
if i > 0: app(s, ", " & tnl)
let extName = if field.ast == nil: field.name.s else: field.ast.strVal
Expand All @@ -119,7 +119,7 @@ proc genTypeInfo(p: PProc, typ: PType): PRope =
var t = typ
if t.kind == tyGenericInst: t = lastSon(t)
result = ropef("NTI$1", [toRope(t.id)])
if ContainsOrIncl(p.g.TypeInfoGenerated, t.id): return
if containsOrIncl(p.g.typeInfoGenerated, t.id): return
case t.kind
of tyDistinct:
result = genTypeInfo(p, typ.sons[0])
Expand All @@ -134,7 +134,7 @@ proc genTypeInfo(p: PProc, typ: PType): PRope =
[result, toRope(ord(t.kind))])
prepend(p.g.typeInfo, s)
appf(p.g.typeInfo, "$1.base = $2;$n",
[result, genTypeInfo(p, typ.sons[0])])
[result, genTypeInfo(p, typ.lastSon)])
of tyArrayConstr, tyArray:
var s = ropef(
"var $1 = {size: 0,kind: $2,base: null,node: null,finalizer: null};$n",
Expand All @@ -145,4 +145,4 @@ proc genTypeInfo(p: PProc, typ: PType): PRope =
of tyEnum: genEnumInfo(p, t, result)
of tyObject: genObjectInfo(p, t, result)
of tyTuple: genTupleInfo(p, t, result)
else: InternalError("genTypeInfo(" & $t.kind & ')')
else: internalError("genTypeInfo(" & $t.kind & ')')
603 changes: 328 additions & 275 deletions compiler/lambdalifting.nim

Large diffs are not rendered by default.

300 changes: 165 additions & 135 deletions compiler/lexer.nim

Large diffs are not rendered by default.

58 changes: 31 additions & 27 deletions compiler/lists.nim
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,17 @@ type
PStrEntry* = ref TStrEntry
TLinkedList* = object # for the "find" operation:
head*, tail*: PListEntry
Counter*: int
counter*: int

TCompareProc* = proc (entry: PListEntry, closure: Pointer): bool {.nimcall.}
TCompareProc* = proc (entry: PListEntry, closure: pointer): bool {.nimcall.}

proc InitLinkedList*(list: var TLinkedList) =
list.Counter = 0
proc initLinkedList*(list: var TLinkedList) =
list.counter = 0
list.head = nil
list.tail = nil

proc Append*(list: var TLinkedList, entry: PListEntry) =
Inc(list.counter)
proc append*(list: var TLinkedList, entry: PListEntry) =
inc(list.counter)
entry.next = nil
entry.prev = list.tail
if list.tail != nil:
Expand All @@ -39,7 +39,7 @@ proc Append*(list: var TLinkedList, entry: PListEntry) =
list.tail = entry
if list.head == nil: list.head = entry

proc Contains*(list: TLinkedList, data: string): bool =
proc contains*(list: TLinkedList, data: string): bool =
var it = list.head
while it != nil:
if PStrEntry(it).data == data:
Expand All @@ -50,15 +50,15 @@ proc newStrEntry(data: string): PStrEntry =
new(result)
result.data = data

proc AppendStr*(list: var TLinkedList, data: string) =
proc appendStr*(list: var TLinkedList, data: string) =
append(list, newStrEntry(data))

proc IncludeStr*(list: var TLinkedList, data: string): bool =
if Contains(list, data): return true
AppendStr(list, data) # else: add to list
proc includeStr*(list: var TLinkedList, data: string): bool =
if contains(list, data): return true
appendStr(list, data) # else: add to list

proc Prepend*(list: var TLinkedList, entry: PListEntry) =
Inc(list.counter)
proc prepend*(list: var TLinkedList, entry: PListEntry) =
inc(list.counter)
entry.prev = nil
entry.next = list.head
if list.head != nil:
Expand All @@ -67,22 +67,22 @@ proc Prepend*(list: var TLinkedList, entry: PListEntry) =
list.head = entry
if list.tail == nil: list.tail = entry

proc PrependStr*(list: var TLinkedList, data: string) =
proc prependStr*(list: var TLinkedList, data: string) =
prepend(list, newStrEntry(data))

proc InsertBefore*(list: var TLinkedList, pos, entry: PListEntry) =
proc insertBefore*(list: var TLinkedList, pos, entry: PListEntry) =
assert(pos != nil)
if pos == list.head:
prepend(list, entry)
else:
Inc(list.counter)
inc(list.counter)
entry.next = pos
entry.prev = pos.prev
if pos.prev != nil: pos.prev.next = entry
pos.prev = entry

proc Remove*(list: var TLinkedList, entry: PListEntry) =
Dec(list.counter)
proc remove*(list: var TLinkedList, entry: PListEntry) =
dec(list.counter)
if entry == list.tail:
list.tail = entry.prev
if entry == list.head:
Expand All @@ -91,22 +91,26 @@ proc Remove*(list: var TLinkedList, entry: PListEntry) =
if entry.prev != nil: entry.prev.next = entry.next

proc bringToFront*(list: var TLinkedList, entry: PListEntry) =
if entry == list.head: return
if entry == list.tail: list.tail = entry.prev
if entry.next != nil: entry.next.prev = entry.prev
if entry.prev != nil: entry.prev.next = entry.next
entry.prev = nil
entry.next = list.head
list.head = entry
when true:
list.remove entry
list.prepend entry
else:
if entry == list.head: return
if entry == list.tail: list.tail = entry.prev
if entry.next != nil: entry.next.prev = entry.prev
if entry.prev != nil: entry.prev.next = entry.next
entry.prev = nil
entry.next = list.head
list.head = entry

proc ExcludeStr*(list: var TLinkedList, data: string) =
proc excludeStr*(list: var TLinkedList, data: string) =
var it = list.head
while it != nil:
let nxt = it.next
if PStrEntry(it).data == data: remove(list, it)
it = nxt

proc Find*(list: TLinkedList, fn: TCompareProc, closure: Pointer): PListEntry =
proc find*(list: TLinkedList, fn: TCompareProc, closure: pointer): PListEntry =
result = list.head
while result != nil:
if fn(result, closure): return
Expand Down
97 changes: 48 additions & 49 deletions compiler/llstream.nim
Original file line number Diff line number Diff line change
Expand Up @@ -23,63 +23,63 @@ type
llsStdIn # stream encapsulates stdin
TLLStream* = object of TObject
kind*: TLLStreamKind # accessible for low-level access (lexbase uses this)
f*: tfile
f*: TFile
s*: string
rd*, wr*: int # for string streams
lineOffset*: int # for fake stdin line numbers

PLLStream* = ref TLLStream

proc LLStreamOpen*(data: string): PLLStream
proc LLStreamOpen*(f: var tfile): PLLStream
proc LLStreamOpen*(filename: string, mode: TFileMode): PLLStream
proc LLStreamOpen*(): PLLStream
proc LLStreamOpenStdIn*(): PLLStream
proc LLStreamClose*(s: PLLStream)
proc LLStreamRead*(s: PLLStream, buf: pointer, bufLen: int): int
proc LLStreamReadLine*(s: PLLStream, line: var string): bool
proc LLStreamReadAll*(s: PLLStream): string
proc LLStreamWrite*(s: PLLStream, data: string)
proc LLStreamWrite*(s: PLLStream, data: Char)
proc LLStreamWrite*(s: PLLStream, buf: pointer, buflen: int)
proc LLStreamWriteln*(s: PLLStream, data: string)
proc llStreamOpen*(data: string): PLLStream
proc llStreamOpen*(f: var TFile): PLLStream
proc llStreamOpen*(filename: string, mode: TFileMode): PLLStream
proc llStreamOpen*(): PLLStream
proc llStreamOpenStdIn*(): PLLStream
proc llStreamClose*(s: PLLStream)
proc llStreamRead*(s: PLLStream, buf: pointer, bufLen: int): int
proc llStreamReadLine*(s: PLLStream, line: var string): bool
proc llStreamReadAll*(s: PLLStream): string
proc llStreamWrite*(s: PLLStream, data: string)
proc llStreamWrite*(s: PLLStream, data: char)
proc llStreamWrite*(s: PLLStream, buf: pointer, buflen: int)
proc llStreamWriteln*(s: PLLStream, data: string)
# implementation

proc LLStreamOpen(data: string): PLLStream =
proc llStreamOpen(data: string): PLLStream =
new(result)
result.s = data
result.kind = llsString

proc LLStreamOpen(f: var tfile): PLLStream =
proc llStreamOpen(f: var TFile): PLLStream =
new(result)
result.f = f
result.kind = llsFile

proc LLStreamOpen(filename: string, mode: TFileMode): PLLStream =
proc llStreamOpen(filename: string, mode: TFileMode): PLLStream =
new(result)
result.kind = llsFile
if not open(result.f, filename, mode): result = nil

proc LLStreamOpen(): PLLStream =
proc llStreamOpen(): PLLStream =
new(result)
result.kind = llsNone

proc LLStreamOpenStdIn(): PLLStream =
proc llStreamOpenStdIn(): PLLStream =
new(result)
result.kind = llsStdIn
result.s = ""
result.lineOffset = -1

proc LLStreamClose(s: PLLStream) =
proc llStreamClose(s: PLLStream) =
case s.kind
of llsNone, llsString, llsStdIn:
nil
discard
of llsFile:
close(s.f)

when not defined(ReadLineFromStdin):
when not defined(readLineFromStdin):
# fallback implementation:
proc ReadLineFromStdin(prompt: string, line: var string): bool =
proc readLineFromStdin(prompt: string, line: var string): bool =
stdout.write(prompt)
result = readLine(stdin, line)

Expand All @@ -99,7 +99,7 @@ proc endsWithOpr*(x: string): bool =
result = x.endsWith(LineContinuationOprs)

proc continueLine(line: string, inTripleString: bool): bool {.inline.} =
result = inTriplestring or
result = inTripleString or
line[0] == ' ' or
line.endsWith(LineContinuationOprs+AdditionalLineContinuationOprs)

Expand All @@ -111,12 +111,12 @@ proc countTriples(s: string): int =
inc i, 2
inc i

proc LLreadFromStdin(s: PLLStream, buf: pointer, bufLen: int): int =
proc llReadFromStdin(s: PLLStream, buf: pointer, bufLen: int): int =
s.s = ""
s.rd = 0
var line = newStringOfCap(120)
var triples = 0
while ReadLineFromStdin(if s.s.len == 0: ">>> " else: "... ", line):
while readLineFromStdin(if s.s.len == 0: ">>> " else: "... ", line):
add(s.s, line)
add(s.s, "\n")
inc triples, countTriples(line)
Expand All @@ -127,7 +127,7 @@ proc LLreadFromStdin(s: PLLStream, buf: pointer, bufLen: int): int =
copyMem(buf, addr(s.s[s.rd]), result)
inc(s.rd, result)

proc LLStreamRead(s: PLLStream, buf: pointer, bufLen: int): int =
proc llStreamRead(s: PLLStream, buf: pointer, bufLen: int): int =
case s.kind
of llsNone:
result = 0
Expand All @@ -139,9 +139,9 @@ proc LLStreamRead(s: PLLStream, buf: pointer, bufLen: int): int =
of llsFile:
result = readBuffer(s.f, buf, bufLen)
of llsStdIn:
result = LLreadFromStdin(s, buf, bufLen)
result = llReadFromStdin(s, buf, bufLen)

proc LLStreamReadLine(s: PLLStream, line: var string): bool =
proc llStreamReadLine(s: PLLStream, line: var string): bool =
setLen(line, 0)
case s.kind
of llsNone:
Expand All @@ -165,48 +165,47 @@ proc LLStreamReadLine(s: PLLStream, line: var string): bool =
of llsStdIn:
result = readLine(stdin, line)

proc LLStreamWrite(s: PLLStream, data: string) =
proc llStreamWrite(s: PLLStream, data: string) =
case s.kind
of llsNone, llsStdIn:
nil
discard
of llsString:
add(s.s, data)
inc(s.wr, len(data))
of llsFile:
write(s.f, data)

proc LLStreamWriteln(s: PLLStream, data: string) =
LLStreamWrite(s, data)
LLStreamWrite(s, "\n")
proc llStreamWriteln(s: PLLStream, data: string) =
llStreamWrite(s, data)
llStreamWrite(s, "\n")

proc LLStreamWrite(s: PLLStream, data: Char) =
proc llStreamWrite(s: PLLStream, data: char) =
var c: char
case s.kind
of llsNone, llsStdIn:
nil
discard
of llsString:
add(s.s, data)
inc(s.wr)
of llsFile:
c = data
discard writeBuffer(s.f, addr(c), sizeof(c))

proc LLStreamWrite(s: PLLStream, buf: pointer, buflen: int) =
proc llStreamWrite(s: PLLStream, buf: pointer, buflen: int) =
case s.kind
of llsNone, llsStdIn:
nil
discard
of llsString:
if bufLen > 0:
setlen(s.s, len(s.s) + bufLen)
copyMem(addr(s.s[0 + s.wr]), buf, bufLen)
inc(s.wr, bufLen)
if buflen > 0:
setLen(s.s, len(s.s) + buflen)
copyMem(addr(s.s[0 + s.wr]), buf, buflen)
inc(s.wr, buflen)
of llsFile:
discard writeBuffer(s.f, buf, bufLen)
discard writeBuffer(s.f, buf, buflen)

proc LLStreamReadAll(s: PLLStream): string =
proc llStreamReadAll(s: PLLStream): string =
const
bufSize = 2048
var bytes, i: int
case s.kind
of llsNone, llsStdIn:
result = ""
Expand All @@ -216,10 +215,10 @@ proc LLStreamReadAll(s: PLLStream): string =
s.rd = len(s.s)
of llsFile:
result = newString(bufSize)
bytes = readBuffer(s.f, addr(result[0]), bufSize)
i = bytes
var bytes = readBuffer(s.f, addr(result[0]), bufSize)
var i = bytes
while bytes == bufSize:
setlen(result, i + bufSize)
setLen(result, i + bufSize)
bytes = readBuffer(s.f, addr(result[i + 0]), bufSize)
inc(i, bytes)
setlen(result, i)
setLen(result, i)
132 changes: 76 additions & 56 deletions compiler/lookups.nim
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ proc considerAcc*(n: PNode): PIdent =
of nkSym: result = n.sym.name
of nkAccQuoted:
case n.len
of 0: GlobalError(n.info, errIdentifierExpected, renderTree(n))
of 0: globalError(n.info, errIdentifierExpected, renderTree(n))
of 1: result = considerAcc(n.sons[0])
else:
var id = ""
Expand All @@ -30,16 +30,17 @@ proc considerAcc*(n: PNode): PIdent =
case x.kind
of nkIdent: id.add(x.ident.s)
of nkSym: id.add(x.sym.name.s)
else: GlobalError(n.info, errIdentifierExpected, renderTree(n))
else: globalError(n.info, errIdentifierExpected, renderTree(n))
result = getIdent(id)
of nkOpenSymChoice, nkClosedSymChoice: result = n.sons[0].sym.name
else:
GlobalError(n.info, errIdentifierExpected, renderTree(n))
globalError(n.info, errIdentifierExpected, renderTree(n))

template addSym*(scope: PScope, s: PSym) =
StrTableAdd(scope.symbols, s)
strTableAdd(scope.symbols, s)

proc addUniqueSym*(scope: PScope, s: PSym): TResult =
if StrTableIncl(scope.symbols, s):
if strTableIncl(scope.symbols, s):
result = Failure
else:
result = Success
Expand All @@ -64,17 +65,17 @@ iterator walkScopes*(scope: PScope): PScope =
current = current.parent

proc localSearchInScope*(c: PContext, s: PIdent): PSym =
result = StrTableGet(c.currentScope.symbols, s)
result = strTableGet(c.currentScope.symbols, s)

proc searchInScopes*(c: PContext, s: PIdent): PSym =
for scope in walkScopes(c.currentScope):
result = StrTableGet(scope.symbols, s)
result = strTableGet(scope.symbols, s)
if result != nil: return
result = nil

proc searchInScopes*(c: PContext, s: PIdent, filter: TSymKinds): PSym =
for scope in walkScopes(c.currentScope):
result = StrTableGet(scope.symbols, s)
result = strTableGet(scope.symbols, s)
if result != nil and result.kind in filter: return
result = nil

Expand All @@ -91,7 +92,8 @@ proc errorSym*(c: PContext, n: PNode): PSym =
result.typ = errorType(c)
incl(result.flags, sfDiscardable)
# pretend it's imported from some unknown module to prevent cascading errors:
c.importTable.addSym(result)
if gCmd != cmdInteractive and c.inCompilesContext == 0:
c.importTable.addSym(result)

type
TOverloadIterMode* = enum
Expand All @@ -107,114 +109,117 @@ type

proc getSymRepr*(s: PSym): string =
case s.kind
of skProc, skMethod, skConverter, skIterator: result = getProcHeader(s)
of skProc, skMethod, skConverter, skIterators: result = getProcHeader(s)
else: result = s.name.s

proc ensureNoMissingOrUnusedSymbols(scope: PScope) =
# check if all symbols have been used and defined:
var it: TTabIter
var s = InitTabIter(it, scope.symbols)
var s = initTabIter(it, scope.symbols)
var missingImpls = 0
while s != nil:
if sfForward in s.flags:
# too many 'implementation of X' errors are annoying
# and slow 'suggest' down:
if missingImpls == 0:
LocalError(s.info, errImplOfXexpected, getSymRepr(s))
localError(s.info, errImplOfXexpected, getSymRepr(s))
inc missingImpls
elif {sfUsed, sfExported} * s.flags == {} and optHints in s.options:
# BUGFIX: check options in s!
if s.kind notin {skForVar, skParam, skMethod, skUnknown, skGenericParam}:
Message(s.info, hintXDeclaredButNotUsed, getSymRepr(s))
s = NextIter(it, scope.symbols)
# XXX: implicit type params are currently skTypes
# maybe they can be made skGenericParam as well.
if s.typ != nil and tfImplicitTypeParam notin s.typ.flags:
message(s.info, hintXDeclaredButNotUsed, getSymRepr(s))
s = nextIter(it, scope.symbols)

proc WrongRedefinition*(info: TLineInfo, s: string) =
proc wrongRedefinition*(info: TLineInfo, s: string) =
if gCmd != cmdInteractive:
localError(info, errAttemptToRedefine, s)

proc addDecl*(c: PContext, sym: PSym) =
if c.currentScope.addUniqueSym(sym) == Failure:
WrongRedefinition(sym.info, sym.Name.s)
wrongRedefinition(sym.info, sym.name.s)

proc addPrelimDecl*(c: PContext, sym: PSym) =
discard c.currentScope.addUniqueSym(sym)

proc addDeclAt*(scope: PScope, sym: PSym) =
if scope.addUniqueSym(sym) == Failure:
WrongRedefinition(sym.info, sym.Name.s)
wrongRedefinition(sym.info, sym.name.s)

proc AddInterfaceDeclAux(c: PContext, sym: PSym) =
proc addInterfaceDeclAux(c: PContext, sym: PSym) =
if sfExported in sym.flags:
# add to interface:
if c.module != nil: StrTableAdd(c.module.tab, sym)
else: InternalError(sym.info, "AddInterfaceDeclAux")
if c.module != nil: strTableAdd(c.module.tab, sym)
else: internalError(sym.info, "AddInterfaceDeclAux")

proc addInterfaceDeclAt*(c: PContext, scope: PScope, sym: PSym) =
addDeclAt(scope, sym)
AddInterfaceDeclAux(c, sym)
addInterfaceDeclAux(c, sym)

proc addOverloadableSymAt*(scope: PScope, fn: PSym) =
if fn.kind notin OverloadableSyms:
InternalError(fn.info, "addOverloadableSymAt")
internalError(fn.info, "addOverloadableSymAt")
return
var check = StrTableGet(scope.symbols, fn.name)
if check != nil and check.Kind notin OverloadableSyms:
WrongRedefinition(fn.info, fn.Name.s)
var check = strTableGet(scope.symbols, fn.name)
if check != nil and check.kind notin OverloadableSyms:
wrongRedefinition(fn.info, fn.name.s)
else:
scope.addSym(fn)

proc addInterfaceDecl*(c: PContext, sym: PSym) =
# it adds the symbol to the interface if appropriate
addDecl(c, sym)
AddInterfaceDeclAux(c, sym)
addInterfaceDeclAux(c, sym)

proc addInterfaceOverloadableSymAt*(c: PContext, scope: PScope, sym: PSym) =
# it adds the symbol to the interface if appropriate
addOverloadableSymAt(scope, sym)
AddInterfaceDeclAux(c, sym)
addInterfaceDeclAux(c, sym)

proc lookUp*(c: PContext, n: PNode): PSym =
# Looks up a symbol. Generates an error in case of nil.
case n.kind
of nkIdent:
result = searchInScopes(c, n.ident)
if result == nil:
LocalError(n.info, errUndeclaredIdentifier, n.ident.s)
localError(n.info, errUndeclaredIdentifier, n.ident.s)
result = errorSym(c, n)
of nkSym:
result = n.sym
of nkAccQuoted:
var ident = considerAcc(n)
result = searchInScopes(c, ident)
if result == nil:
LocalError(n.info, errUndeclaredIdentifier, ident.s)
localError(n.info, errUndeclaredIdentifier, ident.s)
result = errorSym(c, n)
else:
InternalError(n.info, "lookUp")
internalError(n.info, "lookUp")
return
if Contains(c.AmbiguousSymbols, result.id):
LocalError(n.info, errUseQualifier, result.name.s)
if contains(c.ambiguousSymbols, result.id):
localError(n.info, errUseQualifier, result.name.s)
if result.kind == skStub: loadStub(result)

type
TLookupFlag* = enum
checkAmbiguity, checkUndeclared

proc QualifiedLookUp*(c: PContext, n: PNode, flags = {checkUndeclared}): PSym =
proc qualifiedLookUp*(c: PContext, n: PNode, flags = {checkUndeclared}): PSym =
case n.kind
of nkIdent, nkAccQuoted:
var ident = considerAcc(n)
result = searchInScopes(c, ident)
if result == nil and checkUndeclared in flags:
LocalError(n.info, errUndeclaredIdentifier, ident.s)
localError(n.info, errUndeclaredIdentifier, ident.s)
result = errorSym(c, n)
elif checkAmbiguity in flags and result != nil and
Contains(c.AmbiguousSymbols, result.id):
LocalError(n.info, errUseQualifier, ident.s)
contains(c.ambiguousSymbols, result.id):
localError(n.info, errUseQualifier, ident.s)
of nkSym:
result = n.sym
if checkAmbiguity in flags and Contains(c.AmbiguousSymbols, result.id):
LocalError(n.info, errUseQualifier, n.sym.name.s)
if checkAmbiguity in flags and contains(c.ambiguousSymbols, result.id):
localError(n.info, errUseQualifier, n.sym.name.s)
of nkDotExpr:
result = nil
var m = qualifiedLookUp(c, n.sons[0], flags*{checkUndeclared})
Expand All @@ -226,28 +231,31 @@ proc QualifiedLookUp*(c: PContext, n: PNode, flags = {checkUndeclared}): PSym =
ident = considerAcc(n.sons[1])
if ident != nil:
if m == c.module:
result = StrTableGet(c.topLevelScope.symbols, ident)
result = strTableGet(c.topLevelScope.symbols, ident)
else:
result = StrTableGet(m.tab, ident)
result = strTableGet(m.tab, ident)
if result == nil and checkUndeclared in flags:
LocalError(n.sons[1].info, errUndeclaredIdentifier, ident.s)
localError(n.sons[1].info, errUndeclaredIdentifier, ident.s)
result = errorSym(c, n.sons[1])
elif checkUndeclared in flags:
LocalError(n.sons[1].info, errIdentifierExpected,
elif n.sons[1].kind == nkSym:
result = n.sons[1].sym
elif checkUndeclared in flags and
n.sons[1].kind notin {nkOpenSymChoice, nkClosedSymChoice}:
localError(n.sons[1].info, errIdentifierExpected,
renderTree(n.sons[1]))
result = errorSym(c, n.sons[1])
else:
result = nil
if result != nil and result.kind == skStub: loadStub(result)

proc InitOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
proc initOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
case n.kind
of nkIdent, nkAccQuoted:
var ident = considerAcc(n)
o.scope = c.currentScope
o.mode = oimNoQualifier
while true:
result = InitIdentIter(o.it, o.scope.symbols, ident)
result = initIdentIter(o.it, o.scope.symbols, ident)
if result != nil:
break
else:
Expand All @@ -268,21 +276,21 @@ proc InitOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
if ident != nil:
if o.m == c.module:
# a module may access its private members:
result = InitIdentIter(o.it, c.topLevelScope.symbols, ident)
result = initIdentIter(o.it, c.topLevelScope.symbols, ident)
o.mode = oimSelfModule
else:
result = InitIdentIter(o.it, o.m.tab, ident)
result = initIdentIter(o.it, o.m.tab, ident)
else:
LocalError(n.sons[1].info, errIdentifierExpected,
localError(n.sons[1].info, errIdentifierExpected,
renderTree(n.sons[1]))
result = errorSym(c, n.sons[1])
of nkClosedSymChoice, nkOpenSymChoice:
o.mode = oimSymChoice
result = n.sons[0].sym
o.symChoiceIndex = 1
o.inSymChoice = initIntSet()
Incl(o.inSymChoice, result.id)
else: nil
incl(o.inSymChoice, result.id)
else: discard
if result != nil and result.kind == skStub: loadStub(result)

proc lastOverloadScope*(o: TOverloadIter): int =
Expand All @@ -302,7 +310,7 @@ proc nextOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
while result == nil:
o.scope = o.scope.parent
if o.scope == nil: break
result = InitIdentIter(o.it, o.scope.symbols, o.it.name)
result = initIdentIter(o.it, o.scope.symbols, o.it.name)
# BUGFIX: o.it.name <-> n.ident
else:
result = nil
Expand All @@ -313,26 +321,38 @@ proc nextOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
of oimSymChoice:
if o.symChoiceIndex < sonsLen(n):
result = n.sons[o.symChoiceIndex].sym
Incl(o.inSymChoice, result.id)
incl(o.inSymChoice, result.id)
inc o.symChoiceIndex
elif n.kind == nkOpenSymChoice:
# try 'local' symbols too for Koenig's lookup:
o.mode = oimSymChoiceLocalLookup
o.scope = c.currentScope
result = FirstIdentExcluding(o.it, o.scope.symbols,
result = firstIdentExcluding(o.it, o.scope.symbols,
n.sons[0].sym.name, o.inSymChoice)
while result == nil:
o.scope = o.scope.parent
if o.scope == nil: break
result = FirstIdentExcluding(o.it, o.scope.symbols,
result = firstIdentExcluding(o.it, o.scope.symbols,
n.sons[0].sym.name, o.inSymChoice)
of oimSymChoiceLocalLookup:
result = nextIdentExcluding(o.it, o.scope.symbols, o.inSymChoice)
while result == nil:
o.scope = o.scope.parent
if o.scope == nil: break
result = FirstIdentExcluding(o.it, o.scope.symbols,
result = firstIdentExcluding(o.it, o.scope.symbols,
n.sons[0].sym.name, o.inSymChoice)

if result != nil and result.kind == skStub: loadStub(result)


when false:
proc qualifiedLookUpPreferImmediate*(c: PContext, n: PNode,
flags = {checkUndeclared}): PSym =
var o: TOverloadIter
result = initOverloadIter(o, c, n)
var a = result
while a != nil:
if sfImmediate in a.flags: return a
a = nextOverloadIter(o, c, n)
if result == nil and checkUndeclared in flags:
localError(n.info, errUndeclaredIdentifier, n.considerAcc.s)
result = errorSym(c, n)
228 changes: 228 additions & 0 deletions compiler/lowerings.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,228 @@
#
#
# The Nimrod Compiler
# (c) Copyright 2014 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#

## This module implements common simple lowerings.

const
genPrefix* = ":tmp" # prefix for generated names

import ast, astalgo, types, idents, magicsys, msgs, options

proc newTupleAccess*(tup: PNode, i: int): PNode =
result = newNodeIT(nkBracketExpr, tup.info, tup.typ.skipTypes(
abstractInst).sons[i])
addSon(result, copyTree(tup))
var lit = newNodeIT(nkIntLit, tup.info, getSysType(tyInt))
lit.intVal = i
addSon(result, lit)

proc addVar*(father, v: PNode) =
var vpart = newNodeI(nkIdentDefs, v.info, 3)
vpart.sons[0] = v
vpart.sons[1] = ast.emptyNode
vpart.sons[2] = ast.emptyNode
addSon(father, vpart)

proc newAsgnStmt(le, ri: PNode): PNode =
result = newNodeI(nkAsgn, le.info, 2)
result.sons[0] = le
result.sons[1] = ri

proc newFastAsgnStmt(le, ri: PNode): PNode =
result = newNodeI(nkFastAsgn, le.info, 2)
result.sons[0] = le
result.sons[1] = ri

proc lowerTupleUnpacking*(n: PNode; owner: PSym): PNode =
assert n.kind == nkVarTuple
let value = n.lastSon
result = newNodeI(nkStmtList, n.info)

var temp = newSym(skTemp, getIdent(genPrefix), owner, value.info)
temp.typ = skipTypes(value.typ, abstractInst)
incl(temp.flags, sfFromGeneric)

var v = newNodeI(nkVarSection, value.info)
v.addVar(newSymNode(temp))
result.add(v)

result.add newAsgnStmt(newSymNode(temp), value)
for i in 0 .. n.len-3:
result.add newAsgnStmt(n.sons[i], newTupleAccess(value, i))

proc createObj*(owner: PSym, info: TLineInfo): PType =
result = newType(tyObject, owner)
rawAddSon(result, nil)
incl result.flags, tfFinal
result.n = newNodeI(nkRecList, info)

proc addField*(obj: PType; s: PSym) =
# because of 'gensym' support, we have to mangle the name with its ID.
# This is hacky but the clean solution is much more complex than it looks.
var field = newSym(skField, getIdent(s.name.s & $s.id), s.owner, s.info)
let t = skipIntLit(s.typ)
field.typ = t
field.position = sonsLen(obj.n)
addSon(obj.n, newSymNode(field))

proc newDotExpr(obj, b: PSym): PNode =
result = newNodeI(nkDotExpr, obj.info)
let field = getSymFromList(obj.typ.n, getIdent(b.name.s & $b.id))
assert field != nil, b.name.s
addSon(result, newSymNode(obj))
addSon(result, newSymNode(field))
result.typ = field.typ

proc indirectAccess*(a: PNode, b: PSym, info: TLineInfo): PNode =
# returns a[].b as a node
var deref = newNodeI(nkHiddenDeref, info)
deref.typ = a.typ.sons[0]
assert deref.typ.kind == tyObject
let field = getSymFromList(deref.typ.n, getIdent(b.name.s & $b.id))
assert field != nil, b.name.s
addSon(deref, a)
result = newNodeI(nkDotExpr, info)
addSon(result, deref)
addSon(result, newSymNode(field))
result.typ = field.typ

proc indirectAccess*(a, b: PSym, info: TLineInfo): PNode =
result = indirectAccess(newSymNode(a), b, info)

proc genAddrOf*(n: PNode): PNode =
result = newNodeI(nkAddr, n.info, 1)
result.sons[0] = n
result.typ = newType(tyPtr, n.typ.owner)
result.typ.rawAddSon(n.typ)

proc callCodegenProc*(name: string, arg1: PNode;
arg2, arg3: PNode = nil): PNode =
result = newNodeI(nkCall, arg1.info)
let sym = magicsys.getCompilerProc(name)
if sym == nil:
localError(arg1.info, errSystemNeeds, name)
else:
result.add newSymNode(sym)
result.add arg1
if arg2 != nil: result.add arg2
if arg3 != nil: result.add arg3

proc createWrapperProc(f: PNode; threadParam, argsParam: PSym;
varSection, call: PNode): PSym =
var body = newNodeI(nkStmtList, f.info)
body.add varSection
body.add callCodeGenProc("nimArgsPassingDone", newSymNode(threadParam))
body.add call

var params = newNodeI(nkFormalParams, f.info)
params.add emptyNode
params.add threadParam.newSymNode
params.add argsParam.newSymNode

var t = newType(tyProc, threadParam.owner)
t.rawAddSon nil
t.rawAddSon threadParam.typ
t.rawAddSon argsParam.typ
t.n = newNodeI(nkFormalParams, f.info)
t.n.add newNodeI(nkEffectList, f.info)
t.n.add threadParam.newSymNode
t.n.add argsParam.newSymNode

let name = (if f.kind == nkSym: f.sym.name.s else: genPrefix) & "Wrapper"
result = newSym(skProc, getIdent(name), argsParam.owner, f.info)
result.ast = newProcNode(nkProcDef, f.info, body, params, newSymNode(result))
result.typ = t

proc createCastExpr(argsParam: PSym; objType: PType): PNode =
result = newNodeI(nkCast, argsParam.info)
result.add emptyNode
result.add newSymNode(argsParam)
result.typ = newType(tyPtr, objType.owner)
result.typ.rawAddSon(objType)

proc wrapProcForSpawn*(owner: PSym; n: PNode): PNode =
result = newNodeI(nkStmtList, n.info)
if n.kind notin nkCallKinds or not n.typ.isEmptyType:
localError(n.info, "'spawn' takes a call expression of type void")
return
if optThreadAnalysis in gGlobalOptions:
if {tfThread, tfNoSideEffect} * n[0].typ.flags == {}:
localError(n.info, "'spawn' takes a GC safe call expression")
var
threadParam = newSym(skParam, getIdent"thread", owner, n.info)
argsParam = newSym(skParam, getIdent"args", owner, n.info)
block:
let ptrType = getSysType(tyPointer)
threadParam.typ = ptrType
argsParam.typ = ptrType
argsParam.position = 1
var objType = createObj(owner, n.info)
incl(objType.flags, tfFinal)
let castExpr = createCastExpr(argsParam, objType)

var scratchObj = newSym(skVar, getIdent"scratch", owner, n.info)
block:
scratchObj.typ = objType
incl(scratchObj.flags, sfFromGeneric)
var varSectionB = newNodeI(nkVarSection, n.info)
varSectionB.addVar(scratchObj.newSymNode)
result.add varSectionB

var call = newNodeI(nkCall, n.info)
var fn = n.sons[0]
# templates and macros are in fact valid here due to the nature of
# the transformation:
if not (fn.kind == nkSym and fn.sym.kind in {skProc, skTemplate, skMacro,
skMethod, skConverter}):
# for indirect calls we pass the function pointer in the scratchObj
var argType = n[0].typ.skipTypes(abstractInst)
var field = newSym(skField, getIdent"fn", owner, n.info)
field.typ = argType
objType.addField(field)
result.add newFastAsgnStmt(newDotExpr(scratchObj, field), n[0])
fn = indirectAccess(castExpr, field, n.info)
elif fn.kind == nkSym and fn.sym.kind in {skClosureIterator, skIterator}:
localError(n.info, "iterator in spawn environment is not allowed")
elif fn.typ.callConv == ccClosure:
localError(n.info, "closure in spawn environment is not allowed")

call.add(fn)
var varSection = newNodeI(nkVarSection, n.info)
let formals = n[0].typ.n
let tmpName = getIdent(genPrefix)
for i in 1 .. <n.len:
# we pick n's type here, which hopefully is 'tyArray' and not
# 'tyOpenArray':
var argType = n[i].typ.skipTypes(abstractInst)
if i < formals.len and formals[i].typ.kind == tyVar:
localError(n[i].info, "'spawn'ed function cannot have a 'var' parameter")
elif containsTyRef(argType):
localError(n[i].info, "'spawn'ed function cannot refer to 'ref'/closure")

let fieldname = if i < formals.len: formals[i].sym.name else: tmpName
var field = newSym(skField, fieldname, owner, n.info)
field.typ = argType
objType.addField(field)
result.add newFastAsgnStmt(newDotExpr(scratchObj, field), n[i])

var temp = newSym(skTemp, tmpName, owner, n.info)
temp.typ = argType
incl(temp.flags, sfFromGeneric)

var vpart = newNodeI(nkIdentDefs, n.info, 3)
vpart.sons[0] = newSymNode(temp)
vpart.sons[1] = ast.emptyNode
vpart.sons[2] = indirectAccess(castExpr, field, n.info)
varSection.add vpart

call.add(newSymNode(temp))

let wrapper = createWrapperProc(fn, threadParam, argsParam, varSection, call)
result.add callCodeGenProc("nimSpawn", wrapper.newSymNode,
genAddrOf(scratchObj.newSymNode))
60 changes: 39 additions & 21 deletions compiler/magicsys.nim
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,14 @@
import
ast, astalgo, hashes, msgs, platform, nversion, times, idents, rodread

var SystemModule*: PSym
var systemModule*: PSym

proc registerSysType*(t: PType)
# magic symbols in the system module:
proc getSysType*(kind: TTypeKind): PType
proc getCompilerProc*(name: string): PSym
proc registerCompilerProc*(s: PSym)
proc FinishSystem*(tab: TStrTable)
proc finishSystem*(tab: TStrTable)
proc getSysSym*(name: string): PSym
# implementation

Expand All @@ -36,13 +36,25 @@ proc newSysType(kind: TTypeKind, size: int): PType =
result.align = size

proc getSysSym(name: string): PSym =
result = StrTableGet(systemModule.tab, getIdent(name))
result = strTableGet(systemModule.tab, getIdent(name))
if result == nil:
rawMessage(errSystemNeeds, name)
result = newSym(skError, getIdent(name), systemModule, systemModule.info)
result.typ = newType(tyError, systemModule)
if result.kind == skStub: loadStub(result)

proc getSysMagic*(name: string, m: TMagic): PSym =
var ti: TIdentIter
let id = getIdent(name)
result = initIdentIter(ti, systemModule.tab, id)
while result != nil:
if result.kind == skStub: loadStub(result)
if result.magic == m: return result
result = nextIdentIter(ti, systemModule.tab)
rawMessage(errSystemNeeds, name)
result = newSym(skError, id, systemModule, systemModule.info)
result.typ = newType(tyError, systemModule)

proc sysTypeFromName*(name: string): PType =
result = getSysSym(name).typ

Expand All @@ -62,19 +74,19 @@ proc getSysType(kind: TTypeKind): PType =
of tyUInt64: result = sysTypeFromName("uint64")
of tyFloat: result = sysTypeFromName("float")
of tyFloat32: result = sysTypeFromName("float32")
of tyFloat64: result = sysTypeFromName("float64")
of tyFloat64: return sysTypeFromName("float64")
of tyFloat128: result = sysTypeFromName("float128")
of tyBool: result = sysTypeFromName("bool")
of tyChar: result = sysTypeFromName("char")
of tyString: result = sysTypeFromName("string")
of tyCstring: result = sysTypeFromName("cstring")
of tyCString: result = sysTypeFromName("cstring")
of tyPointer: result = sysTypeFromName("pointer")
of tyNil: result = newSysType(tyNil, ptrSize)
else: InternalError("request for typekind: " & $kind)
else: internalError("request for typekind: " & $kind)
gSysTypes[kind] = result
if result.kind != kind:
InternalError("wanted: " & $kind & " got: " & $result.kind)
if result == nil: InternalError("type not found: " & $kind)
internalError("wanted: " & $kind & " got: " & $result.kind)
if result == nil: internalError("type not found: " & $kind)

var
intTypeCache: array[-5..64, PType]
Expand Down Expand Up @@ -103,19 +115,26 @@ proc getIntLitType*(literal: PNode): PType =
result = copyType(ti, ti.owner, false)
result.n = literal

proc getFloatLitType*(literal: PNode): PType =
# for now we do not cache these:
result = newSysType(tyFloat, size=8)
result.n = literal

proc skipIntLit*(t: PType): PType {.inline.} =
if t.kind == tyInt and t.n != nil:
result = getSysType(tyInt)
else:
result = t
if t.n != nil:
if t.kind in {tyInt, tyFloat}:
return getSysType(t.kind)
result = t

proc AddSonSkipIntLit*(father, son: PType) =
proc addSonSkipIntLit*(father, son: PType) =
if isNil(father.sons): father.sons = @[]
add(father.sons, son.skipIntLit)
let s = son.skipIntLit
add(father.sons, s)
propagateToOwner(father, s)

proc setIntLitType*(result: PNode) =
let i = result.intVal
case platform.IntSize
case platform.intSize
of 8: result.typ = getIntLitType(result)
of 4:
if i >= low(int32) and i <= high(int32):
Expand All @@ -139,21 +158,20 @@ proc setIntLitType*(result: PNode) =
result.typ = getSysType(tyInt32)
else:
result.typ = getSysType(tyInt64)
else: InternalError(result.info, "invalid int size")
else: internalError(result.info, "invalid int size")

proc getCompilerProc(name: string): PSym =
var ident = getIdent(name, hashIgnoreStyle(name))
result = StrTableGet(compilerprocs, ident)
result = strTableGet(compilerprocs, ident)
if result == nil:
result = StrTableGet(rodCompilerProcs, ident)
result = strTableGet(rodCompilerprocs, ident)
if result != nil:
strTableAdd(compilerprocs, result)
if result.kind == skStub: loadStub(result)

proc registerCompilerProc(s: PSym) =
strTableAdd(compilerprocs, s)

proc FinishSystem(tab: TStrTable) = nil

initStrTable(compilerprocs)
proc finishSystem(tab: TStrTable) = discard

initStrTable(compilerprocs)
432 changes: 131 additions & 301 deletions compiler/main.nim

Large diffs are not rendered by default.

201 changes: 201 additions & 0 deletions compiler/modules.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
#
#
# The Nimrod Compiler
# (c) Copyright 2014 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#

## implements the module handling

import
ast, astalgo, magicsys, crc, rodread, msgs, cgendata, sigmatch, options,
idents, os, lexer, idgen, passes, syntaxes

type
TNeedRecompile* = enum Maybe, No, Yes, Probing, Recompiled
TCrcStatus* = enum crcNotTaken, crcCached, crcHasChanged, crcNotChanged

TModuleInMemory* = object
compiledAt*: float
crc*: TCrc32
deps*: seq[int32] ## XXX: slurped files are currently not tracked
needsRecompile*: TNeedRecompile
crcStatus*: TCrcStatus

var
gCompiledModules: seq[PSym] = @[]
gMemCacheData*: seq[TModuleInMemory] = @[]
## XXX: we should implement recycling of file IDs
## if the user keeps renaming modules, the file IDs will keep growing

proc getModule(fileIdx: int32): PSym =
if fileIdx >= 0 and fileIdx < gCompiledModules.len:
result = gCompiledModules[fileIdx]

template compiledAt(x: PSym): expr =
gMemCacheData[x.position].compiledAt

template crc(x: PSym): expr =
gMemCacheData[x.position].crc

proc crcChanged(fileIdx: int32): bool =
internalAssert fileIdx >= 0 and fileIdx < gMemCacheData.len

template updateStatus =
gMemCacheData[fileIdx].crcStatus = if result: crcHasChanged
else: crcNotChanged
# echo "TESTING CRC: ", fileIdx.toFilename, " ", result

case gMemCacheData[fileIdx].crcStatus:
of crcHasChanged:
result = true
of crcNotChanged:
result = false
of crcCached:
let newCrc = crcFromFile(fileIdx.toFilename)
result = newCrc != gMemCacheData[fileIdx].crc
gMemCacheData[fileIdx].crc = newCrc
updateStatus()
of crcNotTaken:
gMemCacheData[fileIdx].crc = crcFromFile(fileIdx.toFilename)
result = true
updateStatus()

proc doCRC(fileIdx: int32) =
if gMemCacheData[fileIdx].crcStatus == crcNotTaken:
# echo "FIRST CRC: ", fileIdx.ToFilename
gMemCacheData[fileIdx].crc = crcFromFile(fileIdx.toFilename)

proc addDep(x: PSym, dep: int32) =
growCache gMemCacheData, dep
gMemCacheData[x.position].deps.safeAdd(dep)

proc resetModule*(fileIdx: int32) =
# echo "HARD RESETTING ", fileIdx.toFilename
gMemCacheData[fileIdx].needsRecompile = Yes
gCompiledModules[fileIdx] = nil
cgendata.gModules[fileIdx] = nil
resetSourceMap(fileIdx)

proc resetAllModules* =
for i in 0..gCompiledModules.high:
if gCompiledModules[i] != nil:
resetModule(i.int32)
resetPackageCache()
# for m in cgenModules(): echo "CGEN MODULE FOUND"

proc checkDepMem(fileIdx: int32): TNeedRecompile =
template markDirty =
resetModule(fileIdx)
return Yes

if gMemCacheData[fileIdx].needsRecompile != Maybe:
return gMemCacheData[fileIdx].needsRecompile

if optForceFullMake in gGlobalOptions or
crcChanged(fileIdx):
markDirty

if gMemCacheData[fileIdx].deps != nil:
gMemCacheData[fileIdx].needsRecompile = Probing
for dep in gMemCacheData[fileIdx].deps:
let d = checkDepMem(dep)
if d in {Yes, Recompiled}:
# echo fileIdx.toFilename, " depends on ", dep.toFilename, " ", d
markDirty

gMemCacheData[fileIdx].needsRecompile = No
return No

proc newModule(fileIdx: int32): PSym =
# We cannot call ``newSym`` here, because we have to circumvent the ID
# mechanism, which we do in order to assign each module a persistent ID.
new(result)
result.id = - 1 # for better error checking
result.kind = skModule
let filename = fileIdx.toFilename
result.name = getIdent(splitFile(filename).name)
if not isNimrodIdentifier(result.name.s):
rawMessage(errInvalidModuleName, result.name.s)

result.info = newLineInfo(fileIdx, 1, 1)
result.owner = newSym(skPackage, getIdent(getPackageName(filename)), nil,
result.info)
result.position = fileIdx

growCache gMemCacheData, fileIdx
growCache gCompiledModules, fileIdx
gCompiledModules[result.position] = result

incl(result.flags, sfUsed)
initStrTable(result.tab)
strTableAdd(result.tab, result) # a module knows itself

proc compileModule*(fileIdx: int32, flags: TSymFlags): PSym =
result = getModule(fileIdx)
if result == nil:
growCache gMemCacheData, fileIdx
gMemCacheData[fileIdx].needsRecompile = Probing
result = newModule(fileIdx)
#var rd = handleSymbolFile(result)
var rd: PRodReader
result.flags = result.flags + flags
if gCmd in {cmdCompileToC, cmdCompileToCpp, cmdCheck, cmdIdeTools}:
rd = handleSymbolFile(result)
if result.id < 0:
internalError("handleSymbolFile should have set the module\'s ID")
return
else:
result.id = getID()
processModule(result, nil, rd)
if optCaasEnabled in gGlobalOptions:
gMemCacheData[fileIdx].compiledAt = gLastCmdTime
gMemCacheData[fileIdx].needsRecompile = Recompiled
doCRC fileIdx
else:
if checkDepMem(fileIdx) == Yes:
result = compileModule(fileIdx, flags)
else:
result = gCompiledModules[fileIdx]

proc importModule*(s: PSym, fileIdx: int32): PSym {.procvar.} =
# this is called by the semantic checking phase
result = compileModule(fileIdx, {})
if optCaasEnabled in gGlobalOptions: addDep(s, fileIdx)
if sfSystemModule in result.flags:
localError(result.info, errAttemptToRedefine, result.name.s)

proc includeModule*(s: PSym, fileIdx: int32): PNode {.procvar.} =
result = syntaxes.parseFile(fileIdx)
if optCaasEnabled in gGlobalOptions:
growCache gMemCacheData, fileIdx
addDep(s, fileIdx)
doCRC(fileIdx)

proc `==^`(a, b: string): bool =
try:
result = sameFile(a, b)
except EOS:
result = false

proc compileSystemModule* =
if magicsys.systemModule == nil:
systemFileIdx = fileInfoIdx(options.libpath/"system.nim")
discard compileModule(systemFileIdx, {sfSystemModule})

proc compileProject*(projectFile = gProjectMainIdx) =
let systemFileIdx = fileInfoIdx(options.libpath / "system.nim")
if projectFile == systemFileIdx:
discard compileModule(projectFile, {sfMainModule, sfSystemModule})
else:
compileSystemModule()
discard compileModule(projectFile, {sfMainModule})

var stdinModule: PSym
proc makeStdinModule*(): PSym =
if stdinModule == nil:
stdinModule = newModule(fileInfoIdx"stdin")
stdinModule.id = getID()
result = stdinModule
273 changes: 169 additions & 104 deletions compiler/msgs.nim

Large diffs are not rendered by default.

48 changes: 23 additions & 25 deletions compiler/nimconf.nim
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ proc parseExpr(L: var TLexer, tok: var TToken): bool =
var b = parseAndExpr(L, tok)
result = result or b

proc EvalppIf(L: var TLexer, tok: var TToken): bool =
proc evalppIf(L: var TLexer, tok: var TToken): bool =
ppGetTok(L, tok) # skip 'if' or 'elif'
result = parseExpr(L, tok)
if tok.tokType == tkColon: ppGetTok(L, tok)
Expand All @@ -60,7 +60,7 @@ var condStack: seq[bool] = @[]
proc doEnd(L: var TLexer, tok: var TToken) =
if high(condStack) < 0: lexMessage(L, errTokenExpected, "@if")
ppGetTok(L, tok) # skip 'end'
setlen(condStack, high(condStack))
setLen(condStack, high(condStack))

type
TJumpDest = enum
Expand All @@ -75,18 +75,18 @@ proc doElse(L: var TLexer, tok: var TToken) =

proc doElif(L: var TLexer, tok: var TToken) =
if high(condStack) < 0: lexMessage(L, errTokenExpected, "@if")
var res = EvalppIf(L, tok)
var res = evalppIf(L, tok)
if condStack[high(condStack)] or not res: jumpToDirective(L, tok, jdElseEndif)
else: condStack[high(condStack)] = true

proc jumpToDirective(L: var TLexer, tok: var TToken, dest: TJumpDest) =
var nestedIfs = 0
while True:
while true:
if (tok.ident != nil) and (tok.ident.s == "@"):
ppGetTok(L, tok)
case whichKeyword(tok.ident)
of wIf:
Inc(nestedIfs)
inc(nestedIfs)
of wElse:
if (dest == jdElseEndif) and (nestedIfs == 0):
doElse(L, tok)
Expand All @@ -99,29 +99,29 @@ proc jumpToDirective(L: var TLexer, tok: var TToken, dest: TJumpDest) =
if nestedIfs == 0:
doEnd(L, tok)
break
if nestedIfs > 0: Dec(nestedIfs)
if nestedIfs > 0: dec(nestedIfs)
else:
nil
discard
ppGetTok(L, tok)
elif tok.tokType == tkEof:
elif tok.tokType == tkEof:
lexMessage(L, errTokenExpected, "@end")
else:
else:
ppGetTok(L, tok)

proc parseDirective(L: var TLexer, tok: var TToken) =
ppGetTok(L, tok) # skip @
case whichKeyword(tok.ident)
of wIf:
setlen(condStack, len(condStack) + 1)
var res = EvalppIf(L, tok)
setLen(condStack, len(condStack) + 1)
var res = evalppIf(L, tok)
condStack[high(condStack)] = res
if not res: jumpToDirective(L, tok, jdElseEndif)
of wElif: doElif(L, tok)
of wElse: doElse(L, tok)
of wEnd: doEnd(L, tok)
of wWrite:
ppGetTok(L, tok)
msgs.MsgWriteln(tokToStr(tok))
msgs.msgWriteln(tokToStr(tok))
ppGetTok(L, tok)
else:
case tok.ident.s.normalize
Expand All @@ -135,13 +135,13 @@ proc parseDirective(L: var TLexer, tok: var TToken) =
ppGetTok(L, tok)
var key = tokToStr(tok)
ppGetTok(L, tok)
os.putEnv(key, tokToStr(tok) & os.getenv(key))
os.putEnv(key, tokToStr(tok) & os.getEnv(key))
ppGetTok(L, tok)
of "appendenv":
ppGetTok(L, tok)
var key = tokToStr(tok)
ppGetTok(L, tok)
os.putEnv(key, os.getenv(key) & tokToStr(tok))
os.putEnv(key, os.getEnv(key) & tokToStr(tok))
ppGetTok(L, tok)
else: lexMessage(L, errInvalidDirectiveX, tokToStr(tok))

Expand All @@ -157,7 +157,7 @@ proc checkSymbol(L: TLexer, tok: TToken) =
proc parseAssignment(L: var TLexer, tok: var TToken) =
if tok.ident.id == getIdent("-").id or tok.ident.id == getIdent("--").id:
confTok(L, tok) # skip unnecessary prefix
var info = getLineInfo(L) # safe for later in case of an error
var info = getLineInfo(L, tok) # safe for later in case of an error
checkSymbol(L, tok)
var s = tokToStr(tok)
confTok(L, tok) # skip symbol
Expand All @@ -176,7 +176,7 @@ proc parseAssignment(L: var TLexer, tok: var TToken) =
add(val, tokToStr(tok))
confTok(L, tok)
if tok.tokType == tkBracketRi: confTok(L, tok)
else: lexMessage(L, errTokenExpected, "\']\'")
else: lexMessage(L, errTokenExpected, "']'")
add(val, ']')
if tok.tokType in {tkColon, tkEquals}:
if len(val) > 0: add(val, ':')
Expand All @@ -196,7 +196,7 @@ proc readConfigFile(filename: string) =
L: TLexer
tok: TToken
stream: PLLStream
stream = LLStreamOpen(filename, fmRead)
stream = llStreamOpen(filename, fmRead)
if stream != nil:
initToken(tok)
openLexer(L, filename, stream)
Expand All @@ -213,10 +213,13 @@ proc getUserConfigPath(filename: string): string =
proc getSystemConfigPath(filename: string): string =
# try standard configuration file (installation did not distribute files
# the UNIX way)
result = joinPath([getPrefixDir(), "config", filename])
if not ExistsFile(result): result = "/etc/" & filename
let p = getPrefixDir()
result = joinPath([p, "config", filename])
when defined(unix):
if not existsFile(result): result = joinPath([p, "etc", filename])
if not existsFile(result): result = "/etc/" & filename

proc LoadConfigs*(cfg: string) =
proc loadConfigs*(cfg: string) =
# set default value (can be overwritten):
if libpath == "":
# choose default libpath:
Expand All @@ -240,11 +243,6 @@ proc LoadConfigs*(cfg: string) =
readConfigFile(pd / cfg)

if gProjectName.len != 0:
var conffile = changeFileExt(gProjectFull, "cfg")
if conffile != pd / cfg and existsFile(conffile):
readConfigFile(conffile)
rawMessage(warnConfigDeprecated, conffile)

# new project wide config file:
readConfigFile(changeFileExt(gProjectFull, "nimrod.cfg"))

33 changes: 33 additions & 0 deletions compiler/nimeval.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#
#
# The Nimrod Compiler
# (c) Copyright 2013 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#

## exposes the Nimrod VM to clients.

import
ast, modules, passes, passaux, condsyms,
options, nimconf, lists, sem, semdata, llstream, vm

proc execute*(program: string) =
passes.gIncludeFile = includeModule
passes.gImportModule = importModule
initDefines()
loadConfigs(DefaultConfig)

initDefines()
defineSymbol("nimrodvm")
when hasFFI: defineSymbol("nimffi")
registerPass(verbosePass)
registerPass(semPass)
registerPass(vmPass)

appendStr(searchPaths, options.libpath)
compileSystemModule()
var m = makeStdinModule()
incl(m.flags, sfMainModule)
processModule(m, llStreamOpen(program), nil)
45 changes: 22 additions & 23 deletions compiler/nimlexbase.nim
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ type
buf*: cstring
bufLen*: int # length of buffer in characters
stream*: PLLStream # we read from this stream
LineNumber*: int # the current line number
lineNumber*: int # the current line number
# private data:
sentinel*: int
lineStart*: int # index of last line start in buffer
Expand All @@ -54,11 +54,11 @@ proc openBaseLexer*(L: var TBaseLexer, inputstream: PLLStream,
proc closeBaseLexer*(L: var TBaseLexer)
proc getCurrentLine*(L: TBaseLexer, marker: bool = true): string
proc getColNumber*(L: TBaseLexer, pos: int): int
proc HandleCR*(L: var TBaseLexer, pos: int): int
proc handleCR*(L: var TBaseLexer, pos: int): int
# Call this if you scanned over CR in the buffer; it returns the
# position to continue the scanning from. `pos` must be the position
# of the CR.
proc HandleLF*(L: var TBaseLexer, pos: int): int
proc handleLF*(L: var TBaseLexer, pos: int): int
# Call this if you scanned over LF in the buffer; it returns the the
# position to continue the scanning from. `pos` must be the position
# of the LF.
Expand All @@ -69,9 +69,9 @@ const

proc closeBaseLexer(L: var TBaseLexer) =
dealloc(L.buf)
LLStreamClose(L.stream)
llStreamClose(L.stream)

proc FillBuffer(L: var TBaseLexer) =
proc fillBuffer(L: var TBaseLexer) =
var
charsRead, toCopy, s: int # all are in characters,
# not bytes (in case this
Expand All @@ -80,12 +80,12 @@ proc FillBuffer(L: var TBaseLexer) =
# we know here that pos == L.sentinel, but not if this proc
# is called the first time by initBaseLexer()
assert(L.sentinel < L.bufLen)
toCopy = L.BufLen - L.sentinel - 1
toCopy = L.bufLen - L.sentinel - 1
assert(toCopy >= 0)
if toCopy > 0:
MoveMem(L.buf, addr(L.buf[L.sentinel + 1]), toCopy * chrSize)
moveMem(L.buf, addr(L.buf[L.sentinel + 1]), toCopy * chrSize)
# "moveMem" handles overlapping regions
charsRead = LLStreamRead(L.stream, addr(L.buf[toCopy]),
charsRead = llStreamRead(L.stream, addr(L.buf[toCopy]),
(L.sentinel + 1) * chrSize) div chrSize
s = toCopy + charsRead
if charsRead < L.sentinel + 1:
Expand All @@ -96,19 +96,19 @@ proc FillBuffer(L: var TBaseLexer) =
dec(s) # BUGFIX (valgrind)
while true:
assert(s < L.bufLen)
while (s >= 0) and not (L.buf[s] in NewLines): Dec(s)
while (s >= 0) and not (L.buf[s] in NewLines): dec(s)
if s >= 0:
# we found an appropriate character for a sentinel:
L.sentinel = s
break
else:
# rather than to give up here because the line is too long,
# double the buffer's size and try again:
oldBufLen = L.BufLen
L.bufLen = L.BufLen * 2
oldBufLen = L.bufLen
L.bufLen = L.bufLen * 2
L.buf = cast[cstring](realloc(L.buf, L.bufLen * chrSize))
assert(L.bufLen - oldBuflen == oldBufLen)
charsRead = LLStreamRead(L.stream, addr(L.buf[oldBufLen]),
assert(L.bufLen - oldBufLen == oldBufLen)
charsRead = llStreamRead(L.stream, addr(L.buf[oldBufLen]),
oldBufLen * chrSize) div chrSize
if charsRead < oldBufLen:
L.buf[oldBufLen + charsRead] = EndOfFile
Expand All @@ -126,20 +126,20 @@ proc fillBaseLexer(L: var TBaseLexer, pos: int): int =
result = 0
L.lineStart = result

proc HandleCR(L: var TBaseLexer, pos: int): int =
proc handleCR(L: var TBaseLexer, pos: int): int =
assert(L.buf[pos] == CR)
inc(L.linenumber)
inc(L.lineNumber)
result = fillBaseLexer(L, pos)
if L.buf[result] == LF:
result = fillBaseLexer(L, result)

proc HandleLF(L: var TBaseLexer, pos: int): int =
proc handleLF(L: var TBaseLexer, pos: int): int =
assert(L.buf[pos] == LF)
inc(L.linenumber)
inc(L.lineNumber)
result = fillBaseLexer(L, pos) #L.lastNL := result-1; // BUGFIX: was: result;

proc skip_UTF_8_BOM(L: var TBaseLexer) =
if (L.buf[0] == '\xEF') and (L.buf[1] == '\xBB') and (L.buf[2] == '\xBF'):
proc skipUTF8BOM(L: var TBaseLexer) =
if L.buf[0] == '\xEF' and L.buf[1] == '\xBB' and L.buf[2] == '\xBF':
inc(L.bufpos, 3)
inc(L.lineStart, 3)

Expand All @@ -150,10 +150,10 @@ proc openBaseLexer(L: var TBaseLexer, inputstream: PLLStream, bufLen = 8192) =
L.buf = cast[cstring](alloc(bufLen * chrSize))
L.sentinel = bufLen - 1
L.lineStart = 0
L.linenumber = 1 # lines start at 1
L.lineNumber = 1 # lines start at 1
L.stream = inputstream
fillBuffer(L)
skip_UTF_8_BOM(L)
skipUTF8BOM(L)

proc getColNumber(L: TBaseLexer, pos: int): int =
result = abs(pos - L.lineStart)
Expand All @@ -166,5 +166,4 @@ proc getCurrentLine(L: TBaseLexer, marker: bool = true): string =
inc(i)
result.add("\n")
if marker:
result.add(RepeatChar(getColNumber(L, L.bufpos)) & '^' & "\n")

result.add(repeatChar(getColNumber(L, L.bufpos)) & '^' & "\n")
591 changes: 0 additions & 591 deletions compiler/nimrod.dot

This file was deleted.

24 changes: 18 additions & 6 deletions compiler/nimrod.ini
Original file line number Diff line number Diff line change
@@ -1,9 +1,17 @@
[Project]
Name: "Nimrod"
Version: "$version"
; Windows and i386 must be first!
OS: "windows;linux;macosx;solaris;freebsd;netbsd;openbsd"
CPU: "i386;amd64;powerpc64;arm" # ;sparc
Platforms: """
windows: i386;amd64
linux: i386;amd64;powerpc64;arm;sparc;mips
macosx: i386;amd64;powerpc64
solaris: i386;amd64;sparc
freebsd: i386;amd64
netbsd: i386;amd64
openbsd: i386;amd64
haiku: i386;amd64
"""

Authors: "Andreas Rumpf"
Description: """This is the Nimrod Compiler. Nimrod is a new statically typed,
imperative programming language, that supports procedural, functional, object
Expand Down Expand Up @@ -35,9 +43,8 @@ Start: "doc/overview.html"


[Other]
Files: "readme.txt;install.txt;contributors.txt"
Files: "readme.txt;install.txt;contributors.txt;copying.txt"
Files: "configure;makefile"
Files: "gpl.html"
Files: "*.ini"
Files: "koch.nim"

Expand All @@ -54,6 +61,11 @@ Files: "compiler/readme.txt"
Files: "compiler/nimrod.ini"
Files: "compiler/nimrod.cfg"
Files: "compiler/*.nim"
Files: "compiler/c2nim/*.nim"
Files: "compiler/c2nim/*.cfg"
Files: "compiler/pas2nim/*.nim"
Files: "compiler/pas2nim/*.cfg"

Files: "build/empty.txt"
Files: "bin/empty.txt"

Expand Down Expand Up @@ -137,5 +149,5 @@ flags = "-w"
buildDepends: "gcc (>= 4:4.3.2)"
pkgDepends: "gcc (>= 4:4.3.2)"
shortDesc: "The Nimrod Compiler"
licenses: "bin/nimrod,gpl2;lib/*,lgpl;"
licenses: "bin/nimrod,MIT;lib/*,MIT;"

44 changes: 28 additions & 16 deletions compiler/nimrod.nim
Original file line number Diff line number Diff line change
Expand Up @@ -13,30 +13,30 @@ when defined(gcc) and defined(windows):
else:
{.link: "icons/nimrod_icon.o".}

import
commands, lexer, condsyms, options, msgs, nversion, nimconf, ropes,
extccomp, strutils, os, platform, main, parseopt, service
import
commands, lexer, condsyms, options, msgs, nversion, nimconf, ropes,
extccomp, strutils, os, osproc, platform, main, parseopt, service

when hasTinyCBackend:
import tccgen

when defined(profiler) or defined(memProfiler):
{.hint: "Profiling support is turned on!".}
import nimprof

proc prependCurDir(f: string): string =
when defined(unix):
if os.isAbsolute(f): result = f
else: result = "./" & f
else:
result = f

proc HandleCmdLine() =
proc handleCmdLine() =
if paramCount() == 0:
writeCommandLineUsage()
else:
# Process command line arguments:
ProcessCmdLine(passCmd1, "")
processCmdLine(passCmd1, "")
if gProjectName != "":
try:
gProjectFull = canonicalizePath(gProjectName)
Expand All @@ -47,12 +47,12 @@ proc HandleCmdLine() =
gProjectName = p.name
else:
gProjectPath = getCurrentDir()
LoadConfigs(DefaultConfig) # load all config files
loadConfigs(DefaultConfig) # load all config files
# now process command line arguments again, because some options in the
# command line can overwite the config file's settings
extccomp.initVars()
ProcessCmdLine(passCmd2, "")
MainCommand()
processCmdLine(passCmd2, "")
mainCommand()
if gVerbosity >= 2: echo(GC_getStatistics())
#echo(GC_getStatistics())
if msgs.gErrorCounter == 0:
Expand All @@ -61,12 +61,22 @@ proc HandleCmdLine() =
tccgen.run()
if optRun in gGlobalOptions:
if gCmd == cmdCompileToJS:
var ex = quoteIfContainsWhite(
completeCFilePath(changeFileExt(gProjectFull, "js").prependCurDir))
var ex: string
if options.outFile.len > 0:
ex = options.outFile.prependCurDir.quoteShell
else:
ex = quoteShell(
completeCFilePath(changeFileExt(gProjectFull, "js").prependCurDir))
execExternalProgram("node " & ex & ' ' & service.arguments)
else:
var ex = quoteIfContainsWhite(
changeFileExt(gProjectFull, exeExt).prependCurDir)
var binPath: string
if options.outFile.len > 0:
# If the user specified an outFile path, use that directly.
binPath = options.outFile.prependCurDir
else:
# Figure out ourselves a valid binary name.
binPath = changeFileExt(gProjectFull, ExeExt).prependCurDir
var ex = quoteShell(binPath)
execExternalProgram(ex & ' ' & service.arguments)

when defined(GC_setMaxPause):
Expand All @@ -75,6 +85,8 @@ when defined(GC_setMaxPause):
when compileOption("gc", "v2") or compileOption("gc", "refc"):
# the new correct mark&sweet collector is too slow :-/
GC_disableMarkAndSweep()
condsyms.InitDefines()
HandleCmdLine()
quit(int8(msgs.gErrorCounter > 0))
condsyms.initDefines()

when not defined(selftest):
handleCmdLine()
quit(int8(msgs.gErrorCounter > 0))
11 changes: 11 additions & 0 deletions compiler/nimrod.cfg → compiler/nimrod.nimrod.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,22 @@

mainModule:"nimrod.nim"

# gc:markAndSweep

hint[XDeclaredButNotUsed]:off
path:"llvm"
path:"$projectPath/.."

path:"$lib/packages/docutils"

define:booting
import:testability

@if windows:
cincludes: "$lib/wrappers/libffi/common"
@end

define:useStdoutAsStdmsg

cs:partial
#define:useNodeIds
63 changes: 27 additions & 36 deletions compiler/nimsets.nim
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ proc overlap*(a, b: PNode): bool
proc inSet*(s: PNode, elem: PNode): bool
proc someInSet*(s: PNode, a, b: PNode): bool
proc emptyRange*(a, b: PNode): bool
proc SetHasRange*(s: PNode): bool
proc setHasRange*(s: PNode): bool
# returns true if set contains a range (needed by the code generator)
# these are used for constant folding:
proc unionSets*(a, b: PNode): PNode
Expand All @@ -32,7 +32,7 @@ proc cardSet*(s: PNode): BiggestInt

proc inSet(s: PNode, elem: PNode): bool =
if s.kind != nkCurly:
InternalError(s.info, "inSet")
internalError(s.info, "inSet")
return false
for i in countup(0, sonsLen(s) - 1):
if s.sons[i].kind == nkRange:
Expand All @@ -58,10 +58,10 @@ proc overlap(a, b: PNode): bool =
else:
result = sameValue(a, b)

proc SomeInSet(s: PNode, a, b: PNode): bool =
proc someInSet(s: PNode, a, b: PNode): bool =
# checks if some element of a..b is in the set s
if s.kind != nkCurly:
InternalError(s.info, "SomeInSet")
internalError(s.info, "SomeInSet")
return false
for i in countup(0, sonsLen(s) - 1):
if s.sons[i].kind == nkRange:
Expand All @@ -82,12 +82,12 @@ proc toBitSet(s: PNode, b: var TBitSet) =
if s.sons[i].kind == nkRange:
j = getOrdValue(s.sons[i].sons[0])
while j <= getOrdValue(s.sons[i].sons[1]):
BitSetIncl(b, j - first)
bitSetIncl(b, j - first)
inc(j)
else:
BitSetIncl(b, getOrdValue(s.sons[i]) - first)
bitSetIncl(b, getOrdValue(s.sons[i]) - first)

proc ToTreeSet(s: TBitSet, settype: PType, info: TLineInfo): PNode =
proc toTreeSet(s: TBitSet, settype: PType, info: TLineInfo): PNode =
var
a, b, e, first: BiggestInt # a, b are interval borders
elemType: PType
Expand All @@ -98,14 +98,14 @@ proc ToTreeSet(s: TBitSet, settype: PType, info: TLineInfo): PNode =
result.typ = settype
result.info = info
e = 0
while e < len(s) * elemSize:
while e < len(s) * ElemSize:
if bitSetIn(s, e):
a = e
b = e
while true:
Inc(b)
if (b >= len(s) * elemSize) or not bitSetIn(s, b): break
Dec(b)
inc(b)
if (b >= len(s) * ElemSize) or not bitSetIn(s, b): break
dec(b)
if a == b:
addSon(result, newIntTypeNode(nkIntLit, a + first, elemType))
else:
Expand All @@ -115,34 +115,19 @@ proc ToTreeSet(s: TBitSet, settype: PType, info: TLineInfo): PNode =
addSon(n, newIntTypeNode(nkIntLit, b + first, elemType))
addSon(result, n)
e = b
Inc(e)
inc(e)

type
TSetOP = enum
soUnion, soDiff, soSymDiff, soIntersect

proc nodeSetOp(a, b: PNode, op: TSetOp): PNode =
template nodeSetOp(a, b: PNode, op: expr) {.dirty.} =
var x, y: TBitSet
toBitSet(a, x)
toBitSet(b, y)
case op
of soUnion: BitSetUnion(x, y)
of soDiff: BitSetDiff(x, y)
of soSymDiff: BitSetSymDiff(x, y)
of soIntersect: BitSetIntersect(x, y)
op(x, y)
result = toTreeSet(x, a.typ, a.info)

proc unionSets(a, b: PNode): PNode =
result = nodeSetOp(a, b, soUnion)

proc diffSets(a, b: PNode): PNode =
result = nodeSetOp(a, b, soDiff)

proc intersectSets(a, b: PNode): PNode =
result = nodeSetOp(a, b, soIntersect)

proc symdiffSets(a, b: PNode): PNode =
result = nodeSetOp(a, b, soSymDiff)
proc unionSets(a, b: PNode): PNode = nodeSetOp(a, b, bitSetUnion)
proc diffSets(a, b: PNode): PNode = nodeSetOp(a, b, bitSetDiff)
proc intersectSets(a, b: PNode): PNode = nodeSetOp(a, b, bitSetIntersect)
proc symdiffSets(a, b: PNode): PNode = nodeSetOp(a, b, bitSetSymDiff)

proc containsSets(a, b: PNode): bool =
var x, y: TBitSet
Expand All @@ -156,6 +141,12 @@ proc equalSets(a, b: PNode): bool =
toBitSet(b, y)
result = bitSetEquals(x, y)

proc complement*(a: PNode): PNode =
var x: TBitSet
toBitSet(a, x)
for i in countup(0, high(x)): x[i] = not x[i]
result = toTreeSet(x, a.typ, a.info)

proc cardSet(s: PNode): BiggestInt =
# here we can do better than converting it into a compact set
# we just count the elements directly
Expand All @@ -165,11 +156,11 @@ proc cardSet(s: PNode): BiggestInt =
result = result + getOrdValue(s.sons[i].sons[1]) -
getOrdValue(s.sons[i].sons[0]) + 1
else:
Inc(result)
inc(result)

proc SetHasRange(s: PNode): bool =
proc setHasRange(s: PNode): bool =
if s.kind != nkCurly:
InternalError(s.info, "SetHasRange")
internalError(s.info, "SetHasRange")
return false
for i in countup(0, sonsLen(s) - 1):
if s.sons[i].kind == nkRange:
Expand Down
6 changes: 3 additions & 3 deletions compiler/nversion.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 @@ -15,8 +15,8 @@ const
defaultAsmMarkerSymbol* = '!'
VersionMajor* = 0
VersionMinor* = 9
VersionPatch* = 2
VersionPatch* = 4
VersionAsString* = $VersionMajor & "." & $VersionMinor & "." & $VersionPatch

RodFileVersion* = "1212" # modify this if the rod-format changes!
RodFileVersion* = "1215" # modify this if the rod-format changes!

121 changes: 100 additions & 21 deletions compiler/options.nim
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,15 @@
#

import
os, lists, strutils, strtabs
os, lists, strutils, strtabs, osproc, sets

const
hasTinyCBackend* = defined(tinyc)
useEffectSystem* = true
hasFFI* = defined(useFFI)
newScopeForIf* = false # XXX activate for 0.9.4
newScopeForIf* = true
useCaas* = not defined(noCaas)
noTimeMachine = defined(avoidTimeMachine) and defined(macosx)

type # please make sure we have under 32 options
# (improves code efficiency a lot!)
Expand Down Expand Up @@ -92,13 +94,15 @@ var
gOptions*: TOptions = {optObjCheck, optFieldCheck, optRangeCheck,
optBoundsCheck, optOverflowCheck, optAssert, optWarns,
optHints, optStackTrace, optLineTrace,
optPatterns}
gGlobalOptions*: TGlobalOptions = {optThreadAnalysis}
optPatterns, optNilCheck}
gGlobalOptions*: TGlobalOptions = {}
gExitcode*: int8
gCmd*: TCommands = cmdNone # the command
gSelectedGC* = gcRefc # the selected GC
searchPaths*, lazyPaths*: TLinkedList
outFile*: string = ""
docSeeSrcUrl*: string = "" # if empty, no seeSrc will be generated. \
# The string uses the formatting variables `path` and `line`.
headerFile*: string = ""
gVerbosity* = 1 # how verbose the compiler is
gNumberOfProcessors*: int # number of processors
Expand All @@ -110,6 +114,7 @@ var
gDirtyBufferIdx* = 0'i32 # indicates the fileIdx of the dirty version of
# the tracked source X, saved by the CAAS client.
gDirtyOriginalIdx* = 0'i32 # the original source file of the dirtified buffer.
gNoBabelPath* = false

proc importantComments*(): bool {.inline.} = gCmd in {cmdDoc, cmdIdeTools}
proc usesNativeGC*(): bool {.inline.} = gSelectedGC >= gcRefc
Expand All @@ -131,6 +136,7 @@ const
NimExt* = "nim"
RodExt* = "rod"
HtmlExt* = "html"
JsonExt* = "json"
TexExt* = "tex"
IniExt* = "ini"
DefaultConfig* = "nimrod.cfg"
Expand All @@ -140,7 +146,7 @@ const
# additional configuration variables:
var
gConfigVars* = newStringTable(modeStyleInsensitive)
gDllOverrides = newStringtable(modeCaseInsensitive)
gDllOverrides = newStringTable(modeCaseInsensitive)
libpath* = ""
gProjectName* = "" # holds a name like 'nimrod'
gProjectPath* = "" # holds a path like /home/alice/projects/nimrod/compiler/
Expand Down Expand Up @@ -180,76 +186,145 @@ proc getOutFile*(filename, ext: string): string =

proc getPrefixDir*(): string =
## gets the application directory
result = SplitPath(getAppDir()).head
result = splitPath(getAppDir()).head

proc canonicalizePath*(path: string): string =
result = path.expandFilename
when not FileSystemCaseSensitive: result = result.toLower

proc shortenDir*(dir: string): string =
## returns the interesting part of a dir
var prefix = getPrefixDir() & dirSep
var prefix = getPrefixDir() & DirSep
if startsWith(dir, prefix):
return substr(dir, len(prefix))
prefix = gProjectPath & dirSep
prefix = gProjectPath & DirSep
if startsWith(dir, prefix):
return substr(dir, len(prefix))
result = dir

proc removeTrailingDirSep*(path: string): string =
if (len(path) > 0) and (path[len(path) - 1] == dirSep):
if (len(path) > 0) and (path[len(path) - 1] == DirSep):
result = substr(path, 0, len(path) - 2)
else:
result = path

proc getGeneratedPath: string =
result = if nimcacheDir.len > 0: nimcacheDir else: gProjectPath.shortenDir /
genSubDir


template newPackageCache(): expr =
newStringTable(when FileSystemCaseSensitive:
modeCaseInsensitive
else:
modeCaseSensitive)

var packageCache = newPackageCache()

proc resetPackageCache*() = packageCache = newPackageCache()

iterator myParentDirs(p: string): string =
# XXX os's parentDirs is stupid (multiple yields) and triggers an old bug...
var current = p
while true:
current = current.parentDir
if current.len == 0: break
yield current

proc getPackageName*(path: string): string =
var parents = 0
block packageSearch:
for d in myParentDirs(path):
if packageCache.hasKey(d):
#echo "from cache ", d, " |", packageCache[d], "|", path.splitFile.name
return packageCache[d]
inc parents
for file in walkFiles(d / "*.babel"):
result = file.splitFile.name
break packageSearch
# we also store if we didn't find anything:
if result.isNil: result = ""
for d in myParentDirs(path):
#echo "set cache ", d, " |", result, "|", parents
packageCache[d] = result
dec parents
if parents <= 0: break

proc withPackageName*(path: string): string =
let x = path.getPackageName
if x.len == 0:
result = path
else:
let (p, file, ext) = path.splitFile
result = (p / (x & '_' & file)) & ext

proc toGeneratedFile*(path, ext: string): string =
## converts "/home/a/mymodule.nim", "rod" to "/home/a/nimcache/mymodule.rod"
var (head, tail) = splitPath(path)
#if len(head) > 0: head = shortenDir(head & dirSep)
result = joinPath([getGeneratedPath(), changeFileExt(tail, ext)])
#echo "toGeneratedFile(", path, ", ", ext, ") = ", result

when noTimeMachine:
var alreadyExcludedDirs = initSet[string]()
proc excludeDirFromTimeMachine(dir: string) {.raises: [].} =
## Calls a macosx command on the directory to exclude it from backups.
##
## The macosx tmutil command is invoked to mark the specified path as an
## item to be excluded from time machine backups. If a path already exists
## with files before excluding it, newer files won't be added to the
## directory, but previous files won't be removed from the backup until the
## user deletes that directory.
##
## The whole proc is optional and will ignore all kinds of errors. The only
## way to be sure that it works is to call ``tmutil isexcluded path``.
if alreadyExcludedDirs.contains(dir): return
alreadyExcludedDirs.incl(dir)
try:
var p = startProcess("/usr/bin/tmutil", args = ["addexclusion", dir])
discard p.waitForExit
p.close
except E_Base, EOS:
discard

proc completeGeneratedFilePath*(f: string, createSubDir: bool = true): string =
var (head, tail) = splitPath(f)
#if len(head) > 0: head = removeTrailingDirSep(shortenDir(head & dirSep))
var subdir = getGeneratedPath() # / head
if createSubDir:
try:
createDir(subdir)
when noTimeMachine:
excludeDirFromTimeMachine(subdir)
except EOS:
writeln(stdout, "cannot create directory: " & subdir)
quit(1)
result = joinPath(subdir, tail)
#echo "completeGeneratedFilePath(", f, ") = ", result

iterator iterSearchPath*(SearchPaths: TLinkedList): string =
var it = PStrEntry(SearchPaths.head)
iterator iterSearchPath*(searchPaths: TLinkedList): string =
var it = PStrEntry(searchPaths.head)
while it != nil:
yield it.data
it = PStrEntry(it.Next)
it = PStrEntry(it.next)

proc rawFindFile(f: string): string =
for it in iterSearchPath(SearchPaths):
result = JoinPath(it, f)
for it in iterSearchPath(searchPaths):
result = joinPath(it, f)
if existsFile(result):
return result.canonicalizePath
result = ""

proc rawFindFile2(f: string): string =
var it = PStrEntry(lazyPaths.head)
while it != nil:
result = JoinPath(it.data, f)
result = joinPath(it.data, f)
if existsFile(result):
bringToFront(lazyPaths, it)
return result.canonicalizePath
it = PStrEntry(it.Next)
it = PStrEntry(it.next)
result = ""

proc FindFile*(f: string): string {.procvar.} =
proc findFile*(f: string): string {.procvar.} =
result = f.rawFindFile
if result.len == 0:
result = f.toLower.rawFindFile
Expand All @@ -258,9 +333,13 @@ proc FindFile*(f: string): string {.procvar.} =
if result.len == 0:
result = f.toLower.rawFindFile2

proc findModule*(modulename: string): string {.inline.} =
proc findModule*(modulename, currentModule: string): string =
# returns path to module
result = FindFile(AddFileExt(modulename, nimExt))
let m = addFileExt(modulename, NimExt)
let currentPath = currentModule.splitFile.dir
result = currentPath / m
if not existsFile(result):
result = findFile(m)

proc libCandidates*(s: string, dest: var seq[string]) =
var le = strutils.find(s, '(')
Expand All @@ -287,7 +366,7 @@ proc inclDynlibOverride*(lib: string) =
proc isDynlibOverride*(lib: string): bool =
result = gDllOverrides.hasKey(lib.canonDynlibName)

proc binaryStrSearch*(x: openarray[string], y: string): int =
proc binaryStrSearch*(x: openArray[string], y: string): int =
var a = 0
var b = len(x) - 1
while a <= b:
Expand Down
16 changes: 9 additions & 7 deletions compiler/parampatterns.nim
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,16 @@ const
MaxStackSize* = 64 ## max required stack size by the VM

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

proc add(code: var TPatternCode, op: TOpcode) {.inline.} =
add(code, chr(ord(op)))

proc whichAlias*(p: PSym): TAliasRequest =
if p.constraint != nil:
result = TAliasRequest(p.constraint.strVal[0].ord)
else:
result = aqNone

proc compileConstraints(p: PNode, result: var TPatternCode) =
case p.kind
Expand Down Expand Up @@ -95,14 +97,14 @@ proc compileConstraints(p: PNode, result: var TPatternCode) =
of "nosideeffect": result.add(ppNoSideEffect)
else:
# check all symkinds:
InternalAssert int(high(TSymKind)) < 255
internalAssert int(high(TSymKind)) < 255
for i in low(TSymKind)..high(TSymKind):
if cmpIgnoreStyle(($i).substr(2), spec) == 0:
result.add(ppSymKind)
result.add(chr(i.ord))
return
# check all nodekinds:
InternalAssert int(high(TNodeKind)) < 255
internalAssert int(high(TNodeKind)) < 255
for i in low(TNodeKind)..high(TNodeKind):
if cmpIgnoreStyle($i, spec) == 0:
result.add(ppNodeKind)
Expand All @@ -122,8 +124,8 @@ proc semNodeKindConstraints*(p: PNode): PNode =
if p.len >= 2:
for i in 1.. <p.len:
compileConstraints(p.sons[i], result.strVal)
if result.strVal.len > maxStackSize-1:
InternalError(p.info, "parameter pattern too complex")
if result.strVal.len > MaxStackSize-1:
internalError(p.info, "parameter pattern too complex")
else:
patternError(p)
result.strVal.add(ppEof)
Expand Down Expand Up @@ -214,12 +216,12 @@ proc isAssignable*(owner: PSym, n: PNode): TAssignableResult =
of nkObjUpConv, nkObjDownConv, nkCheckedFieldExpr:
result = isAssignable(owner, n.sons[0])
else:
nil
discard

proc matchNodeKinds*(p, n: PNode): bool =
# matches the parameter constraint 'p' against the concrete AST 'n'.
# Efficiency matters here.
var stack {.noinit.}: array[0..maxStackSize, bool]
var stack {.noinit.}: array[0..MaxStackSize, bool]
# empty patterns are true:
stack[0] = true
var sp = 1
Expand Down
346 changes: 0 additions & 346 deletions compiler/parsecfg.nim

This file was deleted.

Loading