VM supports math and a few os procs

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

View file

@ -7,7 +7,7 @@
# distribution, for details about the copyright. # 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 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-2])
check(c, a.sons[L-1]) check(c, a.sons[L-1])
of nkTypeSection, nkConstSection: of nkTypeSection, nkConstSection:
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
let a = n.sons[i] let a = n.sons[i]
if a.kind == nkCommentStmt: continue if a.kind == nkCommentStmt: continue
checkSonsLen(a, 3) 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 # cause of bugs like these is that the VM does not properly distinguish
# between variable defintions (var foo = e) and variable updates (foo = e). # between variable defintions (var foo = e) and variable updates (foo = e).
include vmhooks
template createStr(x) = template createStr(x) =
x.node = newNode(nkStrLit) x.node = newNode(nkStrLit)
@ -801,7 +803,11 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
let bb = regs[rb].node let bb = regs[rb].node
let isClosure = bb.kind == nkPar let isClosure = bb.kind == nkPar
let prc = if not isClosure: bb.sym else: bb.sons[0].sym 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: if allowFFI notin c.features:
globalError(c.debug[pc], errGenerated, "VM not allowed to do FFI") globalError(c.debug[pc], errGenerated, "VM not allowed to do FFI")
# we pass 'tos.slots' instead of 'regs' so that the compiler can keep # 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: if isClosure:
newFrame.slots[rc].kind = rkNode newFrame.slots[rc].kind = rkNode
newFrame.slots[rc].node = regs[rb].node.sons[1] 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 tos = newFrame
move(regs, newFrame.slots) move(regs, newFrame.slots)
# -1 for the following 'inc pc' # -1 for the following 'inc pc'
@ -1316,6 +1319,8 @@ proc evalExpr*(c: PCtx, n: PNode): PNode =
assert c.code[start].opcode != opcEof assert c.code[start].opcode != opcEof
result = execute(c, start) result = execute(c, start)
include vmops
# for now we share the 'globals' environment. XXX Coming soon: An API for # for now we share the 'globals' environment. XXX Coming soon: An API for
# storing&loading the 'globals' environment to get what a component system # storing&loading the 'globals' environment to get what a component system
# requires. # requires.
@ -1325,6 +1330,7 @@ var
proc setupGlobalCtx(module: PSym) = proc setupGlobalCtx(module: PSym) =
if globalCtx.isNil: globalCtx = newCtx(module) if globalCtx.isNil: globalCtx = newCtx(module)
else: refresh(globalCtx, module) else: refresh(globalCtx, module)
registerAdditionalOps(globalCtx)
proc myOpen(module: PSym): PPassContext = proc myOpen(module: PSym): PPassContext =
#var c = newEvalContext(module, emRepl) #var c = newEvalContext(module, emRepl)

View file

@ -170,7 +170,12 @@ type
sym*: PSym sym*: PSym
slots*: array[TRegister, tuple[inUse: bool, kind: TSlotKind]] slots*: array[TRegister, tuple[inUse: bool, kind: TSlotKind]]
maxSlots*: int maxSlots*: int
VmArgs* = object
ra*, rb*, rc*: Natural
slots*: pointer
VmCallback* = proc (args: VmArgs) {.closure.}
PCtx* = ref TCtx PCtx* = ref TCtx
TCtx* = object of passes.TPassContext # code gen context TCtx* = object of passes.TPassContext # code gen context
code*: seq[TInstr] code*: seq[TInstr]
@ -189,6 +194,7 @@ type
traceActive*: bool traceActive*: bool
loopIterations*: int loopIterations*: int
comesFromHeuristic*: TLineInfo # Heuristic for better macro stack traces comesFromHeuristic*: TLineInfo # Heuristic for better macro stack traces
callbacks*: seq[tuple[key: string, value: VmCallback]]
TPosition* = distinct int TPosition* = distinct int
@ -198,12 +204,15 @@ proc newCtx*(module: PSym): PCtx =
PCtx(code: @[], debug: @[], PCtx(code: @[], debug: @[],
globals: newNode(nkStmtListExpr), constants: newNode(nkStmtList), types: @[], globals: newNode(nkStmtListExpr), constants: newNode(nkStmtList), types: @[],
prc: PProc(blocks: @[]), module: module, loopIterations: MaxLoopIterations, prc: PProc(blocks: @[]), module: module, loopIterations: MaxLoopIterations,
comesFromHeuristic: unknownLineInfo()) comesFromHeuristic: unknownLineInfo(), callbacks: @[])
proc refresh*(c: PCtx, module: PSym) = proc refresh*(c: PCtx, module: PSym) =
c.module = module c.module = module
c.prc = PProc(blocks: @[]) c.prc = PProc(blocks: @[])
proc registerCallback*(c: PCtx; name: string; callback: VmCallback) =
c.callbacks.add((name, callback))
const const
firstABxInstr* = opcTJmp firstABxInstr* = opcTJmp
largeInstrs* = { # instructions which use 2 int32s instead of 1: 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 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 = {}) = proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
case n.kind case n.kind
of nkSym: of nkSym:
@ -1499,7 +1519,8 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
genRdVar(c, n, dest, flags) genRdVar(c, n, dest, flags)
of skProc, skConverter, skMacro, skTemplate, skMethod, skIterators: of skProc, skConverter, skMacro, skTemplate, skMethod, skIterators:
# 'skTemplate' is only allowed for 'getAst' support: # '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) genLit(c, n, dest)
of skConst: of skConst:
gen(c, s.ast, dest) 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" name = "stdlib"
version = "0.9.0" version = "0.9.0"
author = "Dominik Picheta" author = "Dominik Picheta"
description = "Nimrod's standard library." description = "Nim's standard library."
license = "MIT" license = "MIT"