diff options
-rw-r--r-- | compiler/evalffi.nim | 34 | ||||
-rw-r--r-- | compiler/vm.nim | 17 | ||||
-rw-r--r-- | compiler/vmgen.nim | 10 | ||||
-rw-r--r-- | lib/pure/os.nim | 50 | ||||
-rw-r--r-- | lib/system/sysio.nim | 4 | ||||
-rw-r--r-- | lib/system/widestrs.nim | 3 | ||||
-rw-r--r-- | todo.txt | 1 | ||||
-rw-r--r-- | tools/detect/detect.nim | 21 |
8 files changed, 80 insertions, 60 deletions
diff --git a/compiler/evalffi.nim b/compiler/evalffi.nim index 92b79f9b6..f2337f7ce 100644 --- a/compiler/evalffi.nim +++ b/compiler/evalffi.nim @@ -9,7 +9,7 @@ ## This file implements the FFI part of the evaluator for Nimrod code. -import ast, astalgo, ropes, types, options, tables, dynlib, libffi, msgs +import ast, astalgo, ropes, types, options, tables, dynlib, libffi, msgs, os when defined(windows): const libcDll = "msvcrt.dll" @@ -20,7 +20,11 @@ type TDllCache = tables.TTable[string, TLibHandle] var gDllCache = initTable[string, TLibHandle]() - gExeHandle = LoadLib() + +when defined(windows): + var gExeHandle = loadLib(os.getAppFilename()) +else: + var gExeHandle = loadLib() proc getDll(cache: var TDllCache; dll: string; info: TLineInfo): pointer = result = cache[dll] @@ -28,10 +32,10 @@ proc getDll(cache: var TDllCache; dll: string; info: TLineInfo): pointer = var libs: seq[string] = @[] libCandidates(dll, libs) for c in libs: - result = LoadLib(c) + result = loadLib(c) if not result.isNil: break if result.isNil: - GlobalError(info, "cannot load: " & dll) + globalError(info, "cannot load: " & dll) cache[dll] = result const @@ -50,7 +54,7 @@ proc importcSymbol*(sym: PSym): PNode = else: let lib = sym.annex if lib != nil and lib.path.kind notin {nkStrLit..nkTripleStrLit}: - GlobalError(sym.info, "dynlib needs to be a string lit for the REPL") + globalError(sym.info, "dynlib needs to be a string lit for the REPL") var theAddr: pointer if lib.isNil and not gExehandle.isNil: # first try this exe itself: @@ -58,10 +62,12 @@ proc importcSymbol*(sym: PSym): PNode = # then try libc: if theAddr.isNil: let dllhandle = gDllCache.getDll(libcDll, sym.info) - theAddr = dllhandle.checkedSymAddr(name) - else: - let dllhandle = gDllCache.getDll(lib.path.strVal, sym.info) - theAddr = dllhandle.checkedSymAddr(name) + theAddr = dllhandle.symAddr(name) + elif not lib.isNil: + let dllhandle = gDllCache.getDll(if lib.kind == libHeader: libcDll + else: lib.path.strVal, sym.info) + theAddr = dllhandle.symAddr(name) + if theAddr.isNil: globalError(sym.info, "cannot import: " & sym.name.s) result.intVal = cast[TAddress](theAddr) proc mapType(t: ast.PType): ptr libffi.TType = @@ -139,7 +145,7 @@ proc getField(n: PNode; position: int): PSym = else: internalError(n.info, "getField(record case branch)") of nkSym: if n.sym.position == position: result = n.sym - else: nil + else: discard proc packObject(x: PNode, typ: PType, res: pointer) = InternalAssert x.kind in {nkObjConstr, nkPar} @@ -192,7 +198,7 @@ proc pack(v: PNode, typ: PType, res: pointer) = of tyPointer, tyProc, tyCString, tyString: if v.kind == nkNilLit: # nothing to do since the memory is 0 initialized anyway - nil + discard elif v.kind == nkPtrLit: awr(pointer, cast[pointer](v.intVal)) elif v.kind in {nkStrLit..nkTripleStrLit}: @@ -202,7 +208,7 @@ proc pack(v: PNode, typ: PType, res: pointer) = of tyPtr, tyRef, tyVar: if v.kind == nkNilLit: # nothing to do since the memory is 0 initialized anyway - nil + discard elif v.kind == nkPtrLit: awr(pointer, cast[pointer](v.intVal)) else: @@ -220,7 +226,7 @@ proc pack(v: PNode, typ: PType, res: pointer) = of tyObject, tyTuple: packObject(v, typ, res) of tyNil: - nil + discard of tyDistinct, tyGenericInst: pack(v, typ.sons[0], res) else: @@ -241,7 +247,7 @@ proc unpackObjectAdd(x: pointer, n, result: PNode) = pair.sons[1] = unpack(x +! n.sym.offset, n.sym.typ, nil) #echo "offset: ", n.sym.name.s, " ", n.sym.offset result.add pair - else: nil + else: discard proc unpackObject(x: pointer, typ: PType, n: PNode): PNode = # compute the field's offsets: diff --git a/compiler/vm.nim b/compiler/vm.nim index 80b8abb8b..854b491fb 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -632,12 +632,14 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode = # we pass 'tos.slots' instead of 'regs' so that the compiler can keep # 'regs' in a register: when hasFFI: + if c.globals.sons[prc.position-1].kind == nkEmpty: + globalError(c.debug[pc], errGenerated, "canot run " & prc.name.s) let newValue = callForeignFunction(c.globals.sons[prc.position-1], prc.typ, tos.slots, rb+1, rc-1, c.debug[pc]) if newValue.kind != nkEmpty: assert instr.opcode == opcIndCallAsgn - regs[ra] = newValue + asgnRef(regs[ra], newValue) else: globalError(c.debug[pc], errGenerated, "VM not built with FFI support") elif prc.kind != skTemplate: @@ -796,7 +798,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode = decodeB(nkBracket) let newLen = regs[rb].getOrdValue.int setLen(regs[ra].sons, newLen) - of opcSwap, opcCast, opcReset: + of opcSwap, opcReset: internalError(c.debug[pc], "too implement") of opcIsNil: decodeB(nkIntLit) @@ -938,6 +940,15 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode = stackTrace(c, tos, pc, errGenerated, msgKindToString(errIllegalConvFromXtoY) % [ "unknown type" , "unknown type"]) + of opcCast: + let rb = instr.regB + inc pc + let typ = c.types[c.code[pc].regBx - wordExcess] + when hasFFI: + let dest = fficast(regs[rb], typ) + asgnRef(regs[ra], dest) + else: + globalError(c.debug[pc], "cannot evaluate cast") of opcNSetIntVal: decodeB(nkMetaNode) var dest = regs[ra].uast @@ -1074,6 +1085,8 @@ proc myOpen(module: PSym): PPassContext = # XXX produce a new 'globals' environment here: setupGlobalCtx(module) result = globalCtx + when hasFFI: + globalCtx.features = {allowFFI, allowCast} var oldErrorCount: int diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index 134b2d15a..486d24e6c 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -945,7 +945,10 @@ proc genTypeLit(c: PCtx; t: PType; dest: var TDest) = proc importcSym(c: PCtx; info: TLineInfo; s: PSym) = when hasFFI: if allowFFI in c.features: - c.globals.add(importcSymbol(s)) + if s.kind == skVar and lfNoDecl in s.loc.flags: + c.globals.add(copyNode(emptyNode)) + else: + c.globals.add(importcSymbol(s)) s.position = c.globals.len else: localError(info, errGenerated, "VM is not allowed to 'importc'") @@ -1303,6 +1306,11 @@ proc gen(c: PCtx; n: PNode; dest: var TDest) = of nkCurly: genSetConstr(c, n, dest) of nkObjConstr: genObjConstr(c, n, dest) of nkPar, nkClosure: genTupleConstr(c, n, dest) + of nkCast: + if allowCast in c.features: + genConv(c, n, n.sons[1], dest, opcCast) + else: + localError(n.info, errGenerated, "VM is not allowed to 'cast'") else: InternalError n.info, "too implement " & $n.kind diff --git a/lib/pure/os.nim b/lib/pure/os.nim index 71639d821..d5c4acaec 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -341,16 +341,6 @@ when defined(windows): template FindNextFile(a, b: expr): expr = FindNextFileW(a, b) template getCommandLine(): expr = getCommandLineW() - proc skipFindData(f: TWIN32_FIND_DATA): bool {.inline.} = - let - nul = 0 - dot = ord('.') - result = (f.cFilename[0].int == dot) - if result: - result = (f.cFilename[1].int in {dot, nul}) - if result: - result = (f.cFilename[2].int == nul) - template getFilename(f: expr): expr = $cast[WideCString](addr(f.cFilename[0])) else: @@ -358,18 +348,13 @@ when defined(windows): template FindNextFile(a, b: expr): expr = FindNextFileA(a, b) template getCommandLine(): expr = getCommandLineA() - proc skipFindData(f: TWIN32_FIND_DATA): bool {.inline.} = - let - nul = '\0' - dot = '.' - result = (f.cFilename[0] == dot) - if result: - result = (f.cFilename[1] in {dot, nul}) - if result: - result = (f.cFilename[2] == nul) - template getFilename(f: expr): expr = $f.cFilename + proc skipFindData(f: TWIN32_FIND_DATA): bool {.inline.} = + const dot = ord('.') + result = f.cFilename[0].int == dot and(f.cFilename[1].int == 0 or + f.cFilename[1].int == dot and f.cFilename[2].int == 0) + proc existsFile*(filename: string): bool {.rtl, extern: "nos$1", tags: [FReadDir].} = ## Returns true if the file exists, false otherwise. @@ -468,20 +453,21 @@ proc setCurrentDir*(newDir: string) {.inline, tags: [].} = ## `newDir` cannot been set. when defined(Windows): when useWinUnicode: - if SetCurrentDirectoryW(newWideCString(newDir)) == 0'i32: OSError(OSLastError()) + if SetCurrentDirectoryW(newWideCString(newDir)) == 0'i32: + OSError(OSLastError()) else: if SetCurrentDirectoryA(newDir) == 0'i32: OSError(OSLastError()) else: if chdir(newDir) != 0'i32: OSError(OSLastError()) -proc JoinPath*(head, tail: string): string {. +proc joinPath*(head, tail: string): string {. noSideEffect, rtl, extern: "nos$1".} = ## Joins two directory names to one. ## ## For example on Unix: ## ## .. code-block:: nimrod - ## JoinPath("usr", "lib") + ## joinPath("usr", "lib") ## ## results in: ## @@ -495,10 +481,10 @@ proc JoinPath*(head, tail: string): string {. ## examples on Unix: ## ## .. code-block:: nimrod - ## assert JoinPath("usr", "") == "usr/" - ## assert JoinPath("", "lib") == "lib" - ## assert JoinPath("", "/lib") == "/lib" - ## assert JoinPath("usr/", "/lib") == "usr/lib" + ## assert joinPath("usr", "") == "usr/" + ## assert joinPath("", "lib") == "lib" + ## assert joinPath("", "/lib") == "/lib" + ## assert joinPath("usr/", "/lib") == "usr/lib" if len(head) == 0: result = tail elif head[len(head)-1] in {DirSep, AltSep}: @@ -512,14 +498,14 @@ proc JoinPath*(head, tail: string): string {. else: result = head & DirSep & tail -proc JoinPath*(parts: varargs[string]): string {.noSideEffect, +proc joinPath*(parts: varargs[string]): string {.noSideEffect, rtl, extern: "nos$1OpenArray".} = - ## The same as `JoinPath(head, tail)`, but works with any number of directory + ## The same as `joinPath(head, tail)`, but works with any number of directory ## parts. You need to pass at least one element or the proc will assert in ## debug builds and crash on release builds. result = parts[0] for i in 1..high(parts): - result = JoinPath(result, parts[i]) + result = joinPath(result, parts[i]) proc `/` * (head, tail: string): string {.noSideEffect.} = ## The same as ``JoinPath(head, tail)`` @@ -533,7 +519,7 @@ proc `/` * (head, tail: string): string {.noSideEffect.} = ## assert "usr/" / "/lib" == "usr/lib" return JoinPath(head, tail) -proc SplitPath*(path: string): tuple[head, tail: string] {. +proc splitPath*(path: string): tuple[head, tail: string] {. noSideEffect, rtl, extern: "nos$1".} = ## Splits a directory into (head, tail), so that ## ``JoinPath(head, tail) == path``. @@ -699,7 +685,7 @@ proc expandFilename*(filename: string): string {.rtl, extern: "nos$1", if r.isNil: OSError(OSLastError()) setlen(result, c_strlen(result)) -proc ChangeFileExt*(filename, ext: string): string {. +proc changeFileExt*(filename, ext: string): string {. noSideEffect, rtl, extern: "nos$1".} = ## Changes the file extension to `ext`. ## diff --git a/lib/system/sysio.nim b/lib/system/sysio.nim index a877f8b28..5af1c96d4 100644 --- a/lib/system/sysio.nim +++ b/lib/system/sysio.nim @@ -194,9 +194,9 @@ const # should not be translated. -proc Open(f: var TFile, filename: string, +proc open(f: var TFile, filename: string, mode: TFileMode = fmRead, - bufSize: int = -1): Bool = + bufSize: int = -1): bool = var p: pointer = fopen(filename, FormatOpen[mode]) result = (p != nil) f = cast[TFile](p) diff --git a/lib/system/widestrs.nim b/lib/system/widestrs.nim index cf1f0910c..6a699274c 100644 --- a/lib/system/widestrs.nim +++ b/lib/system/widestrs.nim @@ -101,7 +101,8 @@ proc newWideCString*(s: cstring): WideCString = if s.isNil: return nil when not defined(c_strlen): - proc c_strlen(a: CString): int {.nodecl, noSideEffect, importc: "strlen".} + proc c_strlen(a: cstring): int {. + header: "<string.h>", noSideEffect, importc: "strlen".} let L = cstrlen(s) result = newWideCString(s, L) diff --git a/todo.txt b/todo.txt index 4c999226f..a6301ce0b 100644 --- a/todo.txt +++ b/todo.txt @@ -3,7 +3,6 @@ version 0.9.4 - new VM: - implement overflow checking - - implement the FFI - make 'bind' default for templates and introduce 'mixin' - special rule for ``[]=`` diff --git a/tools/detect/detect.nim b/tools/detect/detect.nim index cf61c2823..b2beba828 100644 --- a/tools/detect/detect.nim +++ b/tools/detect/detect.nim @@ -10,7 +10,7 @@ import os, strutils const - cc = "gcc -o $1 $1.c" + cc = "gcc -o $# $#.c" cfile = """ /* Generated by detect.nim */ @@ -37,6 +37,7 @@ var tl = "" proc myExec(cmd: string): bool = + echo "CMD ", cmd return execShellCmd(cmd) == 0 proc header(s: string): bool = @@ -46,7 +47,7 @@ proc header(s: string): bool = f.write("#include $1\n" % s) f.write("int main() { return 0; }\n") close(f) - result = myExec(cc % testh) + result = myExec(cc % [testh.addFileExt(ExeExt), testh]) removeFile(addFileExt(testh, "c")) if result: addf(hd, "#include $1\n", s) @@ -60,13 +61,16 @@ proc main = if open(f, addFileExt(gen, "c"), fmWrite): f.write(cfile % [hd, tl, system.hostOS, system.hostCPU]) close(f) - if not myExec(cc % gen): quit(1) - if not myExec("./" & gen): quit(1) + if not myExec(cc % [gen.addFileExt(ExeExt), gen]): quit(1) + when defined(windows): + if not myExec(gen.addFileExt(ExeExt)): quit(1) + else: + if not myExec("./" & gen): quit(1) removeFile(addFileExt(gen, "c")) echo("Success") proc v(name: string, typ: TTypeKind=cint) = - var n = if name[0] == '_': copy(name, 1) else: name + var n = if name[0] == '_': substr(name, 1) else: name var t = $typ case typ of pointer: @@ -369,7 +373,7 @@ if header("<pthread.h>"): #v("PTHREAD_MUTEX_INITIALIZER") v("PTHREAD_MUTEX_NORMAL") v("PTHREAD_MUTEX_RECURSIVE") #{.importc, header: "<pthread.h>".}: cint - v("PTHREAD_ONCE_INIT") #{.importc, header: "<pthread.h>".}: cint + #v("PTHREAD_ONCE_INIT") #{.importc, header: "<pthread.h>".}: cint v("PTHREAD_PRIO_INHERIT") #{.importc, header: "<pthread.h>".}: cint v("PTHREAD_PRIO_NONE") #{.importc, header: "<pthread.h>".}: cint v("PTHREAD_PRIO_PROTECT") #{.importc, header: "<pthread.h>".}: cint @@ -820,5 +824,8 @@ if header("<spawn.h>"): v("POSIX_SPAWN_SETSIGDEF") v("POSIX_SPAWN_SETSIGMASK") -main() +if header("<stdio.h>"): + v "_IOFBF" + v "_IONBF" +main() |