summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--compiler/nimblecmd.nim2
-rw-r--r--compiler/pretty.nim2
-rw-r--r--compiler/vm.nim14
-rw-r--r--compiler/vmdef.nim13
-rw-r--r--compiler/vmgen.nim23
-rw-r--r--compiler/vmhooks.nim45
-rw-r--r--compiler/vmops.nim66
-rw-r--r--lib/stdlib.nimble (renamed from lib/stdlib.babel)2
8 files changed, 157 insertions, 10 deletions
diff --git a/compiler/nimblecmd.nim b/compiler/nimblecmd.nim
index 0f73c17bd..049b94aa9 100644
--- a/compiler/nimblecmd.nim
+++ b/compiler/nimblecmd.nim
@@ -7,7 +7,7 @@
 #    distribution, for details about the copyright.
 #
 
-## Implements some helper procs for Babel (Nim's package manager) support.
+## Implements some helper procs for Nimble (Nim's package manager) support.
 
 import parseutils, strutils, strtabs, os, options, msgs, lists
 
diff --git a/compiler/pretty.nim b/compiler/pretty.nim
index 5f990a658..356399c1c 100644
--- a/compiler/pretty.nim
+++ b/compiler/pretty.nim
@@ -160,7 +160,7 @@ proc check(c: PGen, n: PNode) =
     check(c, a.sons[L-2])
     check(c, a.sons[L-1])
   of nkTypeSection, nkConstSection:
-    for i in countup(0, sonsLen(n) - 1): 
+    for i in countup(0, sonsLen(n) - 1):
       let a = n.sons[i]
       if a.kind == nkCommentStmt: continue 
       checkSonsLen(a, 3)
diff --git a/compiler/vm.nim b/compiler/vm.nim
index af0b30faa..fe2b9c617 100644
--- a/compiler/vm.nim
+++ b/compiler/vm.nim
@@ -133,6 +133,8 @@ proc createStrKeepNode(x: var TFullReg) =
     # cause of bugs like these is that the VM does not properly distinguish
     # between variable defintions (var foo = e) and variable updates (foo = e).
 
+include vmhooks
+
 template createStr(x) =
   x.node = newNode(nkStrLit)
 
@@ -801,7 +803,11 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
       let bb = regs[rb].node
       let isClosure = bb.kind == nkPar
       let prc = if not isClosure: bb.sym else: bb.sons[0].sym
-      if sfImportc in prc.flags:
+      if prc.offset < -1:
+        # it's a callback:
+        c.callbacks[-prc.offset-2].value(
+          VmArgs(ra: ra, rb: rb, rc: rc, slots: cast[pointer](regs)))
+      elif sfImportc in prc.flags:
         if allowFFI notin c.features:
           globalError(c.debug[pc], errGenerated, "VM not allowed to do FFI")
         # we pass 'tos.slots' instead of 'regs' so that the compiler can keep
@@ -832,9 +838,6 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
         if isClosure:
           newFrame.slots[rc].kind = rkNode
           newFrame.slots[rc].node = regs[rb].node.sons[1]
-        # allocate the temporaries:
-        #for i in rc+ord(isClosure) .. <prc.offset:
-        #  newFrame.slots[i] = newNode(nkEmpty)
         tos = newFrame
         move(regs, newFrame.slots)
         # -1 for the following 'inc pc'
@@ -1316,6 +1319,8 @@ proc evalExpr*(c: PCtx, n: PNode): PNode =
   assert c.code[start].opcode != opcEof
   result = execute(c, start)
 
+include vmops
+
 # for now we share the 'globals' environment. XXX Coming soon: An API for
 # storing&loading the 'globals' environment to get what a component system
 # requires.
@@ -1325,6 +1330,7 @@ var
 proc setupGlobalCtx(module: PSym) =
   if globalCtx.isNil: globalCtx = newCtx(module)
   else: refresh(globalCtx, module)
+  registerAdditionalOps(globalCtx)
 
 proc myOpen(module: PSym): PPassContext =
   #var c = newEvalContext(module, emRepl)
diff --git a/compiler/vmdef.nim b/compiler/vmdef.nim
index e25fd6392..d7cdafb69 100644
--- a/compiler/vmdef.nim
+++ b/compiler/vmdef.nim
@@ -170,7 +170,12 @@ type
     sym*: PSym
     slots*: array[TRegister, tuple[inUse: bool, kind: TSlotKind]]
     maxSlots*: int
-    
+
+  VmArgs* = object
+    ra*, rb*, rc*: Natural
+    slots*: pointer
+  VmCallback* = proc (args: VmArgs) {.closure.}
+  
   PCtx* = ref TCtx
   TCtx* = object of passes.TPassContext # code gen context
     code*: seq[TInstr]
@@ -189,6 +194,7 @@ type
     traceActive*: bool
     loopIterations*: int
     comesFromHeuristic*: TLineInfo # Heuristic for better macro stack traces
+    callbacks*: seq[tuple[key: string, value: VmCallback]]
 
   TPosition* = distinct int
 
@@ -198,12 +204,15 @@ proc newCtx*(module: PSym): PCtx =
   PCtx(code: @[], debug: @[],
     globals: newNode(nkStmtListExpr), constants: newNode(nkStmtList), types: @[],
     prc: PProc(blocks: @[]), module: module, loopIterations: MaxLoopIterations,
-    comesFromHeuristic: unknownLineInfo())
+    comesFromHeuristic: unknownLineInfo(), callbacks: @[])
 
 proc refresh*(c: PCtx, module: PSym) =
   c.module = module
   c.prc = PProc(blocks: @[])
 
+proc registerCallback*(c: PCtx; name: string; callback: VmCallback) =
+  c.callbacks.add((name, callback))
+
 const
   firstABxInstr* = opcTJmp
   largeInstrs* = { # instructions which use 2 int32s instead of 1:
diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim
index 6a6f85d76..05c894ee3 100644
--- a/compiler/vmgen.nim
+++ b/compiler/vmgen.nim
@@ -1489,6 +1489,26 @@ proc genTupleConstr(c: PCtx, n: PNode, dest: var TDest) =
 
 proc genProc*(c: PCtx; s: PSym): int
 
+proc matches(s: PSym; x: string): bool =
+  let y = x.split('.')
+  var s = s
+  var L = y.len-1
+  while L >= 0:
+    if s == nil or y[L].cmpIgnoreStyle(s.name.s) != 0: return false
+    s = s.owner
+    dec L
+  result = true
+
+proc procIsCallback(c: PCtx; s: PSym): bool =
+  if s.offset < -1: return true
+  var i = -2
+  for key, value in items(c.callbacks):
+    if s.matches(key): 
+      doAssert s.offset == -1
+      s.offset = i
+      return true
+    dec i
+
 proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
   case n.kind
   of nkSym:
@@ -1499,7 +1519,8 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
       genRdVar(c, n, dest, flags)
     of skProc, skConverter, skMacro, skTemplate, skMethod, skIterators:
       # 'skTemplate' is only allowed for 'getAst' support:
-      if sfImportc in s.flags: c.importcSym(n.info, s)
+      if procIsCallback(c, s): discard
+      elif sfImportc in s.flags: c.importcSym(n.info, s)
       genLit(c, n, dest)
     of skConst:
       gen(c, s.ast, dest)
diff --git a/compiler/vmhooks.nim b/compiler/vmhooks.nim
new file mode 100644
index 000000000..cce87d433
--- /dev/null
+++ b/compiler/vmhooks.nim
@@ -0,0 +1,45 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2014 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+template setX(k, field) {.immediate, dirty.} =
+  var s: seq[TFullReg]
+  move(s, cast[seq[TFullReg]](a.slots))
+  if s[a.ra].kind != k:
+    myreset(s[a.ra])
+    s[a.ra].kind = k
+  s[a.ra].field = v
+
+proc setResult*(a: VmArgs; v: BiggestInt) = setX(rkInt, intVal)
+proc setResult*(a: VmArgs; v: BiggestFloat) = setX(rkFloat, floatVal)
+proc setResult*(a: VmArgs; v: bool) = 
+  let v = v.ord
+  setX(rkInt, intVal)
+
+proc setResult*(a: VmArgs; v: string) =
+  var s: seq[TFullReg]
+  move(s, cast[seq[TFullReg]](a.slots))
+  if s[a.ra].kind != rkNode:
+    myreset(s[a.ra])
+    s[a.ra].kind = rkNode
+  s[a.ra].node = newNode(nkStrLit)
+  s[a.ra].node.strVal = v
+
+template getX(k, field) {.immediate, dirty.} =
+  doAssert i < a.rc-1
+  let s = cast[seq[TFullReg]](a.slots)
+  doAssert s[i+a.rb+1].kind == k
+  result = s[i+a.rb+1].field
+
+proc getInt*(a: VmArgs; i: Natural): BiggestInt = getX(rkInt, intVal)
+proc getFloat*(a: VmArgs; i: Natural): BiggestFloat = getX(rkFloat, floatVal)
+proc getString*(a: VmArgs; i: Natural): string =
+  doAssert i < a.rc-1
+  let s = cast[seq[TFullReg]](a.slots)
+  doAssert s[i+a.rb+1].kind == rkNode
+  result = s[i+a.rb+1].node.strVal
diff --git a/compiler/vmops.nim b/compiler/vmops.nim
new file mode 100644
index 000000000..8e75cc23a
--- /dev/null
+++ b/compiler/vmops.nim
@@ -0,0 +1,66 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2014 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+# Unforunately this cannot be a module yet:
+#import vmdeps, vm
+from math import sqrt, ln, log10, log2, exp, round, arccos, arcsin,
+  arctan, arctan2, cos, cosh, hypot, sinh, sin, tan, tanh, pow, trunc, 
+  floor, ceil, fmod
+
+from os import getEnv, existsEnv, dirExists, fileExists
+
+template mathop(op) {.immediate, dirty.} =
+  registerCallback(c, "stdlib.math." & astToStr(op), `op Wrapper`)
+
+template osop(op) {.immediate, dirty.} =
+  registerCallback(c, "stdlib.os." & astToStr(op), `op Wrapper`)
+
+template wrap1f(op) {.immediate, dirty.} =
+  proc `op Wrapper`(a: VmArgs) {.nimcall.} =
+    setResult(a, op(getFloat(a, 0)))
+  mathop op
+
+template wrap2f(op) {.immediate, dirty.} =
+  proc `op Wrapper`(a: VmArgs) {.nimcall.} =
+    setResult(a, op(getFloat(a, 0), getFloat(a, 1)))
+  mathop op
+
+template wrap1s(op) {.immediate, dirty.} =
+  proc `op Wrapper`(a: VmArgs) {.nimcall.} =
+    setResult(a, op(getString(a, 0)))
+  osop op
+
+proc registerAdditionalOps*(c: PCtx) =
+  wrap1f(sqrt)
+  wrap1f(ln)
+  wrap1f(log10)
+  wrap1f(log2)
+  wrap1f(exp)
+  wrap1f(round)
+  wrap1f(arccos)
+  wrap1f(arcsin)
+  wrap1f(arctan)
+  wrap2f(arctan2)
+  wrap1f(cos)
+  wrap1f(cosh)
+  wrap2f(hypot)
+  wrap1f(sinh)
+  wrap1f(sin)
+  wrap1f(tan)
+  wrap1f(tanh)
+  wrap2f(pow)
+  wrap1f(trunc)
+  wrap1f(floor)
+  wrap1f(ceil)
+  wrap2f(fmod)
+
+  wrap1s(getEnv)
+  wrap1s(existsEnv)
+  wrap1s(dirExists)
+  wrap1s(fileExists)
diff --git a/lib/stdlib.babel b/lib/stdlib.nimble
index f22598aba..0805ead54 100644
--- a/lib/stdlib.babel
+++ b/lib/stdlib.nimble
@@ -2,5 +2,5 @@
 name          = "stdlib"
 version       = "0.9.0"
 author        = "Dominik Picheta"
-description   = "Nimrod's standard library."
+description   = "Nim's standard library."
 license       = "MIT"