mirror of
https://github.com/nim-lang/Nim.git
synced 2026-04-18 13:30:33 +00:00
changes to threads; --recursivePath support
This commit is contained in:
@@ -30,6 +30,7 @@ path="$lib/windows"
|
||||
path="$lib/posix"
|
||||
path="$lib/ecmas"
|
||||
path="$lib/pure/unidecode"
|
||||
#recursivePath:"$user/.babel/lib"
|
||||
|
||||
@if release or quick:
|
||||
obj_checks:off
|
||||
|
||||
@@ -22,6 +22,7 @@ Advanced options:
|
||||
--os:SYMBOL set the target operating system (cross-compilation)
|
||||
--cpu:SYMBOL set the target processor (cross-compilation)
|
||||
--debuginfo enables debug information
|
||||
--debugger:on|off turn Embedded Nimrod Debugger on|off
|
||||
-t, --passc:OPTION pass an option to the C compiler
|
||||
-l, --passl:OPTION pass an option to the linker
|
||||
--genMapping generate a mapping file containing
|
||||
|
||||
@@ -18,7 +18,7 @@ Options:
|
||||
-f, --forceBuild force rebuilding of all modules
|
||||
--stackTrace:on|off turn stack 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
|
||||
--objChecks:on|off turn obj conversion checks on|off
|
||||
--fieldChecks:on|off turn case variant field checks on|off
|
||||
|
||||
@@ -16,11 +16,11 @@
|
||||
## .. code-block:: nimrod
|
||||
##
|
||||
## var
|
||||
## thr: array [0..4, TThread]
|
||||
## thr: array [0..4, TThread[tuple[a,b: int]]]
|
||||
## L: TLock
|
||||
##
|
||||
## proc threadFunc(c: pointer) {.procvar.} =
|
||||
## for i in 0..9:
|
||||
## proc threadFunc(interval: tuple[a,b: int]) {.procvar.} =
|
||||
## for i in interval.a..interval.b:
|
||||
## Aquire(L) # lock stdout
|
||||
## echo i
|
||||
## Release(L)
|
||||
@@ -28,10 +28,12 @@
|
||||
## InitLock(L)
|
||||
##
|
||||
## 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):
|
||||
## 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
|
||||
# the Nimrod calling convention. This is needed because thread procs are
|
||||
@@ -41,10 +43,9 @@
|
||||
# GC'ed closures in Nimrod.
|
||||
|
||||
type
|
||||
TThreadProc* = proc (closure: pointer) ## Standard Nimrod thread proc.
|
||||
TThreadProcClosure {.pure, final.} = object
|
||||
fn: TThreadProc
|
||||
data: pointer
|
||||
TThreadProcClosure {.pure, final.}[TParam] = object
|
||||
fn: proc (p: TParam)
|
||||
data: TParam
|
||||
|
||||
when defined(Windows):
|
||||
type
|
||||
@@ -60,17 +61,22 @@ when defined(Windows):
|
||||
|
||||
TWinThreadProc = proc (x: pointer): int32 {.stdcall.}
|
||||
|
||||
TLock* = TSysLock ## Standard Nimrod Lock type.
|
||||
|
||||
proc InitLock*(L: var TLock) {.stdcall,
|
||||
proc InitSysLock(L: var TSysLock) {.stdcall,
|
||||
dynlib: "kernel32", importc: "InitializeCriticalSection".}
|
||||
## 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".}
|
||||
## Aquires the lock `L`.
|
||||
|
||||
proc Release*(L: var TLock) {.stdcall,
|
||||
proc ReleaseSys(L: var TSysLock) {.stdcall,
|
||||
dynlib: "kernel32", importc: "LeaveCriticalSection".}
|
||||
## Releases the lock `L`.
|
||||
|
||||
@@ -99,8 +105,8 @@ when defined(Windows):
|
||||
proc TerminateThread(hThread: THandle, dwExitCode: int32): int32 {.
|
||||
stdcall, dynlib: "kernel32", importc: "TerminateThread".}
|
||||
|
||||
proc threadProcWrapper(closure: pointer): int32 {.stdcall.} =
|
||||
var c = cast[ptr TThreadProcClosure](closure)
|
||||
proc threadProcWrapper[TParam](closure: pointer): int32 {.stdcall.} =
|
||||
var c = cast[ptr TThreadProcClosure[TParam]](closure)
|
||||
c.fn(c.data)
|
||||
# implicitely return 0
|
||||
|
||||
@@ -109,16 +115,18 @@ else:
|
||||
TSysLock {.importc: "pthread_mutex_t", header: "<sys/types.h>".} = int
|
||||
TSysThread {.importc: "pthread_t", header: "<sys/types.h>".} = int
|
||||
|
||||
TLock* = TSysLock
|
||||
|
||||
proc InitLockAux(L: var TSysLock, attr: pointer = nil) {.
|
||||
proc InitSysLock(L: var TSysLock, attr: pointer = nil) {.
|
||||
importc: "pthread_mutex_init", header: "<pthread.h>".}
|
||||
|
||||
proc InitLock*(L: var TLock) {.inline.} =
|
||||
InitLockAux(L)
|
||||
proc Aquire*(L: var TLock) {.
|
||||
proc AquireSys(L: var TSysLock) {.
|
||||
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>".}
|
||||
|
||||
proc pthread_create(a1: var TSysThread, a2: ptr int,
|
||||
@@ -131,44 +139,205 @@ else:
|
||||
proc pthread_cancel(a1: TSysThread): cint {.
|
||||
importc: "pthread_cancel", header: "<pthread.h>".}
|
||||
|
||||
proc threadProcWrapper(closure: pointer) {.noconv.} =
|
||||
var c = cast[ptr TThreadProcClosure](closure)
|
||||
proc threadProcWrapper[TParam](closure: pointer) {.noconv.} =
|
||||
var c = cast[ptr TThreadProcClosure[TParam]](closure)
|
||||
c.fn(c.data)
|
||||
|
||||
{.passL: "-pthread".}
|
||||
{.passC: "-pthread".}
|
||||
|
||||
type
|
||||
TThread* = object of TObject ## Nimrod thread.
|
||||
sys: TSysThread
|
||||
c: TThreadProcClosure
|
||||
|
||||
const
|
||||
noDeadlocks = true # compileOption("deadlockPrevention")
|
||||
|
||||
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:
|
||||
discard pthread_create(t.sys, nil, threadProcWrapper, addr(t.c))
|
||||
when noDeadLocks:
|
||||
type
|
||||
TLock* {.pure, final.} = object ## Standard Nimrod Lock type.
|
||||
key: int # used for identity and global order!
|
||||
sys: TSysLock
|
||||
next: ptr TLock
|
||||
else:
|
||||
type
|
||||
TLock* = TSysLock
|
||||
|
||||
type
|
||||
TThread* {.pure, final.}[TParam] = object ## Nimrod thread.
|
||||
sys: TSysThread
|
||||
c: TThreadProcClosure[TParam]
|
||||
|
||||
proc joinThread*(t: TThread) =
|
||||
|
||||
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.
|
||||
when defined(windows):
|
||||
when hostOS == "windows":
|
||||
discard WaitForSingleObject(t.sys, -1'i32)
|
||||
else:
|
||||
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
|
||||
## you don't have full control over `t` and its aquired ressources.
|
||||
when defined(windows):
|
||||
## you don't have full control over `t` and its aquired resources.
|
||||
when hostOS == "windows":
|
||||
discard TerminateThread(t.sys, 1'i32)
|
||||
else:
|
||||
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])
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#
|
||||
#
|
||||
# Nimrod's Runtime Library
|
||||
# (c) Copyright 2010 Andreas Rumpf
|
||||
# (c) Copyright 2011 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
@@ -24,3 +24,27 @@ proc nimLoadLibraryError(path: string) {.compilerproc, 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>".}
|
||||
|
||||
|
||||
14
rod/cgen.nim
14
rod/cgen.nim
@@ -380,14 +380,20 @@ proc assignLocalVar(p: BProc, s: PSym) =
|
||||
appf(p.s[cpsLocals], " $1;$n", [s.loc.r])
|
||||
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) =
|
||||
if s.loc.k == locNone:
|
||||
fillLoc(s.loc, locGlobalVar, s.typ, mangleName(s), OnHeap)
|
||||
useHeader(p.module, s)
|
||||
if lfNoDecl in s.loc.flags: return
|
||||
if sfImportc in s.flags: app(p.module.s[cfsVars], "extern ")
|
||||
if sfThreadVar in s.flags: app(p.module.s[cfsVars], "NIM_THREADVAR ")
|
||||
app(p.module.s[cfsVars], getTypeDesc(p.module, s.loc.t))
|
||||
if sfThreadVar in s.flags: declareThreadVar(p.module, s)
|
||||
else: app(p.module.s[cfsVars], getTypeDesc(p.module, s.loc.t))
|
||||
if sfRegister in s.flags: app(p.module.s[cfsVars], " register")
|
||||
if sfVolatile in s.flags: app(p.module.s[cfsVars], " volatile")
|
||||
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)])
|
||||
else:
|
||||
app(m.s[cfsVars], "extern ")
|
||||
if sfThreadVar in sym.flags: app(m.s[cfsVars], "NIM_THREADVAR ")
|
||||
app(m.s[cfsVars], getTypeDesc(m, sym.loc.t))
|
||||
if sfThreadVar in sym.flags: declareThreadVar(m, sym)
|
||||
else: app(m.s[cfsVars], getTypeDesc(m, sym.loc.t))
|
||||
if sfRegister in sym.flags: app(m.s[cfsVars], " register")
|
||||
if sfVolatile in sym.flags: app(m.s[cfsVars], " volatile")
|
||||
appf(m.s[cfsVars], " $1;$n", [sym.loc.r])
|
||||
|
||||
@@ -25,7 +25,7 @@ proc ProcessCommand*(switch: string, pass: TCmdLinePass)
|
||||
proc processSwitch*(switch, arg: string, pass: TCmdlinePass, info: TLineInfo)
|
||||
# implementation
|
||||
|
||||
const
|
||||
const
|
||||
HelpMessage = "Nimrod Compiler Version $1 (" & compileDate & ") [$2: $3]\n" &
|
||||
"Copyright (c) 2004-2011 by Andreas Rumpf\n"
|
||||
|
||||
@@ -49,7 +49,7 @@ Options:
|
||||
-f, --forceBuild force rebuilding of all modules
|
||||
--stackTrace:on|off turn stack 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
|
||||
--objChecks:on|off turn obj conversion 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)
|
||||
--cpu:SYMBOL set the target processor (cross-compilation)
|
||||
--debuginfo enables debug information
|
||||
--debugger:on|off turn Embedded Nimrod Debugger on|off
|
||||
-t, --passc:OPTION pass an option to the C compiler
|
||||
-l, --passl:OPTION pass an option to the linker
|
||||
--genMapping generate a mapping file containing
|
||||
@@ -212,9 +213,6 @@ proc ProcessSpecificNote(arg: string, state: TSpecialWord, pass: TCmdlinePass,
|
||||
of wOn: incl(gNotes, n)
|
||||
of wOff: excl(gNotes, n)
|
||||
else: liMessage(info, errOnOrOffExpectedButXFound, arg)
|
||||
|
||||
proc processPath(path: string): string =
|
||||
result = UnixToNativePath(path % ["nimrod", getPrefixDir(), "lib", libpath])
|
||||
|
||||
proc processCompile(filename: string) =
|
||||
var found = findFile(filename)
|
||||
@@ -269,20 +267,32 @@ proc testCompileOption*(switch: string, info: TLineInfo): bool =
|
||||
of wRun, wR: result = contains(gGlobalOptions, optRun)
|
||||
of wSymbolFiles: result = contains(gGlobalOptions, optSymbolFiles)
|
||||
of wGenScript: result = contains(gGlobalOptions, optGenScript)
|
||||
of wThreads: result = contains(gGlobalOptions, optThreads)
|
||||
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) =
|
||||
var
|
||||
theOS: TSystemOS
|
||||
cpu: TSystemCPU
|
||||
key, val, path: string
|
||||
key, val: string
|
||||
case whichKeyword(switch)
|
||||
of wPath, wP:
|
||||
expectArg(switch, arg, pass, info)
|
||||
path = processPath(arg)
|
||||
if not contains(options.searchPaths, path):
|
||||
lists.PrependStr(options.searchPaths, path)
|
||||
addPath(processPath(arg))
|
||||
#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:
|
||||
expectArg(switch, arg, pass, info)
|
||||
options.outFile = arg
|
||||
@@ -356,6 +366,7 @@ proc processSwitch(switch, arg: string, pass: TCmdlinePass, info: TLineInfo) =
|
||||
of wLineDir: ProcessOnOffSwitch({optLineDir}, arg, pass, info)
|
||||
of wAssertions, wA: ProcessOnOffSwitch({optAssert}, arg, pass, info)
|
||||
of wDeadCodeElim: ProcessOnOffSwitchG({optDeadCodeElim}, arg, pass, info)
|
||||
of wThreads: ProcessOnOffSwitchG({optThreads}, arg, pass, info)
|
||||
of wOpt:
|
||||
expectArg(switch, arg, pass, info)
|
||||
case whichKeyword(arg)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# (c) Copyright 2009 Andreas Rumpf
|
||||
# (c) Copyright 2011 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
@@ -21,28 +21,12 @@ type
|
||||
m*: PSym
|
||||
mode*: TOverloadIterMode
|
||||
|
||||
|
||||
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 =
|
||||
proc getSymRepr*(s: PSym): string =
|
||||
case s.kind
|
||||
of skProc, skMethod, skConverter, skIterator: result = getProcHeader(s)
|
||||
else: result = s.name.s
|
||||
|
||||
proc CloseScope(tab: var TSymTab) =
|
||||
proc CloseScope*(tab: var TSymTab) =
|
||||
var
|
||||
it: TTabIter
|
||||
s: PSym
|
||||
@@ -59,14 +43,14 @@ proc CloseScope(tab: var TSymTab) =
|
||||
s = NextIter(it, tab.stack[tab.tos - 1])
|
||||
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)
|
||||
|
||||
proc addDecl(c: PContext, sym: PSym) =
|
||||
proc addDecl*(c: PContext, sym: PSym) =
|
||||
if SymTabAddUnique(c.tab, sym) == Failure:
|
||||
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:
|
||||
liMessage(sym.info, errAttemptToRedefine, sym.Name.s)
|
||||
|
||||
@@ -81,7 +65,7 @@ proc addInterfaceDeclAt*(c: PContext, sym: PSym, at: Natural) =
|
||||
addDeclAt(c, sym, at)
|
||||
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):
|
||||
InternalError(fn.info, "addOverloadableSymAt")
|
||||
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)
|
||||
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
|
||||
addDecl(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
|
||||
addOverloadableSymAt(c, sym, at)
|
||||
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.
|
||||
case n.kind
|
||||
of nkAccQuoted:
|
||||
@@ -118,26 +102,32 @@ proc lookUp(c: PContext, n: PNode): PSym =
|
||||
liMessage(n.info, errUseQualifier, result.name.s)
|
||||
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
|
||||
of nkIdent:
|
||||
result = SymtabGet(c.Tab, n.ident)
|
||||
if result == nil:
|
||||
if result == nil and checkUndeclared in flags:
|
||||
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)
|
||||
of nkSym:
|
||||
#
|
||||
# result := SymtabGet(c.Tab, n.sym.name);
|
||||
# if result = nil then
|
||||
# result = SymtabGet(c.Tab, n.sym.name)
|
||||
# if result == nil:
|
||||
# liMessage(n.info, errUndeclaredIdentifier, n.sym.name.s)
|
||||
# else
|
||||
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)
|
||||
of nkDotExpr:
|
||||
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):
|
||||
var ident: PIdent = nil
|
||||
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)
|
||||
else:
|
||||
result = StrTableGet(m.tab, ident)
|
||||
if result == nil:
|
||||
if result == nil and checkUndeclared in flags:
|
||||
liMessage(n.sons[1].info, errUndeclaredIdentifier, ident.s)
|
||||
else:
|
||||
elif checkUndeclared in flags:
|
||||
liMessage(n.sons[1].info, errIdentifierExpected, renderTree(n.sons[1]))
|
||||
of nkAccQuoted:
|
||||
result = QualifiedLookup(c, n.sons[0], ambiguousCheck)
|
||||
result = QualifiedLookup(c, n.sons[0], flags)
|
||||
else:
|
||||
result = nil #liMessage(n.info, errIdentifierExpected, '')
|
||||
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 =
|
||||
var ident: PIdent
|
||||
result = nil
|
||||
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)
|
||||
of nkSym:
|
||||
result = n.sym
|
||||
o.mode = oimDone #
|
||||
# o.stackPtr := c.tab.tos;
|
||||
# o.mode := oimNoQualifier;
|
||||
# while (result = nil) do begin
|
||||
# dec(o.stackPtr);
|
||||
# if o.stackPtr < 0 then break;
|
||||
# result := InitIdentIter(o.it, c.tab.stack[o.stackPtr], n.sym.name);
|
||||
# end;
|
||||
o.mode = oimDone
|
||||
# o.stackPtr = c.tab.tos
|
||||
# o.mode = oimNoQualifier
|
||||
# while result == nil:
|
||||
# dec(o.stackPtr)
|
||||
# if o.stackPtr < 0: break
|
||||
# result = InitIdentIter(o.it, c.tab.stack[o.stackPtr], n.sym.name)
|
||||
of nkDotExpr:
|
||||
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):
|
||||
ident = nil
|
||||
if (n.sons[1].kind == nkIdent):
|
||||
@@ -210,7 +199,7 @@ proc InitOverloadIter(o: var TOverloadIter, c: PContext, n: PNode): PSym =
|
||||
nil
|
||||
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
|
||||
of oimDone:
|
||||
result = nil
|
||||
@@ -222,8 +211,8 @@ proc nextOverloadIter(o: var TOverloadIter, c: PContext, n: PNode): PSym =
|
||||
while (result == nil):
|
||||
dec(o.stackPtr)
|
||||
if o.stackPtr < 0: break
|
||||
result = InitIdentIter(o.it, c.tab.stack[o.stackPtr], o.it.name) # BUGFIX:
|
||||
# o.it.name <-> n.ident
|
||||
result = InitIdentIter(o.it, c.tab.stack[o.stackPtr], o.it.name)
|
||||
# BUGFIX: o.it.name <-> n.ident
|
||||
else:
|
||||
result = nil
|
||||
of oimSelfModule:
|
||||
|
||||
@@ -30,7 +30,8 @@ type # please make sure we have under 32 options
|
||||
TOptions* = set[TOption]
|
||||
TGlobalOption* = enum
|
||||
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
|
||||
optGenDynLib, # generate a dynamic library
|
||||
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
|
||||
optSkipConfigFile, # skip the general 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]
|
||||
TCommands* = enum # Nimrod's commands
|
||||
cmdNone, cmdCompileToC, cmdCompileToCpp, cmdCompileToOC,
|
||||
@@ -142,7 +144,7 @@ proc shortenDir(dir: string): string =
|
||||
return copy(dir, len(prefix))
|
||||
result = dir
|
||||
|
||||
proc removeTrailingDirSep(path: string): string =
|
||||
proc removeTrailingDirSep*(path: string): string =
|
||||
if (len(path) > 0) and (path[len(path) - 1] == dirSep):
|
||||
result = copy(path, 0, len(path) - 2)
|
||||
else:
|
||||
|
||||
@@ -631,7 +631,7 @@ proc makeDeref(n: PNode): PNode =
|
||||
|
||||
proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
## 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:
|
||||
return semSym(c, n, s, flags)
|
||||
|
||||
@@ -940,7 +940,7 @@ proc semMacroStmt(c: PContext, n: PNode, semCheck: bool = true): PNode =
|
||||
var a: PNode
|
||||
if isCallExpr(n.sons[0]): a = n.sons[0].sons[0]
|
||||
else: a = n.sons[0]
|
||||
var s = qualifiedLookup(c, a, false)
|
||||
var s = qualifiedLookup(c, a, {checkUndeclared})
|
||||
if s != nil:
|
||||
case s.kind
|
||||
of skMacro:
|
||||
@@ -1014,7 +1014,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||
of nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit:
|
||||
# check if it is an expression macro:
|
||||
checkMinSonsLen(n, 1)
|
||||
var s = qualifiedLookup(c, n.sons[0], false)
|
||||
var s = qualifiedLookup(c, n.sons[0], {checkUndeclared})
|
||||
if s != nil:
|
||||
case s.kind
|
||||
of skMacro: result = semMacroExpr(c, n, s)
|
||||
@@ -1037,10 +1037,10 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||
result = semMacroStmt(c, n)
|
||||
of nkBracketExpr:
|
||||
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}:
|
||||
# type parameters: partial generic specialization
|
||||
result = partialSpecialization(c, n, s)
|
||||
result = explictGenericInstantiation(c, n, s)
|
||||
else:
|
||||
result = semArrayAccess(c, n, flags)
|
||||
of nkPragmaExpr:
|
||||
|
||||
@@ -21,12 +21,14 @@ type
|
||||
TSemGenericFlags = set[TSemGenericFlag]
|
||||
|
||||
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)
|
||||
result = semGenericStmt(c, n, flags)
|
||||
closeScope(c.tab)
|
||||
|
||||
proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym): PNode =
|
||||
incl(s.flags, sfUsed)
|
||||
case s.kind
|
||||
of skUnknown:
|
||||
# Introduced in this pass! Leave it as an identifier.
|
||||
@@ -55,20 +57,29 @@ proc getIdentNode(n: PNode): PNode =
|
||||
illFormedAst(n)
|
||||
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 =
|
||||
var
|
||||
L: int
|
||||
a: PNode
|
||||
s: PSym
|
||||
result = n
|
||||
if n == nil: return
|
||||
case n.kind
|
||||
of nkIdent, nkAccQuoted:
|
||||
s = lookUp(c, n)
|
||||
if withinBind in flags: result = symChoice(c, n, s)
|
||||
else: result = semGenericStmtSymbol(c, n, s)
|
||||
of nkIdent:
|
||||
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)
|
||||
else: result = semGenericStmtSymbol(c, n, s)
|
||||
of nkDotExpr:
|
||||
s = QualifiedLookUp(c, n, true)
|
||||
var s = QualifiedLookUp(c, n, {})
|
||||
if s != nil: result = semGenericStmtSymbol(c, n, s)
|
||||
of nkSym..nkNilLit:
|
||||
nil
|
||||
@@ -77,8 +88,9 @@ proc semGenericStmt(c: PContext, n: PNode, flags: TSemGenericFlags = {}): PNode
|
||||
of nkCall, nkHiddenCallConv, nkInfix, nkPrefix, nkCommand, nkCallStrLit:
|
||||
# check if it is an expression macro:
|
||||
checkMinSonsLen(n, 1)
|
||||
s = qualifiedLookup(c, n.sons[0], false)
|
||||
if (s != nil):
|
||||
var s = qualifiedLookup(c, n.sons[0], {})
|
||||
if s != nil:
|
||||
incl(s.flags, sfUsed)
|
||||
case s.kind
|
||||
of skMacro:
|
||||
return semMacroExpr(c, n, s, false)
|
||||
@@ -100,16 +112,16 @@ proc semGenericStmt(c: PContext, n: PNode, flags: TSemGenericFlags = {}): PNode
|
||||
of nkMacroStmt:
|
||||
result = semMacroStmt(c, n, false)
|
||||
of nkIfStmt:
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
for i in countup(0, sonsLen(n)-1):
|
||||
n.sons[i] = semGenericStmtScope(c, n.sons[i])
|
||||
of nkWhileStmt:
|
||||
openScope(c.tab)
|
||||
for i in countup(0, sonsLen(n) - 1): n.sons[i] = semGenericStmt(c, n.sons[i])
|
||||
for i in countup(0, sonsLen(n)-1): n.sons[i] = semGenericStmt(c, n.sons[i])
|
||||
closeScope(c.tab)
|
||||
of nkCaseStmt:
|
||||
openScope(c.tab)
|
||||
n.sons[0] = semGenericStmt(c, n.sons[0])
|
||||
for i in countup(1, sonsLen(n) - 1):
|
||||
for i in countup(1, sonsLen(n)-1):
|
||||
a = n.sons[i]
|
||||
checkMinSonsLen(a, 1)
|
||||
L = sonsLen(a)
|
||||
|
||||
@@ -106,6 +106,7 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
|
||||
else:
|
||||
result.typ = newTypeS(tyProc, c)
|
||||
addSon(result.typ, nil)
|
||||
result.typ.callConv = fn.typ.callConv
|
||||
oldPrc = GenericCacheGet(c, fn, result)
|
||||
if oldPrc == nil:
|
||||
# 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)
|
||||
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
|
||||
|
||||
@@ -162,7 +162,7 @@ proc propertyWriteAccess(c: PContext, n, a: PNode): PNode =
|
||||
addSon(result, newIdentNode(getIdent(id.s & '='), n.info))
|
||||
# a[0] is already checked for semantics, that does ``builtinFieldAccess``
|
||||
# this is ugly. XXX Semantic checking should use the ``nfSem`` flag for
|
||||
# nodes!
|
||||
# nodes?
|
||||
addSon(result, a[0])
|
||||
addSon(result, semExpr(c, n[1]))
|
||||
result = semDirectCallAnalyseEffects(c, result, {})
|
||||
@@ -182,18 +182,6 @@ proc semAsgn(c: PContext, n: PNode): PNode =
|
||||
a = builtinFieldAccess(c, a, {efLValue})
|
||||
if a == nil:
|
||||
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:
|
||||
# a[i..j] = x
|
||||
# --> `[..]=`(a, i, j, x)
|
||||
@@ -204,7 +192,6 @@ proc semAsgn(c: PContext, n: PNode): PNode =
|
||||
return semExprNoType(c, result)
|
||||
else:
|
||||
a = semExprWithType(c, a, {efLValue})
|
||||
#n.sons[0] = semExprWithType(c, n.sons[0], {efLValue})
|
||||
n.sons[0] = a
|
||||
n.sons[1] = semExprWithType(c, n.sons[1])
|
||||
var le = a.typ
|
||||
@@ -288,7 +275,6 @@ proc semVar(c: PContext, n: PNode): PNode =
|
||||
else:
|
||||
def = nil
|
||||
if not typeAllowed(typ, skVar):
|
||||
#debug(typ);
|
||||
liMessage(a.info, errXisNoType, typeToString(typ))
|
||||
tup = skipTypes(typ, {tyGenericInst})
|
||||
if a.kind == nkVarTuple:
|
||||
|
||||
@@ -178,7 +178,7 @@ proc semOrdinal(c: PContext, n: PNode, prev: PType): PType =
|
||||
liMessage(n.info, errXExpectsOneTypeParam, "ordinal")
|
||||
|
||||
proc semTypeIdent(c: PContext, n: PNode): PSym =
|
||||
result = qualifiedLookup(c, n, true)
|
||||
result = qualifiedLookup(c, n, {checkAmbiguity, checkUndeclared})
|
||||
if (result != nil):
|
||||
markUsed(n, result)
|
||||
if result.kind != skType: liMessage(n.info, errTypeExpected)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# (c) Copyright 2010 Andreas Rumpf
|
||||
# (c) Copyright 2011 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
@@ -82,11 +82,11 @@ proc cmpCandidates(a, b: TCandidate): int =
|
||||
result = a.convMatches - b.convMatches
|
||||
|
||||
proc writeMatches(c: TCandidate) =
|
||||
Writeln(stdout, "exact matches: " & $(c.exactMatches))
|
||||
Writeln(stdout, "subtype matches: " & $(c.subtypeMatches))
|
||||
Writeln(stdout, "conv matches: " & $(c.convMatches))
|
||||
Writeln(stdout, "intconv matches: " & $(c.intConvMatches))
|
||||
Writeln(stdout, "generic matches: " & $(c.genericMatches))
|
||||
Writeln(stdout, "exact matches: " & $c.exactMatches)
|
||||
Writeln(stdout, "subtype matches: " & $c.subtypeMatches)
|
||||
Writeln(stdout, "conv matches: " & $c.convMatches)
|
||||
Writeln(stdout, "intconv matches: " & $c.intConvMatches)
|
||||
Writeln(stdout, "generic matches: " & $c.genericMatches)
|
||||
|
||||
proc getNotFoundError(c: PContext, n: PNode): string =
|
||||
# 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
|
||||
not sameMethodDispatcher(x.calleeSym, y.calleeSym):
|
||||
if x.state != csMatch:
|
||||
InternalError(n.info, "x.state is not csMatch") #writeMatches(x);
|
||||
#writeMatches(y);
|
||||
InternalError(n.info, "x.state is not csMatch")
|
||||
liMessage(n.Info, errGenerated, msgKindToString(errAmbiguousCallXYZ) % [
|
||||
getProcHeader(x.calleeSym), getProcHeader(y.calleeSym),
|
||||
x.calleeSym.Name.s])
|
||||
@@ -740,3 +739,20 @@ proc semDirectCall(c: PContext, n: PNode, filter: TSymKinds): PNode =
|
||||
initialBinding = nil
|
||||
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
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# (c) Copyright 2010 Andreas Rumpf
|
||||
# (c) Copyright 2011 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
@@ -747,7 +747,7 @@ proc typeAllowedNode(marker: var TIntSet, n: PNode, kind: TSymKind): bool =
|
||||
result = true
|
||||
if n != nil:
|
||||
result = typeAllowedAux(marker, n.typ, kind)
|
||||
if not result: debug(n.typ)
|
||||
#if not result: debug(n.typ)
|
||||
if result:
|
||||
case n.kind
|
||||
of nkNone..nkNilLit:
|
||||
|
||||
@@ -59,7 +59,8 @@ type
|
||||
wPretty,
|
||||
wDoc, wGenDepend, wListDef, wCheck, wParse, wScan, wJs, wOC,
|
||||
wRst2html, wRst2tex, wI,
|
||||
wWrite, wPutEnv, wPrependEnv, wAppendEnv, wThreadVar, wEmit
|
||||
wWrite, wPutEnv, wPrependEnv, wAppendEnv, wThreadVar, wEmit, wThreads,
|
||||
wRecursivePath
|
||||
|
||||
TSpecialWords* = set[TSpecialWord]
|
||||
|
||||
@@ -107,7 +108,8 @@ const
|
||||
"compiletooc",
|
||||
"pretty", "doc", "gendepend", "listdef", "check", "parse", "scan",
|
||||
"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: String): TSpecialWord
|
||||
|
||||
5
todo.txt
5
todo.txt
@@ -1,6 +1,6 @@
|
||||
- built-in serialization
|
||||
- thread support: threadvar on Windows seems broken;
|
||||
add --deadlock_prevention:on|off switch
|
||||
- built-in serialization
|
||||
|
||||
- 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)
|
||||
- nested tuple unpacking
|
||||
- fast assignment optimization for TPeg
|
||||
|
||||
- better error messages for used keywords as identifiers
|
||||
- case statement branches should support constant sets
|
||||
|
||||
Library
|
||||
-------
|
||||
|
||||
@@ -47,13 +47,13 @@ if [ $# -eq 1 ] ; then
|
||||
docdir="$1/?proj/doc"
|
||||
datadir="$1/?proj/data"
|
||||
|
||||
mkdir -p $1/?proj
|
||||
mkdir -p $bindir
|
||||
mkdir -p $configdir
|
||||
mkdir -p $1/?proj || exit 1
|
||||
mkdir -p $bindir || exit 1
|
||||
mkdir -p $configdir || exit 1
|
||||
;;
|
||||
esac
|
||||
mkdir -p $libdir
|
||||
mkdir -p $docdir
|
||||
mkdir -p $libdir || exit 1
|
||||
mkdir -p $docdir || exit 1
|
||||
echo "copying files..."
|
||||
#var createdDirs = newStringTable()
|
||||
#for cat in fcConfig..fcLib:
|
||||
@@ -63,30 +63,30 @@ if [ $# -eq 1 ] ; then
|
||||
# mk = unixDirVars[cat] & "/" & mk
|
||||
# if not createdDirs.hasKey(mk):
|
||||
# createdDirs[mk] = "true"
|
||||
mkdir -p ?mk
|
||||
mkdir -p ?mk || exit 1
|
||||
# end if
|
||||
# end if
|
||||
# end for
|
||||
#end for
|
||||
|
||||
#for f in items(c.cat[fcUnixBin]):
|
||||
cp ?f $bindir/?f.skipRoot
|
||||
cp ?f $bindir/?f.skipRoot || exit 1
|
||||
chmod 755 $bindir/?f.skipRoot
|
||||
#end for
|
||||
#for f in items(c.cat[fcConfig]):
|
||||
cp ?f $configdir/?f.skipRoot
|
||||
cp ?f $configdir/?f.skipRoot || exit 1
|
||||
chmod 644 $configdir/?f.skipRoot
|
||||
#end for
|
||||
#for f in items(c.cat[fcData]):
|
||||
cp ?f $datadir/?f.skipRoot
|
||||
cp ?f $datadir/?f.skipRoot || exit 1
|
||||
chmod 644 $datadir/?f.skipRoot
|
||||
#end for
|
||||
#for f in items(c.cat[fcDoc]):
|
||||
cp ?f $docdir/?f.skipRoot
|
||||
cp ?f $docdir/?f.skipRoot || exit 1
|
||||
chmod 644 $docdir/?f.skipRoot
|
||||
#end for
|
||||
#for f in items(c.cat[fcLib]):
|
||||
cp ?f $libdir/?f.skipRoot
|
||||
cp ?f $libdir/?f.skipRoot || exit 1
|
||||
chmod 644 $libdir/?f.skipRoot
|
||||
#end for
|
||||
|
||||
|
||||
@@ -33,6 +33,8 @@ Changes affecting backwards compatibility
|
||||
Additions
|
||||
---------
|
||||
|
||||
- Added ``scgi`` module.
|
||||
- Added ``smtp`` module.
|
||||
- Added ``re.findAll``, ``pegs.findAll``.
|
||||
- Added ``os.findExe``.
|
||||
- Added ``strutils.align``, ``strutils.tokenize``, ``strutils.wordWrap``.
|
||||
@@ -40,7 +42,7 @@ Additions
|
||||
- Pegs support new built-ins: ``\letter``, ``\upper``, ``\lower``,
|
||||
``\title``, ``\white``.
|
||||
- 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.
|
||||
- Additional operations were added to the ``complex`` module.
|
||||
- Added ``strutils.formatFloat``, ``strutils.formatBiggestFloat``.
|
||||
|
||||
Reference in New Issue
Block a user