mirror of
https://github.com/nim-lang/Nim.git
synced 2026-02-12 22:33:49 +00:00
implemented 'let' statement
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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}:
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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]",
|
||||
|
||||
@@ -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!
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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) =
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
|
||||
25
doc/tut1.txt
25
doc/tut1.txt
@@ -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``
|
||||
|
||||
10
doc/tut2.txt
10
doc/tut2.txt
@@ -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.
|
||||
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
11
tests/reject/tlet.nim
Normal 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
16
tests/reject/tlet2.nim
Normal 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
19
tests/run/tlet.nim
Normal 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()
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
11
todo.txt
11
todo.txt
@@ -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
|
||||
|
||||
@@ -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*.
|
||||
|
||||
Reference in New Issue
Block a user