Nim (formerly Nimrod) is a statically typed, imperative programming language that tries to give the programmer ultimate power without compromising runtime efficiency. It is designed to rival C in execution speed.
It supports soft realtime garbage collection on thread-local heaps and uses asynchronous message passing between threads. There are language features for parallelizing functions via a binding to OpenMP. It has system programming features such as direct access to memory. Pointers to garbage collected memory are distinguished from pointers to manually managed memory.
It compiles to commented C code. The compiler can create standard shared libraries linkable from C programs. It can also be made to output JavaScript, C++ or Objective C.
The Nim distribution contains an officially supported wrapper[L1 ] for Tcl that makes calling Tcl code from Nim code easy. Example:
# Example to embed TCL in Nim import tcl, os const myScript = """puts "Hello, World - In quotes" """ myScript2 = """ package require Tk pack [entry .e -textvar e -width 50] bind .e <Return> { set e [regsub { *=.*} $e ""] ;# remove evaluation (Chris) catch {expr [string map {/ *1./} $e]} res append e " = $res" } """ FindExecutable(getAppFilename()) var interp = CreateInterp() if interp == nil: quit("cannot create TCL interpreter") if Init(interp) != TCL_OK: quit("cannot init interpreter") if tcl.Eval(interp, myScript) != TCL_OK: quit("cannot execute script.tcl")
MJ: The following example demonstrates starting Tk and registering a Nim procedure (call) for use in Tcl:
import os,tcl # initialize Tcl and Tk FindExecutable(getAppFilename()) let interp = CreateInterp() discard Eval(interp, "set env(TCL_LIBRARY) [file join [file dir [info nameofexecutable]] tclbridge tcl tcl8.6]") var result = Init(interp) if result != tcl.TCL_OK: quit("Could't load Tcl " & $GetStringResult(interp)) discard Eval(interp, "package require Tk") # close app with main window discard Eval(interp, "wm protocol . WM_DELETE_WINDOW exit") # register call proc proc call(clientData: TClientData, interp: PInterp, argc: int, argv: TArgv): int{.cdecl.} = tcl.SetResult(interp, cstring("name called"), cast[TFreeProc](nil)) return tcl.TCL_OK discard CreateObjCommand(interp, cstring("name"), cast[TObjCmdProc](call), cast[TClientData](nil), cast[TCmdDeleteProc](nil)) # execute call proc from Tcl result = Eval(interp, "name") if result != tcl.TCL_OK: quit("Could't create command " & $GetStringResult(interp)) echo GetStringResult(interp) # wait till main window closes discard Eval(interp, "vwait forever")
The following small piece of Nim of code creates a loadable extension for Windows. Build the dll with:
nim c --app:lib ext.nim
const libName* = "tcl86.dll" proc Tcl_PkgProvide(interp: pointer, name: cstring, version: cstring) : cint {.cdecl, importc, dynlib: libName.} proc Ext_Init(interp: pointer): cint {.exportc,dynlib,cdecl.} = return Tcl_PkgProvide(interp, "ext", "0.1")
MJ - To create a stubs enabled extension one can use the nimble package at: https://github.com/mpcjanssen/tclstubs-nimble . This is only tested on windows and linux. An example extension would look like the code below. Building is just a very simple nim c --app:lib -d:release tcluuid.nim
import uuids from tclstubs as Tcl import nil proc Uuids_Cmd(clientData: Tcl.PClientData, interp: Tcl.PInterp, objc: cint, objv: Tcl.PPObj): cint = Tcl.SetObjResult(interp, Tcl.NewStringObj($genUUID(),-1)) return Tcl.OK proc Uuids_Init(interp: Tcl.PInterp): cint {.exportc,dynlib.} = discard Tcl.InitStubs(interp, "8.5",0) if Tcl.CreateObjCommand(interp, "uuid", Uuids_Cmd, nil, nil)!=nil: return Tcl.OK else: return Tcl.ERROR