summary refs log tree commit diff stats
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rwxr-xr-xcompiler/ast.nim7
-rw-r--r--compiler/ccgcalls.nim2
-rwxr-xr-xcompiler/ccgexprs.nim4
-rwxr-xr-xcompiler/ccgstmts.nim2
-rwxr-xr-xcompiler/ccgtypes.nim2
-rwxr-xr-xcompiler/cgen.nim3
-rwxr-xr-xcompiler/docgen.nim18
-rwxr-xr-xcompiler/ecmasgen.nim6
-rwxr-xr-xcompiler/evals.nim4
-rwxr-xr-xcompiler/msgs.nim3
-rwxr-xr-xcompiler/nversion.nim2
-rwxr-xr-xcompiler/parser.nim2
-rwxr-xr-xcompiler/pragmas.nim1
-rwxr-xr-xcompiler/renderer.nim27
-rwxr-xr-xcompiler/rodwrite.nim11
-rwxr-xr-xcompiler/semexprs.nim3
-rwxr-xr-xcompiler/semgnrc.nim2
-rwxr-xr-xcompiler/semstmts.nim25
-rwxr-xr-xcompiler/semthreads.nim4
-rwxr-xr-xcompiler/semtypes.nim3
-rwxr-xr-xcompiler/transf.nim6
-rwxr-xr-xcompiler/types.nim2
22 files changed, 69 insertions, 70 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim
index d80f2289e..3d07fda07 100755
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -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
diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim
index dbb9190d2..1c57479ae 100644
--- a/compiler/ccgcalls.nim
+++ b/compiler/ccgcalls.nim
@@ -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}:
diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim
index 4138aecd2..caaab1ab5 100755
--- a/compiler/ccgexprs.nim
+++ b/compiler/ccgexprs.nim
@@ -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)
diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim
index ca6f1fd91..da9a05188 100755
--- a/compiler/ccgstmts.nim
+++ b/compiler/ccgstmts.nim
@@ -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)
diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim
index bfd8c8723..490282fae 100755
--- a/compiler/ccgtypes.nim
+++ b/compiler/ccgtypes.nim
@@ -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: 
diff --git a/compiler/cgen.nim b/compiler/cgen.nim
index ca58e4b1c..5c730af80 100755
--- a/compiler/cgen.nim
+++ b/compiler/cgen.nim
@@ -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:
diff --git a/compiler/docgen.nim b/compiler/docgen.nim
index e76545c22..5e1e4b59c 100755
--- a/compiler/docgen.nim
+++ b/compiler/docgen.nim
@@ -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 
diff --git a/compiler/ecmasgen.nim b/compiler/ecmasgen.nim
index 3d9e99d44..588abfc93 100755
--- a/compiler/ecmasgen.nim
+++ b/compiler/ecmasgen.nim
@@ -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)
diff --git a/compiler/evals.nim b/compiler/evals.nim
index c92143a5b..c44ea3aeb 100755
--- a/compiler/evals.nim
+++ b/compiler/evals.nim
@@ -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)
diff --git a/compiler/msgs.nim b/compiler/msgs.nim
index a1fd73c88..1b218ad7e 100755
--- a/compiler/msgs.nim
+++ b/compiler/msgs.nim
@@ -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]",
diff --git a/compiler/nversion.nim b/compiler/nversion.nim
index b0a40f204..a0deda76e 100755
--- a/compiler/nversion.nim
+++ b/compiler/nversion.nim
@@ -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!
 
diff --git a/compiler/parser.nim b/compiler/parser.nim
index 361c297fb..e3bf3a748 100755
--- a/compiler/parser.nim
+++ b/compiler/parser.nim
@@ -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)
diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim
index 5eb6263e9..d4ea3226d 100755
--- a/compiler/pragmas.nim
+++ b/compiler/pragmas.nim
@@ -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
diff --git a/compiler/renderer.nim b/compiler/renderer.nim
index a38fba907..09539f23d 100755
--- a/compiler/renderer.nim
+++ b/compiler/renderer.nim
@@ -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:
diff --git a/compiler/rodwrite.nim b/compiler/rodwrite.nim
index ee56ec0a9..e08d78ae2 100755
--- a/compiler/rodwrite.nim
+++ b/compiler/rodwrite.nim
@@ -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): 
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index d21f557d4..cedce3c9c 100755
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -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
diff --git a/compiler/semgnrc.nim b/compiler/semgnrc.nim
index 488bdcf8a..a81347eda 100755
--- a/compiler/semgnrc.nim
+++ b/compiler/semgnrc.nim
@@ -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 
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index 2818ecbd1..60c0d5913 100755
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -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)
diff --git a/compiler/semthreads.nim b/compiler/semthreads.nim
index dcb38ff90..e402463cf 100755
--- a/compiler/semthreads.nim
+++ b/compiler/semthreads.nim
@@ -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, 
diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim
index ca7988aeb..9e78f98e3 100755
--- a/compiler/semtypes.nim
+++ b/compiler/semtypes.nim
@@ -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) = 
diff --git a/compiler/transf.nim b/compiler/transf.nim
index 3c715be6d..5f3becaf6 100755
--- a/compiler/transf.nim
+++ b/compiler/transf.nim
@@ -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)
diff --git a/compiler/types.nim b/compiler/types.nim
index 31c94236a..6ce4c6e48 100755
--- a/compiler/types.nim
+++ b/compiler/types.nim
@@ -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