summary refs log tree commit diff stats
path: root/tests/exception/tfinally3.nim
blob: 6098672a22a62c85fb04eb9cbebfb347e3e698df (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
discard """
  file: "tfinally3.nim"
  outputsub: '''false
Within finally->try'''
  exitCode: 1
"""
# Test break in try statement:

proc main: bool =
  while true:
    try:
      return true
    finally:
      break
  return false

echo main() #OUT false

# bug #5871
try:
  raise newException(Exception, "First")
finally:
  try:
    raise newException(Exception, "Within finally->try")
  except:
    echo getCurrentExceptionMsg()
0000; background-color: #ddffdd } /* Generic.Inserted */ .highlight .go { color: #888888 } /* Generic.Output */ .highlight .gp { color: #555555 } /* Generic.Prompt */ .highlight .gs { font-weight: bold } /* Generic.Strong */ .highlight .gu { color: #666666 } /* Generic.Subheading */ .highlight .gt { color: #aa0000 } /* Generic.Traceback */ .highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */ .highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */ .highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */ .highlight .kp { color: #008800 } /* Keyword.Pseudo */ .highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */ .highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */ .highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */ .highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */ .highlight .na { color: #336699 } /* Name.Attribute */ .highlight .nb { color: #003388 } /* Name.Builtin */ .highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */ .highlight .no { color: #003366; font-weight: bold } /* Name.Constant */ .highlight .nd { color: #555555 } /* Name.Decorator */ .highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */ .highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */ .highlight .nl { color: #336699; font-style: italic } /* Name.Label */ .highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */ .highlight .py { color: #336699; font-weight: bold } /* Name.Property */ .highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */ .highlight .nv { color: #336699 } /* Name.Variable */ .highlight .ow { color: #008800 } /* Operator.Word */ .highlight .w { color: #bbbbbb } /* Text.Whitespace */ .highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */ .highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */ .highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */ .highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */ .highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */ .highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */ .highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */ .highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */ .highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */ .highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */ .highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */ .highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */ .highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */ .highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */ .highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */ .highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */ .highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */ .highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */ .highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */ .highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */ .highlight .vc { color: #336699 } /* Name.Variable.Class */ .highlight .vg { color: #dd7700 } /* Name.Variable.Global */ .highlight .vi { color: #3333bb } /* Name.Variable.Instance */ .highlight .vm { color: #336699 } /* Name.Variable.Magic */ .highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
#
#
#           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

# ---------------- 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 in {tkInd, tkSad, tkDed, 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)
    ppGetTok(L, tok)

proc parseAndExpr(L: var TLexer, tok: PToken): bool = 
  result = parseAtom(L, tok)
  while tok.ident.id == ord(wAnd): 
    ppGetTok(L, tok)          # skip "and"
    var b = parseAtom(L, tok)
    result = result and b

proc parseExpr(L: var TLexer, tok: PToken): bool = 
  result = parseAndExpr(L, tok)
  while tok.ident.id == ord(wOr): 
    ppGetTok(L, tok)          # skip "or"
    var 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] = @[]

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) = 
  if high(condStack) < 0: lexMessage(L, errTokenExpected, "@if")
  var 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 = 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) = 
  ppGetTok(L, tok)            # skip @
  case whichKeyword(tok.ident)
  of wIf: 
    setlen(condStack, len(condStack) + 1)
    var 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)
    var key = tokToStr(tok)
    ppGetTok(L, tok)
    os.putEnv(key, tokToStr(tok))
    ppGetTok(L, tok)
  of wPrependEnv: 
    ppGetTok(L, tok)
    var key = tokToStr(tok)
    ppGetTok(L, tok)
    os.putEnv(key, tokToStr(tok) & os.getenv(key))
    ppGetTok(L, tok)
  of wAppendenv: 
    ppGetTok(L, tok)
    var 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 tok.tokType notin {tkSymbol..pred(tkIntLit), tkStrLit..tkTripleStrLit}: 
    lexMessage(L, errIdentifierExpected, tokToStr(tok))
  
proc parseAssignment(L: var TLexer, tok: PToken) = 
  if tok.ident.id == getIdent("-").id or tok.ident.id == getIdent("--").id:
    confTok(L, tok)           # skip unnecessary prefix
  var info = getLineInfo(L)   # safe for later in case of an error
  checkSymbol(L, tok)
  var s = tokToStr(tok)
  confTok(L, tok)             # skip symbol
  var 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 in {tkColon, tkEquals}: 
    if len(val) > 0: add(val, ':')
    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 optSkipConfigFile notin gGlobalOptions:
    readConfigFile(getConfigPath(configfilename))
  
proc LoadConfig*(project: string) = 
  # set default value (can be overwritten):
  if libpath == "": 
    # choose default libpath:
    var 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 optSkipProjConfigFile notin gGlobalOptions and project != "": 
    var conffile = changeFileExt(project, "cfg")
    if existsFile(conffile): readConfigFile(conffile)