diff options
Diffstat (limited to 'compiler/nimconf.nim')
-rw-r--r-- | compiler/nimconf.nim | 110 |
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() |