Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes #1994 #4874

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion compiler/ast.nim
Expand Up @@ -547,7 +547,7 @@ type
mNone,
mDefined, mDefinedInScope, mCompiles, mArrGet, mArrPut, mAsgn,
mLow, mHigh, mSizeOf, mTypeTrait, mIs, mOf, mAddr, mTypeOf, mRoof, mPlugin,
mEcho, mShallowCopy, mSlurp, mStaticExec,
mEcho, mShallowCopy, mSlurp, mStaticExec, mStaticExecEx,
mParseExprToAst, mParseStmtToAst, mExpandToAst, mQuoteAst,
mUnaryLt, mInc, mDec, mOrd,
mNew, mNewFinalize, mNewSeq, mNewSeqOfCap,
Expand Down
42 changes: 35 additions & 7 deletions compiler/vm.nim
Expand Up @@ -401,6 +401,18 @@ template handleJmpBack() {.dirty.} =
globalError(c.debug[pc], errTooManyIterations)
dec(c.loopIterations)

template execGorgeEx(c: PCtx, regs: seq[TFullReg], pc: var int,
tos: PStackFrame): tuple[output: string, resultCode: int] =
inc(pc)
let
rd = c.code[pc].regA
gorgeRes = opGorgeEx(regs[rb].node.strVal, regs[rc].node.strVal,
regs[rd].node.strVal, c.debug[pc])
if gorgeRes.resultCode == -1:
stackTrace(c, tos, pc, errExecutionOfProgramFailed,
regs[rb].node.strVal)
gorgeRes

proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
var pc = start
var tos = tos
Expand Down Expand Up @@ -1240,13 +1252,29 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
c.module)
of opcGorge:
decodeBC(rkNode)
inc pc
let rd = c.code[pc].regA

createStr regs[ra]
regs[ra].node.strVal = opGorge(regs[rb].node.strVal,
regs[rc].node.strVal, regs[rd].node.strVal,
c.debug[pc])
let gorgeRes = execGorgeEx(c, regs, pc, tos)
if gorgeRes.resultCode != 0:
let re = c.code[pc].regB
if regs[re].intVal == 1:
stackTrace(c, tos, pc, errExecutionOfProgramFailed,
regs[rb].node.strVal & " returned " & $gorgeRes.resultCode)
else:
createStr regs[ra]
regs[ra].node.strVal = ""
else:
createStr regs[ra]
regs[ra].node.strVal = gorgeRes.output
of opcGorgeEx:
decodeBC(rkNode)
let gorgeRes = execGorgeEx(c, regs, pc, tos)
regs[ra].node = newNode(nkPar)
var
retOutput = newNode(nkStrLit)
retCode = newNode(nkIntLit)
retOutput.strVal = gorgeRes.output
retCode.intVal = gorgeRes.resultCode
regs[ra].node.add(retOutput)
regs[ra].node.add(retCode)
of opcNError:
decodeB(rkNode)
let a = regs[ra].node
Expand Down
1 change: 1 addition & 0 deletions compiler/vmdef.nim
Expand Up @@ -92,6 +92,7 @@ type

opcSlurp,
opcGorge,
opcGorgeEx,
opcParseExprToAst,
opcParseStmtToAst,
opcQueryErrorFlag,
Expand Down
58 changes: 26 additions & 32 deletions compiler/vmdeps.nim
Expand Up @@ -9,48 +9,42 @@

import ast, types, msgs, os, osproc, streams, options, idents, securehash

proc readOutput(p: Process): string =
result = ""
var output = p.outputStream
while not output.atEnd:
result.add(output.readLine)
result.add("\n")
if result.len > 0:
result.setLen(result.len - "\n".len)
discard p.waitForExit
proc execute(cmd, input, workingDir: string, info: TLineInfo):
tuple[output: string, resultCode: int] =
result.output = ""
try:
var p = startProcess(cmd, workingDir,
options={poEvalCommand, poStderrToStdout})
if input.len != 0:
p.inputStream.write(input)
p.inputStream.close()
var output = p.outputStream
while not output.atEnd:
result.output.add(output.readLine)
result.output.add("\n")
if result.output.len > 0:
result.output.setLen(result.output.len - "\n".len)
result.resultCode = p.waitForExit
except IOError, OSError:
localError(info, errExecutionOfProgramFailed, cmd)
result.resultCode = -1

proc opGorge*(cmd, input, cache: string, info: TLineInfo): string =
proc opGorgeEx*(cmd, input, cache: string, info: TLineInfo):
tuple[output: string, resultCode: int] =
let workingDir = parentDir(info.toFullPath)
if cache.len > 0:# and optForceFullMake notin gGlobalOptions:
let h = secureHash(cmd & "\t" & input & "\t" & cache)
let filename = options.toGeneratedFile("gorge_" & $h, "txt")
var f: File
if open(f, filename):
result = f.readAll
result = (f.readAll, 0)
f.close
return
var readSuccessful = false
try:
var p = startProcess(cmd, workingDir,
options={poEvalCommand, poStderrToStdout})
if input.len != 0:
p.inputStream.write(input)
p.inputStream.close()
result = p.readOutput
readSuccessful = true
writeFile(filename, result)
except IOError, OSError:
if not readSuccessful: result = ""
result = execute(cmd, input, workingDir, info)
if result.resultCode == 0:
writeFile(filename, result.output)
else:
try:
var p = startProcess(cmd, workingDir,
options={poEvalCommand, poStderrToStdout})
if input.len != 0:
p.inputStream.write(input)
p.inputStream.close()
result = p.readOutput
except IOError, OSError:
result = ""
result = execute(cmd, input, workingDir, info)

proc opSlurp*(file: string, info: TLineInfo, module: PSym): string =
try:
Expand Down
17 changes: 16 additions & 1 deletion compiler/vmgen.nim
Expand Up @@ -651,6 +651,20 @@ proc genBinaryABCD(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) =
c.freeTemp(tmp2)
c.freeTemp(tmp3)

proc genBinaryABCDE(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) =
let
tmp = c.genx(n.sons[1])
tmp2 = c.genx(n.sons[2])
tmp3 = c.genx(n.sons[3])
tmp4 = c.genx(n.sons[4])
if dest < 0: dest = c.getTemp(n.typ)
c.gABC(n, opc, dest, tmp, tmp2)
c.gABC(n, opc, tmp3, tmp4)
c.freeTemp(tmp)
c.freeTemp(tmp2)
c.freeTemp(tmp3)
c.freeTemp(tmp4)

proc genNarrow(c: PCtx; n: PNode; dest: TDest) =
let t = skipTypes(n.typ, abstractVar-{tyTypeDesc})
# uint is uint64 in the VM, we we only need to mask the result for
Expand Down Expand Up @@ -988,7 +1002,8 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
c.gABC(n, opcTypeTrait, dest, tmp)
c.freeTemp(tmp)
of mSlurp: genUnaryABC(c, n, dest, opcSlurp)
of mStaticExec: genBinaryABCD(c, n, dest, opcGorge)
of mStaticExec: genBinaryABCDE(c, n, dest, opcGorge)
of mStaticExecEx: genBinaryABCD(c, n, dest, opcGorgeEx)
of mNLen: genUnaryABI(c, n, dest, opcLenSeq)
of mGetImpl: genUnaryABC(c, n, dest, opcGetImpl)
of mNChild: genBinaryABC(c, n, dest, opcNChild)
Expand Down
22 changes: 18 additions & 4 deletions lib/system.nim
Expand Up @@ -3303,12 +3303,14 @@ proc staticRead*(filename: string): string {.magic: "Slurp".}
##
## `slurp <#slurp>`_ is an alias for ``staticRead``.

proc gorge*(command: string, input = "", cache = ""): string {.
magic: "StaticExec".} = discard
proc gorge*(command: string, input = "", cache = "",
onErrorBreak: bool = false): string
{.magic: "StaticExec".} = discard
## This is an alias for `staticExec <#staticExec>`_.

proc staticExec*(command: string, input = "", cache = ""): string {.
magic: "StaticExec".} = discard
proc staticExec*(command: string, input = "", cache = "",
onErrorBreak: bool = false): string
{.magic: "StaticExec".} = discard
## Executes an external process at compile-time.
## if `input` is not an empty string, it will be passed as a standard input
## to the executed program.
Expand All @@ -3329,6 +3331,18 @@ proc staticExec*(command: string, input = "", cache = ""): string {.
##
## .. code-block:: nim
## const stateMachine = staticExec("dfaoptimizer", "input", "0.8.0")
##
## If ``onErrorBreak`` is true, execution will stop with a stacktrace if the
## process did not return 0.

proc gorgeEx*(command: string, input = "", cache = ""):
tuple[output: string, resultCode: int] {.magic: "StaticExecEx".} = discard
## This is an alias for `staticExecEx <#staticExecEx>`_.

proc staticExecEx*(command: string, input = "", cache = ""):
tuple[output: string, resultCode: int] {.magic: "StaticExecEx".} = discard
## Like `staticExec <#staticExec>`_, but returns the command's output and
## result code.

proc `+=`*[T: SomeOrdinal|uint|uint64](x: var T, y: T) {.
magic: "Inc", noSideEffect.}
Expand Down
20 changes: 14 additions & 6 deletions tests/vm/tgorge.nim
Expand Up @@ -3,10 +3,18 @@ import os
template getScriptDir(): string =
parentDir(instantiationInfo(-1, true).filename)

const
execName = when defined(windows): "tgorge.bat" else: "sh tgorge.sh"
relOutput = gorge(execName)
absOutput = gorge(getScriptDir() / execName)
block gorge:
const
execName = when defined(windows): "tgorge.bat" else: "./tgorge.sh"
relOutput = gorge(execName)
absOutput = gorge(getScriptDir() / execName)

doAssert relOutput == "gorge test"
doAssert absOutput == "gorge test"
doAssert relOutput == "gorge test"
doAssert absOutput == "gorge test"

block gorgeEx:
const
execName = when defined(windows): "tgorgeex.bat" else: "./tgorgeex.sh"
res = gorgeEx(execName)
doAssert res.output == "gorgeex test"
doAssert res.resultCode == 1
2 changes: 2 additions & 0 deletions tests/vm/tgorgeex.bat
@@ -0,0 +1,2 @@
@echo gorgeex test
@exit /b 1
3 changes: 3 additions & 0 deletions tests/vm/tgorgeex.sh
@@ -0,0 +1,3 @@
#!/bin/sh
echo "gorgeex test"
exit 1