summary refs log tree commit diff stats
path: root/compiler/nimconf.nim
diff options
context:
space:
mode:
authorAraq <rumpf_a@web.de>2011-04-12 01:13:42 +0200
committerAraq <rumpf_a@web.de>2011-04-12 01:13:42 +0200
commitcd292568d775d55d9abb51e962882ecda12c03a9 (patch)
tree85451f0e1f17dc0463350915f12bdd0a82a73455 /compiler/nimconf.nim
parent46c41e43690cba9bc1caff6a994bb6915df8a1b7 (diff)
downloadNim-cd292568d775d55d9abb51e962882ecda12c03a9.tar.gz
big repo cleanup
Diffstat (limited to 'compiler/nimconf.nim')
-rwxr-xr-xcompiler/nimconf.nim257
1 files changed, 257 insertions, 0 deletions
diff --git a/compiler/nimconf.nim b/compiler/nimconf.nim
new file mode 100755
index 000000000..c41417fb1
--- /dev/null
+++ b/compiler/nimconf.nim
@@ -0,0 +1,257 @@
+#
+#
+#           The Nimrod Compiler
+#        (c) Copyright 2011 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+# This module handles the reading of the config file.
+
+import 
+  llstream, nversion, commands, os, strutils, msgs, platform, condsyms, scanner, 
+  options, idents, wordrecg
+
+proc LoadConfig*(project: string)
+proc LoadSpecialConfig*(configfilename: string)
+# implementation
+# ---------------- configuration file parser -----------------------------
+# we use Nimrod's scanner here to safe space and work
+
+proc ppGetTok(L: var TLexer, tok: PToken) = 
+  # simple filter
+  rawGetTok(L, tok[] )
+  while (tok.tokType == tkInd) or (tok.tokType == tkSad) or
+      (tok.tokType == tkDed) or (tok.tokType == tkComment): 
+    rawGetTok(L, tok[] )
+  
+proc parseExpr(L: var TLexer, tok: PToken): bool
+proc parseAtom(L: var TLexer, tok: PToken): bool = 
+  if tok.tokType == tkParLe: 
+    ppGetTok(L, tok)
+    result = parseExpr(L, tok)
+    if tok.tokType == tkParRi: ppGetTok(L, tok)
+    else: lexMessage(L, errTokenExpected, "\')\'")
+  elif tok.ident.id == ord(wNot): 
+    ppGetTok(L, tok)
+    result = not parseAtom(L, tok)
+  else: 
+    result = isDefined(tok.ident) #condsyms.listSymbols();
+                                  #writeln(tok.ident.s + ' has the value: ', result);
+    ppGetTok(L, tok)
+
+proc parseAndExpr(L: var TLexer, tok: PToken): bool = 
+  var b: bool
+  result = parseAtom(L, tok)
+  while tok.ident.id == ord(wAnd): 
+    ppGetTok(L, tok)          # skip "and"
+    b = parseAtom(L, tok)
+    result = result and b
+
+proc parseExpr(L: var TLexer, tok: PToken): bool = 
+  var b: bool
+  result = parseAndExpr(L, tok)
+  while tok.ident.id == ord(wOr): 
+    ppGetTok(L, tok)          # skip "or"
+    b = parseAndExpr(L, tok)
+    result = result or b
+
+proc EvalppIf(L: var TLexer, tok: PToken): bool = 
+  ppGetTok(L, tok)            # skip 'if' or 'elif'
+  result = parseExpr(L, tok)
+  if tok.tokType == tkColon: ppGetTok(L, tok)
+  else: lexMessage(L, errTokenExpected, "\':\'")
+  
+var condStack: seq[bool]
+
+condStack = @ []
+proc doEnd(L: var TLexer, tok: PToken) = 
+  if high(condStack) < 0: lexMessage(L, errTokenExpected, "@if")
+  ppGetTok(L, tok)            # skip 'end'
+  setlen(condStack, high(condStack))
+
+type 
+  TJumpDest = enum 
+    jdEndif, jdElseEndif
+
+proc jumpToDirective(L: var TLexer, tok: PToken, dest: TJumpDest)
+proc doElse(L: var TLexer, tok: PToken) = 
+  if high(condStack) < 0: lexMessage(L, errTokenExpected, "@if")
+  ppGetTok(L, tok)
+  if tok.tokType == tkColon: ppGetTok(L, tok)
+  if condStack[high(condStack)]: jumpToDirective(L, tok, jdEndif)
+  
+proc doElif(L: var TLexer, tok: PToken) = 
+  var res: bool
+  if high(condStack) < 0: lexMessage(L, errTokenExpected, "@if")
+  res = EvalppIf(L, tok)
+  if condStack[high(condStack)] or not res: jumpToDirective(L, tok, jdElseEndif)
+  else: condStack[high(condStack)] = true
+  
+proc jumpToDirective(L: var TLexer, tok: PToken, dest: TJumpDest) = 
+  var nestedIfs: int
+  nestedIfs = 0
+  while True: 
+    if (tok.ident != nil) and (tok.ident.s == "@"): 
+      ppGetTok(L, tok)
+      case whichKeyword(tok.ident)
+      of wIf: 
+        Inc(nestedIfs)
+      of wElse: 
+        if (dest == jdElseEndif) and (nestedIfs == 0): 
+          doElse(L, tok)
+          break 
+      of wElif: 
+        if (dest == jdElseEndif) and (nestedIfs == 0): 
+          doElif(L, tok)
+          break 
+      of wEnd: 
+        if nestedIfs == 0: 
+          doEnd(L, tok)
+          break 
+        if nestedIfs > 0: Dec(nestedIfs)
+      else: 
+        nil
+      ppGetTok(L, tok)
+    elif tok.tokType == tkEof: 
+      lexMessage(L, errTokenExpected, "@end")
+    else: 
+      ppGetTok(L, tok)
+  
+proc parseDirective(L: var TLexer, tok: PToken) = 
+  var 
+    res: bool
+    key: string
+  ppGetTok(L, tok)            # skip @
+  case whichKeyword(tok.ident)
+  of wIf: 
+    setlen(condStack, len(condStack) + 1)
+    res = EvalppIf(L, tok)
+    condStack[high(condStack)] = res
+    if not res: 
+      jumpToDirective(L, tok, jdElseEndif)
+  of wElif: 
+    doElif(L, tok)
+  of wElse: 
+    doElse(L, tok)
+  of wEnd: 
+    doEnd(L, tok)
+  of wWrite: 
+    ppGetTok(L, tok)
+    msgs.MsgWriteln(tokToStr(tok))
+    ppGetTok(L, tok)
+  of wPutEnv: 
+    ppGetTok(L, tok)
+    key = tokToStr(tok)
+    ppGetTok(L, tok)
+    os.putEnv(key, tokToStr(tok))
+    ppGetTok(L, tok)
+  of wPrependEnv: 
+    ppGetTok(L, tok)
+    key = tokToStr(tok)
+    ppGetTok(L, tok)
+    os.putEnv(key, tokToStr(tok) & os.getenv(key))
+    ppGetTok(L, tok)
+  of wAppendenv: 
+    ppGetTok(L, tok)
+    key = tokToStr(tok)
+    ppGetTok(L, tok)
+    os.putEnv(key, os.getenv(key) & tokToStr(tok))
+    ppGetTok(L, tok)
+  else: lexMessage(L, errInvalidDirectiveX, tokToStr(tok))
+  
+proc confTok(L: var TLexer, tok: PToken) = 
+  ppGetTok(L, tok)
+  while (tok.ident != nil) and (tok.ident.s == "@"): 
+    parseDirective(L, tok)    # else: give the token to the parser
+  
+proc checkSymbol(L: TLexer, tok: PToken) = 
+  if not (tok.tokType in {tkSymbol..pred(tkIntLit), tkStrLit..tkTripleStrLit}): 
+    lexMessage(L, errIdentifierExpected, tokToStr(tok))
+  
+proc parseAssignment(L: var TLexer, tok: PToken) = 
+  var 
+    s, val: string
+    info: TLineInfo
+  if (tok.ident.id == getIdent("-").id) or (tok.ident.id == getIdent("--").id): 
+    confTok(L, tok)           # skip unnecessary prefix
+  info = getLineInfo(L)       # safe for later in case of an error
+  checkSymbol(L, tok)
+  s = tokToStr(tok)
+  confTok(L, tok)             # skip symbol
+  val = ""
+  while tok.tokType == tkDot: 
+    add(s, '.')
+    confTok(L, tok)
+    checkSymbol(L, tok)
+    add(s, tokToStr(tok))
+    confTok(L, tok)
+  if tok.tokType == tkBracketLe: 
+    # BUGFIX: val, not s!
+    # BUGFIX: do not copy '['!
+    confTok(L, tok)
+    checkSymbol(L, tok)
+    add(val, tokToStr(tok))
+    confTok(L, tok)
+    if tok.tokType == tkBracketRi: confTok(L, tok)
+    else: lexMessage(L, errTokenExpected, "\']\'")
+    add(val, ']')
+  if (tok.tokType == tkColon) or (tok.tokType == tkEquals): 
+    if len(val) > 0: 
+      add(val, ':')           # BUGFIX
+    confTok(L, tok)           # skip ':' or '='
+    checkSymbol(L, tok)
+    add(val, tokToStr(tok))
+    confTok(L, tok)           # skip symbol
+    while (tok.ident != nil) and (tok.ident.id == getIdent("&").id): 
+      confTok(L, tok)
+      checkSymbol(L, tok)
+      add(val, tokToStr(tok))
+      confTok(L, tok)
+  processSwitch(s, val, passPP, info)
+
+proc readConfigFile(filename: string) = 
+  var 
+    L: TLexer
+    tok: PToken
+    stream: PLLStream
+  new(tok)
+  stream = LLStreamOpen(filename, fmRead)
+  if stream != nil: 
+    openLexer(L, filename, stream)
+    tok.tokType = tkEof       # to avoid a pointless warning
+    confTok(L, tok)           # read in the first token
+    while tok.tokType != tkEof: parseAssignment(L, tok)
+    if len(condStack) > 0: lexMessage(L, errTokenExpected, "@end")
+    closeLexer(L)
+    if gVerbosity >= 1: rawMessage(hintConf, filename)
+  
+proc getConfigPath(filename: string): string = 
+  # try local configuration file:
+  result = joinPath(getConfigDir(), filename)
+  if not ExistsFile(result): 
+    # try standard configuration file (installation did not distribute files
+    # the UNIX way)
+    result = joinPath([getPrefixDir(), "config", filename])
+    if not ExistsFile(result): 
+      result = "/etc/" & filename
+
+proc LoadSpecialConfig(configfilename: string) = 
+  if not (optSkipConfigFile in gGlobalOptions): 
+    readConfigFile(getConfigPath(configfilename))
+  
+proc LoadConfig(project: string) = 
+  var conffile, prefix: string
+  # set default value (can be overwritten):
+  if libpath == "": 
+    # choose default libpath:
+    prefix = getPrefixDir()
+    if (prefix == "/usr"): libpath = "/usr/lib/nimrod"
+    elif (prefix == "/usr/local"): libpath = "/usr/local/lib/nimrod"
+    else: libpath = joinPath(prefix, "lib")
+  LoadSpecialConfig("nimrod.cfg") # read project config file:
+  if not (optSkipProjConfigFile in gGlobalOptions) and (project != ""): 
+    conffile = changeFileExt(project, "cfg")
+    if existsFile(conffile): readConfigFile(conffile)
+