summary refs log tree commit diff stats
path: root/compiler
diff options
context:
space:
mode:
authorZahary Karadjov <zahary@gmail.com>2012-11-15 15:01:52 +0200
committerZahary Karadjov <zahary@gmail.com>2012-11-28 01:15:13 +0200
commit091c1b30756a15c76ca09c0d95cfbb946aa9ea13 (patch)
tree18f876f9a6a5e998d08e9c6568c983747429c138 /compiler
parentc43bf78000b21001726b31eb4259b90b3c91e03c (diff)
downloadNim-091c1b30756a15c76ca09c0d95cfbb946aa9ea13.tar.gz
caas is now drivable through stdin
* added idetools --eval
* streams.readLine recognises and applies the backspace character
Diffstat (limited to 'compiler')
-rwxr-xr-xcompiler/cgen.nim8
-rwxr-xr-xcompiler/commands.nim3
-rwxr-xr-xcompiler/depends.nim7
-rw-r--r--compiler/docgen2.nim6
-rwxr-xr-xcompiler/ecmasgen.nim8
-rwxr-xr-xcompiler/evals.nim6
-rwxr-xr-xcompiler/main.nim97
-rwxr-xr-xcompiler/nimconf.nim19
-rwxr-xr-xcompiler/nimrod.cfg13
-rwxr-xr-xcompiler/options.nim2
-rwxr-xr-xcompiler/passaux.nim11
-rwxr-xr-xcompiler/passes.nim58
-rwxr-xr-xcompiler/rodwrite.nim8
-rwxr-xr-xcompiler/sem.nim9
-rw-r--r--compiler/service.nim41
-rwxr-xr-xcompiler/transf.nim8
16 files changed, 169 insertions, 135 deletions
diff --git a/compiler/cgen.nim b/compiler/cgen.nim
index 5bdbefde1..cf6af671e 100755
--- a/compiler/cgen.nim
+++ b/compiler/cgen.nim
@@ -19,7 +19,6 @@ import
 when options.hasTinyCBackend:
   import tccgen
 
-proc cgenPass*(): TPass
 # implementation
 
 var
@@ -1157,10 +1156,5 @@ proc myClose(b: PPassContext, n: PNode): PNode =
     writeMapping(gMapping)
     if generatedHeader != nil: writeHeader(generatedHeader)
 
-proc cgenPass(): TPass = 
-  initPass(result)
-  result.open = myOpen
-  result.openCached = myOpenCached
-  result.process = myProcess
-  result.close = myClose
+const cgenPass* = makePass(myOpen, myOpenCached, myProcess, myClose)
 
diff --git a/compiler/commands.nim b/compiler/commands.nim
index 50b4a1e6f..979da3db8 100755
--- a/compiler/commands.nim
+++ b/compiler/commands.nim
@@ -458,6 +458,9 @@ proc processSwitch(switch, arg: string, pass: TCmdlinePass, info: TLineInfo) =
   of "def":
     expectNoArg(switch, arg, pass, info)
     incl(gGlobalOptions, optDef)
+  of "eval":
+    expectArg(switch, arg, pass, info)
+    gEvalExpr = arg
   of "context":
     expectNoArg(switch, arg, pass, info)
     incl(gGlobalOptions, optContext)
diff --git a/compiler/depends.nim b/compiler/depends.nim
index 4fde24ab4..f050c0993 100755
--- a/compiler/depends.nim
+++ b/compiler/depends.nim
@@ -12,7 +12,6 @@
 import 
   os, options, ast, astalgo, msgs, ropes, idents, passes, importer
 
-proc genDependPass*(): TPass
 proc generateDot*(project: string)
 
 type 
@@ -55,7 +54,5 @@ proc myOpen(module: PSym, filename: string): PPassContext =
   g.filename = filename
   result = g
 
-proc gendependPass(): TPass = 
-  initPass(result)
-  result.open = myOpen
-  result.process = addDotDependency
+const gendependPass* = makePass(open = myOpen, process = addDotDependency)
+
diff --git a/compiler/docgen2.nim b/compiler/docgen2.nim
index 2d175adbf..6fa179e0f 100644
--- a/compiler/docgen2.nim
+++ b/compiler/docgen2.nim
@@ -45,11 +45,7 @@ proc myOpen(module: PSym, filename: string): PPassContext =
   g.doc = d
   result = g
 
-proc docgen2Pass*(): TPass = 
-  initPass(result)
-  result.open = myOpen
-  result.process = processNode
-  result.close = close
+const docgen2Pass* = makePass(open = myOpen, process = processNode, close = close)
 
 proc finishDoc2Pass*(project: string) = 
   nil
diff --git a/compiler/ecmasgen.nim b/compiler/ecmasgen.nim
index cff4cc1dd..d341a93be 100755
--- a/compiler/ecmasgen.nim
+++ b/compiler/ecmasgen.nim
@@ -17,7 +17,6 @@ import
   times, ropes, math, passes, ccgutils, wordrecg, renderer, rodread, rodutils,
   intsets, cgmeth
 
-proc ecmasgenPass*(): TPass
 # implementation
 
 type 
@@ -1620,9 +1619,4 @@ proc myOpenCached(s: PSym, filename: string, rd: PRodReader): PPassContext =
 proc myOpen(s: PSym, filename: string): PPassContext = 
   result = newModule(s, filename)
 
-proc ecmasgenPass(): TPass = 
-  InitPass(result)
-  result.open = myOpen
-  result.close = myClose
-  result.openCached = myOpenCached
-  result.process = myProcess
+const ecmasgenPass* = makePass(myOpen, myOpenCached, myProcess, myClose)
diff --git a/compiler/evals.nim b/compiler/evals.nim
index 20d354aaf..f503922c2 100755
--- a/compiler/evals.nim
+++ b/compiler/evals.nim
@@ -1440,9 +1440,5 @@ proc myOpen(module: PSym, filename: string): PPassContext =
 proc myProcess(c: PPassContext, n: PNode): PNode = 
   result = eval(PEvalContext(c), n)
 
-proc evalPass*(): TPass = 
-  initPass(result)
-  result.open = myOpen
-  result.close = myProcess
-  result.process = myProcess
+const evalPass* = makePass(myOpen, nil, myProcess, myProcess)
 
diff --git a/compiler/main.nim b/compiler/main.nim
index dabd5309b..448efbd1d 100755
--- a/compiler/main.nim
+++ b/compiler/main.nim
@@ -16,7 +16,7 @@ import
   wordrecg, sem, semdata, idents, passes, docgen, extccomp,
   cgen, ecmasgen,
   platform, nimconf, importer, passaux, depends, evals, types, idgen,
-  tables, docgen2, service
+  tables, docgen2, service, magicsys, parser
 
 const
   has_LLVM_Backend = false
@@ -89,22 +89,30 @@ proc `==^`(a, b: string): bool =
   except EOS:
     result = false
 
+proc compileSystemModule =
+  if magicsys.SystemModule == nil:
+    discard CompileModule(options.libpath /"system", {sfSystemModule})
+
 proc CompileProject(projectFile = gProjectFull) =
   let systemFile = options.libpath / "system"
   if projectFile.addFileExt(nimExt) ==^ systemFile.addFileExt(nimExt):
     discard CompileModule(projectFile, {sfMainModule, sfSystemModule})
   else:
-    discard CompileModule(systemFile, {sfSystemModule})
+    compileSystemModule()
     discard CompileModule(projectFile, {sfMainModule})
 
+proc rodPass =
+  if optSymbolFiles in gGlobalOptions:
+    registerPass(rodwritePass)
+
 proc semanticPasses =
-  registerPass(verbosePass())
-  registerPass(sem.semPass())
+  registerPass verbosePass
+  registerPass semPass
 
 proc CommandGenDepend =
   semanticPasses()
-  registerPass(genDependPass())
-  registerPass(cleanupPass())
+  registerPass(genDependPass)
+  registerPass(cleanupPass)
   compileProject()
   generateDot(gProjectFull)
   execExternalProgram("dot -Tpng -o" & changeFileExt(gProjectFull, "png") &
@@ -113,21 +121,21 @@ proc CommandGenDepend =
 proc CommandCheck =
   msgs.gErrorMax = high(int)  # do not stop after first error
   semanticPasses()            # use an empty backend for semantic checking only
-  registerPass(rodwrite.rodwritePass())
+  rodPass()
   compileProject(mainCommandArg())
 
 proc CommandDoc2 =
   msgs.gErrorMax = high(int)  # do not stop after first error
   semanticPasses()
-  registerPass(docgen2Pass())
+  registerPass(docgen2Pass)
   #registerPass(cleanupPass())
   compileProject(mainCommandArg())
   finishDoc2Pass(gProjectFull)
 
 proc CommandCompileToC =
   semanticPasses()
-  registerPass(cgen.cgenPass())
-  registerPass(rodwrite.rodwritePass())
+  registerPass(cgenPass)
+  rodPass()
   #registerPass(cleanupPass())
   compileProject()
   if gCmd != cmdRun:
@@ -137,7 +145,7 @@ when has_LLVM_Backend:
   proc CommandCompileToLLVM =
     semanticPasses()
     registerPass(llvmgen.llvmgenPass())
-    registerPass(rodwrite.rodwritePass())
+    rodPass()
     #registerPass(cleanupPass())
     compileProject()
 
@@ -148,27 +156,50 @@ proc CommandCompileToEcmaScript =
   DefineSymbol("nimrod") # 'nimrod' is always defined
   DefineSymbol("ecmascript")
   semanticPasses()
-  registerPass(ecmasgenPass())
+  registerPass(ecmasgenPass)
   compileProject()
 
-proc CommandInteractive =
-  msgs.gErrorMax = high(int)  # do not stop after first error
+proc InteractivePasses =
   incl(gGlobalOptions, optSafeCode)
   #setTarget(osNimrodVM, cpuNimrodVM)
   initDefines()
   DefineSymbol("nimrodvm")
-  registerPass(verbosePass())
-  registerPass(sem.semPass())
-  registerPass(evals.evalPass()) # load system module:
-  discard CompileModule(options.libpath /"system", {sfSystemModule})
+  registerPass(verbosePass)
+  registerPass(semPass)
+  registerPass(evalPass)
+
+var stdinModule: PSym
+proc makeStdinModule: PSym =
+  if stdinModule == nil:
+    stdinModule = newModule("stdin")
+    stdinModule.id = getID()
+  result = stdinModule
+
+proc CommandInteractive =
+  msgs.gErrorMax = high(int)  # do not stop after first error
+  InteractivePasses()
+  compileSystemModule()
   if commandArgs.len > 0:
     discard CompileModule(mainCommandArg(), {})
   else:
-    var m = newModule("stdin")
-    m.id = getID()
+    var m = makeStdinModule()
     incl(m.flags, sfMainModule)
     processModule(m, "stdin", LLStreamOpenStdIn(), nil)
 
+const evalPasses = [verbosePass, semPass, evalPass]
+
+proc evalNim(nodes: PNode, module: PSym, filename: string) =
+  # we don't want to mess with gPasses here, because in nimrod serve
+  # scenario, it may be set up properly for normal cgenPass() compilation
+  carryPasses(nodes, module, filename, evalPasses)
+
+proc commandEval(exp: string) =
+  if SystemModule == nil:
+    InteractivePasses()
+    compileSystemModule()
+  var echoExp = "echo \"eval\\t\", " & "repr(" & exp & ")"
+  evalNim(echoExp.parseString, makeStdinModule(), "stdin")
+
 proc CommandPretty =
   var module = parseFile(addFileExt(mainCommandArg(), NimExt))
   if module != nil: 
@@ -194,7 +225,7 @@ proc CommandScan =
 proc CommandSuggest =
   msgs.gErrorMax = high(int)  # do not stop after first error
   semanticPasses()
-  registerPass(rodwrite.rodwritePass())
+  rodPass()
   compileProject()
 
 proc wantMainModule =
@@ -202,6 +233,8 @@ proc wantMainModule =
     Fatal(gCmdLineInfo, errCommandExpectsFilename)
   
 proc MainCommand =
+  # In "nimrod serve" scenario, each command must reset the registered passes
+  clearPasses()
   appendStr(searchPaths, options.libpath)
   if gProjectFull.len != 0:
     # current path is always looked first for modules
@@ -299,20 +332,20 @@ proc MainCommand =
   of "i": 
     gCmd = cmdInteractive
     CommandInteractive()
+  of "e":
+    # XXX: temporary command for easier testing
+    commandEval(mainCommandArg())
   of "idetools":
     gCmd = cmdIdeTools
-    wantMainModule()
-    CommandSuggest()
+    if gEvalExpr != "":
+      commandEval(gEvalExpr)
+    else:
+      wantMainModule()
+      CommandSuggest()
   of "serve":
     gCmd = cmdIdeTools
-    msgs.gErrorMax = high(int)  # do not stop after first error
-    semanticPasses()
-    # no need to write rod files and would slow down things:
-    #registerPass(rodwrite.rodwritePass())
-    discard CompileModule(options.libpath / "system", {sfSystemModule})
-    service.serve(proc () =
-      let projectFile = mainCommandArg()
-      discard CompileModule(projectFile, {sfMainModule})
-    )
+    msgs.gErrorMax = high(int)  # do not stop after first error     
+    serve(MainCommand)
+    
   else: rawMessage(errInvalidCommandX, command)
 
diff --git a/compiler/nimconf.nim b/compiler/nimconf.nim
index f4f6d0a42..0f0b76827 100755
--- a/compiler/nimconf.nim
+++ b/compiler/nimconf.nim
@@ -235,15 +235,16 @@ proc LoadConfigs*(cfg: string) =
   if optSkipParentConfigFiles notin gGlobalOptions:
     for dir in parentDirs(pd, fromRoot=true, inclusive=false):
       readConfigFile(dir / cfg)
-    
-  if optSkipProjConfigFile notin gGlobalOptions and gProjectName.len != 0:
+  
+  if optSkipProjConfigFile notin gGlobalOptions:
     readConfigFile(pd / cfg)
     
-    var conffile = changeFileExt(gProjectFull, "cfg")
-    if conffile != pd / cfg and existsFile(conffile):
-      readConfigFile(conffile)
-      rawMessage(warnConfigDeprecated, conffile)
-    
-    # new project wide config file:
-    readConfigFile(changeFileExt(gProjectFull, "nimrod.cfg"))
+    if gProjectName.len != 0:
+      var conffile = changeFileExt(gProjectFull, "cfg")
+      if conffile != pd / cfg and existsFile(conffile):
+        readConfigFile(conffile)
+        rawMessage(warnConfigDeprecated, conffile)
+      
+      # new project wide config file:
+      readConfigFile(changeFileExt(gProjectFull, "nimrod.cfg"))
  
diff --git a/compiler/nimrod.cfg b/compiler/nimrod.cfg
index 42a5ed5f5..aa49729b9 100755
--- a/compiler/nimrod.cfg
+++ b/compiler/nimrod.cfg
@@ -1,9 +1,12 @@
 # Special configuration file for the Nimrod project
 
---hint[XDeclaredButNotUsed]=off
-path="llvm"
-path="$projectPath/.."
+mainModule:"nimrod.nim"
 
-path="$nimrod/packages/docutils"
+hint[XDeclaredButNotUsed]:off
+path:"llvm"
+path:"$projectPath/.."
+
+path:"$nimrod/packages/docutils"
+
+define:booting
 
---define:booting
diff --git a/compiler/options.nim b/compiler/options.nim
index 42fca1ad1..ba2a9eb41 100755
--- a/compiler/options.nim
+++ b/compiler/options.nim
@@ -94,8 +94,8 @@ var
   gCmd*: TCommands = cmdNone  # the command
   gVerbosity*: int            # how verbose the compiler is
   gNumberOfProcessors*: int   # number of processors
-
   gWholeProject*: bool # for 'doc2': output any dependency
+  gEvalExpr*: string          # expression for idetools --eval
   
 const 
   genSubDir* = "nimcache"
diff --git a/compiler/passaux.nim b/compiler/passaux.nim
index 1ee6023c8..655b8ae68 100755
--- a/compiler/passaux.nim
+++ b/compiler/passaux.nim
@@ -26,10 +26,7 @@ proc verboseProcess(context: PPassContext, n: PNode): PNode =
     incl(msgs.gNotes, hintProcessing)
     Message(n.info, hintProcessing, $idgen.gBackendId)
   
-proc verbosePass*(): TPass = 
-  initPass(result)
-  result.open = verboseOpen
-  result.process = verboseProcess
+const verbosePass* = makePass(open = verboseOpen, process = verboseProcess)
 
 proc cleanUp(c: PPassContext, n: PNode): PNode = 
   result = n                  
@@ -46,7 +43,5 @@ proc cleanUp(c: PPassContext, n: PNode): PNode =
   else: 
     nil
 
-proc cleanupPass*(): TPass = 
-  initPass(result)
-  result.process = cleanUp
-  result.close = cleanUp
+const cleanupPass* = makePass(process = cleanUp, close = cleanUp)
+
diff --git a/compiler/passes.nim b/compiler/passes.nim
index 9b4a1b365..4941ac3b3 100755
--- a/compiler/passes.nim
+++ b/compiler/passes.nim
@@ -18,21 +18,34 @@ import
 type  
   TPassContext* = object of TObject # the pass's context
     fromCache*: bool  # true if created by "openCached"
-    
+   
   PPassContext* = ref TPassContext
-  TPass* = tuple[
-    open: proc (module: PSym, filename: string): PPassContext {.nimcall.},
-    openCached: proc (module: PSym, filename: string,
-                     rd: PRodReader): PPassContext {.nimcall.},
-    close: proc (p: PPassContext, n: PNode): PNode {.nimcall.},
-    process: proc (p: PPassContext, topLevelStmt: PNode): PNode {.nimcall.}]
-    
+
+  TPassOpen* = proc (module: PSym, filename: string): PPassContext {.nimcall.}
+  TPassOpenCached* = proc (module: PSym, filename: string,
+                           rd: PRodReader): PPassContext {.nimcall.}
+  TPassClose* = proc (p: PPassContext, n: PNode): PNode {.nimcall.}
+  TPassProcess* = proc (p: PPassContext, topLevelStmt: PNode): PNode {.nimcall.}
+
+  TPass* = tuple[open: TPassOpen, openCached: TPassOpenCached,
+                 process: TPassProcess, close: TPassClose]
+
+  TPassData* = tuple[input: PNode, closeOutput: Pnode]
+  TPasses* = openarray[TPass]
+
 # a pass is a tuple of procedure vars ``TPass.close`` may produce additional 
 # nodes. These are passed to the other close procedures. 
 # This mechanism used to be used for the instantiation of generics.
 
-proc registerPass*(p: TPass)
-proc initPass*(p: var TPass)
+proc makePass*(open: TPassOpen = nil,
+               openCached: TPassOpenCached = nil,
+               process: TPassProcess = nil,
+               close: TPassClose = nil): TPass =
+  result.open = open
+  result.openCached = openCached
+  result.close = close
+  result.process = process
+
   # This implements a memory preserving scheme: Top level statements are
   # processed in a pipeline. The compiler never looks at a whole module
   # any longer. However, this is simple to change, as new passes may perform
@@ -74,12 +87,28 @@ type
 
 var 
   gPasses: array[0..maxPasses - 1, TPass]
-  gPassesLen: int
+  gPassesLen*: int
+
+proc clearPasses* =
+  gPassesLen = 0
 
-proc registerPass(p: TPass) = 
+proc registerPass*(p: TPass) = 
   gPasses[gPassesLen] = p
   inc(gPassesLen)
 
+proc carryPass*(p: TPass, module: PSym, filename: string,
+                m: TPassData): TPassData =
+  var c = p.open(module, filename)
+  result.input = p.process(c, m.input)
+  result.closeOutput = if p.close != nil: p.close(c, m.closeOutput)
+                       else: m.closeOutput
+
+proc carryPasses*(nodes: PNode, module: PSym, file: string, passes: TPasses) =
+  var passdata: TPassData
+  passdata.input = nodes
+  for pass in passes:
+    passdata = carryPass(pass, module, file, passdata)
+
 proc openPasses(a: var TPassContextArray, module: PSym, filename: string) = 
   for i in countup(0, gPassesLen - 1): 
     if not isNil(gPasses[i].open): 
@@ -175,8 +204,3 @@ proc processModule(module: PSym, filename: string, stream: PLLStream,
     for i in countup(0, sonsLen(n) - 1): processTopLevelStmtCached(n.sons[i], a)
     closePassesCached(a)
 
-proc initPass(p: var TPass) = 
-  p.open = nil
-  p.openCached = nil
-  p.close = nil
-  p.process = nil
diff --git a/compiler/rodwrite.nim b/compiler/rodwrite.nim
index 5be9a2439..c89f06b37 100755
--- a/compiler/rodwrite.nim
+++ b/compiler/rodwrite.nim
@@ -15,7 +15,6 @@ import
   intsets, os, options, strutils, nversion, ast, astalgo, msgs, platform,
   condsyms, ropes, idents, crc, rodread, passes, importer, idgen, rodutils
 
-proc rodwritePass*(): TPass
 # implementation
 
 type 
@@ -583,10 +582,5 @@ proc myClose(c: PPassContext, n: PNode): PNode =
   writeRod(w)
   idgen.saveMaxIds(options.gProjectPath / options.gProjectName)
 
-proc rodwritePass(): TPass = 
-  initPass(result)
-  if optSymbolFiles in gGlobalOptions: 
-    result.open = myOpen
-    result.close = myClose
-    result.process = process
+const rodwritePass* = makePass(open = myOpen, close = myClose, process = process)
 
diff --git a/compiler/sem.nim b/compiler/sem.nim
index 911eafb08..86d9bf872 100755
--- a/compiler/sem.nim
+++ b/compiler/sem.nim
@@ -17,7 +17,6 @@ import
   semthreads, intsets, transf, evals, idgen, aliases, cgmeth, lambdalifting,
   evaltempl, patterns, parampatterns, sempass2
 
-proc semPass*(): TPass
 # implementation
 
 type 
@@ -288,9 +287,5 @@ proc myClose(context: PPassContext, n: PNode): PNode =
   popOwner()
   popProcCon(c)
 
-proc semPass(): TPass =
-  initPass(result)
-  result.open = myOpen
-  result.openCached = myOpenCached
-  result.close = myClose
-  result.process = myProcess
+const semPass* = makePass(myOpen, myOpenCached, myProcess, myClose)
+
diff --git a/compiler/service.nim b/compiler/service.nim
index b1741b7bd..2ed2b75f5 100644
--- a/compiler/service.nim
+++ b/compiler/service.nim
@@ -56,17 +56,30 @@ proc ProcessCmdLine*(pass: TCmdLinePass, cmd: string) =
       rawMessage(errArgsNeedRunOption, [])
 
 proc serve*(action: proc (){.nimcall.}) =
-  var server = Socket()
-  let p = getConfigVar("server.port")
-  let port = if p.len > 0: parseInt(p).TPort else: 6000.TPort
-  server.bindAddr(port, getConfigVar("server.address"))
-  var inp = "".TaintedString
-  server.listen()
-  new(stdoutSocket)
-  while true:
-    accept(server, stdoutSocket)
-    discard stdoutSocket.recvLine(inp)
-    processCmdLine(passCmd2, inp.string)
-    action()
-    stdoutSocket.send("\c\L")
-    stdoutSocket.close()
+  let typ = getConfigVar("server.type")
+  case typ
+  of "stdin":
+    while true:
+      var line = stdin.readLine.string
+      if line == "quit": quit()
+      processCmdLine(passCmd2, line)
+      action()
+  of "tcp", "":
+    var server = Socket()
+    let p = getConfigVar("server.port")
+    let port = if p.len > 0: parseInt(p).TPort else: 6000.TPort
+    server.bindAddr(port, getConfigVar("server.address"))
+    var inp = "".TaintedString
+    server.listen()
+    new(stdoutSocket)
+    while true:
+      accept(server, stdoutSocket)
+      discard stdoutSocket.recvLine(inp)
+      processCmdLine(passCmd2, inp.string)
+      action()
+      stdoutSocket.send("\c\L")
+      stdoutSocket.close()
+  else:
+    echo "Invalid server.type:", typ
+    quit 1
+
diff --git a/compiler/transf.nim b/compiler/transf.nim
index dfa4095b4..5ba997524 100755
--- a/compiler/transf.nim
+++ b/compiler/transf.nim
@@ -696,12 +696,8 @@ when false:
     result = openTransf(module, filename)
     for m in items(rd.methods): methodDef(m, true)
 
-  proc transfPass(): TPass = 
-    initPass(result)
-    result.open = openTransf
-    result.openCached = openTransfCached
-    result.process = processTransf
-    result.close = processTransf # we need to process generics too!
+  const transfPass* = makePass(openTransf, openTransfCached,
+    processTransf, processTransf) # we need to process generics too!
   
 proc transformBody*(module: PSym, n: PNode, prc: PSym): PNode =
   if nfTransf in n.flags or prc.kind in {skTemplate, skMacro}: