This commit is contained in:
Araq
2015-04-28 20:21:53 +02:00
parent 3fa2e79814
commit 26eae7d00e
10 changed files with 317 additions and 67 deletions

View File

@@ -111,7 +111,7 @@ proc mapSetType(typ: PType): TCTypeKind =
else: result = ctArray
proc mapType(typ: PType): TCTypeKind =
## Maps a nimrod type to a C type
## Maps a Nim type to a C type
case typ.kind
of tyNone, tyStmt: result = ctVoid
of tyBool: result = ctBool

View File

@@ -89,6 +89,10 @@ proc fitNode(c: PContext, formal: PType, arg: PNode): PNode =
let x = result.skipConv
if x.kind == nkPar and formal.kind != tyExpr:
changeType(x, formal, check=true)
else:
result = skipHiddenSubConv(result)
#result.typ = takeType(formal, arg.typ)
#echo arg.info, " picked ", result.typ.typeToString
proc inferWithMetatype(c: PContext, formal: PType,
arg: PNode, coerceDistincts = false): PNode

View File

@@ -535,44 +535,45 @@ proc semArrayConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
result.sons[i] = fitNode(c, typ, result.sons[i])
result.typ.sons[0] = makeRangeType(c, 0, sonsLen(result) - 1, n.info)
proc fixAbstractType(c: PContext, n: PNode) =
# XXX finally rewrite that crap!
for i in countup(1, sonsLen(n) - 1):
var it = n.sons[i]
case it.kind
of nkHiddenStdConv, nkHiddenSubConv:
if it.sons[1].kind == nkBracket:
it.sons[1].typ = arrayConstrType(c, it.sons[1])
#it.sons[1] = semArrayConstr(c, it.sons[1])
if skipTypes(it.typ, abstractVar).kind in {tyOpenArray, tyVarargs}:
#if n.sons[0].kind == nkSym and IdentEq(n.sons[0].sym.name, "[]="):
# debug(n)
template fixAbstractType(c: PContext, n: PNode) =
when false:
# XXX finally rewrite that crap!
for i in countup(1, sonsLen(n) - 1):
var it = n.sons[i]
case it.kind
of nkHiddenStdConv, nkHiddenSubConv:
if it.sons[1].kind == nkBracket:
it.sons[1].typ = arrayConstrType(c, it.sons[1])
#it.sons[1] = semArrayConstr(c, it.sons[1])
if skipTypes(it.typ, abstractVar).kind in {tyOpenArray, tyVarargs}:
#if n.sons[0].kind == nkSym and IdentEq(n.sons[0].sym.name, "[]="):
# debug(n)
var s = skipTypes(it.sons[1].typ, abstractVar)
if s.kind == tyArrayConstr and s.sons[1].kind == tyEmpty:
s = copyType(s, getCurrOwner(), false)
skipTypes(s, abstractVar).sons[1] = elemType(
skipTypes(it.typ, abstractVar))
it.sons[1].typ = s
elif s.kind == tySequence and s.sons[0].kind == tyEmpty:
s = copyType(s, getCurrOwner(), false)
skipTypes(s, abstractVar).sons[0] = elemType(
skipTypes(it.typ, abstractVar))
it.sons[1].typ = s
var s = skipTypes(it.sons[1].typ, abstractVar)
if s.kind == tyArrayConstr and s.sons[1].kind == tyEmpty:
s = copyType(s, getCurrOwner(), false)
skipTypes(s, abstractVar).sons[1] = elemType(
skipTypes(it.typ, abstractVar))
it.sons[1].typ = s
elif s.kind == tySequence and s.sons[0].kind == tyEmpty:
s = copyType(s, getCurrOwner(), false)
skipTypes(s, abstractVar).sons[0] = elemType(
skipTypes(it.typ, abstractVar))
it.sons[1].typ = s
elif skipTypes(it.sons[1].typ, abstractVar).kind in
{tyNil, tyArrayConstr, tyTuple, tySet}:
var s = skipTypes(it.typ, abstractVar)
if s.kind != tyExpr:
changeType(it.sons[1], s, check=true)
n.sons[i] = it.sons[1]
of nkBracket:
# an implicitly constructed array (passed to an open array):
n.sons[i] = semArrayConstr(c, it, {})
else:
discard
#if (it.typ == nil):
# InternalError(it.info, "fixAbstractType: " & renderTree(it))
elif skipTypes(it.sons[1].typ, abstractVar).kind in
{tyNil, tyArrayConstr, tyTuple, tySet}:
var s = skipTypes(it.typ, abstractVar)
if s.kind != tyExpr:
changeType(it.sons[1], s, check=true)
n.sons[i] = it.sons[1]
of nkBracket:
# an implicitly constructed array (passed to an open array):
n.sons[i] = semArrayConstr(c, it, {})
else:
discard
#if (it.typ == nil):
# InternalError(it.info, "fixAbstractType: " & renderTree(it))
proc skipObjConv(n: PNode): PNode =
case n.kind

View File

@@ -431,7 +431,8 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
mExit, mInc, ast.mDec, mEcho, mSwap, mAppendStrCh,
mAppendStrStr, mAppendSeqElem, mSetLengthStr, mSetLengthSeq,
mParseExprToAst, mParseStmtToAst, mExpandToAst, mTypeTrait, mDotDot,
mNLen..mNError, mEqRef, mSlurp, mStaticExec, mNGenSym, mSpawn, mParallel:
mNLen..mNError, mEqRef, mSlurp, mStaticExec, mNGenSym, mSpawn,
mParallel, mPlugin:
discard
else: internalError(a.info, "evalOp(" & $m & ')')
@@ -544,7 +545,7 @@ proc foldConv*(n, a: PNode; check = false): PNode =
discard
else:
result = a
result.typ = n.typ
result.typ = takeType(n.typ, a.typ)
proc getArrayConstr(m: PSym, n: PNode): PNode =
if n.kind == nkBracket:

View File

@@ -187,7 +187,9 @@ proc instantiateProcType(c: PContext, pt: TIdTable,
let param = copySym(oldParam)
param.owner = prc
param.typ = result.sons[i]
param.ast = oldParam.ast.copyTree
if oldParam.ast != nil:
param.ast = fitNode(c, param.typ, oldParam.ast)
# don't be lazy here and call replaceTypeVarsN(cl, originalParams[i])!
result.n.sons[i] = newSymNode(param)
addDecl(c, param)

View File

@@ -1200,15 +1200,6 @@ proc isInlineIterator*(t: PType): bool =
result = t.kind == tyIter or
(t.kind == tyBuiltInTypeClass and t.base.kind == tyIter)
proc isEmptyContainer*(t: PType): bool =
case t.kind
of tyExpr, tyNil: result = true
of tyArray, tyArrayConstr: result = t.sons[1].kind == tyEmpty
of tySet, tySequence, tyOpenArray, tyVarargs:
result = t.sons[0].kind == tyEmpty
of tyGenericInst: result = isEmptyContainer(t.lastSon)
else: result = false
proc incMatches(m: var TCandidate; r: TTypeRelation; convMatch = 1) =
case r
of isConvertible, isIntConv: inc(m.convMatches, convMatch)
@@ -1313,7 +1304,7 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
if arg.typ == nil:
result = arg
elif skipTypes(arg.typ, abstractVar-{tyTypeDesc}).kind == tyTuple:
result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c)
result = implicitConv(nkHiddenSubConv, f, arg, m, c)
elif arg.typ.isEmptyContainer:
result = arg.copyTree
result.typ = getInstantiatedType(c, arg, m, f)
@@ -1328,7 +1319,7 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
inc(m.exactMatches)
result = arg
if skipTypes(f, abstractVar-{tyTypeDesc}).kind in {tyTuple}:
result = implicitConv(nkHiddenStdConv, f, arg, m, c)
result = implicitConv(nkHiddenSubConv, f, arg, m, c)
of isNone:
# do not do this in ``typeRel`` as it then can't infere T in ``ref T``:
if a.kind in {tyProxy, tyUnknown}:
@@ -1580,6 +1571,8 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
#assert(container == nil)
if container.isNil:
container = newNodeIT(nkBracket, n.sons[a].info, arrayConstr(c, arg))
else:
incrIndexType(container.typ)
addSon(container, arg)
setSon(m.call, formal.position + 1,
implicitConv(nkHiddenStdConv, formal.typ, container, m, c))

View File

@@ -379,6 +379,9 @@ proc transformConv(c: PTransf, n: PNode): PTransNode =
result = transformSons(c, n)
of tyOpenArray, tyVarargs:
result = transform(c, n.sons[1])
PNode(result).typ = takeType(n.typ, n.sons[1].typ)
#echo n.info, " came here and produced ", typeToString(PNode(result).typ),
# " from ", typeToString(n.typ), " and ", typeToString(n.sons[1].typ)
of tyCString:
if source.kind == tyString:
result = newTransNode(nkStringToCString, n, 1)

View File

@@ -1439,3 +1439,45 @@ proc skipConv*(n: PNode): PNode =
proc skipConvTakeType*(n: PNode): PNode =
result = n.skipConv
result.typ = n.typ
proc isEmptyContainer*(t: PType): bool =
case t.kind
of tyExpr, tyNil: result = true
of tyArray, tyArrayConstr: result = t.sons[1].kind == tyEmpty
of tySet, tySequence, tyOpenArray, tyVarargs:
result = t.sons[0].kind == tyEmpty
of tyGenericInst: result = isEmptyContainer(t.lastSon)
else: result = false
proc takeType*(formal, arg: PType): PType =
# param: openArray[string] = []
# [] is an array constructor of length 0 of type string!
if arg.kind == tyNil:
# and not (formal.kind == tyProc and formal.callConv == ccClosure):
result = formal
elif formal.kind in {tyOpenArray, tyVarargs, tySequence} and
arg.isEmptyContainer:
let a = copyType(arg.skipTypes({tyGenericInst}), arg.owner, keepId=false)
a.sons[ord(arg.kind in {tyArray, tyArrayConstr})] = formal.sons[0]
result = a
elif formal.kind == tySet and arg.kind == tySet:
result = formal
else:
result = arg
proc skipHiddenSubConv*(n: PNode): PNode =
if n.kind == nkHiddenSubConv:
# param: openArray[string] = []
# [] is an array constructor of length 0 of type string!
let formal = n.typ
result = n.sons[1]
let arg = result.typ
let dest = takeType(formal, arg)
if dest == arg and formal.kind != tyExpr:
#echo n.info, " came here for ", formal.typeToString
result = n
else:
result = copyTree(result)
result.typ = dest
else:
result = n

View File

@@ -1,6 +1,7 @@
discard """
file: "tsets.nim"
output: "Ha ein F ist in s!"
output: '''Ha ein F ist in s!
false'''
"""
# Test the handling of sets
@@ -15,30 +16,30 @@ type
TAZ = range['a'..'z']
TAZset = set[TAZ]
TTokType* = enum
TTokType* = enum
tkInvalid, tkEof,
tkSymbol,
tkAddr, tkAnd, tkAs, tkAsm, tkBlock, tkBreak, tkCase, tkCast, tkConst,
tkContinue, tkConverter, tkDiscard, tkDiv, tkElif, tkElse, tkEnd, tkEnum,
tkExcept, tkException, tkFinally, tkFor, tkFrom, tkGeneric, tkIf, tkImplies,
tkImport, tkIn, tkInclude, tkIs, tkIsnot, tkIterator, tkLambda, tkMacro,
tkMethod, tkMod, tkNil, tkNot, tkNotin, tkObject, tkOf, tkOr, tkOut, tkProc,
tkPtr, tkRaise, tkRecord, tkRef, tkReturn, tkShl, tkShr, tkTemplate, tkTry,
tkAddr, tkAnd, tkAs, tkAsm, tkBlock, tkBreak, tkCase, tkCast, tkConst,
tkContinue, tkConverter, tkDiscard, tkDiv, tkElif, tkElse, tkEnd, tkEnum,
tkExcept, tkException, tkFinally, tkFor, tkFrom, tkGeneric, tkIf, tkImplies,
tkImport, tkIn, tkInclude, tkIs, tkIsnot, tkIterator, tkLambda, tkMacro,
tkMethod, tkMod, tkNil, tkNot, tkNotin, tkObject, tkOf, tkOr, tkOut, tkProc,
tkPtr, tkRaise, tkRecord, tkRef, tkReturn, tkShl, tkShr, tkTemplate, tkTry,
tkType, tkVar, tkWhen, tkWhere, tkWhile, tkWith, tkWithout, tkXor, tkYield,
tkIntLit, tkInt8Lit, tkInt16Lit, tkInt32Lit, tkInt64Lit, tkFloatLit,
tkFloat32Lit, tkFloat64Lit, tkStrLit, tkRStrLit, tkTripleStrLit, tkCharLit,
tkRCharLit, tkParLe, tkParRi, tkBracketLe, tkBracketRi, tkCurlyLe,
tkCurlyRi, tkBracketDotLe, tkBracketDotRi,
tkCurlyDotLe, tkCurlyDotRi,
tkIntLit, tkInt8Lit, tkInt16Lit, tkInt32Lit, tkInt64Lit, tkFloatLit,
tkFloat32Lit, tkFloat64Lit, tkStrLit, tkRStrLit, tkTripleStrLit, tkCharLit,
tkRCharLit, tkParLe, tkParRi, tkBracketLe, tkBracketRi, tkCurlyLe,
tkCurlyRi, tkBracketDotLe, tkBracketDotRi,
tkCurlyDotLe, tkCurlyDotRi,
tkParDotLe, tkParDotRi,
tkComma, tkSemiColon, tkColon, tkEquals, tkDot, tkDotDot, tkHat, tkOpr,
tkComma, tkSemiColon, tkColon, tkEquals, tkDot, tkDotDot, tkHat, tkOpr,
tkComment, tkAccent, tkInd, tkSad, tkDed,
tkSpaces, tkInfixOpr, tkPrefixOpr, tkPostfixOpr
TTokTypeRange = range[tkSymbol..tkDed]
TTokTypes* = set[TTokTypeRange]
const
toktypes: TTokTypes = {TTokTypeRange(tkSymbol)..pred(tkIntLit),
toktypes: TTokTypes = {TTokTypeRange(tkSymbol)..pred(tkIntLit),
tkStrLit..tkTripleStrLit}
var
@@ -62,3 +63,142 @@ for x in low(TTokTypeRange) .. high(TTokTypeRange):
#OUT Ha ein F ist in s!
type
TMsgKind* = enum
errUnknown, errIllFormedAstX, errInternal, errCannotOpenFile, errGenerated,
errXCompilerDoesNotSupportCpp, errStringLiteralExpected,
errIntLiteralExpected, errInvalidCharacterConstant,
errClosingTripleQuoteExpected, errClosingQuoteExpected,
errTabulatorsAreNotAllowed, errInvalidToken, errLineTooLong,
errInvalidNumber, errNumberOutOfRange, errNnotAllowedInCharacter,
errClosingBracketExpected, errMissingFinalQuote, errIdentifierExpected,
errNewlineExpected,
errInvalidModuleName,
errOperatorExpected, errTokenExpected, errStringAfterIncludeExpected,
errRecursiveDependencyX, errOnOrOffExpected, errNoneSpeedOrSizeExpected,
errInvalidPragma, errUnknownPragma, errInvalidDirectiveX,
errAtPopWithoutPush, errEmptyAsm, errInvalidIndentation,
errExceptionExpected, errExceptionAlreadyHandled,
errYieldNotAllowedHere, errYieldNotAllowedInTryStmt,
errInvalidNumberOfYieldExpr, errCannotReturnExpr, errAttemptToRedefine,
errStmtInvalidAfterReturn, errStmtExpected, errInvalidLabel,
errInvalidCmdLineOption, errCmdLineArgExpected, errCmdLineNoArgExpected,
errInvalidVarSubstitution, errUnknownVar, errUnknownCcompiler,
errOnOrOffExpectedButXFound, errNoneBoehmRefcExpectedButXFound,
errNoneSpeedOrSizeExpectedButXFound, errGuiConsoleOrLibExpectedButXFound,
errUnknownOS, errUnknownCPU, errGenOutExpectedButXFound,
errArgsNeedRunOption, errInvalidMultipleAsgn, errColonOrEqualsExpected,
errExprExpected, errUndeclaredIdentifier, errUseQualifier, errTypeExpected,
errSystemNeeds, errExecutionOfProgramFailed, errNotOverloadable,
errInvalidArgForX, errStmtHasNoEffect, errXExpectsTypeOrValue,
errXExpectsArrayType, errIteratorCannotBeInstantiated, errExprXAmbiguous,
errConstantDivisionByZero, errOrdinalTypeExpected,
errOrdinalOrFloatTypeExpected, errOverOrUnderflow,
errCannotEvalXBecauseIncompletelyDefined, errChrExpectsRange0_255,
errDynlibRequiresExportc, errUndeclaredFieldX, errNilAccess,
errIndexOutOfBounds, errIndexTypesDoNotMatch, errBracketsInvalidForType,
errValueOutOfSetBounds, errFieldInitTwice, errFieldNotInit,
errExprXCannotBeCalled, errExprHasNoType, errExprXHasNoType,
errCastNotInSafeMode, errExprCannotBeCastedToX, errCommaOrParRiExpected,
errCurlyLeOrParLeExpected, errSectionExpected, errRangeExpected,
errMagicOnlyInSystem, errPowerOfTwoExpected,
errStringMayNotBeEmpty, errCallConvExpected, errProcOnlyOneCallConv,
errSymbolMustBeImported, errExprMustBeBool, errConstExprExpected,
errDuplicateCaseLabel, errRangeIsEmpty, errSelectorMustBeOfCertainTypes,
errSelectorMustBeOrdinal, errOrdXMustNotBeNegative, errLenXinvalid,
errWrongNumberOfVariables, errExprCannotBeRaised, errBreakOnlyInLoop,
errTypeXhasUnknownSize, errConstNeedsConstExpr, errConstNeedsValue,
errResultCannotBeOpenArray, errSizeTooBig, errSetTooBig,
errBaseTypeMustBeOrdinal, errInheritanceOnlyWithNonFinalObjects,
errInheritanceOnlyWithEnums, errIllegalRecursionInTypeX,
errCannotInstantiateX, errExprHasNoAddress, errXStackEscape,
errVarForOutParamNeeded,
errPureTypeMismatch, errTypeMismatch, errButExpected, errButExpectedX,
errAmbiguousCallXYZ, errWrongNumberOfArguments,
errXCannotBePassedToProcVar,
errXCannotBeInParamDecl, errPragmaOnlyInHeaderOfProc, errImplOfXNotAllowed,
errImplOfXexpected, errNoSymbolToBorrowFromFound, errDiscardValueX,
errInvalidDiscard, errIllegalConvFromXtoY, errCannotBindXTwice,
errInvalidOrderInArrayConstructor,
errInvalidOrderInEnumX, errEnumXHasHoles, errExceptExpected, errInvalidTry,
errOptionExpected, errXisNoLabel, errNotAllCasesCovered,
errUnknownSubstitionVar, errComplexStmtRequiresInd, errXisNotCallable,
errNoPragmasAllowedForX, errNoGenericParamsAllowedForX,
errInvalidParamKindX, errDefaultArgumentInvalid, errNamedParamHasToBeIdent,
errNoReturnTypeForX, errConvNeedsOneArg, errInvalidPragmaX,
errXNotAllowedHere, errInvalidControlFlowX,
errXisNoType, errCircumNeedsPointer, errInvalidExpression,
errInvalidExpressionX, errEnumHasNoValueX, errNamedExprExpected,
errNamedExprNotAllowed, errXExpectsOneTypeParam,
errArrayExpectsTwoTypeParams, errInvalidVisibilityX, errInitHereNotAllowed,
errXCannotBeAssignedTo, errIteratorNotAllowed, errXNeedsReturnType,
errNoReturnTypeDeclared,
errInvalidCommandX, errXOnlyAtModuleScope,
errXNeedsParamObjectType,
errTemplateInstantiationTooNested, errInstantiationFrom,
errInvalidIndexValueForTuple, errCommandExpectsFilename,
errMainModuleMustBeSpecified,
errXExpected,
errTIsNotAConcreteType,
errInvalidSectionStart, errGridTableNotImplemented, errGeneralParseError,
errNewSectionExpected, errWhitespaceExpected, errXisNoValidIndexFile,
errCannotRenderX, errVarVarTypeNotAllowed, errInstantiateXExplicitly,
errOnlyACallOpCanBeDelegator, errUsingNoSymbol,
errMacroBodyDependsOnGenericTypes,
errDestructorNotGenericEnough,
errInlineIteratorsAsProcParams,
errXExpectsTwoArguments,
errXExpectsObjectTypes, errXcanNeverBeOfThisSubtype, errTooManyIterations,
errCannotInterpretNodeX, errFieldXNotFound, errInvalidConversionFromTypeX,
errAssertionFailed, errCannotGenerateCodeForX, errXRequiresOneArgument,
errUnhandledExceptionX, errCyclicTree, errXisNoMacroOrTemplate,
errXhasSideEffects, errIteratorExpected, errLetNeedsInit,
errThreadvarCannotInit, errWrongSymbolX, errIllegalCaptureX,
errXCannotBeClosure, errXMustBeCompileTime,
errCannotInferTypeOfTheLiteral,
errCannotInferReturnType,
errGenericLambdaNotAllowed,
errCompilerDoesntSupportTarget,
errUser,
warnCannotOpenFile,
warnOctalEscape, warnXIsNeverRead, warnXmightNotBeenInit,
warnDeprecated, warnConfigDeprecated,
warnSmallLshouldNotBeUsed, warnUnknownMagic, warnRedefinitionOfLabel,
warnUnknownSubstitutionX, warnLanguageXNotSupported,
warnFieldXNotSupported, warnCommentXIgnored,
warnNilStatement, warnTypelessParam,
warnDifferentHeaps, warnWriteToForeignHeap, warnUnsafeCode,
warnEachIdentIsTuple, warnShadowIdent,
warnProveInit, warnProveField, warnProveIndex, warnGcUnsafe, warnGcUnsafe2,
warnUninit, warnGcMem, warnDestructor, warnLockLevel, warnResultShadowed,
warnUser,
hintSuccess, hintSuccessX,
hintLineTooLong, hintXDeclaredButNotUsed, hintConvToBaseNotNeeded,
hintConvFromXtoItselfNotNeeded, hintExprAlwaysX, hintQuitCalled,
hintProcessing, hintCodeBegin, hintCodeEnd, hintConf, hintPath,
hintConditionAlwaysTrue, hintName, hintPattern,
hintUser
const
fatalMin* = errUnknown
fatalMax* = errInternal
errMin* = errUnknown
errMax* = errUser
warnMin* = warnCannotOpenFile
warnMax* = pred(hintSuccess)
hintMin* = hintSuccess
hintMax* = high(TMsgKind)
type
TNoteKind* = range[warnMin..hintMax] # "notes" are warnings or hints
TNoteKinds* = set[TNoteKind]
var
gNotes*: TNoteKinds = {low(TNoteKind)..high(TNoteKind)} -
{warnShadowIdent, warnUninit,
warnProveField, warnProveIndex, warnGcUnsafe}
#import compiler.msgs
echo warnUninit in gNotes

View File

@@ -1,5 +1,13 @@
discard """
output: "1"
output: '''1
foo
bar
baz
foo
bar
baz
yes
no'''
"""
# bug #1708
@@ -24,3 +32,59 @@ when true:
const foo2: seq[string] = @[]
echo foo[0][0][0]
proc takeEmpty(x: openArray[string] = []) = discard
takeEmpty()
takeEmpty([])
proc takeEmpty2(x: openArray[string] = @[]) = discard
takeEmpty2()
takeEmpty2([])
takeEmpty2(@[])
#takeEmpty2([nil])
#rawMessage(errExecutionOfProgramFailed, [])
# bug #2470
const
stuff: seq[string] = @[]
for str in stuff:
echo "str=", str
# bug #1354
proc foo4[T](more: seq[T] = @[]) =
var more2 = more
foo4[int]()
proc maino: int =
var wd: cstring = nil
inc result
discard maino()
proc varargso(a: varargs[string]) =
for x in a:
echo x
varargso(["foo", "bar", "baz"])
varargso("foo", "bar", "baz")
type
Flago = enum
tfNeedsInit, tfNotNil
var s: set[Flago] = {tfNeedsInit}
if {tfNeedsInit, tfNotNil} * s != {}:
echo "yes"
else:
echo "no"
if {tfNeedsInit, tfNotNil} * s <= {tfNotNil}:
echo "yes"
else:
echo "no"