big refactoring: parser compiles again
This commit is contained in:
parent
79ec95a9b5
commit
61e57cfa13
15 changed files with 1156 additions and 1228 deletions
|
|
@ -11,7 +11,7 @@
|
|||
|
||||
import
|
||||
llstream, nversion, commands, os, strutils, msgs, platform, condsyms, lexer,
|
||||
options, idents, wordrecg, strtabs
|
||||
options, idents, wordrecg, strtabs, configuration
|
||||
|
||||
# ---------------- configuration file parser -----------------------------
|
||||
# we use Nim's scanner here to save space and work
|
||||
|
|
@ -27,12 +27,12 @@ proc parseAtom(L: var TLexer, tok: var TToken; config: ConfigRef): bool =
|
|||
ppGetTok(L, tok)
|
||||
result = parseExpr(L, tok, config)
|
||||
if tok.tokType == tkParRi: ppGetTok(L, tok)
|
||||
else: lexMessage(L, errTokenExpected, "\')\'")
|
||||
else: lexMessage(L, errGenerated, "expected closing ')'")
|
||||
elif tok.ident.id == ord(wNot):
|
||||
ppGetTok(L, tok)
|
||||
result = not parseAtom(L, tok, config)
|
||||
else:
|
||||
result = isDefined(tok.ident)
|
||||
result = isDefined(config, tok.ident.s)
|
||||
ppGetTok(L, tok)
|
||||
|
||||
proc parseAndExpr(L: var TLexer, tok: var TToken; config: ConfigRef): bool =
|
||||
|
|
@ -53,12 +53,12 @@ proc evalppIf(L: var TLexer, tok: var TToken; config: ConfigRef): bool =
|
|||
ppGetTok(L, tok) # skip 'if' or 'elif'
|
||||
result = parseExpr(L, tok, config)
|
||||
if tok.tokType == tkColon: ppGetTok(L, tok)
|
||||
else: lexMessage(L, errTokenExpected, "\':\'")
|
||||
else: lexMessage(L, errGenerated, "expected ':'")
|
||||
|
||||
var condStack: seq[bool] = @[]
|
||||
#var condStack: seq[bool] = @[]
|
||||
|
||||
proc doEnd(L: var TLexer, tok: var TToken) =
|
||||
if high(condStack) < 0: lexMessage(L, errTokenExpected, "@if")
|
||||
proc doEnd(L: var TLexer, tok: var TToken; condStack: var seq[bool]) =
|
||||
if high(condStack) < 0: lexMessage(L, errGenerated, "expected @if")
|
||||
ppGetTok(L, tok) # skip 'end'
|
||||
setLen(condStack, high(condStack))
|
||||
|
||||
|
|
@ -66,20 +66,22 @@ type
|
|||
TJumpDest = enum
|
||||
jdEndif, jdElseEndif
|
||||
|
||||
proc jumpToDirective(L: var TLexer, tok: var TToken, dest: TJumpDest; config: ConfigRef)
|
||||
proc doElse(L: var TLexer, tok: var TToken; config: ConfigRef) =
|
||||
if high(condStack) < 0: lexMessage(L, errTokenExpected, "@if")
|
||||
proc jumpToDirective(L: var TLexer, tok: var TToken, dest: TJumpDest; config: ConfigRef;
|
||||
condStack: var seq[bool])
|
||||
proc doElse(L: var TLexer, tok: var TToken; 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)
|
||||
if condStack[high(condStack)]: jumpToDirective(L, tok, jdEndif, config, condStack)
|
||||
|
||||
proc doElif(L: var TLexer, tok: var TToken; config: ConfigRef) =
|
||||
if high(condStack) < 0: lexMessage(L, errTokenExpected, "@if")
|
||||
proc doElif(L: var TLexer, tok: var TToken; 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)
|
||||
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 TLexer, tok: var TToken, dest: TJumpDest; config: ConfigRef;
|
||||
condStack: var seq[bool]) =
|
||||
var nestedIfs = 0
|
||||
while true:
|
||||
if tok.ident != nil and tok.ident.s == "@":
|
||||
|
|
@ -89,36 +91,36 @@ proc jumpToDirective(L: var TLexer, tok: var TToken, dest: TJumpDest; config: Co
|
|||
inc(nestedIfs)
|
||||
of wElse:
|
||||
if dest == jdElseEndif and nestedIfs == 0:
|
||||
doElse(L, tok, config)
|
||||
doElse(L, tok, config, condStack)
|
||||
break
|
||||
of wElif:
|
||||
if dest == jdElseEndif and nestedIfs == 0:
|
||||
doElif(L, tok, config)
|
||||
doElif(L, tok, config, condStack)
|
||||
break
|
||||
of wEnd:
|
||||
if nestedIfs == 0:
|
||||
doEnd(L, tok)
|
||||
doEnd(L, tok, condStack)
|
||||
break
|
||||
if nestedIfs > 0: dec(nestedIfs)
|
||||
else:
|
||||
discard
|
||||
ppGetTok(L, tok)
|
||||
elif tok.tokType == tkEof:
|
||||
lexMessage(L, errTokenExpected, "@end")
|
||||
lexMessage(L, errGenerated, "expected @end")
|
||||
else:
|
||||
ppGetTok(L, tok)
|
||||
|
||||
proc parseDirective(L: var TLexer, tok: var TToken; config: ConfigRef) =
|
||||
proc parseDirective(L: var TLexer, tok: var TToken; config: ConfigRef; condStack: var seq[bool]) =
|
||||
ppGetTok(L, tok) # skip @
|
||||
case whichKeyword(tok.ident)
|
||||
of wIf:
|
||||
setLen(condStack, len(condStack) + 1)
|
||||
let res = evalppIf(L, tok, config)
|
||||
condStack[high(condStack)] = res
|
||||
if not res: jumpToDirective(L, tok, jdElseEndif, config)
|
||||
of wElif: doElif(L, tok, config)
|
||||
of wElse: doElse(L, tok, config)
|
||||
of wEnd: doEnd(L, tok)
|
||||
if not res: jumpToDirective(L, tok, jdElseEndif, config, condStack)
|
||||
of wElif: doElif(L, tok, config, condStack)
|
||||
of wElse: doElse(L, tok, config, condStack)
|
||||
of wEnd: doEnd(L, tok, condStack)
|
||||
of wWrite:
|
||||
ppGetTok(L, tok)
|
||||
msgs.msgWriteln(strtabs.`%`(tokToStr(tok), options.gConfigVars,
|
||||
|
|
@ -144,53 +146,55 @@ proc parseDirective(L: var TLexer, tok: var TToken; config: ConfigRef) =
|
|||
ppGetTok(L, tok)
|
||||
os.putEnv(key, os.getEnv(key) & tokToStr(tok))
|
||||
ppGetTok(L, tok)
|
||||
else: lexMessage(L, errInvalidDirectiveX, tokToStr(tok))
|
||||
else:
|
||||
lexMessage(L, errGenerated, "invalid directive: '$1'" % tokToStr(tok))
|
||||
|
||||
proc confTok(L: var TLexer, tok: var TToken; config: ConfigRef) =
|
||||
proc confTok(L: var TLexer, tok: var TToken; config: ConfigRef; condStack: var seq[bool]) =
|
||||
ppGetTok(L, tok)
|
||||
while tok.ident != nil and tok.ident.s == "@":
|
||||
parseDirective(L, tok, config) # else: give the token to the parser
|
||||
parseDirective(L, tok, config, condStack) # else: give the token to the parser
|
||||
|
||||
proc checkSymbol(L: TLexer, tok: TToken) =
|
||||
if tok.tokType notin {tkSymbol..tkInt64Lit, tkStrLit..tkTripleStrLit}:
|
||||
lexMessage(L, errIdentifierExpected, tokToStr(tok))
|
||||
lexMessage(L, errGenerated, "expected identifier, but got: " & tokToStr(tok))
|
||||
|
||||
proc parseAssignment(L: var TLexer, tok: var TToken; config: ConfigRef) =
|
||||
proc parseAssignment(L: var TLexer, tok: var TToken;
|
||||
config: ConfigRef; condStack: var seq[bool]) =
|
||||
if tok.ident.s == "-" or tok.ident.s == "--":
|
||||
confTok(L, tok, config) # skip unnecessary prefix
|
||||
confTok(L, tok, config, condStack) # skip unnecessary prefix
|
||||
var info = getLineInfo(L, tok) # save for later in case of an error
|
||||
checkSymbol(L, tok)
|
||||
var s = tokToStr(tok)
|
||||
confTok(L, tok, config) # skip symbol
|
||||
confTok(L, tok, config, condStack) # skip symbol
|
||||
var val = ""
|
||||
while tok.tokType == tkDot:
|
||||
add(s, '.')
|
||||
confTok(L, tok, config)
|
||||
confTok(L, tok, config, condStack)
|
||||
checkSymbol(L, tok)
|
||||
add(s, tokToStr(tok))
|
||||
confTok(L, tok, config)
|
||||
confTok(L, tok, config, condStack)
|
||||
if tok.tokType == tkBracketLe:
|
||||
# BUGFIX: val, not s!
|
||||
# BUGFIX: do not copy '['!
|
||||
confTok(L, tok, config)
|
||||
confTok(L, tok, config, condStack)
|
||||
checkSymbol(L, tok)
|
||||
add(val, tokToStr(tok))
|
||||
confTok(L, tok, config)
|
||||
if tok.tokType == tkBracketRi: confTok(L, tok, config)
|
||||
else: lexMessage(L, errTokenExpected, "']'")
|
||||
confTok(L, tok, config, condStack)
|
||||
if tok.tokType == tkBracketRi: confTok(L, tok, config, condStack)
|
||||
else: lexMessage(L, errGenerated, "expected closing ']'")
|
||||
add(val, ']')
|
||||
let percent = tok.ident != nil and tok.ident.s == "%="
|
||||
if tok.tokType in {tkColon, tkEquals} or percent:
|
||||
if len(val) > 0: add(val, ':')
|
||||
confTok(L, tok, config) # skip ':' or '=' or '%'
|
||||
confTok(L, tok, config, condStack) # skip ':' or '=' or '%'
|
||||
checkSymbol(L, tok)
|
||||
add(val, tokToStr(tok))
|
||||
confTok(L, tok, config) # skip symbol
|
||||
confTok(L, tok, config, condStack) # skip symbol
|
||||
while tok.ident != nil and tok.ident.s == "&":
|
||||
confTok(L, tok, config)
|
||||
confTok(L, tok, config, condStack)
|
||||
checkSymbol(L, tok)
|
||||
add(val, tokToStr(tok))
|
||||
confTok(L, tok, config)
|
||||
confTok(L, tok, config, condStack)
|
||||
if percent:
|
||||
processSwitch(s, strtabs.`%`(val, options.gConfigVars,
|
||||
{useEnvironment, useEmpty}), passPP, info, config)
|
||||
|
|
@ -207,34 +211,35 @@ proc readConfigFile(filename: string; cache: IdentCache; config: ConfigRef) =
|
|||
initToken(tok)
|
||||
openLexer(L, filename, stream, cache, config)
|
||||
tok.tokType = tkEof # to avoid a pointless warning
|
||||
confTok(L, tok, config) # read in the first token
|
||||
while tok.tokType != tkEof: parseAssignment(L, tok, config)
|
||||
if len(condStack) > 0: lexMessage(L, errTokenExpected, "@end")
|
||||
var condStack: seq[bool] = @[]
|
||||
confTok(L, tok, config, condStack) # read in the first token
|
||||
while tok.tokType != tkEof: parseAssignment(L, tok, config, condStack)
|
||||
if len(condStack) > 0: lexMessage(L, errGenerated, "expected @end")
|
||||
closeLexer(L)
|
||||
rawMessage(hintConf, filename)
|
||||
rawMessage(config, hintConf, filename)
|
||||
|
||||
proc getUserConfigPath(filename: string): string =
|
||||
result = joinPath(getConfigDir(), filename)
|
||||
|
||||
proc getSystemConfigPath(filename: string): string =
|
||||
proc getSystemConfigPath(conf: ConfigRef; filename: string): string =
|
||||
# try standard configuration file (installation did not distribute files
|
||||
# the UNIX way)
|
||||
let p = getPrefixDir()
|
||||
let p = getPrefixDir(conf)
|
||||
result = joinPath([p, "config", filename])
|
||||
when defined(unix):
|
||||
if not existsFile(result): result = joinPath([p, "etc", filename])
|
||||
if not existsFile(result): result = "/etc/" & filename
|
||||
|
||||
proc loadConfigs*(cfg: string; cache: IdentCache; config: ConfigRef = nil) =
|
||||
setDefaultLibpath()
|
||||
setDefaultLibpath(config)
|
||||
|
||||
if optSkipConfigFile notin gGlobalOptions:
|
||||
readConfigFile(getSystemConfigPath(cfg), cache, config)
|
||||
readConfigFile(getSystemConfigPath(config, cfg), cache, config)
|
||||
|
||||
if optSkipUserConfigFile notin gGlobalOptions:
|
||||
readConfigFile(getUserConfigPath(cfg), cache, config)
|
||||
|
||||
var pd = if gProjectPath.len > 0: gProjectPath else: getCurrentDir()
|
||||
let pd = if gProjectPath.len > 0: gProjectPath else: getCurrentDir()
|
||||
if optSkipParentConfigFiles notin gGlobalOptions:
|
||||
for dir in parentDirs(pd, fromRoot=true, inclusive=false):
|
||||
readConfigFile(dir / cfg, cache, config)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue