implemented 'let' statement

This commit is contained in:
Araq
2011-11-29 17:27:48 +01:00
parent 31a994cc10
commit 7fcbdc6d42
33 changed files with 169 additions and 103 deletions

View File

@@ -144,11 +144,11 @@ type
nkForStmt, # a for statement
nkWhileStmt, # a while statement
nkCaseStmt, # a case statement
nkTypeSection, # a type section (consists of type definitions)
nkVarSection, # a var section
nkLetSection, # a let section
nkConstSection, # a const section
nkConstDef, # a const definition
nkTypeSection, # a type section (consists of type definitions)
nkTypeDef, # a type definition
nkYieldStmt, # the yield statement as a tree
nkTryStmt, # a try statement
@@ -315,8 +315,9 @@ type
skTemp, # a temporary variable (introduced by compiler)
skModule, # module identifier
skType, # a type
skConst, # a constant
skVar, # a variable
skLet, # a 'let' symbol
skConst, # a constant
skResult, # special 'result' variable
skProc, # a proc
skMethod, # a method
@@ -580,7 +581,7 @@ const
ConstantDataTypes*: TTypeKinds = {tyArrayConstr, tyArray, tySet,
tyTuple, tySequence}
ExportableSymKinds* = {skVar, skConst, skProc, skMethod, skType, skIterator,
skMacro, skTemplate, skConverter, skEnumField, skStub}
skMacro, skTemplate, skConverter, skEnumField, skLet, skStub}
PersistentNodeFlags*: TNodeFlags = {nfBase2, nfBase8, nfBase16, nfAllConst}
namePos* = 0
genericParamsPos* = 1

View File

@@ -53,7 +53,7 @@ proc isInCurrentFrame(p: BProc, n: PNode): bool =
# this does not work reliably because of forwarding + inlining can break it
case n.kind
of nkSym:
if n.sym.kind in {skVar, skResult, skTemp} and p.prc != nil:
if n.sym.kind in {skVar, skResult, skTemp, skLet} and p.prc != nil:
result = p.prc.id == n.sym.owner.id
of nkDotExpr, nkBracketExpr:
if skipTypes(n.sons[0].typ, abstractInst).kind notin {tyVar,tyPtr,tyRef}:

View File

@@ -139,7 +139,7 @@ proc getStorageLoc(n: PNode): TStorageLoc =
case n.sym.kind
of skParam, skForVar, skTemp:
result = OnStack
of skVar, skResult:
of skVar, skResult, skLet:
if sfGlobal in n.sym.flags: result = OnHeap
else: result = OnStack
of skConst:
@@ -1607,7 +1607,7 @@ proc expr(p: BProc, e: PNode, d: var TLoc) =
genComplexConst(p, sym, d)
of skEnumField:
putIntoDest(p, d, e.typ, toRope(sym.position))
of skVar, skResult:
of skVar, skResult, skLet:
if sfGlobal in sym.flags: genVarPrototype(p.module, sym)
if sym.loc.r == nil or sym.loc.t == nil:
InternalError(e.info, "expr: var not init " & sym.name.s)

View File

@@ -666,7 +666,7 @@ proc genStmts(p: BProc, t: PNode) =
of nkBlockStmt: genBlock(p, t, a)
of nkIfStmt: genIfStmt(p, t)
of nkWhileStmt: genWhileStmt(p, t)
of nkVarSection: genVarStmt(p, t)
of nkVarSection, nkLetSection: genVarStmt(p, t)
of nkConstSection: genConstStmt(p, t)
of nkForStmt: internalError(t.info, "for statement not eliminated")
of nkCaseStmt: genCaseStmt(p, t)

View File

@@ -37,7 +37,7 @@ proc mangleName(s: PSym): PRope =
case s.kind
of skProc, skMethod, skConverter, skConst:
result = toRope("@")
of skVar, skResult:
of skVar, skResult, skLet:
if sfGlobal in s.flags: result = toRope("@")
else: result = toRope("%")
of skForVar, skTemp, skParam, skType, skEnumField, skModule:

View File

@@ -339,6 +339,7 @@ proc assignLocalVar(p: BProc, s: PSym) =
# for each module that uses them!
if s.loc.k == locNone:
fillLoc(s.loc, locLocalVar, s.typ, mangleName(s), OnStack)
if s.kind == skLet: incl(s.loc.flags, lfNoDeepCopy)
app(p.s[cpsLocals], getTypeDesc(p.module, s.loc.t))
if sfRegister in s.flags: app(p.s[cpsLocals], " register")
if (sfVolatile in s.flags) or (p.nestedTryStmts.len > 0):
@@ -473,7 +474,7 @@ proc cgsym(m: BModule, name: string): PRope =
if sym != nil:
case sym.kind
of skProc, skMethod, skConverter: genProc(m, sym)
of skVar, skResult: genVarPrototype(m, sym)
of skVar, skResult, skLet: genVarPrototype(m, sym)
of skType: discard getTypeDesc(m, sym.typ)
else: InternalError("cgsym: " & name)
else:

View File

@@ -785,18 +785,12 @@ proc generateDoc(d: PDoc, n: PNode) =
of nkMacroDef: genItem(d, n, n.sons[namePos], skMacro)
of nkTemplateDef: genItem(d, n, n.sons[namePos], skTemplate)
of nkConverterDef: genItem(d, n, n.sons[namePos], skConverter)
of nkVarSection:
for i in countup(0, sonsLen(n) - 1):
of nkTypeSection, nkVarSection, nkLetSection, nkConstSection:
for i in countup(0, sonsLen(n) - 1):
if n.sons[i].kind != nkCommentStmt:
genItem(d, n.sons[i], n.sons[i].sons[0], skVar)
of nkConstSection:
for i in countup(0, sonsLen(n) - 1):
if n.sons[i].kind != nkCommentStmt:
genItem(d, n.sons[i], n.sons[i].sons[0], skConst)
of nkTypeSection:
for i in countup(0, sonsLen(n) - 1):
if n.sons[i].kind != nkCommentStmt:
genItem(d, n.sons[i], n.sons[i].sons[0], skType)
# order is always 'type var let const':
genItem(d, n.sons[i], n.sons[i].sons[0],
succ(skType, ord(n.kind)-ord(nkTypeSection)))
of nkStmtList:
for i in countup(0, sonsLen(n) - 1): generateDoc(d, n.sons[i])
of nkWhenStmt:
@@ -810,7 +804,7 @@ proc generateDoc(d: PDoc, n: PNode) =
proc genSection(d: PDoc, kind: TSymKind) =
const sectionNames: array[skModule..skTemplate, string] = [
"Imports", "Types", "Consts", "Vars", "Vars", "Procs", "Methods",
"Imports", "Types", "Vars", "Lets", "Consts", "Vars", "Procs", "Methods",
"Iterators", "Converters", "Macros", "Templates"
]
if d.section[kind] == nil: return

View File

@@ -835,7 +835,7 @@ proc genAddr(p: var TProc, n: PNode, r: var TCompRes) =
s = n.sons[0].sym
if s.loc.r == nil: InternalError(n.info, "genAddr: 3")
case s.kind
of skVar, skResult:
of skVar, skLet, skResult:
if mapType(n.typ) == etyObject:
# make addr() a no-op:
r.kind = etyNone
@@ -866,7 +866,7 @@ proc genSym(p: var TProc, n: PNode, r: var TCompRes) =
if s.loc.r == nil:
InternalError(n.info, "symbol has no generated name: " & s.name.s)
case s.kind
of skVar, skParam, skTemp, skResult:
of skVar, skLet, skParam, skTemp, skResult:
var k = mapType(s.typ)
if k == etyBaseIndex:
r.kind = etyBaseIndex
@@ -1339,7 +1339,7 @@ proc genStmt(p: var TProc, n: PNode, r: var TCompRes) =
of nkBlockStmt: genBlock(p, n, r)
of nkIfStmt: genIfStmt(p, n, r)
of nkWhileStmt: genWhileStmt(p, n, r)
of nkVarSection: genVarStmt(p, n, r)
of nkVarSection, nkLetSection: genVarStmt(p, n, r)
of nkConstSection: genConstStmt(p, n, r)
of nkForStmt: internalError(n.info, "for statement not eliminated")
of nkCaseStmt: genCaseStmt(p, n, r)

View File

@@ -452,7 +452,7 @@ proc evalSym(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode =
case s.kind
of skProc, skConverter, skMacro:
result = s.getBody
of skVar, skForVar, skTemp, skResult:
of skVar, skLet, skForVar, skTemp, skResult:
if sfGlobal notin s.flags:
result = evalVariable(c.tos, s, flags)
else:
@@ -1195,7 +1195,7 @@ proc evalAux(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode =
of nkWhenStmt, nkIfStmt, nkIfExpr: result = evalIf(c, n)
of nkWhileStmt: result = evalWhile(c, n)
of nkCaseStmt: result = evalCase(c, n)
of nkVarSection: result = evalVar(c, n)
of nkVarSection, nkLetSection: result = evalVar(c, n)
of nkTryStmt: result = evalTry(c, n)
of nkRaiseStmt: result = evalRaise(c, n)
of nkReturnStmt: result = evalReturn(c, n)

View File

@@ -92,7 +92,7 @@ type
errCannotInterpretNodeX, errFieldXNotFound, errInvalidConversionFromTypeX,
errAssertionFailed, errCannotGenerateCodeForX, errXRequiresOneArgument,
errUnhandledExceptionX, errCyclicTree, errXisNoMacroOrTemplate,
errXhasSideEffects, errIteratorExpected, errWrongSymbolX,
errXhasSideEffects, errIteratorExpected, errLetNeedsInit, errWrongSymbolX,
errUser,
warnCannotOpenFile,
warnOctalEscape, warnXIsNeverRead, warnXmightNotBeenInit,
@@ -320,6 +320,7 @@ const
errXisNoMacroOrTemplate: "\'$1\' is no macro or template",
errXhasSideEffects: "\'$1\' can have side effects",
errIteratorExpected: "iterator within for loop context expected",
errLetNeedsInit: "'let' symbol requires an initialization",
errWrongSymbolX: "usage of \'$1\' is a user-defined error",
errUser: "$1",
warnCannotOpenFile: "cannot open \'$1\' [CannotOpenFile]",

View File

@@ -18,5 +18,5 @@ const
VersionPatch* = 13
VersionAsString* = $VersionMajor & "." & $VersionMinor & "." & $VersionPatch
RodFileVersion* = "1032" # modify this if the rod-format changes!
RodFileVersion* = "1033" # modify this if the rod-format changes!

View File

@@ -1352,7 +1352,7 @@ proc complexOrSimpleStmt(p: var TParser): PNode =
of tkConverter: result = parseRoutine(p, nkConverterDef)
of tkType: result = parseSection(p, nkTypeSection, parseTypeDef)
of tkConst: result = parseSection(p, nkConstSection, parseConstant)
of tkLet: result = parseSection(p, nkLetSection, parseConstant)
of tkLet: result = parseSection(p, nkLetSection, parseVariable)
of tkWhen: result = parseIfOrWhen(p, nkWhenStmt)
of tkVar: result = parseSection(p, nkVarSection, parseVariable)
of tkBind: result = parseBind(p)

View File

@@ -52,6 +52,7 @@ const
wImportcpp, wImportobjc, wError, wNoInit}
constPragmas* = {wImportc, wExportc, wHeader, wDeprecated, wMagic, wNodecl,
wExtern, wImportcpp, wImportobjc, wError}
letPragmas* = varPragmas
procTypePragmas* = {FirstCallConv..LastCallConv, wVarargs, wNosideEffect,
wThread}
allRoutinePragmas* = procPragmas + iteratorPragmas + lambdaPragmas

View File

@@ -385,7 +385,7 @@ proc lsub(n: PNode): int =
of nkProcTy: result = lsons(n) + len("proc_")
of nkEnumTy: result = lsub(n.sons[0]) + lcomma(n, 1) + len("enum_")
of nkEnumFieldDef: result = lsons(n) + 3
of nkVarSection:
of nkVarSection, nkLetSection:
if sonsLen(n) > 1: result = maxLineLen + 1
else: result = lsons(n) + len("var_")
of nkReturnStmt: result = lsub(n.sons[0]) + len("return_")
@@ -650,7 +650,7 @@ proc gident(g: var TSrcGen, n: PNode) =
else:
t = tkOpr
put(g, t, s)
if (n.kind == nkSym) and (renderIds in g.flags): put(g, tkIntLit, $(n.sym.id))
if n.kind == nkSym and renderIds in g.flags: put(g, tkIntLit, $n.sym.id)
proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
var
@@ -825,7 +825,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
of nkDerefExpr:
gsub(g, n.sons[0])
putWithSpace(g, tkOpr, "^")
# unfortunately this requires a space, because ^. would be only one operator
# unfortunately this requires a space, because ^. would be only one opr
of nkAccQuoted:
put(g, tkAccent, "`")
if n.len > 0: gsub(g, n.sons[0])
@@ -960,10 +960,11 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
initContext(a)
incl(a.flags, rfInConstExpr)
gsection(g, n, a, tkConst, "const")
of nkVarSection:
of nkVarSection, nkLetSection:
L = sonsLen(n)
if L == 0: return
putWithSpace(g, tkVar, "var")
if L == 0: return
if n.kind == nkVarSection: putWithSpace(g, tkVar, "var")
else: putWithSpace(g, tkLet, "let")
if L > 1:
gcoms(g)
indentNL(g)
@@ -1084,21 +1085,23 @@ proc renderTree(n: PNode, renderFlags: TRenderFlags = {}): string =
gsub(g, n)
result = g.buf
proc renderModule(n: PNode, filename: string, renderFlags: TRenderFlags = {}) =
var
proc renderModule(n: PNode, filename: string,
renderFlags: TRenderFlags = {}) =
var
f: tfile
g: TSrcGen
initSrcGen(g, renderFlags)
for i in countup(0, sonsLen(n) - 1):
for i in countup(0, sonsLen(n) - 1):
gsub(g, n.sons[i])
optNL(g)
case n.sons[i].kind
of nkTypeSection, nkConstSection, nkVarSection, nkCommentStmt: putNL(g)
of nkTypeSection, nkConstSection, nkVarSection, nkLetSection,
nkCommentStmt: putNL(g)
else: nil
gcoms(g)
if optStdout in gGlobalOptions:
if optStdout in gGlobalOptions:
write(stdout, g.buf)
elif open(f, filename, fmWrite):
elif open(f, filename, fmWrite):
write(f, g.buf)
close(f)
else:

View File

@@ -531,17 +531,10 @@ proc process(c: PPassContext, n: PNode): PNode =
if n.sons[bodyPos].kind != nkEmpty or s.magic != mNone or
sfForward notin s.flags:
addInterfaceSym(w, s)
of nkVarSection:
of nkVarSection, nkLetSection, nkConstSection:
for i in countup(0, sonsLen(n) - 1):
var a = n.sons[i]
if a.kind == nkCommentStmt: continue
if a.kind != nkIdentDefs: InternalError(a.info, "rodwrite.process")
addInterfaceSym(w, a.sons[0].sym)
of nkConstSection:
for i in countup(0, sonsLen(n) - 1):
var a = n.sons[i]
if a.kind == nkCommentStmt: continue
if a.kind != nkConstDef: InternalError(a.info, "rodwrite.process")
if a.kind == nkCommentStmt: continue
addInterfaceSym(w, a.sons[0].sym)
of nkTypeSection:
for i in countup(0, sonsLen(n) - 1):

View File

@@ -81,7 +81,7 @@ proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
result = newSymNode(s, n.info)
of skMacro: result = semMacroExpr(c, n, s)
of skTemplate: result = semTemplateExpr(c, n, s)
of skVar, skResult:
of skVar, skLet, skResult:
markUsed(n, s)
# if a proc accesses a global variable, it is not side effect free:
if sfGlobal in s.flags: incl(c.p.owner.flags, sfSideEffect)
@@ -372,6 +372,7 @@ proc isAssignable(c: PContext, n: PNode): TAssignableResult =
result = arNone
case n.kind
of nkSym:
# don't list 'skLet' here:
if n.sym.kind in {skVar, skResult, skTemp}:
if c.p.owner.id == n.sym.owner.id: result = arLocalLValue
else: result = arLValue

View File

@@ -163,7 +163,7 @@ proc semGenericStmt(c: PContext, n: PNode,
for j in countup(0, L-2):
a.sons[j] = semGenericStmt(c, a.sons[j], flags+{withinTypeDesc}, toBind)
a.sons[L-1] = semGenericStmtScope(c, a.sons[L-1], flags, toBind)
of nkVarSection:
of nkVarSection, nkLetSection:
for i in countup(0, sonsLen(n) - 1):
var a = n.sons[i]
if a.kind == nkCommentStmt: continue

View File

@@ -222,15 +222,15 @@ proc semIdentDef(c: PContext, n: PNode, kind: TSymKind): PSym =
incl(result.flags, sfGlobal)
else:
result = semIdentWithPragma(c, kind, n, {})
proc semVar(c: PContext, n: PNode): PNode =
proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
var b: PNode
result = copyNode(n)
for i in countup(0, sonsLen(n)-1):
var a = n.sons[i]
if gCmd == cmdIdeTools: suggestStmt(c, a)
if a.kind == nkCommentStmt: continue
if (a.kind != nkIdentDefs) and (a.kind != nkVarTuple): IllFormedAst(a)
if a.kind notin {nkIdentDefs, nkVarTuple, nkConstDef}: IllFormedAst(a)
checkMinSonsLen(a, 3)
var length = sonsLen(a)
var typ: PType
@@ -247,22 +247,24 @@ proc semVar(c: PContext, n: PNode): PNode =
else: typ = def.typ
else:
def = ast.emptyNode
if symkind == skLet: GlobalError(a.info, errLetNeedsInit)
# this can only happen for errornous var statements:
if typ == nil: continue
if not typeAllowed(typ, skVar):
if not typeAllowed(typ, symkind):
GlobalError(a.info, errXisNoType, typeToString(typ))
var tup = skipTypes(typ, {tyGenericInst})
if a.kind == nkVarTuple:
if tup.kind != tyTuple: GlobalError(a.info, errXExpected, "tuple")
if length - 2 != sonsLen(tup):
if length-2 != sonsLen(tup):
GlobalError(a.info, errWrongNumberOfVariables)
b = newNodeI(nkVarTuple, a.info)
newSons(b, length)
b.sons[length - 2] = ast.emptyNode # no type desc
b.sons[length - 1] = def
b.sons[length-2] = ast.emptyNode # no type desc
b.sons[length-1] = def
addSon(result, b)
for j in countup(0, length-3):
var v = semIdentDef(c, a.sons[j], skVar)
for j in countup(0, length-3):
var v = semIdentDef(c, a.sons[j], symkind)
addInterfaceDecl(c, v)
if def != nil and def.kind != nkEmpty:
# this is only needed for the evaluation pass:
@@ -277,7 +279,7 @@ proc semVar(c: PContext, n: PNode): PNode =
else:
v.typ = tup.sons[j]
b.sons[j] = newSymNode(v)
proc semConst(c: PContext, n: PNode): PNode =
result = copyNode(n)
for i in countup(0, sonsLen(n) - 1):
@@ -823,7 +825,8 @@ proc SemStmt(c: PContext, n: PNode): PNode =
of nkPragma, nkCommentStmt, nkNilLit, nkEmpty: nil
else: localError(n.sons[j].info, errStmtInvalidAfterReturn)
of nkRaiseStmt: result = semRaise(c, n)
of nkVarSection: result = semVar(c, n)
of nkVarSection: result = semVarOrLet(c, n, skVar)
of nkLetSection: result = semVarOrLet(c, n, skLet)
of nkConstSection: result = semConst(c, n)
of nkTypeSection: result = SemTypeSection(c, n)
of nkIfStmt: result = SemIf(c, n)

View File

@@ -107,7 +107,7 @@ proc analyseSym(c: PProcCtx, n: PNode): TThreadOwner =
result = c.mapping[v.id]
if result != toUndefined: return
case v.kind
of skVar, skResult:
of skVar, skLet, skResult:
result = toNil
if sfGlobal in v.flags:
if sfThread in v.flags:
@@ -348,7 +348,7 @@ proc analyse(c: PProcCtx, n: PNode): TThreadOwner =
var a = analyse(c, n.sons[0])
if a != toMine: Message(n.info, warnDifferentHeaps)
result = toVoid
of nkVarSection: result = analyseVarSection(c, n)
of nkVarSection, nkLetSection: result = analyseVarSection(c, n)
of nkConstSection: result = analyseConstSection(c, n)
of nkTypeSection, nkCommentStmt: result = toVoid
of nkIfStmt, nkWhileStmt, nkTryStmt, nkCaseStmt, nkStmtList, nkBlockStmt,

View File

@@ -242,9 +242,10 @@ proc semIdentWithPragma(c: PContext, kind: TSymKind, n: PNode,
# process pragmas later, because result.typ has not been set yet
of skField: pragma(c, result, n.sons[1], fieldPragmas)
of skVar: pragma(c, result, n.sons[1], varPragmas)
of skLet: pragma(c, result, n.sons[1], letPragmas)
of skConst: pragma(c, result, n.sons[1], constPragmas)
else: nil
else:
else:
result = semIdentVis(c, kind, n, allowed)
proc checkForOverlap(c: PContext, t, ex: PNode, branchIndex: int) =

View File

@@ -294,7 +294,7 @@ proc introduceNewLocalVars(c: PTransf, n: PNode): PTransNode =
of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit:
# nothing to be done for leaves:
result = PTransNode(n)
of nkVarSection:
of nkVarSection, nkLetSection:
result = transformVarSection(c, n)
else:
result = newTransNode(n)
@@ -518,7 +518,7 @@ proc gatherVars(c: PTransf, n: PNode, marked: var TIntSet, owner: PSym,
var s = n.sym
var found = false
case s.kind
of skVar: found = sfGlobal notin s.flags
of skVar, skLet: found = sfGlobal notin s.flags
of skTemp, skForVar, skParam, skResult: found = true
else: nil
if found and owner.id != s.owner.id and not ContainsOrIncl(marked, s.id):
@@ -714,7 +714,7 @@ proc transform(c: PTransf, n: PNode): PTransNode =
of nkConstSection:
# do not replace ``const c = 3`` with ``const 3 = 3``
return transformConstSection(c, n)
of nkVarSection:
of nkVarSection, nkLetSection:
if c.inlining > 0:
# we need to copy the variables for multiple yield statements:
result = transformVarSection(c, n)

View File

@@ -816,7 +816,7 @@ proc matchType*(a: PType, pattern: openArray[tuple[k:TTypeKind, i:int]],
result = a.kind == last
proc typeAllowedAux(marker: var TIntSet, typ: PType, kind: TSymKind): bool =
assert(kind in {skVar, skConst, skParam, skResult})
assert(kind in {skVar, skLet, skConst, skParam, skResult})
# if we have already checked the type, return true, because we stop the
# evaluation if something is wrong:
result = true

View File

@@ -1555,7 +1555,6 @@ variables of the same type:
If an initializer is given the type can be omitted: the variable is then of the
same type as the initializing expression. Variables are always initialized
with a default value if there is no initializing expression. The default
value depends on the type and is always a zero in binary.
@@ -1586,6 +1585,19 @@ The implicit initialization can be avoided for optimization reasons with the
a {.noInit.}: array [0..1023, char]
let statement
~~~~~~~~~~~~~
A `Let`:idx: statement declares new local and global `single assignment`:idx:
variables and binds a value to them. The syntax is the of the ``var``
statement, except that the keyword ``var`` is replaced by the keyword ``let``.
Let variables are not l-values and can thus not be passed to ``var`` parameters
nor can their address be taken. They cannot be assigned new values.
For let variables the same pragmas are available as for ordinary variables.
Const section
~~~~~~~~~~~~~

View File

@@ -213,6 +213,17 @@ constants:
z = y + 5 # computations are possible
The let statement
=================
The ``let`` statement works like the ``var`` statement but the declared
symbols are *single assignment* variables: After the initialization their
value cannot change:
.. code-block::
let x = "abc" # introduces a new variable `x` and binds a value to it
x = "xyz" # Illegal: assignment to `x`
Control flow statements
=======================
@@ -227,7 +238,7 @@ If statement
The if statement is one way to branch the control flow:
.. code-block:: nimrod
var name = readLine(stdin)
let name = readLine(stdin)
if name == "":
echo("Poor soul, you lost your name?")
elif name == "name":
@@ -247,7 +258,7 @@ Another way to branch is provided by the case statement. A case statement is
a multi-branch:
.. code-block:: nimrod
var name = readLine(stdin)
let name = readLine(stdin)
case name
of "":
echo("Poor soul, you lost your name?")
@@ -270,7 +281,7 @@ For integers or other ordinal types value ranges are also possible:
from strutils import parseInt
Echo("A number please: ")
var n = parseInt(readLine(stdin))
let n = parseInt(readLine(stdin))
case n
of 0..2, 4..7: Echo("The number is in the set: {0, 1, 2, 4, 5, 6, 7}")
of 3, 8: Echo("The number is 3 or 8")
@@ -410,7 +421,7 @@ the next iteration immediately:
.. code-block:: nimrod
while true:
var x = readLine(stdin)
let x = readLine(stdin)
if x == "": continue
Echo(x)
@@ -717,8 +728,8 @@ However, this cannot be done for mutually recursive procedures:
Here ``odd`` depends on ``even`` and vice versa. Thus ``even`` needs to be
introduced to the compiler before it is completely defined. The syntax for
such a `forward declaration` is simple: just omit the ``=`` and the procedure's
body.
such a `forward declaration`:idx: is simple: just omit the ``=`` and the
procedure's body.
Iterators
@@ -846,7 +857,7 @@ to mark them to be of another integer type:
.. code-block:: nimrod
var
let
x = 0 # x is of type ``int``
y = 0'i8 # y is of type ``int8``
z = 0'i64 # z is of type ``int64``

View File

@@ -580,13 +580,13 @@ via a special ``:`` syntax:
.. code-block:: nimrod
template withFile(f: expr, filename: string, mode: TFileMode,
actions: stmt): stmt =
body: stmt): stmt =
block:
var fn = filename
let fn = filename
var f: TFile
if open(f, fn, mode):
try:
actions
body
finally:
close(f)
else:
@@ -596,10 +596,10 @@ via a special ``:`` syntax:
txt.writeln("line 1")
txt.writeln("line 2")
In the example the two ``writeln`` statements are bound to the ``actions``
In the example the two ``writeln`` statements are bound to the ``body``
parameter. The ``withFile`` template contains boilerplate code and helps to
avoid a common bug: to forget to close the file. Note how the
``var fn = filename`` statement ensures that ``filename`` is evaluated only
``let fn = filename`` statement ensures that ``filename`` is evaluated only
once.

View File

@@ -37,8 +37,8 @@ type
nnkElifBranch, nnkExceptBranch, nnkElse, nnkMacroStmt,
nnkAsmStmt, nnkPragma, nnkIfStmt, nnkWhenStmt,
nnkForStmt, nnkWhileStmt, nnkCaseStmt,
nnkVarSection, nnkLetSection, nnkConstSection,
nnkConstDef, nnkTypeSection, nnkTypeDef,
nnkTypeSection, nnkVarSection, nnkLetSection, nnkConstSection,
nnkConstDef, nnkTypeDef,
nnkYieldStmt, nnkTryStmt, nnkFinally, nnkRaiseStmt,
nnkReturnStmt, nnkBreakStmt, nnkContinueStmt, nnkBlockStmt,
nnkDiscardStmt, nnkStmtList, nnkImportStmt, nnkFromStmt,

View File

@@ -360,7 +360,8 @@ proc threadId*[TArg](t: var TThread[TArg]): TThreadId[TArg] {.inline.} =
result = addr(t)
proc myThreadId*[TArg](): TThreadId[TArg] =
## returns the thread ID of the thread that calls this proc.
## returns the thread ID of the thread that calls this proc. This is unsafe
## because the type ``TArg`` is not checked for consistency!
result = cast[TThreadId[TArg]](ThreadVarGetValue(globalsSlot))
when false:

11
tests/reject/tlet.nim Normal file
View File

@@ -0,0 +1,11 @@
discard """
line: "10"
errormsg: "'name' cannot be assigned to"
"""
Echo("What's your name? ")
let name = readLine(stdin)
while name == "":
Echo("Please tell me your name: ")
name = readLine(stdin)

16
tests/reject/tlet2.nim Normal file
View File

@@ -0,0 +1,16 @@
discard """
line: "13"
errormsg: "for a 'var' type a variable needs to be passed"
"""
proc divmod(a, b: int, res, remainder: var int) =
res = a div b # integer division
remainder = a mod b # integer modulo operation
let
x = 9
y = 3
divmod(8, 5, x, y) # modifies x and y
echo(x)
echo(y)

19
tests/run/tlet.nim Normal file
View File

@@ -0,0 +1,19 @@
discard """
output: '''Very funny, your name is name.
nameabc'''
"""
proc main =
let name = "name"
if name == "":
echo("Poor soul, you lost your name?")
elif name == "name":
echo("Very funny, your name is name.")
else:
Echo("Hi, ", name, "!")
let (x, y) = ("abc", name)
echo y, x
main()

View File

@@ -103,7 +103,7 @@ proc parseSpec(filename: string): TSpec =
# ----------------------------------------------------------------------------
var
let
pegLineError =
peg"{[^(]*} '(' {\d+} ', ' \d+ ') ' ('Error'/'Warning') ':' \s* {.*}"
pegOtherError = peg"'Error:' \s* {.*}"
@@ -111,10 +111,10 @@ var
pegOfInterest = pegLineError / pegOtherError
proc callCompiler(cmdTemplate, filename, options: string): TSpec =
var c = parseCmdLine(cmdTemplate % [options, filename])
let c = parseCmdLine(cmdTemplate % [options, filename])
var p = startProcess(command=c[0], args=c[1.. -1],
options={poStdErrToStdOut, poUseShell})
var outp = p.outputStream
let outp = p.outputStream
var suc = ""
var err = ""
var x = newStringOfCap(120)
@@ -222,7 +222,7 @@ proc cmpMsgs(r: var TResults, expected, given: TSpec, test: string) =
inc(r.passed)
proc rejectSingleTest(r: var TResults, test, options: string) =
var test = test.addFileExt(".nim")
let test = test.addFileExt(".nim")
var t = extractFilename(test)
inc(r.total)
echo t
@@ -240,10 +240,10 @@ proc reject(r: var TResults, dir, options: string) =
proc compile(r: var TResults, pattern, options: string) =
for test in os.walkFiles(pattern):
var t = extractFilename(test)
let t = extractFilename(test)
echo t
inc(r.total)
var expected = parseSpec(test)
let expected = parseSpec(test)
if expected.disabled:
r.addResult(t, "", reIgnored)
inc(r.skipped)
@@ -253,11 +253,11 @@ proc compile(r: var TResults, pattern, options: string) =
if not given.err: inc(r.passed)
proc compileSingleTest(r: var TResults, test, options: string) =
var test = test.addFileExt(".nim")
var t = extractFilename(test)
let test = test.addFileExt(".nim")
let t = extractFilename(test)
inc(r.total)
echo t
var given = callCompiler(cmdTemplate, test, options)
let given = callCompiler(cmdTemplate, test, options)
r.addResult(t, given.msg, if given.err: reFailure else: reSuccess)
if not given.err: inc(r.passed)

View File

@@ -2,7 +2,10 @@ version 0.8.14
==============
- bug: compiler uses full file names again
- stdlib and compiler should not use deprecated endOfFile and readline
- implicit invokation of `items`/`pairs` seems nice
- warning for implicit openArray -> varargs convention
- implement explicit varargs; **but** ``len(varargs)`` problem remains!
--> solve by implicit conversion from varargs to openarray
version 0.9.0
=============
@@ -11,18 +14,13 @@ version 0.9.0
escape analysis for string/seq seems to be easy to do too
- dead code elim for JS backend; 'of' operator for JS backend
- test the sort implementation again
- 'let x = y'
- const ptr/ref
- unsigned ints and bignums; requires abstract integer literal type:
use tyInt+node for that
- implement the high level optimizer
- warning for implicit openArray -> varargs convention
- implement explicit varargs; **but** ``len(varargs)`` problem remains!
--> solve by implicit conversion from varargs to openarray
- change overloading resolution
- implement closures; implement proper coroutines
- implement ``partial`` pragma for partial evaluation
- implicit invokation of `items`/`pairs` seems nice
- we need to support iteration of 2 different data structures in parallel
- make exceptions compatible with C++ exceptions
- ``=`` should be overloadable; requires specialization for ``=``
@@ -52,7 +50,6 @@ Bugs
- bug: stress testing basic method example (eval example)
without ``-d:release`` leaks memory; good way to figure out how a
fixed amount of stack can hold an arbitrary number of GC roots!
- bug: osproc.execProcess() should raise an exception if the exit code is not 0
version 0.9.XX

View File

@@ -74,6 +74,7 @@ Language Additions
heart's content.
- ``bind`` (used for symbol binding in templates and generics) is now a
declarative statement.
- Nimrod now supports single assignment variables via the ``let`` statement.
- The slice assignment ``a[i..j] = b`` where ``a`` is a sequence or string
now supports *splicing*.
@@ -114,7 +115,6 @@ Compiler Additions
Library Additions
-----------------
- Added ``system.mainThreadId``.
- Added ``system.allocShared``, ``system.allocShared0``,
``system.deallocShared``, ``system.reallocShared``.
- Slicing as implemented by the system module now supports *splicing*.