summary refs log tree commit diff stats
path: root/compiler/nimconf.nim
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/nimconf.nim')
-rw-r--r--compiler/nimconf.nim110
1 files changed, 78 insertions, 32 deletions
diff --git a/compiler/nimconf.nim b/compiler/nimconf.nim
index 93cc21573..5417cd1e9 100644
--- a/compiler/nimconf.nim
+++ b/compiler/nimconf.nim
@@ -10,19 +10,24 @@
 # This module handles the reading of the config file.
 
 import
-  llstream, commands, os, strutils, msgs, lexer,
-  options, idents, wordrecg, strtabs, lineinfos, pathutils
+  llstream, commands, msgs, lexer, ast,
+  options, idents, wordrecg, lineinfos, pathutils, scriptconfig
+
+import std/[os, strutils, strtabs]
+
+when defined(nimPreviewSlimSystem):
+  import std/syncio
 
 # ---------------- configuration file parser -----------------------------
-# we use Nim's scanner here to save space and work
+# we use Nim's lexer here to save space and work
 
-proc ppGetTok(L: var TLexer, tok: var TToken) =
+proc ppGetTok(L: var Lexer, tok: var Token) =
   # simple filter
   rawGetTok(L, tok)
   while tok.tokType in {tkComment}: rawGetTok(L, tok)
 
-proc parseExpr(L: var TLexer, tok: var TToken; config: ConfigRef): bool
-proc parseAtom(L: var TLexer, tok: var TToken; config: ConfigRef): bool =
+proc parseExpr(L: var Lexer, tok: var Token; config: ConfigRef): bool
+proc parseAtom(L: var Lexer, tok: var Token; config: ConfigRef): bool =
   if tok.tokType == tkParLe:
     ppGetTok(L, tok)
     result = parseExpr(L, tok, config)
@@ -35,21 +40,21 @@ proc parseAtom(L: var TLexer, tok: var TToken; config: ConfigRef): bool =
     result = isDefined(config, tok.ident.s)
     ppGetTok(L, tok)
 
-proc parseAndExpr(L: var TLexer, tok: var TToken; config: ConfigRef): bool =
+proc parseAndExpr(L: var Lexer, tok: var Token; config: ConfigRef): bool =
   result = parseAtom(L, tok, config)
   while tok.tokType == tkAnd:
     ppGetTok(L, tok)          # skip "and"
     var b = parseAtom(L, tok, config)
     result = result and b
 
-proc parseExpr(L: var TLexer, tok: var TToken; config: ConfigRef): bool =
+proc parseExpr(L: var Lexer, tok: var Token; config: ConfigRef): bool =
   result = parseAndExpr(L, tok, config)
   while tok.tokType == tkOr:
     ppGetTok(L, tok)          # skip "or"
     var b = parseAndExpr(L, tok, config)
     result = result or b
 
-proc evalppIf(L: var TLexer, tok: var TToken; config: ConfigRef): bool =
+proc evalppIf(L: var Lexer, tok: var Token; config: ConfigRef): bool =
   ppGetTok(L, tok)            # skip 'if' or 'elif'
   result = parseExpr(L, tok, config)
   if tok.tokType == tkColon: ppGetTok(L, tok)
@@ -57,7 +62,7 @@ proc evalppIf(L: var TLexer, tok: var TToken; config: ConfigRef): bool =
 
 #var condStack: seq[bool] = @[]
 
-proc doEnd(L: var TLexer, tok: var TToken; condStack: var seq[bool]) =
+proc doEnd(L: var Lexer, tok: var Token; condStack: var seq[bool]) =
   if high(condStack) < 0: lexMessage(L, errGenerated, "expected @if")
   ppGetTok(L, tok)            # skip 'end'
   setLen(condStack, high(condStack))
@@ -66,21 +71,21 @@ type
   TJumpDest = enum
     jdEndif, jdElseEndif
 
-proc jumpToDirective(L: var TLexer, tok: var TToken, dest: TJumpDest; config: ConfigRef;
+proc jumpToDirective(L: var Lexer, tok: var Token, dest: TJumpDest; config: ConfigRef;
                      condStack: var seq[bool])
-proc doElse(L: var TLexer, tok: var TToken; config: ConfigRef; condStack: var seq[bool]) =
+proc doElse(L: var Lexer, tok: var Token; config: ConfigRef; condStack: var seq[bool]) =
   if high(condStack) < 0: lexMessage(L, errGenerated, "expected @if")
   ppGetTok(L, tok)
   if tok.tokType == tkColon: ppGetTok(L, tok)
   if condStack[high(condStack)]: jumpToDirective(L, tok, jdEndif, config, condStack)
 
-proc doElif(L: var TLexer, tok: var TToken; config: ConfigRef; condStack: var seq[bool]) =
+proc doElif(L: var Lexer, tok: var Token; config: ConfigRef; condStack: var seq[bool]) =
   if high(condStack) < 0: lexMessage(L, errGenerated, "expected @if")
   var res = evalppIf(L, tok, config)
   if condStack[high(condStack)] or not res: jumpToDirective(L, tok, jdElseEndif, config, condStack)
   else: condStack[high(condStack)] = true
 
-proc jumpToDirective(L: var TLexer, tok: var TToken, dest: TJumpDest; config: ConfigRef;
+proc jumpToDirective(L: var Lexer, tok: var Token, dest: TJumpDest; config: ConfigRef;
                      condStack: var seq[bool]) =
   var nestedIfs = 0
   while true:
@@ -110,7 +115,7 @@ proc jumpToDirective(L: var TLexer, tok: var TToken, dest: TJumpDest; config: Co
     else:
       ppGetTok(L, tok)
 
-proc parseDirective(L: var TLexer, tok: var TToken; config: ConfigRef; condStack: var seq[bool]) =
+proc parseDirective(L: var Lexer, tok: var Token; config: ConfigRef; condStack: var seq[bool]) =
   ppGetTok(L, tok)            # skip @
   case whichKeyword(tok.ident)
   of wIf:
@@ -149,17 +154,17 @@ proc parseDirective(L: var TLexer, tok: var TToken; config: ConfigRef; condStack
     else:
       lexMessage(L, errGenerated, "invalid directive: '$1'" % $tok)
 
-proc confTok(L: var TLexer, tok: var TToken; config: ConfigRef; condStack: var seq[bool]) =
+proc confTok(L: var Lexer, tok: var Token; config: ConfigRef; condStack: var seq[bool]) =
   ppGetTok(L, tok)
   while tok.ident != nil and tok.ident.s == "@":
     parseDirective(L, tok, config, condStack)    # else: give the token to the parser
 
-proc checkSymbol(L: TLexer, tok: TToken) =
+proc checkSymbol(L: Lexer, tok: Token) =
   if tok.tokType notin {tkSymbol..tkInt64Lit, tkStrLit..tkTripleStrLit}:
     lexMessage(L, errGenerated, "expected identifier, but got: " & $tok)
 
-proc parseAssignment(L: var TLexer, tok: var TToken;
-                     config: ConfigRef; condStack: var seq[bool]) =
+proc parseAssignment(L: var Lexer, tok: var Token;
+                     config: ConfigRef; filename: AbsoluteFile; condStack: var seq[bool]) =
   if tok.ident != nil:
     if tok.ident.s == "-" or tok.ident.s == "--":
       confTok(L, tok, config, condStack)           # skip unnecessary prefix
@@ -202,6 +207,7 @@ proc parseAssignment(L: var TLexer, tok: var TToken;
       checkSymbol(L, tok)
       val.add($tok)
       confTok(L, tok, config, condStack)
+  config.currentConfigDir = parentDir(filename.string)
   if percent:
     processSwitch(s, strtabs.`%`(val, config.configVars,
                                 {useEnvironment, useEmpty}), passPP, info, config)
@@ -211,20 +217,21 @@ proc parseAssignment(L: var TLexer, tok: var TToken;
 proc readConfigFile*(filename: AbsoluteFile; cache: IdentCache;
                     config: ConfigRef): bool =
   var
-    L: TLexer
-    tok: TToken
+    L: Lexer = default(Lexer)
+    tok: Token
     stream: PLLStream
   stream = llStreamOpen(filename, fmRead)
   if stream != nil:
-    initToken(tok)
     openLexer(L, filename, stream, cache, config)
-    tok.tokType = tkEof       # to avoid a pointless warning
+    tok = Token(tokType: tkEof)       # to avoid a pointless warning
     var condStack: seq[bool] = @[]
     confTok(L, tok, config, condStack)           # read in the first token
-    while tok.tokType != tkEof: parseAssignment(L, tok, config, condStack)
+    while tok.tokType != tkEof: parseAssignment(L, tok, config, filename, condStack)
     if condStack.len > 0: lexMessage(L, errGenerated, "expected @end")
     closeLexer(L)
     return true
+  else:
+    result = false
 
 proc getUserConfigPath*(filename: RelativeFile): AbsoluteFile =
   result = getConfigDir().AbsoluteDir / RelativeDir"nim" / filename
@@ -238,29 +245,48 @@ proc getSystemConfigPath*(conf: ConfigRef; filename: RelativeFile): AbsoluteFile
     if not fileExists(result): result = p / RelativeDir"etc/nim" / filename
     if not fileExists(result): result = AbsoluteDir"/etc/nim" / filename
 
-proc loadConfigs*(cfg: RelativeFile; cache: IdentCache; conf: ConfigRef) =
+proc loadConfigs*(cfg: RelativeFile; cache: IdentCache; conf: ConfigRef; idgen: IdGenerator) =
   setDefaultLibpath(conf)
-
-  var configFiles = newSeq[AbsoluteFile]()
-
   template readConfigFile(path) =
     let configPath = path
     if readConfigFile(configPath, cache, conf):
-      configFiles.add(configPath)
+      conf.configFiles.add(configPath)
+
+  template runNimScriptIfExists(path: AbsoluteFile, isMain = false) =
+    let p = path # eval once
+    var s: PLLStream = nil
+    if isMain and optWasNimscript in conf.globalOptions:
+      if conf.projectIsStdin: s = stdin.llStreamOpen
+      elif conf.projectIsCmd: s = llStreamOpen(conf.cmdInput)
+    if s == nil and fileExists(p): s = llStreamOpen(p, fmRead)
+    if s != nil:
+      conf.configFiles.add(p)
+      runNimScript(cache, p, idgen, freshDefines = false, conf, s)
 
   if optSkipSystemConfigFile notin conf.globalOptions:
     readConfigFile(getSystemConfigPath(conf, cfg))
 
+    if cfg == DefaultConfig:
+      runNimScriptIfExists(getSystemConfigPath(conf, DefaultConfigNims))
+
   if optSkipUserConfigFile notin conf.globalOptions:
     readConfigFile(getUserConfigPath(cfg))
 
+    if cfg == DefaultConfig:
+      runNimScriptIfExists(getUserConfigPath(DefaultConfigNims))
+
   let pd = if not conf.projectPath.isEmpty: conf.projectPath else: AbsoluteDir(getCurrentDir())
   if optSkipParentConfigFiles notin conf.globalOptions:
     for dir in parentDirs(pd.string, fromRoot=true, inclusive=false):
       readConfigFile(AbsoluteDir(dir) / cfg)
 
+      if cfg == DefaultConfig:
+        runNimScriptIfExists(AbsoluteDir(dir) / DefaultConfigNims)
+
   if optSkipProjConfigFile notin conf.globalOptions:
     readConfigFile(pd / cfg)
+    if cfg == DefaultConfig:
+      runNimScriptIfExists(pd / DefaultConfigNims)
 
     if conf.projectName.len != 0:
       # new project wide config file:
@@ -269,6 +295,26 @@ proc loadConfigs*(cfg: RelativeFile; cache: IdentCache; conf: ConfigRef) =
         projectConfig = changeFileExt(conf.projectFull, "nim.cfg")
       readConfigFile(projectConfig)
 
-  for filename in configFiles:
-    # delayed to here so that `hintConf` is honored
-    rawMessage(conf, hintConf, filename.string)
+
+  let scriptFile = conf.projectFull.changeFileExt("nims")
+  let scriptIsProj = scriptFile == conf.projectFull
+  template showHintConf =
+    for filename in conf.configFiles:
+      # delayed to here so that `hintConf` is honored
+      rawMessage(conf, hintConf, filename.string)
+  if conf.cmd == cmdNimscript:
+    showHintConf()
+    conf.configFiles.setLen 0
+  if conf.cmd notin {cmdIdeTools, cmdCheck, cmdDump}:
+    if conf.cmd == cmdNimscript:
+      runNimScriptIfExists(conf.projectFull, isMain = true)
+    else:
+      runNimScriptIfExists(scriptFile, isMain = true)
+  else:
+    if not scriptIsProj:
+      runNimScriptIfExists(scriptFile, isMain = true)
+    else:
+      # 'nimsuggest foo.nims' means to just auto-complete the NimScript file
+      # `nim check foo.nims' means to check the syntax of the NimScript file
+      discard
+  showHintConf()