Moved Nimble-specific Nimscript definitions to nimscriptapi module.
* Moved package info reading procedures to a packageparser module. This is to prevent recu rsive dependencies between nimscriptsupport and packageinfo modules. * Passed the Options object to all procedures which read package info (necessary for nimscriptsupport module, to find the path of the nimscriptapi module) * Introduced an ``isInstalled`` field to the ``PackageInfo`` type. This is a bug fix for g etRealDir: it no longer uses the ``src`` field in the path it returns for installed packag es' PackageInfo objects. * Improved error reporting from NimScript evaluator. * Renamed compiler/options import to ``compiler_options`` in ``nimscriptsupport`` module. * Backward compatibility for .babel packages in getNameVersion proc. * Introduced a getInstalledPkgsMin procedure which does not read package info, but only pr ovides minimal info instead.
This commit is contained in:
parent
84f371982b
commit
ca99ad7d21
9 changed files with 426 additions and 300 deletions
|
|
@ -6,15 +6,16 @@
|
|||
|
||||
import
|
||||
compiler/ast, compiler/modules, compiler/passes, compiler/passaux,
|
||||
compiler/condsyms, compiler/options, compiler/sem, compiler/semdata,
|
||||
compiler/condsyms, compiler/sem, compiler/semdata,
|
||||
compiler/llstream, compiler/vm, compiler/vmdef, compiler/commands,
|
||||
compiler/msgs, compiler/magicsys, compiler/lists
|
||||
|
||||
from compiler/scriptconfig import setupVM
|
||||
from compiler/idents import getIdent
|
||||
from compiler/astalgo import strTableGet
|
||||
import compiler/options as compiler_options
|
||||
|
||||
import nimbletypes, version
|
||||
import nimbletypes, version, options, packageinfo
|
||||
import os, strutils, strtabs, times, osproc
|
||||
|
||||
type
|
||||
|
|
@ -33,27 +34,27 @@ proc raiseVariableError(ident, typ: string) {.noinline.} =
|
|||
|
||||
proc isStrLit(n: PNode): bool = n.kind in {nkStrLit..nkTripleStrLit}
|
||||
|
||||
proc getGlobal(ident: string): string =
|
||||
let n = vm.globalCtx.getGlobalValue(getSysSym ident)
|
||||
proc getGlobal(ident: PSym): string =
|
||||
let n = vm.globalCtx.getGlobalValue(ident)
|
||||
if n.isStrLit:
|
||||
result = if n.strVal.isNil: "" else: n.strVal
|
||||
else:
|
||||
raiseVariableError(ident, "string")
|
||||
raiseVariableError(ident.name.s, "string")
|
||||
|
||||
proc getGlobalAsSeq(ident: string): seq[string] =
|
||||
let n = vm.globalCtx.getGlobalValue(getSysSym ident)
|
||||
proc getGlobalAsSeq(ident: PSym): seq[string] =
|
||||
let n = vm.globalCtx.getGlobalValue(ident)
|
||||
result = @[]
|
||||
if n.kind == nkBracket:
|
||||
for x in n:
|
||||
if x.isStrLit:
|
||||
result.add x.strVal
|
||||
else:
|
||||
raiseVariableError(ident, "seq[string]")
|
||||
raiseVariableError(ident.name.s, "seq[string]")
|
||||
else:
|
||||
raiseVariableError(ident, "seq[string]")
|
||||
raiseVariableError(ident.name.s, "seq[string]")
|
||||
|
||||
proc extractRequires(result: var seq[PkgTuple]) =
|
||||
let n = vm.globalCtx.getGlobalValue(getSysSym "requiresData")
|
||||
proc extractRequires(ident: PSym, result: var seq[PkgTuple]) =
|
||||
let n = vm.globalCtx.getGlobalValue(ident)
|
||||
if n.kind == nkBracket:
|
||||
for x in n:
|
||||
if x.kind == nkPar and x.len == 2 and x[0].isStrLit and x[1].isStrLit:
|
||||
|
|
@ -140,13 +141,13 @@ proc setupVM(module: PSym; scriptName: string,
|
|||
cbconf thisDir:
|
||||
setResult(a, vthisDir)
|
||||
cbconf put:
|
||||
options.setConfigVar(getString(a, 0), getString(a, 1))
|
||||
compiler_options.setConfigVar(getString(a, 0), getString(a, 1))
|
||||
cbconf get:
|
||||
setResult(a, options.getConfigVar(a.getString 0))
|
||||
setResult(a, compiler_options.getConfigVar(a.getString 0))
|
||||
cbconf exists:
|
||||
setResult(a, options.existsConfigVar(a.getString 0))
|
||||
setResult(a, compiler_options.existsConfigVar(a.getString 0))
|
||||
cbconf nimcacheDir:
|
||||
setResult(a, options.getNimcacheDir())
|
||||
setResult(a, compiler_options.getNimcacheDir())
|
||||
cbconf paramStr:
|
||||
setResult(a, os.paramStr(int a.getInt 0))
|
||||
cbconf paramCount:
|
||||
|
|
@ -156,7 +157,7 @@ proc setupVM(module: PSym; scriptName: string,
|
|||
cbconf cmpIgnoreCase:
|
||||
setResult(a, strutils.cmpIgnoreCase(a.getString 0, a.getString 1))
|
||||
cbconf setCommand:
|
||||
options.command = a.getString 0
|
||||
compiler_options.command = a.getString 0
|
||||
let arg = a.getString 1
|
||||
if arg.len > 0:
|
||||
gProjectName = arg
|
||||
|
|
@ -165,15 +166,40 @@ proc setupVM(module: PSym; scriptName: string,
|
|||
except OSError:
|
||||
gProjectFull = gProjectName
|
||||
cbconf getCommand:
|
||||
setResult(a, options.command)
|
||||
setResult(a, compiler_options.command)
|
||||
cbconf switch:
|
||||
if not flags.isNil:
|
||||
flags[a.getString 0] = a.getString 1
|
||||
|
||||
proc execScript(scriptName: string, flags: StringTableRef) =
|
||||
proc findNimscriptApi(options: Options): string =
|
||||
## Returns the directory containing ``nimscriptapi.nim``
|
||||
var inPath = false
|
||||
let pkgs = getInstalledPkgsMin(options.getPkgsDir(), options)
|
||||
var pkg: PackageInfo
|
||||
if pkgs.findPkg(("nimble", newVRAny()), pkg):
|
||||
let pkgDir = pkg.getRealDir()
|
||||
if fileExists(pkgDir / "nimblepkg" / "nimscriptapi.nim"):
|
||||
result = pkgDir
|
||||
inPath = true
|
||||
if not inPath:
|
||||
# Try finding it in exe's path
|
||||
if fileExists(getAppDir() / "nimblepkg" / "nimscriptapi.nim"):
|
||||
result = getAppDir()
|
||||
inPath = true
|
||||
if not inPath:
|
||||
raise newException(NimbleError, "Cannot find nimscriptapi.nim")
|
||||
|
||||
proc execScript(scriptName: string, flags: StringTableRef, options: Options) =
|
||||
## Executes the specified script.
|
||||
##
|
||||
## No clean up is performed and must be done manually!
|
||||
if "nimblepkg/nimscriptapi" notin compiler_options.implicitIncludes:
|
||||
compiler_options.implicitIncludes.add("nimblepkg/nimscriptapi")
|
||||
|
||||
# Ensure that "nimblepkg/nimscriptapi" is in the PATH.
|
||||
let nimscriptApiPath = findNimscriptApi(options)
|
||||
appendStr(searchPaths, nimscriptApiPath)
|
||||
|
||||
setDefaultLibpath()
|
||||
passes.gIncludeFile = includeModule
|
||||
passes.gImportModule = importModule
|
||||
|
|
@ -185,19 +211,28 @@ proc execScript(scriptName: string, flags: StringTableRef) =
|
|||
registerPass(semPass)
|
||||
registerPass(evalPass)
|
||||
|
||||
appendStr(searchPaths, options.libpath)
|
||||
appendStr(searchPaths, compiler_options.libpath)
|
||||
|
||||
var m = makeModule(scriptName)
|
||||
incl(m.flags, sfMainModule)
|
||||
vm.globalCtx = setupVM(m, scriptName, flags)
|
||||
|
||||
# Setup builtins defined in nimscriptapi.nim
|
||||
template cbApi(name, body) {.dirty.} =
|
||||
vm.globalCtx.registerCallback "stdlib.system." & astToStr(name),
|
||||
proc (a: VmArgs) =
|
||||
body
|
||||
# TODO: This doesn't work.
|
||||
cbApi getPkgDir:
|
||||
setResult(a, "FOOBAR")
|
||||
|
||||
compileSystemModule()
|
||||
processModule(m, llStreamOpen(scriptName, fmRead), nil)
|
||||
|
||||
proc cleanup() =
|
||||
# ensure everything can be called again:
|
||||
options.gProjectName = ""
|
||||
options.command = ""
|
||||
compiler_options.gProjectName = ""
|
||||
compiler_options.command = ""
|
||||
resetAllModulesHard()
|
||||
clearPasses()
|
||||
msgs.gErrorMax = 1
|
||||
|
|
@ -205,7 +240,8 @@ proc cleanup() =
|
|||
vm.globalCtx = nil
|
||||
initDefines()
|
||||
|
||||
proc readPackageInfoFromNims*(scriptName: string; result: var PackageInfo) =
|
||||
proc readPackageInfoFromNims*(scriptName: string, options: Options,
|
||||
result: var PackageInfo) =
|
||||
## Executes the `scriptName` nimscript file. Reads the package information
|
||||
## that it populates.
|
||||
|
||||
|
|
@ -217,20 +253,35 @@ proc readPackageInfoFromNims*(scriptName: string; result: var PackageInfo) =
|
|||
# The error counter is incremented after the writeLnHook is invoked.
|
||||
if msgs.gErrorCounter > 0:
|
||||
raise newException(NimbleError, previousMsg)
|
||||
elif previousMsg.len > 0:
|
||||
echo(previousMsg)
|
||||
if output.normalize.startsWith("error"):
|
||||
raise newException(NimbleError, output)
|
||||
previousMsg = output
|
||||
|
||||
compiler_options.command = internalCmd
|
||||
|
||||
# Execute the nimscript file.
|
||||
execScript(scriptName, nil)
|
||||
execScript(scriptName, nil, options)
|
||||
|
||||
# Extract all the necessary fields populated by the nimscript file.
|
||||
proc getSym(thisModule: PSym, ident: string): PSym =
|
||||
thisModule.tab.strTableGet(getIdent(ident))
|
||||
|
||||
template trivialField(field) =
|
||||
result.field = getGlobal(astToStr field)
|
||||
result.field = getGlobal(getSym(thisModule, astToStr field))
|
||||
|
||||
template trivialFieldSeq(field) =
|
||||
result.field.add getGlobalAsSeq(astToStr field)
|
||||
result.field.add getGlobalAsSeq(getSym(thisModule, astToStr field))
|
||||
|
||||
# Grab the module Sym for .nimble file (nimscriptapi is included in it).
|
||||
let idx = fileInfoIdx(scriptName)
|
||||
let thisModule = getModule(idx)
|
||||
assert(not thisModule.isNil)
|
||||
assert thisModule.kind == skModule
|
||||
|
||||
# keep reasonable default:
|
||||
let name = getGlobal"packageName"
|
||||
let name = getGlobal(thisModule.tab.strTableGet(getIdent"packageName"))
|
||||
if name.len > 0: result.name = name
|
||||
|
||||
trivialField version
|
||||
|
|
@ -246,13 +297,13 @@ proc readPackageInfoFromNims*(scriptName: string; result: var PackageInfo) =
|
|||
trivialFieldSeq installFiles
|
||||
trivialFieldSeq installExt
|
||||
|
||||
extractRequires result.requires
|
||||
extractRequires(getSym(thisModule, "requiresData"), result.requires)
|
||||
|
||||
let binSeq = getGlobalAsSeq("bin")
|
||||
let binSeq = getGlobalAsSeq(getSym(thisModule, "bin"))
|
||||
for i in binSeq:
|
||||
result.bin.add(i.addFileExt(ExeExt))
|
||||
|
||||
let backend = getGlobal("backend")
|
||||
let backend = getGlobal(getSym(thisModule, "backend"))
|
||||
if backend.len == 0:
|
||||
result.backend = "c"
|
||||
elif cmpIgnoreStyle(backend, "javascript") == 0:
|
||||
|
|
@ -262,19 +313,22 @@ proc readPackageInfoFromNims*(scriptName: string; result: var PackageInfo) =
|
|||
|
||||
cleanup()
|
||||
|
||||
proc execTask*(scriptName, taskName: string): ExecutionResult =
|
||||
proc execTask*(scriptName, taskName: string,
|
||||
options: Options): ExecutionResult =
|
||||
## Executes the specified task in the specified script.
|
||||
##
|
||||
## `scriptName` should be a filename pointing to the nimscript file.
|
||||
result.success = true
|
||||
result.flags = newStringTable()
|
||||
options.command = internalCmd
|
||||
compiler_options.command = internalCmd
|
||||
echo("Executing task ", taskName, " in ", scriptName)
|
||||
|
||||
execScript(scriptName, result.flags)
|
||||
execScript(scriptName, result.flags, options)
|
||||
# Explicitly execute the task procedure, instead of relying on hack.
|
||||
assert vm.globalCtx.module.kind == skModule
|
||||
let prc = vm.globalCtx.module.tab.strTableGet(getIdent(taskName & "Task"))
|
||||
let idx = fileInfoIdx(scriptName)
|
||||
let thisModule = getModule(idx)
|
||||
assert thisModule.kind == skModule
|
||||
let prc = thisModule.tab.strTableGet(getIdent(taskName & "Task"))
|
||||
if prc.isNil:
|
||||
# Procedure not defined in the NimScript module.
|
||||
result.success = false
|
||||
|
|
@ -282,27 +336,27 @@ proc execTask*(scriptName, taskName: string): ExecutionResult =
|
|||
discard vm.globalCtx.execProc(prc, [])
|
||||
|
||||
# Read the command, arguments and flags set by the executed task.
|
||||
result.command = options.command
|
||||
result.command = compiler_options.command
|
||||
result.arguments = @[]
|
||||
for arg in options.gProjectName.split():
|
||||
for arg in compiler_options.gProjectName.split():
|
||||
result.arguments.add(arg)
|
||||
|
||||
cleanup()
|
||||
|
||||
proc getNimScriptCommand(): string =
|
||||
options.command
|
||||
compiler_options.command
|
||||
|
||||
proc setNimScriptCommand(command: string) =
|
||||
options.command = command
|
||||
compiler_options.command = command
|
||||
|
||||
proc hasTaskRequestedCommand*(execResult: ExecutionResult): bool =
|
||||
## Determines whether the last executed task used ``setCommand``
|
||||
return execResult.command != internalCmd
|
||||
|
||||
proc listTasks*(scriptName: string) =
|
||||
proc listTasks*(scriptName: string, options: Options) =
|
||||
setNimScriptCommand("help")
|
||||
|
||||
execScript(scriptName, nil)
|
||||
execScript(scriptName, nil, options)
|
||||
# TODO: Make the 'task' template generate explicit data structure containing
|
||||
# all the task names + descriptions.
|
||||
cleanup()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue