VM supports math and a few os procs

This commit is contained in:
Araq
2014-08-30 16:37:27 +02:00
parent c40f981e64
commit 1f85b3b5d3
8 changed files with 157 additions and 10 deletions

View File

@@ -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

View File

@@ -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)

View File

@@ -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)

View File

@@ -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:

View File

@@ -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)

45
compiler/vmhooks.nim Normal file
View File

@@ -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

66
compiler/vmops.nim Normal file
View File

@@ -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)

View File

@@ -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"