mirror of
https://github.com/nim-lang/Nim.git
synced 2026-01-23 04:50:45 +00:00
VM supports math and a few os procs
This commit is contained in:
@@ -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
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
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"
|
||||
version = "0.9.0"
|
||||
author = "Dominik Picheta"
|
||||
description = "Nimrod's standard library."
|
||||
description = "Nim's standard library."
|
||||
license = "MIT"
|
||||
Reference in New Issue
Block a user