VM supports math and a few os procs
This commit is contained in:
parent
c40f981e64
commit
1f85b3b5d3
8 changed files with 157 additions and 10 deletions
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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
45
compiler/vmhooks.nim
Normal 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
66
compiler/vmops.nim
Normal 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)
|
||||||
|
|
@ -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"
|
||||||
Loading…
Add table
Add a link
Reference in a new issue