changes to threads; --recursivePath support

This commit is contained in:
Araq 2011-01-29 01:47:58 +01:00
commit f46870fe1c
20 changed files with 396 additions and 180 deletions

View file

@ -30,6 +30,7 @@ path="$lib/windows"
path="$lib/posix" path="$lib/posix"
path="$lib/ecmas" path="$lib/ecmas"
path="$lib/pure/unidecode" path="$lib/pure/unidecode"
#recursivePath:"$user/.babel/lib"
@if release or quick: @if release or quick:
obj_checks:off obj_checks:off

View file

@ -22,6 +22,7 @@ Advanced options:
--os:SYMBOL set the target operating system (cross-compilation) --os:SYMBOL set the target operating system (cross-compilation)
--cpu:SYMBOL set the target processor (cross-compilation) --cpu:SYMBOL set the target processor (cross-compilation)
--debuginfo enables debug information --debuginfo enables debug information
--debugger:on|off turn Embedded Nimrod Debugger on|off
-t, --passc:OPTION pass an option to the C compiler -t, --passc:OPTION pass an option to the C compiler
-l, --passl:OPTION pass an option to the linker -l, --passl:OPTION pass an option to the linker
--genMapping generate a mapping file containing --genMapping generate a mapping file containing

View file

@ -18,7 +18,7 @@ Options:
-f, --forceBuild force rebuilding of all modules -f, --forceBuild force rebuilding of all modules
--stackTrace:on|off turn stack tracing on|off --stackTrace:on|off turn stack tracing on|off
--lineTrace:on|off turn line tracing on|off --lineTrace:on|off turn line tracing on|off
--debugger:on|off turn Embedded Nimrod Debugger on|off --threads:on|off turn support for multi-threading on|off
-x, --checks:on|off turn all runtime checks on|off -x, --checks:on|off turn all runtime checks on|off
--objChecks:on|off turn obj conversion checks on|off --objChecks:on|off turn obj conversion checks on|off
--fieldChecks:on|off turn case variant field checks on|off --fieldChecks:on|off turn case variant field checks on|off

View file

@ -16,11 +16,11 @@
## .. code-block:: nimrod ## .. code-block:: nimrod
## ##
## var ## var
## thr: array [0..4, TThread] ## thr: array [0..4, TThread[tuple[a,b: int]]]
## L: TLock ## L: TLock
## ##
## proc threadFunc(c: pointer) {.procvar.} = ## proc threadFunc(interval: tuple[a,b: int]) {.procvar.} =
## for i in 0..9: ## for i in interval.a..interval.b:
## Aquire(L) # lock stdout ## Aquire(L) # lock stdout
## echo i ## echo i
## Release(L) ## Release(L)
@ -28,10 +28,12 @@
## InitLock(L) ## InitLock(L)
## ##
## for i in 0..high(thr): ## for i in 0..high(thr):
## createThread(thr[i], threadFunc) ## createThread(thr[i], threadFunc, (i*10, i*10+5))
## for i in 0..high(thr): ## for i in 0..high(thr):
## joinThread(thr[i]) ## joinThread(thr[i])
when not defined(boehmgc) and not defined(nogc):
{.error: "Thread support requires --gc:boehm or --gc:none".}
# We jump through some hops here to ensure that Nimrod thread procs can have # We jump through some hops here to ensure that Nimrod thread procs can have
# the Nimrod calling convention. This is needed because thread procs are # the Nimrod calling convention. This is needed because thread procs are
@ -41,10 +43,9 @@
# GC'ed closures in Nimrod. # GC'ed closures in Nimrod.
type type
TThreadProc* = proc (closure: pointer) ## Standard Nimrod thread proc. TThreadProcClosure {.pure, final.}[TParam] = object
TThreadProcClosure {.pure, final.} = object fn: proc (p: TParam)
fn: TThreadProc data: TParam
data: pointer
when defined(Windows): when defined(Windows):
type type
@ -60,17 +61,22 @@ when defined(Windows):
TWinThreadProc = proc (x: pointer): int32 {.stdcall.} TWinThreadProc = proc (x: pointer): int32 {.stdcall.}
TLock* = TSysLock ## Standard Nimrod Lock type. proc InitSysLock(L: var TSysLock) {.stdcall,
proc InitLock*(L: var TLock) {.stdcall,
dynlib: "kernel32", importc: "InitializeCriticalSection".} dynlib: "kernel32", importc: "InitializeCriticalSection".}
## Initializes the lock `L`. ## Initializes the lock `L`.
proc Aquire*(L: var TLock) {.stdcall, proc TryAquireSysAux(L: var TSysLock): int32 {.stdcall,
dynlib: "kernel32", importc: "TryEnterCriticalSection".}
## Tries to aquire the lock `L`.
proc TryAquireSys(L: var TSysLock): bool {.inline.} =
result = TryAquireSysAux(L) != 0'i32
proc AquireSys(L: var TSysLock) {.stdcall,
dynlib: "kernel32", importc: "EnterCriticalSection".} dynlib: "kernel32", importc: "EnterCriticalSection".}
## Aquires the lock `L`. ## Aquires the lock `L`.
proc Release*(L: var TLock) {.stdcall, proc ReleaseSys(L: var TSysLock) {.stdcall,
dynlib: "kernel32", importc: "LeaveCriticalSection".} dynlib: "kernel32", importc: "LeaveCriticalSection".}
## Releases the lock `L`. ## Releases the lock `L`.
@ -99,8 +105,8 @@ when defined(Windows):
proc TerminateThread(hThread: THandle, dwExitCode: int32): int32 {. proc TerminateThread(hThread: THandle, dwExitCode: int32): int32 {.
stdcall, dynlib: "kernel32", importc: "TerminateThread".} stdcall, dynlib: "kernel32", importc: "TerminateThread".}
proc threadProcWrapper(closure: pointer): int32 {.stdcall.} = proc threadProcWrapper[TParam](closure: pointer): int32 {.stdcall.} =
var c = cast[ptr TThreadProcClosure](closure) var c = cast[ptr TThreadProcClosure[TParam]](closure)
c.fn(c.data) c.fn(c.data)
# implicitely return 0 # implicitely return 0
@ -109,16 +115,18 @@ else:
TSysLock {.importc: "pthread_mutex_t", header: "<sys/types.h>".} = int TSysLock {.importc: "pthread_mutex_t", header: "<sys/types.h>".} = int
TSysThread {.importc: "pthread_t", header: "<sys/types.h>".} = int TSysThread {.importc: "pthread_t", header: "<sys/types.h>".} = int
TLock* = TSysLock proc InitSysLock(L: var TSysLock, attr: pointer = nil) {.
proc InitLockAux(L: var TSysLock, attr: pointer = nil) {.
importc: "pthread_mutex_init", header: "<pthread.h>".} importc: "pthread_mutex_init", header: "<pthread.h>".}
proc InitLock*(L: var TLock) {.inline.} = proc AquireSys(L: var TSysLock) {.
InitLockAux(L)
proc Aquire*(L: var TLock) {.
importc: "pthread_mutex_lock", header: "<pthread.h>".} importc: "pthread_mutex_lock", header: "<pthread.h>".}
proc Release*(L: var TLock) {. proc TryAquireSysAux(L: var TSysLock): cint {.
importc: "pthread_mutex_trylock", header: "<pthread.h>".}
proc TryAquireSys(L: var TSysLock): bool {.inline.} =
result = TryAquireSysAux(L) == 0'i32
proc ReleaseSys(L: var TSysLock) {.
importc: "pthread_mutex_unlock", header: "<pthread.h>".} importc: "pthread_mutex_unlock", header: "<pthread.h>".}
proc pthread_create(a1: var TSysThread, a2: ptr int, proc pthread_create(a1: var TSysThread, a2: ptr int,
@ -131,44 +139,205 @@ else:
proc pthread_cancel(a1: TSysThread): cint {. proc pthread_cancel(a1: TSysThread): cint {.
importc: "pthread_cancel", header: "<pthread.h>".} importc: "pthread_cancel", header: "<pthread.h>".}
proc threadProcWrapper(closure: pointer) {.noconv.} = proc threadProcWrapper[TParam](closure: pointer) {.noconv.} =
var c = cast[ptr TThreadProcClosure](closure) var c = cast[ptr TThreadProcClosure[TParam]](closure)
c.fn(c.data) c.fn(c.data)
{.passL: "-pthread".} {.passL: "-pthread".}
{.passC: "-pthread".} {.passC: "-pthread".}
const
noDeadlocks = true # compileOption("deadlockPrevention")
when noDeadLocks:
type type
TThread* = object of TObject ## Nimrod thread. TLock* {.pure, final.} = object ## Standard Nimrod Lock type.
sys: TSysThread key: int # used for identity and global order!
c: TThreadProcClosure sys: TSysLock
next: ptr TLock
proc createThread*(t: var TThread, tp: TThreadProc,
closure: pointer = nil) =
## creates a new thread `t` and starts its execution. Entry point is the
## proc `tp`. `closure` is passed to `tp`.
t.c.data = closure
t.c.fn = tp
when defined(windows):
var dummyThreadId: int32
t.sys = CreateThread(nil, 0'i32, threadProcWrapper, addr(t.c), 0'i32,
dummyThreadId)
else: else:
discard pthread_create(t.sys, nil, threadProcWrapper, addr(t.c)) type
TLock* = TSysLock
proc joinThread*(t: TThread) = type
TThread* {.pure, final.}[TParam] = object ## Nimrod thread.
sys: TSysThread
c: TThreadProcClosure[TParam]
when nodeadlocks:
var
lockList {.threadvar.}: ptr TLock
deadlocksPrevented* = 0 ## counts the number of times a
## deadlock has been prevented
proc InitLock*(L: var TLock) {.inline.} =
## Initializes the lock `L`.
when noDeadlocks:
InitSysLock(L.sys)
L.key = cast[int](addr(L))
else:
InitSysLock(L)
proc TryAquire*(L: var TLock): bool {.inline.} =
## Try to aquires the lock `L`. Returns `true` on success.
when noDeadlocks:
result = TryAquireSys(L.sys)
else:
result = TryAquireSys(L)
proc Aquire*(L: var TLock) =
## Aquires the lock `L`.
when nodeadlocks:
# Note: we MUST NOT change the linked list of locks before we have aquired
# the proper locks! This is because the pointer to the next lock is part
# of the lock itself!
assert L.key != 0
var p = lockList
if p == nil:
# simple case: no lock aquired yet:
AquireSys(L.sys)
locklist = addr(L)
L.next = nil
else:
# check where to put L into the list:
var r = p
var last: ptr TLock = nil
while L.key < r.key:
if r.next == nil:
# best case: L needs to be aquired as last lock, so we can
# skip a good amount of work:
AquireSys(L.sys)
r.next = addr(L)
L.next = nil
return
last = r
r = r.next
# special case: thread already holds L!
if L.key == r.key: return
# bad case: L needs to be somewhere in between
# release all locks after L:
var rollback = r
while r != nil:
ReleaseSys(r.sys)
r = r.next
# and aquire them in the correct order again:
AquireSys(L.sys)
r = rollback
while r != nil:
assert r.key < L.key
AquireSys(r.sys)
r = r.next
# now that we have all the locks we need, we can insert L
# into our list:
if last != nil:
L.next = last.next
last.next = addr(L)
else:
L.next = lockList
lockList = addr(L)
inc(deadlocksPrevented)
else:
AquireSys(L)
proc Release*(L: var TLock) =
## Releases the lock `L`.
when nodeadlocks:
assert L.key != 0
var p = lockList
var last: ptr TLock = nil
while true:
# if we don't find the lock, die by reading from nil!
if p.key == L.key:
if last != nil:
last.next = p.next
else:
assert p == lockList
lockList = locklist.next
L.next = nil
break
last = p
p = p.next
ReleaseSys(L.sys)
else:
ReleaseSys(L)
proc joinThread*[TParam](t: TThread[TParam]) {.inline.} =
## waits for the thread `t` until it has terminated. ## waits for the thread `t` until it has terminated.
when defined(windows): when hostOS == "windows":
discard WaitForSingleObject(t.sys, -1'i32) discard WaitForSingleObject(t.sys, -1'i32)
else: else:
discard pthread_join(t.sys, nil) discard pthread_join(t.sys, nil)
proc destroyThread*(t: var TThread) = proc destroyThread*[TParam](t: var TThread[TParam]) {.inline.} =
## forces the thread `t` to terminate. This is potentially dangerous if ## forces the thread `t` to terminate. This is potentially dangerous if
## you don't have full control over `t` and its aquired ressources. ## you don't have full control over `t` and its aquired resources.
when defined(windows): when hostOS == "windows":
discard TerminateThread(t.sys, 1'i32) discard TerminateThread(t.sys, 1'i32)
else: else:
discard pthread_cancel(t.sys) discard pthread_cancel(t.sys)
proc createThread*[TParam](t: var TThread[TParam],
tp: proc (param: TParam),
param: TParam) =
## creates a new thread `t` and starts its execution. Entry point is the
## proc `tp`. `param` is passed to `tp`.
t.c.data = param
t.c.fn = tp
when hostOS == "windows":
var dummyThreadId: int32
t.sys = CreateThread(nil, 0'i32, threadProcWrapper[TParam],
addr(t.c), 0'i32, dummyThreadId)
else:
discard pthread_create(t.sys, nil, threadProcWrapper[TParam], addr(t.c))
when isMainModule:
var
thr: array [0..4, TThread[tuple[a,b: int]]]
L, M, N: TLock
proc threadFunc(interval: tuple[a,b: int]) {.procvar.} =
for i in interval.a..interval.b:
case i mod 6
of 0:
Aquire(L) # lock stdout
Aquire(M)
Aquire(N)
of 1:
Aquire(L)
Aquire(N) # lock stdout
Aquire(M)
of 2:
Aquire(M)
Aquire(L)
Aquire(N)
of 3:
Aquire(M)
Aquire(N)
Aquire(L)
of 4:
Aquire(N)
Aquire(M)
Aquire(L)
of 5:
Aquire(N)
Aquire(L)
Aquire(M)
else: assert false
echo i
echo "deadlocks prevented: ", deadlocksPrevented
Release(L)
Release(M)
Release(N)
InitLock(L)
InitLock(M)
InitLock(N)
for i in 0..high(thr):
createThread(thr[i], threadFunc, (i*100, i*100+50))
for i in 0..high(thr):
joinThread(thr[i])

View file

@ -1,7 +1,7 @@
# #
# #
# Nimrod's Runtime Library # Nimrod's Runtime Library
# (c) Copyright 2010 Andreas Rumpf # (c) Copyright 2011 Andreas Rumpf
# #
# See the file "copying.txt", included in this # See the file "copying.txt", included in this
# distribution, for details about the copyright. # distribution, for details about the copyright.
@ -24,3 +24,27 @@ proc nimLoadLibraryError(path: string) {.compilerproc, noinline.}
proc setStackBottom(theStackBottom: pointer) {.compilerRtl, noinline.} proc setStackBottom(theStackBottom: pointer) {.compilerRtl, noinline.}
# Support for thread local storage:
when false:
when defined(windows):
proc TlsAlloc(): int32 {.importc: "TlsAlloc", stdcall, dynlib: "kernel32".}
proc TlsSetValue(dwTlsIndex: int32, lpTlsValue: pointer) {.
importc: "TlsSetValue", stdcall, dynlib: "kernel32".}
proc TlsGetValue(dwTlsIndex: int32): pointer {.
importc: "TlsGetValue", stdcall, dynlib: "kernel32".}
else:
type
Tpthread_key {.importc: "pthread_key_t", header: "<sys/types.h>".} = int
proc pthread_getspecific(a1: Tpthread_key): pointer {.
importc: "pthread_getspecific", header: "<pthread.h>".}
proc pthread_key_create(a1: ptr Tpthread_key,
a2: proc (x: pointer) {.noconv.}): int32 {.
importc: "pthread_key_create", header: "<pthread.h>".}
proc pthread_key_delete(a1: Tpthread_key): int32 {.
importc: "pthread_key_delete", header: "<pthread.h>".}
proc pthread_setspecific(a1: Tpthread_key, a2: pointer): int32 {.
importc: "pthread_setspecific", header: "<pthread.h>".}

View file

@ -380,14 +380,20 @@ proc assignLocalVar(p: BProc, s: PSym) =
appf(p.s[cpsLocals], " $1;$n", [s.loc.r]) appf(p.s[cpsLocals], " $1;$n", [s.loc.r])
localDebugInfo(p, s) localDebugInfo(p, s)
proc declareThreadVar(m: BModule, s: PSym) =
if optThreads in gGlobalOptions:
app(m.s[cfsVars], "NIM_THREADVAR ")
app(m.s[cfsVars], getTypeDesc(m, s.loc.t))
proc assignGlobalVar(p: BProc, s: PSym) = proc assignGlobalVar(p: BProc, s: PSym) =
if s.loc.k == locNone: if s.loc.k == locNone:
fillLoc(s.loc, locGlobalVar, s.typ, mangleName(s), OnHeap) fillLoc(s.loc, locGlobalVar, s.typ, mangleName(s), OnHeap)
useHeader(p.module, s) useHeader(p.module, s)
if lfNoDecl in s.loc.flags: return if lfNoDecl in s.loc.flags: return
if sfImportc in s.flags: app(p.module.s[cfsVars], "extern ") if sfImportc in s.flags: app(p.module.s[cfsVars], "extern ")
if sfThreadVar in s.flags: app(p.module.s[cfsVars], "NIM_THREADVAR ") if sfThreadVar in s.flags: declareThreadVar(p.module, s)
app(p.module.s[cfsVars], getTypeDesc(p.module, s.loc.t)) else: app(p.module.s[cfsVars], getTypeDesc(p.module, s.loc.t))
if sfRegister in s.flags: app(p.module.s[cfsVars], " register") if sfRegister in s.flags: app(p.module.s[cfsVars], " register")
if sfVolatile in s.flags: app(p.module.s[cfsVars], " volatile") if sfVolatile in s.flags: app(p.module.s[cfsVars], " volatile")
appf(p.module.s[cfsVars], " $1;$n", [s.loc.r]) appf(p.module.s[cfsVars], " $1;$n", [s.loc.r])
@ -686,8 +692,8 @@ proc genVarPrototype(m: BModule, sym: PSym) =
[sym.loc.r, getTypeDesc(m, sym.loc.t)]) [sym.loc.r, getTypeDesc(m, sym.loc.t)])
else: else:
app(m.s[cfsVars], "extern ") app(m.s[cfsVars], "extern ")
if sfThreadVar in sym.flags: app(m.s[cfsVars], "NIM_THREADVAR ") if sfThreadVar in sym.flags: declareThreadVar(m, sym)
app(m.s[cfsVars], getTypeDesc(m, sym.loc.t)) else: app(m.s[cfsVars], getTypeDesc(m, sym.loc.t))
if sfRegister in sym.flags: app(m.s[cfsVars], " register") if sfRegister in sym.flags: app(m.s[cfsVars], " register")
if sfVolatile in sym.flags: app(m.s[cfsVars], " volatile") if sfVolatile in sym.flags: app(m.s[cfsVars], " volatile")
appf(m.s[cfsVars], " $1;$n", [sym.loc.r]) appf(m.s[cfsVars], " $1;$n", [sym.loc.r])

View file

@ -49,7 +49,7 @@ Options:
-f, --forceBuild force rebuilding of all modules -f, --forceBuild force rebuilding of all modules
--stackTrace:on|off turn stack tracing on|off --stackTrace:on|off turn stack tracing on|off
--lineTrace:on|off turn line tracing on|off --lineTrace:on|off turn line tracing on|off
--debugger:on|off turn Embedded Nimrod Debugger on|off --threads:on|off turn support for multi-threading on|off
-x, --checks:on|off turn all runtime checks on|off -x, --checks:on|off turn all runtime checks on|off
--objChecks:on|off turn obj conversion checks on|off --objChecks:on|off turn obj conversion checks on|off
--fieldChecks:on|off turn case variant field checks on|off --fieldChecks:on|off turn case variant field checks on|off
@ -92,6 +92,7 @@ Advanced options:
--os:SYMBOL set the target operating system (cross-compilation) --os:SYMBOL set the target operating system (cross-compilation)
--cpu:SYMBOL set the target processor (cross-compilation) --cpu:SYMBOL set the target processor (cross-compilation)
--debuginfo enables debug information --debuginfo enables debug information
--debugger:on|off turn Embedded Nimrod Debugger on|off
-t, --passc:OPTION pass an option to the C compiler -t, --passc:OPTION pass an option to the C compiler
-l, --passl:OPTION pass an option to the linker -l, --passl:OPTION pass an option to the linker
--genMapping generate a mapping file containing --genMapping generate a mapping file containing
@ -213,9 +214,6 @@ proc ProcessSpecificNote(arg: string, state: TSpecialWord, pass: TCmdlinePass,
of wOff: excl(gNotes, n) of wOff: excl(gNotes, n)
else: liMessage(info, errOnOrOffExpectedButXFound, arg) else: liMessage(info, errOnOrOffExpectedButXFound, arg)
proc processPath(path: string): string =
result = UnixToNativePath(path % ["nimrod", getPrefixDir(), "lib", libpath])
proc processCompile(filename: string) = proc processCompile(filename: string) =
var found = findFile(filename) var found = findFile(filename)
if found == "": found = filename if found == "": found = filename
@ -269,20 +267,32 @@ proc testCompileOption*(switch: string, info: TLineInfo): bool =
of wRun, wR: result = contains(gGlobalOptions, optRun) of wRun, wR: result = contains(gGlobalOptions, optRun)
of wSymbolFiles: result = contains(gGlobalOptions, optSymbolFiles) of wSymbolFiles: result = contains(gGlobalOptions, optSymbolFiles)
of wGenScript: result = contains(gGlobalOptions, optGenScript) of wGenScript: result = contains(gGlobalOptions, optGenScript)
of wThreads: result = contains(gGlobalOptions, optThreads)
else: InvalidCmdLineOption(passCmd1, switch, info) else: InvalidCmdLineOption(passCmd1, switch, info)
proc processPath(path: string): string =
result = UnixToNativePath(path % ["nimrod", getPrefixDir(), "lib", libpath,
"home", removeTrailingDirSep(os.getHomeDir())])
proc addPath(path: string) =
if not contains(options.searchPaths, path):
lists.PrependStr(options.searchPaths, path)
proc processSwitch(switch, arg: string, pass: TCmdlinePass, info: TLineInfo) = proc processSwitch(switch, arg: string, pass: TCmdlinePass, info: TLineInfo) =
var var
theOS: TSystemOS theOS: TSystemOS
cpu: TSystemCPU cpu: TSystemCPU
key, val, path: string key, val: string
case whichKeyword(switch) case whichKeyword(switch)
of wPath, wP: of wPath, wP:
expectArg(switch, arg, pass, info) expectArg(switch, arg, pass, info)
path = processPath(arg) addPath(processPath(arg))
if not contains(options.searchPaths, path):
lists.PrependStr(options.searchPaths, path)
#discard lists.IncludeStr(options.searchPaths, path) #discard lists.IncludeStr(options.searchPaths, path)
of wRecursivePath:
expectArg(switch, arg, pass, info)
var path = processPath(arg)
for p in os.walkDirRec(path, {pcDir}): addPath(p)
addPath(path)
of wOut, wO: of wOut, wO:
expectArg(switch, arg, pass, info) expectArg(switch, arg, pass, info)
options.outFile = arg options.outFile = arg
@ -356,6 +366,7 @@ proc processSwitch(switch, arg: string, pass: TCmdlinePass, info: TLineInfo) =
of wLineDir: ProcessOnOffSwitch({optLineDir}, arg, pass, info) of wLineDir: ProcessOnOffSwitch({optLineDir}, arg, pass, info)
of wAssertions, wA: ProcessOnOffSwitch({optAssert}, arg, pass, info) of wAssertions, wA: ProcessOnOffSwitch({optAssert}, arg, pass, info)
of wDeadCodeElim: ProcessOnOffSwitchG({optDeadCodeElim}, arg, pass, info) of wDeadCodeElim: ProcessOnOffSwitchG({optDeadCodeElim}, arg, pass, info)
of wThreads: ProcessOnOffSwitchG({optThreads}, arg, pass, info)
of wOpt: of wOpt:
expectArg(switch, arg, pass, info) expectArg(switch, arg, pass, info)
case whichKeyword(arg) case whichKeyword(arg)

View file

@ -1,7 +1,7 @@
# #
# #
# The Nimrod Compiler # The Nimrod Compiler
# (c) Copyright 2009 Andreas Rumpf # (c) Copyright 2011 Andreas Rumpf
# #
# See the file "copying.txt", included in this # See the file "copying.txt", included in this
# distribution, for details about the copyright. # distribution, for details about the copyright.
@ -21,28 +21,12 @@ type
m*: PSym m*: PSym
mode*: TOverloadIterMode mode*: TOverloadIterMode
proc getSymRepr*(s: PSym): string =
proc getSymRepr*(s: PSym): string
proc CloseScope*(tab: var TSymTab)
proc AddSym*(t: var TStrTable, n: PSym)
proc addDecl*(c: PContext, sym: PSym)
proc addDeclAt*(c: PContext, sym: PSym, at: Natural)
proc addOverloadableSymAt*(c: PContext, fn: PSym, at: Natural)
proc addInterfaceDecl*(c: PContext, sym: PSym)
proc addInterfaceOverloadableSymAt*(c: PContext, sym: PSym, at: int)
proc lookUp*(c: PContext, n: PNode): PSym
# Looks up a symbol. Generates an error in case of nil.
proc QualifiedLookUp*(c: PContext, n: PNode, ambiguousCheck: bool): PSym
proc InitOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym
proc nextOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym
# implementation
proc getSymRepr(s: PSym): string =
case s.kind case s.kind
of skProc, skMethod, skConverter, skIterator: result = getProcHeader(s) of skProc, skMethod, skConverter, skIterator: result = getProcHeader(s)
else: result = s.name.s else: result = s.name.s
proc CloseScope(tab: var TSymTab) = proc CloseScope*(tab: var TSymTab) =
var var
it: TTabIter it: TTabIter
s: PSym s: PSym
@ -59,14 +43,14 @@ proc CloseScope(tab: var TSymTab) =
s = NextIter(it, tab.stack[tab.tos - 1]) s = NextIter(it, tab.stack[tab.tos - 1])
astalgo.rawCloseScope(tab) astalgo.rawCloseScope(tab)
proc AddSym(t: var TStrTable, n: PSym) = proc AddSym*(t: var TStrTable, n: PSym) =
if StrTableIncl(t, n): liMessage(n.info, errAttemptToRedefine, n.name.s) if StrTableIncl(t, n): liMessage(n.info, errAttemptToRedefine, n.name.s)
proc addDecl(c: PContext, sym: PSym) = proc addDecl*(c: PContext, sym: PSym) =
if SymTabAddUnique(c.tab, sym) == Failure: if SymTabAddUnique(c.tab, sym) == Failure:
liMessage(sym.info, errAttemptToRedefine, sym.Name.s) liMessage(sym.info, errAttemptToRedefine, sym.Name.s)
proc addDeclAt(c: PContext, sym: PSym, at: Natural) = proc addDeclAt*(c: PContext, sym: PSym, at: Natural) =
if SymTabAddUniqueAt(c.tab, sym, at) == Failure: if SymTabAddUniqueAt(c.tab, sym, at) == Failure:
liMessage(sym.info, errAttemptToRedefine, sym.Name.s) liMessage(sym.info, errAttemptToRedefine, sym.Name.s)
@ -81,7 +65,7 @@ proc addInterfaceDeclAt*(c: PContext, sym: PSym, at: Natural) =
addDeclAt(c, sym, at) addDeclAt(c, sym, at)
AddInterfaceDeclAux(c, sym) AddInterfaceDeclAux(c, sym)
proc addOverloadableSymAt(c: PContext, fn: PSym, at: Natural) = proc addOverloadableSymAt*(c: PContext, fn: PSym, at: Natural) =
if not (fn.kind in OverloadableSyms): if not (fn.kind in OverloadableSyms):
InternalError(fn.info, "addOverloadableSymAt") InternalError(fn.info, "addOverloadableSymAt")
var check = StrTableGet(c.tab.stack[at], fn.name) var check = StrTableGet(c.tab.stack[at], fn.name)
@ -89,17 +73,17 @@ proc addOverloadableSymAt(c: PContext, fn: PSym, at: Natural) =
liMessage(fn.info, errAttemptToRedefine, fn.Name.s) liMessage(fn.info, errAttemptToRedefine, fn.Name.s)
SymTabAddAt(c.tab, fn, at) SymTabAddAt(c.tab, fn, at)
proc addInterfaceDecl(c: PContext, sym: PSym) = proc addInterfaceDecl*(c: PContext, sym: PSym) =
# it adds the symbol to the interface if appropriate # it adds the symbol to the interface if appropriate
addDecl(c, sym) addDecl(c, sym)
AddInterfaceDeclAux(c, sym) AddInterfaceDeclAux(c, sym)
proc addInterfaceOverloadableSymAt(c: PContext, sym: PSym, at: int) = proc addInterfaceOverloadableSymAt*(c: PContext, sym: PSym, at: int) =
# it adds the symbol to the interface if appropriate # it adds the symbol to the interface if appropriate
addOverloadableSymAt(c, sym, at) addOverloadableSymAt(c, sym, at)
AddInterfaceDeclAux(c, sym) AddInterfaceDeclAux(c, sym)
proc lookUp(c: PContext, n: PNode): PSym = proc lookUp*(c: PContext, n: PNode): PSym =
# Looks up a symbol. Generates an error in case of nil. # Looks up a symbol. Generates an error in case of nil.
case n.kind case n.kind
of nkAccQuoted: of nkAccQuoted:
@ -118,26 +102,32 @@ proc lookUp(c: PContext, n: PNode): PSym =
liMessage(n.info, errUseQualifier, result.name.s) liMessage(n.info, errUseQualifier, result.name.s)
if result.kind == skStub: loadStub(result) if result.kind == skStub: loadStub(result)
proc QualifiedLookUp(c: PContext, n: PNode, ambiguousCheck: bool): PSym = type
TLookupFlag* = enum
checkAmbiguity, checkUndeclared
proc QualifiedLookUp*(c: PContext, n: PNode, flags = {checkUndeclared}): PSym =
case n.kind case n.kind
of nkIdent: of nkIdent:
result = SymtabGet(c.Tab, n.ident) result = SymtabGet(c.Tab, n.ident)
if result == nil: if result == nil and checkUndeclared in flags:
liMessage(n.info, errUndeclaredIdentifier, n.ident.s) liMessage(n.info, errUndeclaredIdentifier, n.ident.s)
elif ambiguousCheck and IntSetContains(c.AmbiguousSymbols, result.id): elif checkAmbiguity in flags and IntSetContains(c.AmbiguousSymbols,
result.id):
liMessage(n.info, errUseQualifier, n.ident.s) liMessage(n.info, errUseQualifier, n.ident.s)
of nkSym: of nkSym:
# #
# result := SymtabGet(c.Tab, n.sym.name); # result = SymtabGet(c.Tab, n.sym.name)
# if result = nil then # if result == nil:
# liMessage(n.info, errUndeclaredIdentifier, n.sym.name.s) # liMessage(n.info, errUndeclaredIdentifier, n.sym.name.s)
# else # else
result = n.sym result = n.sym
if ambiguousCheck and IntSetContains(c.AmbiguousSymbols, result.id): if checkAmbiguity in flags and IntSetContains(c.AmbiguousSymbols,
result.id):
liMessage(n.info, errUseQualifier, n.sym.name.s) liMessage(n.info, errUseQualifier, n.sym.name.s)
of nkDotExpr: of nkDotExpr:
result = nil result = nil
var m = qualifiedLookUp(c, n.sons[0], false) var m = qualifiedLookUp(c, n.sons[0], flags*{checkUndeclared})
if (m != nil) and (m.kind == skModule): if (m != nil) and (m.kind == skModule):
var ident: PIdent = nil var ident: PIdent = nil
if (n.sons[1].kind == nkIdent): if (n.sons[1].kind == nkIdent):
@ -150,17 +140,17 @@ proc QualifiedLookUp(c: PContext, n: PNode, ambiguousCheck: bool): PSym =
result = StrTableGet(c.tab.stack[ModuleTablePos], ident) result = StrTableGet(c.tab.stack[ModuleTablePos], ident)
else: else:
result = StrTableGet(m.tab, ident) result = StrTableGet(m.tab, ident)
if result == nil: if result == nil and checkUndeclared in flags:
liMessage(n.sons[1].info, errUndeclaredIdentifier, ident.s) liMessage(n.sons[1].info, errUndeclaredIdentifier, ident.s)
else: elif checkUndeclared in flags:
liMessage(n.sons[1].info, errIdentifierExpected, renderTree(n.sons[1])) liMessage(n.sons[1].info, errIdentifierExpected, renderTree(n.sons[1]))
of nkAccQuoted: of nkAccQuoted:
result = QualifiedLookup(c, n.sons[0], ambiguousCheck) result = QualifiedLookup(c, n.sons[0], flags)
else: else:
result = nil #liMessage(n.info, errIdentifierExpected, '') result = nil
if (result != nil) and (result.kind == skStub): loadStub(result) 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 =
var ident: PIdent var ident: PIdent
result = nil result = nil
case n.kind case n.kind
@ -173,17 +163,16 @@ proc InitOverloadIter(o: var TOverloadIter, c: PContext, n: PNode): PSym =
result = InitIdentIter(o.it, c.tab.stack[o.stackPtr], n.ident) result = InitIdentIter(o.it, c.tab.stack[o.stackPtr], n.ident)
of nkSym: of nkSym:
result = n.sym result = n.sym
o.mode = oimDone # o.mode = oimDone
# o.stackPtr := c.tab.tos; # o.stackPtr = c.tab.tos
# o.mode := oimNoQualifier; # o.mode = oimNoQualifier
# while (result = nil) do begin # while result == nil:
# dec(o.stackPtr); # dec(o.stackPtr)
# if o.stackPtr < 0 then break; # if o.stackPtr < 0: break
# result := InitIdentIter(o.it, c.tab.stack[o.stackPtr], n.sym.name); # result = InitIdentIter(o.it, c.tab.stack[o.stackPtr], n.sym.name)
# end;
of nkDotExpr: of nkDotExpr:
o.mode = oimOtherModule o.mode = oimOtherModule
o.m = qualifiedLookUp(c, n.sons[0], false) o.m = qualifiedLookUp(c, n.sons[0])
if (o.m != nil) and (o.m.kind == skModule): if (o.m != nil) and (o.m.kind == skModule):
ident = nil ident = nil
if (n.sons[1].kind == nkIdent): if (n.sons[1].kind == nkIdent):
@ -210,7 +199,7 @@ proc InitOverloadIter(o: var TOverloadIter, c: PContext, n: PNode): PSym =
nil nil
if (result != nil) and (result.kind == skStub): loadStub(result) if (result != nil) and (result.kind == skStub): loadStub(result)
proc nextOverloadIter(o: var TOverloadIter, c: PContext, n: PNode): PSym = proc nextOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
case o.mode case o.mode
of oimDone: of oimDone:
result = nil result = nil
@ -222,8 +211,8 @@ proc nextOverloadIter(o: var TOverloadIter, c: PContext, n: PNode): PSym =
while (result == nil): while (result == nil):
dec(o.stackPtr) dec(o.stackPtr)
if o.stackPtr < 0: break if o.stackPtr < 0: break
result = InitIdentIter(o.it, c.tab.stack[o.stackPtr], o.it.name) # BUGFIX: result = InitIdentIter(o.it, c.tab.stack[o.stackPtr], o.it.name)
# o.it.name <-> n.ident # BUGFIX: o.it.name <-> n.ident
else: else:
result = nil result = nil
of oimSelfModule: of oimSelfModule:

View file

@ -30,7 +30,8 @@ type # please make sure we have under 32 options
TOptions* = set[TOption] TOptions* = set[TOption]
TGlobalOption* = enum TGlobalOption* = enum
gloptNone, optForceFullMake, optBoehmGC, optRefcGC, optDeadCodeElim, gloptNone, optForceFullMake, optBoehmGC, optRefcGC, optDeadCodeElim,
optListCmd, optCompileOnly, optNoLinking, optSafeCode, # only allow safe code optListCmd, optCompileOnly, optNoLinking,
optSafeCode, # only allow safe code
optCDebug, # turn on debugging information optCDebug, # turn on debugging information
optGenDynLib, # generate a dynamic library optGenDynLib, # generate a dynamic library
optGenGuiApp, # generate a GUI application optGenGuiApp, # generate a GUI application
@ -40,7 +41,8 @@ type # please make sure we have under 32 options
optSymbolFiles, # use symbol files for speeding up compilation optSymbolFiles, # use symbol files for speeding up compilation
optSkipConfigFile, # skip the general config file optSkipConfigFile, # skip the general config file
optSkipProjConfigFile, # skip the project's config file optSkipProjConfigFile, # skip the project's config file
optNoMain # do not generate a "main" proc optNoMain, # do not generate a "main" proc
optThreads # support for multi-threading
TGlobalOptions* = set[TGlobalOption] TGlobalOptions* = set[TGlobalOption]
TCommands* = enum # Nimrod's commands TCommands* = enum # Nimrod's commands
cmdNone, cmdCompileToC, cmdCompileToCpp, cmdCompileToOC, cmdNone, cmdCompileToC, cmdCompileToCpp, cmdCompileToOC,
@ -142,7 +144,7 @@ proc shortenDir(dir: string): string =
return copy(dir, len(prefix)) return copy(dir, len(prefix))
result = dir result = dir
proc removeTrailingDirSep(path: string): string = 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 = copy(path, 0, len(path) - 2) result = copy(path, 0, len(path) - 2)
else: else:

View file

@ -631,7 +631,7 @@ proc makeDeref(n: PNode): PNode =
proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode = proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
## returns nil if it's not a built-in field access ## returns nil if it's not a built-in field access
var s = qualifiedLookup(c, n, true) # check for ambiguity var s = qualifiedLookup(c, n, {checkAmbiguity, checkUndeclared})
if s != nil: if s != nil:
return semSym(c, n, s, flags) return semSym(c, n, s, flags)
@ -940,7 +940,7 @@ proc semMacroStmt(c: PContext, n: PNode, semCheck: bool = true): PNode =
var a: PNode var a: PNode
if isCallExpr(n.sons[0]): a = n.sons[0].sons[0] if isCallExpr(n.sons[0]): a = n.sons[0].sons[0]
else: a = n.sons[0] else: a = n.sons[0]
var s = qualifiedLookup(c, a, false) var s = qualifiedLookup(c, a, {checkUndeclared})
if s != nil: if s != nil:
case s.kind case s.kind
of skMacro: of skMacro:
@ -1014,7 +1014,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
of nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit: of nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit:
# check if it is an expression macro: # check if it is an expression macro:
checkMinSonsLen(n, 1) checkMinSonsLen(n, 1)
var s = qualifiedLookup(c, n.sons[0], false) var s = qualifiedLookup(c, n.sons[0], {checkUndeclared})
if s != nil: if s != nil:
case s.kind case s.kind
of skMacro: result = semMacroExpr(c, n, s) of skMacro: result = semMacroExpr(c, n, s)
@ -1037,10 +1037,10 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
result = semMacroStmt(c, n) result = semMacroStmt(c, n)
of nkBracketExpr: of nkBracketExpr:
checkMinSonsLen(n, 1) checkMinSonsLen(n, 1)
var s = qualifiedLookup(c, n.sons[0], false) var s = qualifiedLookup(c, n.sons[0], {checkUndeclared})
if s != nil and s.kind in {skProc, skMethod, skConverter, skIterator}: if s != nil and s.kind in {skProc, skMethod, skConverter, skIterator}:
# type parameters: partial generic specialization # type parameters: partial generic specialization
result = partialSpecialization(c, n, s) result = explictGenericInstantiation(c, n, s)
else: else:
result = semArrayAccess(c, n, flags) result = semArrayAccess(c, n, flags)
of nkPragmaExpr: of nkPragmaExpr:

View file

@ -21,12 +21,14 @@ type
TSemGenericFlags = set[TSemGenericFlag] TSemGenericFlags = set[TSemGenericFlag]
proc semGenericStmt(c: PContext, n: PNode, flags: TSemGenericFlags = {}): PNode proc semGenericStmt(c: PContext, n: PNode, flags: TSemGenericFlags = {}): PNode
proc semGenericStmtScope(c: PContext, n: PNode, flags: TSemGenericFlags = {}): PNode = proc semGenericStmtScope(c: PContext, n: PNode,
flags: TSemGenericFlags = {}): PNode =
openScope(c.tab) openScope(c.tab)
result = semGenericStmt(c, n, flags) result = semGenericStmt(c, n, flags)
closeScope(c.tab) closeScope(c.tab)
proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym): PNode = proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym): PNode =
incl(s.flags, sfUsed)
case s.kind case s.kind
of skUnknown: of skUnknown:
# Introduced in this pass! Leave it as an identifier. # Introduced in this pass! Leave it as an identifier.
@ -55,20 +57,29 @@ proc getIdentNode(n: PNode): PNode =
illFormedAst(n) illFormedAst(n)
result = nil result = nil
# of nkAccQuoted:
# s = lookUp(c, n)
# if withinBind in flags: result = symChoice(c, n, s)
# else: result = semGenericStmtSymbol(c, n, s)
proc semGenericStmt(c: PContext, n: PNode, flags: TSemGenericFlags = {}): PNode = proc semGenericStmt(c: PContext, n: PNode, flags: TSemGenericFlags = {}): PNode =
var var
L: int L: int
a: PNode a: PNode
s: PSym
result = n result = n
if n == nil: return if n == nil: return
case n.kind case n.kind
of nkIdent, nkAccQuoted: of nkIdent:
s = lookUp(c, n) var s = SymtabGet(c.Tab, n.ident)
if s == nil:
# no error if symbol cannot be bound, unless in ``bind`` context:
if withinBind in flags:
liMessage(n.info, errUndeclaredIdentifier, n.ident.s)
else:
if withinBind in flags: result = symChoice(c, n, s) if withinBind in flags: result = symChoice(c, n, s)
else: result = semGenericStmtSymbol(c, n, s) else: result = semGenericStmtSymbol(c, n, s)
of nkDotExpr: of nkDotExpr:
s = QualifiedLookUp(c, n, true) var s = QualifiedLookUp(c, n, {})
if s != nil: result = semGenericStmtSymbol(c, n, s) if s != nil: result = semGenericStmtSymbol(c, n, s)
of nkSym..nkNilLit: of nkSym..nkNilLit:
nil nil
@ -77,8 +88,9 @@ proc semGenericStmt(c: PContext, n: PNode, flags: TSemGenericFlags = {}): PNode
of nkCall, nkHiddenCallConv, nkInfix, nkPrefix, nkCommand, nkCallStrLit: of nkCall, nkHiddenCallConv, nkInfix, nkPrefix, nkCommand, nkCallStrLit:
# check if it is an expression macro: # check if it is an expression macro:
checkMinSonsLen(n, 1) checkMinSonsLen(n, 1)
s = qualifiedLookup(c, n.sons[0], false) var s = qualifiedLookup(c, n.sons[0], {})
if (s != nil): if s != nil:
incl(s.flags, sfUsed)
case s.kind case s.kind
of skMacro: of skMacro:
return semMacroExpr(c, n, s, false) return semMacroExpr(c, n, s, false)

View file

@ -106,6 +106,7 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
else: else:
result.typ = newTypeS(tyProc, c) result.typ = newTypeS(tyProc, c)
addSon(result.typ, nil) addSon(result.typ, nil)
result.typ.callConv = fn.typ.callConv
oldPrc = GenericCacheGet(c, fn, result) oldPrc = GenericCacheGet(c, fn, result)
if oldPrc == nil: if oldPrc == nil:
# add it here, so that recursive generic procs are possible: # add it here, so that recursive generic procs are possible:
@ -244,10 +245,3 @@ proc generateTypeInstance(p: PContext, pt: TIdTable, arg: PNode,
result = ReplaceTypeVarsT(cl, t) result = ReplaceTypeVarsT(cl, t)
popInfoContext() popInfoContext()
proc partialSpecialization(c: PContext, n: PNode, s: PSym): PNode =
for i in 1..sonsLen(n)-1:
n.sons[i].typ = semTypeNode(c, n.sons[i], nil)
# we cannot check for the proper number of type parameters because in
# `f[a,b](x, y)` `f` is not resolved yet properly.
# XXX: BUG this should be checked somehow!
result = n

View file

@ -162,7 +162,7 @@ proc propertyWriteAccess(c: PContext, n, a: PNode): PNode =
addSon(result, newIdentNode(getIdent(id.s & '='), n.info)) addSon(result, newIdentNode(getIdent(id.s & '='), n.info))
# a[0] is already checked for semantics, that does ``builtinFieldAccess`` # a[0] is already checked for semantics, that does ``builtinFieldAccess``
# this is ugly. XXX Semantic checking should use the ``nfSem`` flag for # this is ugly. XXX Semantic checking should use the ``nfSem`` flag for
# nodes! # nodes?
addSon(result, a[0]) addSon(result, a[0])
addSon(result, semExpr(c, n[1])) addSon(result, semExpr(c, n[1]))
result = semDirectCallAnalyseEffects(c, result, {}) result = semDirectCallAnalyseEffects(c, result, {})
@ -182,18 +182,6 @@ proc semAsgn(c: PContext, n: PNode): PNode =
a = builtinFieldAccess(c, a, {efLValue}) a = builtinFieldAccess(c, a, {efLValue})
if a == nil: if a == nil:
return propertyWriteAccess(c, n, n[0]) return propertyWriteAccess(c, n, n[0])
when false:
checkSonsLen(a, 2)
var id = considerAcc(a.sons[1])
result = newNodeI(nkCall, n.info)
addSon(result, newIdentNode(getIdent(id.s & '='), n.info))
addSon(result, semExpr(c, a.sons[0]))
addSon(result, semExpr(c, n.sons[1]))
result = semDirectCallAnalyseEffects(c, result, {})
if result != nil:
fixAbstractType(c, result)
analyseIfAddressTakenInCall(c, result)
return
of nkBracketExpr: of nkBracketExpr:
# a[i..j] = x # a[i..j] = x
# --> `[..]=`(a, i, j, x) # --> `[..]=`(a, i, j, x)
@ -204,7 +192,6 @@ proc semAsgn(c: PContext, n: PNode): PNode =
return semExprNoType(c, result) return semExprNoType(c, result)
else: else:
a = semExprWithType(c, a, {efLValue}) a = semExprWithType(c, a, {efLValue})
#n.sons[0] = semExprWithType(c, n.sons[0], {efLValue})
n.sons[0] = a n.sons[0] = a
n.sons[1] = semExprWithType(c, n.sons[1]) n.sons[1] = semExprWithType(c, n.sons[1])
var le = a.typ var le = a.typ
@ -288,7 +275,6 @@ proc semVar(c: PContext, n: PNode): PNode =
else: else:
def = nil def = nil
if not typeAllowed(typ, skVar): if not typeAllowed(typ, skVar):
#debug(typ);
liMessage(a.info, errXisNoType, typeToString(typ)) liMessage(a.info, errXisNoType, typeToString(typ))
tup = skipTypes(typ, {tyGenericInst}) tup = skipTypes(typ, {tyGenericInst})
if a.kind == nkVarTuple: if a.kind == nkVarTuple:

View file

@ -178,7 +178,7 @@ proc semOrdinal(c: PContext, n: PNode, prev: PType): PType =
liMessage(n.info, errXExpectsOneTypeParam, "ordinal") liMessage(n.info, errXExpectsOneTypeParam, "ordinal")
proc semTypeIdent(c: PContext, n: PNode): PSym = proc semTypeIdent(c: PContext, n: PNode): PSym =
result = qualifiedLookup(c, n, true) result = qualifiedLookup(c, n, {checkAmbiguity, checkUndeclared})
if (result != nil): if (result != nil):
markUsed(n, result) markUsed(n, result)
if result.kind != skType: liMessage(n.info, errTypeExpected) if result.kind != skType: liMessage(n.info, errTypeExpected)

View file

@ -1,7 +1,7 @@
# #
# #
# The Nimrod Compiler # The Nimrod Compiler
# (c) Copyright 2010 Andreas Rumpf # (c) Copyright 2011 Andreas Rumpf
# #
# See the file "copying.txt", included in this # See the file "copying.txt", included in this
# distribution, for details about the copyright. # distribution, for details about the copyright.
@ -82,11 +82,11 @@ proc cmpCandidates(a, b: TCandidate): int =
result = a.convMatches - b.convMatches result = a.convMatches - b.convMatches
proc writeMatches(c: TCandidate) = proc writeMatches(c: TCandidate) =
Writeln(stdout, "exact matches: " & $(c.exactMatches)) Writeln(stdout, "exact matches: " & $c.exactMatches)
Writeln(stdout, "subtype matches: " & $(c.subtypeMatches)) Writeln(stdout, "subtype matches: " & $c.subtypeMatches)
Writeln(stdout, "conv matches: " & $(c.convMatches)) Writeln(stdout, "conv matches: " & $c.convMatches)
Writeln(stdout, "intconv matches: " & $(c.intConvMatches)) Writeln(stdout, "intconv matches: " & $c.intConvMatches)
Writeln(stdout, "generic matches: " & $(c.genericMatches)) Writeln(stdout, "generic matches: " & $c.genericMatches)
proc getNotFoundError(c: PContext, n: PNode): string = proc getNotFoundError(c: PContext, n: PNode): string =
# Gives a detailed error message; this is separated from semDirectCall, # Gives a detailed error message; this is separated from semDirectCall,
@ -710,8 +710,7 @@ proc semDirectCallWithBinding(c: PContext, n, f: PNode, filter: TSymKinds,
elif y.state == csMatch and cmpCandidates(x, y) == 0 and elif y.state == csMatch and cmpCandidates(x, y) == 0 and
not sameMethodDispatcher(x.calleeSym, y.calleeSym): not sameMethodDispatcher(x.calleeSym, y.calleeSym):
if x.state != csMatch: if x.state != csMatch:
InternalError(n.info, "x.state is not csMatch") #writeMatches(x); InternalError(n.info, "x.state is not csMatch")
#writeMatches(y);
liMessage(n.Info, errGenerated, msgKindToString(errAmbiguousCallXYZ) % [ liMessage(n.Info, errGenerated, msgKindToString(errAmbiguousCallXYZ) % [
getProcHeader(x.calleeSym), getProcHeader(y.calleeSym), getProcHeader(x.calleeSym), getProcHeader(y.calleeSym),
x.calleeSym.Name.s]) x.calleeSym.Name.s])
@ -740,3 +739,20 @@ proc semDirectCall(c: PContext, n: PNode, filter: TSymKinds): PNode =
initialBinding = nil initialBinding = nil
result = semDirectCallWithBinding(c, n, f, filter, initialBinding) result = semDirectCallWithBinding(c, n, f, filter, initialBinding)
proc explictGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
assert n.kind == nkBracketExpr
for i in 1..sonsLen(n)-1:
n.sons[i].typ = semTypeNode(c, n.sons[i], nil)
# we cannot check for the proper number of type parameters because in
# `f[a,b](x, y)` `f` is not resolved yet properly.
# XXX: BUG this should be checked somehow!
assert n.sons[0].kind == nkSym
var x: TCandidate
initCandidate(x, s, n)
var newInst = generateInstance(c, s, x.bindings, n.info)
markUsed(n, s)
result = newSymNode(newInst)
result.info = n.info

View file

@ -1,7 +1,7 @@
# #
# #
# The Nimrod Compiler # The Nimrod Compiler
# (c) Copyright 2010 Andreas Rumpf # (c) Copyright 2011 Andreas Rumpf
# #
# See the file "copying.txt", included in this # See the file "copying.txt", included in this
# distribution, for details about the copyright. # distribution, for details about the copyright.
@ -747,7 +747,7 @@ proc typeAllowedNode(marker: var TIntSet, n: PNode, kind: TSymKind): bool =
result = true result = true
if n != nil: if n != nil:
result = typeAllowedAux(marker, n.typ, kind) result = typeAllowedAux(marker, n.typ, kind)
if not result: debug(n.typ) #if not result: debug(n.typ)
if result: if result:
case n.kind case n.kind
of nkNone..nkNilLit: of nkNone..nkNilLit:

View file

@ -59,7 +59,8 @@ type
wPretty, wPretty,
wDoc, wGenDepend, wListDef, wCheck, wParse, wScan, wJs, wOC, wDoc, wGenDepend, wListDef, wCheck, wParse, wScan, wJs, wOC,
wRst2html, wRst2tex, wI, wRst2html, wRst2tex, wI,
wWrite, wPutEnv, wPrependEnv, wAppendEnv, wThreadVar, wEmit wWrite, wPutEnv, wPrependEnv, wAppendEnv, wThreadVar, wEmit, wThreads,
wRecursivePath
TSpecialWords* = set[TSpecialWord] TSpecialWords* = set[TSpecialWord]
@ -107,7 +108,8 @@ const
"compiletooc", "compiletooc",
"pretty", "doc", "gendepend", "listdef", "check", "parse", "scan", "pretty", "doc", "gendepend", "listdef", "check", "parse", "scan",
"js", "oc", "rst2html", "rst2tex", "i", "js", "oc", "rst2html", "rst2tex", "i",
"write", "putenv", "prependenv", "appendenv", "threadvar", "emit"] "write", "putenv", "prependenv", "appendenv", "threadvar", "emit",
"threads", "recursivepath"]
proc whichKeyword*(id: PIdent): TSpecialWord proc whichKeyword*(id: PIdent): TSpecialWord
proc whichKeyword*(id: String): TSpecialWord proc whichKeyword*(id: String): TSpecialWord

View file

@ -1,6 +1,6 @@
- built-in serialization
- thread support: threadvar on Windows seems broken; - thread support: threadvar on Windows seems broken;
add --deadlock_prevention:on|off switch add --deadlock_prevention:on|off switch
- built-in serialization
- ban ``nil`` from the AST. This might also fix bugs concerning macros. - ban ``nil`` from the AST. This might also fix bugs concerning macros.
@ -66,7 +66,8 @@ Low priority
- tlastmod returns wrong results on BSD (Linux, MacOS X: works) - tlastmod returns wrong results on BSD (Linux, MacOS X: works)
- nested tuple unpacking - nested tuple unpacking
- fast assignment optimization for TPeg - fast assignment optimization for TPeg
- better error messages for used keywords as identifiers
- case statement branches should support constant sets
Library Library
------- -------

View file

@ -47,13 +47,13 @@ if [ $# -eq 1 ] ; then
docdir="$1/?proj/doc" docdir="$1/?proj/doc"
datadir="$1/?proj/data" datadir="$1/?proj/data"
mkdir -p $1/?proj mkdir -p $1/?proj || exit 1
mkdir -p $bindir mkdir -p $bindir || exit 1
mkdir -p $configdir mkdir -p $configdir || exit 1
;; ;;
esac esac
mkdir -p $libdir mkdir -p $libdir || exit 1
mkdir -p $docdir mkdir -p $docdir || exit 1
echo "copying files..." echo "copying files..."
#var createdDirs = newStringTable() #var createdDirs = newStringTable()
#for cat in fcConfig..fcLib: #for cat in fcConfig..fcLib:
@ -63,30 +63,30 @@ if [ $# -eq 1 ] ; then
# mk = unixDirVars[cat] & "/" & mk # mk = unixDirVars[cat] & "/" & mk
# if not createdDirs.hasKey(mk): # if not createdDirs.hasKey(mk):
# createdDirs[mk] = "true" # createdDirs[mk] = "true"
mkdir -p ?mk mkdir -p ?mk || exit 1
# end if # end if
# end if # end if
# end for # end for
#end for #end for
#for f in items(c.cat[fcUnixBin]): #for f in items(c.cat[fcUnixBin]):
cp ?f $bindir/?f.skipRoot cp ?f $bindir/?f.skipRoot || exit 1
chmod 755 $bindir/?f.skipRoot chmod 755 $bindir/?f.skipRoot
#end for #end for
#for f in items(c.cat[fcConfig]): #for f in items(c.cat[fcConfig]):
cp ?f $configdir/?f.skipRoot cp ?f $configdir/?f.skipRoot || exit 1
chmod 644 $configdir/?f.skipRoot chmod 644 $configdir/?f.skipRoot
#end for #end for
#for f in items(c.cat[fcData]): #for f in items(c.cat[fcData]):
cp ?f $datadir/?f.skipRoot cp ?f $datadir/?f.skipRoot || exit 1
chmod 644 $datadir/?f.skipRoot chmod 644 $datadir/?f.skipRoot
#end for #end for
#for f in items(c.cat[fcDoc]): #for f in items(c.cat[fcDoc]):
cp ?f $docdir/?f.skipRoot cp ?f $docdir/?f.skipRoot || exit 1
chmod 644 $docdir/?f.skipRoot chmod 644 $docdir/?f.skipRoot
#end for #end for
#for f in items(c.cat[fcLib]): #for f in items(c.cat[fcLib]):
cp ?f $libdir/?f.skipRoot cp ?f $libdir/?f.skipRoot || exit 1
chmod 644 $libdir/?f.skipRoot chmod 644 $libdir/?f.skipRoot
#end for #end for

View file

@ -33,6 +33,8 @@ Changes affecting backwards compatibility
Additions Additions
--------- ---------
- Added ``scgi`` module.
- Added ``smtp`` module.
- Added ``re.findAll``, ``pegs.findAll``. - Added ``re.findAll``, ``pegs.findAll``.
- Added ``os.findExe``. - Added ``os.findExe``.
- Added ``strutils.align``, ``strutils.tokenize``, ``strutils.wordWrap``. - Added ``strutils.align``, ``strutils.tokenize``, ``strutils.wordWrap``.
@ -40,7 +42,7 @@ Additions
- Pegs support new built-ins: ``\letter``, ``\upper``, ``\lower``, - Pegs support new built-ins: ``\letter``, ``\upper``, ``\lower``,
``\title``, ``\white``. ``\title``, ``\white``.
- Pegs support the new built-in ``\skip`` operation. - Pegs support the new built-in ``\skip`` operation.
- Source code filters are now properly documented. - Source code filters are now documented.
- Added ``emit`` pragma for direct code generator control. - Added ``emit`` pragma for direct code generator control.
- Additional operations were added to the ``complex`` module. - Additional operations were added to the ``complex`` module.
- Added ``strutils.formatFloat``, ``strutils.formatBiggestFloat``. - Added ``strutils.formatFloat``, ``strutils.formatBiggestFloat``.