# # # The Nim Compiler # (c) Copyright 2015 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. # # Unfortunately this cannot be a module yet: #import vmdeps, vm from std/math import sqrt, ln, log10, log2, exp, round, arccos, arcsin, arctan, arctan2, cos, cosh, hypot, sinh, sin, tan, tanh, pow, trunc, floor, ceil, `mod`, cbrt, arcsinh, arccosh, arctanh, erf, erfc, gamma, lgamma from std/sequtils import toSeq when declared(math.copySign): # pending bug #18762, avoid renaming math from std/math as math2 import copySign when declared(math.signbit): # ditto from std/math as math3 import signbit from std/os import getEnv, existsEnv, delEnv, putEnv, envPairs, dirExists, fileExists, walkDir, getAppFilename, raiseOSError, osLastError from std/times import cpuTime from std/hashes import hash from std/osproc import nil when defined(nimPreviewSlimSystem): import std/syncio else: from std/formatfloat import addFloatRoundtrip, addFloatSprintf # There are some useful procs in vmconv. import vmconv, vmmarshal template mathop(op) {.dirty.} = registerCallback(c, "stdlib.math." & astToStr(op), `op Wrapper`) template osop(op) {.dirty.} = registerCallback(c, "stdlib.os." & astToStr(op), `op Wrapper`) template timesop(op) {.dirty.} = registerCallback(c, "stdlib.times." & astToStr(op), `op Wrapper`) template systemop(op) {.dirty.} = registerCallback(c, "stdlib.system." & astToStr(op), `op Wrapper`) template ioop(op) {.dirty.} = registerCallback(c, "stdlib.syncio." & astToStr(op), `op Wrapper`) template macrosop(op) {.dirty.} = registerCallback(c, "stdlib.macros." & astToStr(op), `op Wrapper`) template wrap1fMath(op) {.dirty.} = proc `op Wrapper`(a: VmArgs) {.nimcall.} = doAssert a.numArgs == 1 setResult(a, op(getFloat(a, 0))) mathop op template wrap2fMath(op) {.dirty.} = proc `op Wrapper`(a: VmArgs) {.nimcall.} = setResult(a, op(getFloat(a, 0), getFloat(a, 1))) mathop op template wrap0(op, modop) {.dirty.} = proc `op Wrapper`(a: VmArgs) {.nimcall.} = setResult(a, op()) modop op template wrap1s(op, modop) {.dirty.} = proc `op Wrapper`(a: VmArgs) {.nimcall.} = setResult(a, op(getString(a, 0))) modop op template wrap2s(op, modop) {.dirty.} = proc `op Wrapper`(a: VmArgs) {.nimcall.} = setResult(a, op(getString(a, 0), getString(a, 1))) modop op template wrap2si(op, modop) {.dirty.} = proc `op Wrapper`(a: VmArgs) {.nimcall.} = setResult(a, op(getString(a, 0), getInt(a, 1))) modop op template wrap1svoid(op, modop) {.dirty.} = proc `op Wrapper`(a: VmArgs) {.nimcall.} = op(getString(a, 0)) modop op template wrap2svoid(op, modop) {.dirty.} = proc `op Wrapper`(a: VmArgs) {.nimcall.} = op(getString(a, 0), getString(a, 1)) modop op template wrapDangerous(op, modop) {.dirty.} = if vmopsDanger notin c.config.features and (defined(nimsuggest) or c.config.cmd == cmdCheck): proc `op Wrapper`(a: VmArgs) {.nimcall.} = discard modop op else: proc `op Wrapper`(a: VmArgs) {.nimcall.} = op(getString(a, 0), getString(a, 1)) modop op proc getCurrentExceptionMsgWrapper(a: VmArgs) {.nimcall.} = setResult(a, if a.currentException.isNil: "" else: a.currentException[3].skipColon.strVal) proc getCurrentExceptionWrapper(a: VmArgs) {.nimcall.} = setResult(a, a.currentException) proc staticWalkDirImpl(path: string, relative: bool): PNode = result = newNode(nkBracket) for k, f in walkDir(path, relative): result.add toLit((k, f)) when defined(nimHasInvariant): from std / compilesettings import SingleValueSetting, MultipleValueSetting proc querySettingImpl(conf: ConfigRef, switch: BiggestInt): string = case SingleValueSetting(switch) of arguments: result = conf.arguments of outFile: result = conf.outFile.string of outDir: result = conf.outDir.string of nimcacheDir: result = conf.getNimcacheDir().string of projectName: result = conf.projectName of projectPath: result = conf.projectPath.string of projectFull: result = conf.projectFull.string of command: result = conf.command of commandLine: result = conf.commandLine of linkOptions: result = conf.linkOptions of compileOptions: result = conf.compileOptions of ccompilerPath: result = conf.cCompilerPath of backend: result = $conf.backend of libPath: result = conf.libpath.string of gc: result = $conf.selectedGC of mm: result = $conf.selectedGC proc querySettingSeqImpl(conf: ConfigRef, switch: BiggestInt): seq[string] = template copySeq(field: untyped): untyped = for i in field: result.add i.string case MultipleValueSetting(switch) of nimblePaths: copySeq(conf.nimblePaths) of searchPaths: copySeq(conf.searchPaths) of lazyPaths: copySeq(conf.lazyPaths) of commandArgs: result = conf.commandArgs of cincludes: copySeq(conf.cIncludes) of clibs: copySeq(conf.cLibs) proc stackTrace2(c: PCtx, msg: string, n: PNode) = stackTrace(c, PStackFrame(prc: c.prc.sym, comesFrom: 0, next: nil), c.exceptionInstr, msg, n.info) proc registerAdditionalOps*(c: PCtx) = template wrapIterator(fqname: string, iter: untyped) = registerCallback c, fqname, proc(a: VmArgs) = setResult(a, toLit(toSeq(iter))) proc gorgeExWrapper(a: VmArgs) = let ret = opGorge(getString(a, 0), getString(a, 1), getString(a, 2), a.currentLineInfo, c.config) setResult a, ret.toLit proc getProjectPathWrapper(a: VmArgs) = setResult a, c.config.projectPath.string wrap1fMath(sqrt) wrap1fMath(cbrt) wrap1fMath(ln) wrap1fMath(log10) wrap1fMath(log2) wrap1fMath(exp) wrap1fMath(arccos) wrap1fMath(arcsin) wrap1fMath(arctan) wrap1fMath(arcsinh) wrap1fMath(arccosh) wrap1fMath(arctanh) wrap2fMath(arctan2) wrap1fMath(cos) wrap1fMath(cosh) wrap2fMath(hypot) wrap1fMath(sinh) wrap1fMath(sin) wrap1fMath(tan) wrap1fMath(tanh) wrap2fMath(pow) wrap1fMath(trunc) wrap1fMath(floor) wrap1fMath(ceil) wrap1fMath(erf) wrap1fMath(erfc) wrap1fMath(gamma) wrap1fMath(lgamma) when declared(copySign): wrap2fMath(copySign) when declared(signbit): wrap1fMath(signbit) registerCallback c, "stdlib.math.round", proc (a: VmArgs) {.nimcall.} = let n = a.numArgs case n of 1: setResult(a, round(getFloat(a, 0))) of 2: setResult(a, round(getFloat(a, 0), getInt(a, 1).int)) else: doAssert false, $n proc `mod Wrapper`(a: VmArgs) {.nimcall.} = setResult(a, `mod`(getFloat(a, 0), getFloat(a, 1))) registerCallback(c, "stdlib.math.mod", `mod Wrapper`) when defined(nimcore): wrap2s(getEnv, osop) wrap1s(existsEnv, osop) wrap2svoid(putEnv, osop) wrap1svoid(delEnv, osop) wrap1s(dirExists, osop) wrap1s(fileExists, osop) wrapDangerous(writeFile, ioop) wrap1s(readFile, ioop) wrap2si(readLines, ioop) systemop getCurrentExceptionMsg systemop getCurrentException registerCallback c, "stdlib.*.staticWalkDir", proc (a: VmArgs) {.nimcall.} = setResult(a, staticWalkDirImpl(getString(a, 0), getBool(a, 1))) when defined(nimHasInvariant): registerCallback c, "stdlib.compilesettings.querySetting", proc (a: VmArgs) = setResult(a, querySettingImpl(c.config, getInt(a, 0))) registerCallback c, "stdlib.compilesettings.querySettingSeq", proc (a: VmArgs) = setResult(a, querySettingSeqImpl(c.config, getInt(a, 0))) if defined(nimsuggest) or c.config.cmd == cmdCheck: discard "don't run staticExec for 'nim suggest'" else: systemop gorgeEx macrosop getProjectPath registerCallback c, "stdlib.os.getCurrentCompilerExe", proc (a: VmArgs) {.nimcall.} = setResult(a, getAppFilename()) registerCallback c, "stdlib.macros.symBodyHash", proc (a: VmArgs) = let n = getNode(a, 0) if n.kind != nkSym: stackTrace2(c, "symBodyHash() requires a symbol. '$#' is of kind '$#'" % [$n, $n.kind], n) setResult(a, $symBodyDigest(c.graph, n.sym)) registerCallback c, "stdlib.macros.isExported", proc(a: VmArgs) = let n = getNode(a, 0) if n.kind != nkSym: stackTrace2(c, "isExported() requires a symbol. '$#' is of kind '$#'" % [$n, $n.kind], n) setResult(a, sfExported in n.sym.flags) registerCallback c, "stdlib.vmutils.vmTrace", proc (a: VmArgs) = c.config.isVmTrace = getBool(a, 0) proc hashVmImpl(a: VmArgs) = var res = hashes.hash(a.getString(0), a.getInt(1).int, a.getInt(2).int) if c.config.backend == backendJs: # emulate JS's terrible integers: res = cast[int32](res) setResult(a, res) registerCallback c, "stdlib.hashes.hashVmImpl", hashVmImpl proc hashVmImplByte(a: VmArgs) = # nkBracket[...] let sPos = a.getInt(1).int let ePos = a.getInt(2).int let arr = a.getNode(0) var bytes = newSeq[byte](arr.len) for i in 0..= effectListLen and fn.typ.n[0][effectIndex] != nil: for e in fn.typ.n[0][effectIndex]: list.add opMapTypeInstToAst(c.cache, e.typ.skipTypes({tyRef}), e.info, c.idgen) else: list.add newIdentNode(getIdent(c.cache, "UncomputedEffects"), fn.info) setResult(a, list) registerCallback c, "stdlib.effecttraits.getRaisesListImpl", proc (a: VmArgs) = getEffectList(c, a, exceptionEffects) registerCallback c, "stdlib.effecttraits.getTagsListImpl", proc (a: VmArgs) = getEffectList(c, a, tagEffects) registerCallback c, "stdlib.effecttraits.getForbidsListImpl", proc (a: VmArgs) = getEffectList(c, a, forbiddenEffects) registerCallback c, "stdlib.effecttraits.isGcSafeImpl", proc (a: VmArgs) = let fn = getNode(a, 0) setResult(a, fn.typ != nil and tfGcSafe in fn.typ.flags) registerCallback c, "stdlib.effecttraits.hasNoSideEffectsImpl", proc (a: VmArgs) = let fn = getNode(a, 0) setResult(a, (fn.typ != nil and tfNoSideEffect in fn.typ.flags) or (fn.kind == nkSym and fn.sym.kind == skFunc)) registerCallback c, "stdlib.typetraits.hasClosureImpl", proc (a: VmArgs) = let fn = getNode(a, 0) setResult(a, fn.kind == nkClosure or (fn.typ != nil and fn.typ.callConv == ccClosure)) registerCallback c, "stdlib.formatfloat.addFloatRoundtrip", proc(a: VmArgs) = let p = a.getVar(0) let x = a.getFloat(1) addFloatRoundtrip(p.strVal, x) registerCallback c, "stdlib.formatfloat.addFloatSprintf", proc(a: VmArgs) = let p = a.getVar(0) let x = a.getFloat(1) addFloatSprintf(p.strVal, x) wrapIterator("stdlib.os.envPairsImplSeq"): envPairs() registerCallback c, "stdlib.marshal.toVM", proc(a: VmArgs) = let typ = a.getNode(0).typ case typ.kind of tyInt..tyInt64, tyUInt..tyUInt64: setResult(a, loadAny(a.getString(1), typ, c.cache, c.config, c.idgen).intVal) of tyFloat..tyFloat128: setResult(a, loadAny(a.getString(1), typ, c.cache, c.config, c.idgen).floatVal) else: setResult(a, loadAny(a.getString(1), typ, c.cache, c.config, c.idgen)) registerCallback c, "stdlib.marshal.loadVM", proc(a: VmArgs) = let typ = a.getNode(0).typ let p = a.getReg(1) var res: string storeAny(res, typ, regToNode(p[]), c.config) setResult(a, res)