implemented 'let' statement
This commit is contained in:
parent
31a994cc10
commit
7fcbdc6d42
33 changed files with 169 additions and 103 deletions
|
|
@ -144,11 +144,11 @@ type
|
||||||
nkForStmt, # a for statement
|
nkForStmt, # a for statement
|
||||||
nkWhileStmt, # a while statement
|
nkWhileStmt, # a while statement
|
||||||
nkCaseStmt, # a case statement
|
nkCaseStmt, # a case statement
|
||||||
|
nkTypeSection, # a type section (consists of type definitions)
|
||||||
nkVarSection, # a var section
|
nkVarSection, # a var section
|
||||||
nkLetSection, # a let section
|
nkLetSection, # a let section
|
||||||
nkConstSection, # a const section
|
nkConstSection, # a const section
|
||||||
nkConstDef, # a const definition
|
nkConstDef, # a const definition
|
||||||
nkTypeSection, # a type section (consists of type definitions)
|
|
||||||
nkTypeDef, # a type definition
|
nkTypeDef, # a type definition
|
||||||
nkYieldStmt, # the yield statement as a tree
|
nkYieldStmt, # the yield statement as a tree
|
||||||
nkTryStmt, # a try statement
|
nkTryStmt, # a try statement
|
||||||
|
|
@ -315,8 +315,9 @@ type
|
||||||
skTemp, # a temporary variable (introduced by compiler)
|
skTemp, # a temporary variable (introduced by compiler)
|
||||||
skModule, # module identifier
|
skModule, # module identifier
|
||||||
skType, # a type
|
skType, # a type
|
||||||
skConst, # a constant
|
|
||||||
skVar, # a variable
|
skVar, # a variable
|
||||||
|
skLet, # a 'let' symbol
|
||||||
|
skConst, # a constant
|
||||||
skResult, # special 'result' variable
|
skResult, # special 'result' variable
|
||||||
skProc, # a proc
|
skProc, # a proc
|
||||||
skMethod, # a method
|
skMethod, # a method
|
||||||
|
|
@ -580,7 +581,7 @@ const
|
||||||
ConstantDataTypes*: TTypeKinds = {tyArrayConstr, tyArray, tySet,
|
ConstantDataTypes*: TTypeKinds = {tyArrayConstr, tyArray, tySet,
|
||||||
tyTuple, tySequence}
|
tyTuple, tySequence}
|
||||||
ExportableSymKinds* = {skVar, skConst, skProc, skMethod, skType, skIterator,
|
ExportableSymKinds* = {skVar, skConst, skProc, skMethod, skType, skIterator,
|
||||||
skMacro, skTemplate, skConverter, skEnumField, skStub}
|
skMacro, skTemplate, skConverter, skEnumField, skLet, skStub}
|
||||||
PersistentNodeFlags*: TNodeFlags = {nfBase2, nfBase8, nfBase16, nfAllConst}
|
PersistentNodeFlags*: TNodeFlags = {nfBase2, nfBase8, nfBase16, nfAllConst}
|
||||||
namePos* = 0
|
namePos* = 0
|
||||||
genericParamsPos* = 1
|
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
|
# this does not work reliably because of forwarding + inlining can break it
|
||||||
case n.kind
|
case n.kind
|
||||||
of nkSym:
|
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
|
result = p.prc.id == n.sym.owner.id
|
||||||
of nkDotExpr, nkBracketExpr:
|
of nkDotExpr, nkBracketExpr:
|
||||||
if skipTypes(n.sons[0].typ, abstractInst).kind notin {tyVar,tyPtr,tyRef}:
|
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
|
case n.sym.kind
|
||||||
of skParam, skForVar, skTemp:
|
of skParam, skForVar, skTemp:
|
||||||
result = OnStack
|
result = OnStack
|
||||||
of skVar, skResult:
|
of skVar, skResult, skLet:
|
||||||
if sfGlobal in n.sym.flags: result = OnHeap
|
if sfGlobal in n.sym.flags: result = OnHeap
|
||||||
else: result = OnStack
|
else: result = OnStack
|
||||||
of skConst:
|
of skConst:
|
||||||
|
|
@ -1607,7 +1607,7 @@ proc expr(p: BProc, e: PNode, d: var TLoc) =
|
||||||
genComplexConst(p, sym, d)
|
genComplexConst(p, sym, d)
|
||||||
of skEnumField:
|
of skEnumField:
|
||||||
putIntoDest(p, d, e.typ, toRope(sym.position))
|
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 sfGlobal in sym.flags: genVarPrototype(p.module, sym)
|
||||||
if sym.loc.r == nil or sym.loc.t == nil:
|
if sym.loc.r == nil or sym.loc.t == nil:
|
||||||
InternalError(e.info, "expr: var not init " & sym.name.s)
|
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 nkBlockStmt: genBlock(p, t, a)
|
||||||
of nkIfStmt: genIfStmt(p, t)
|
of nkIfStmt: genIfStmt(p, t)
|
||||||
of nkWhileStmt: genWhileStmt(p, t)
|
of nkWhileStmt: genWhileStmt(p, t)
|
||||||
of nkVarSection: genVarStmt(p, t)
|
of nkVarSection, nkLetSection: genVarStmt(p, t)
|
||||||
of nkConstSection: genConstStmt(p, t)
|
of nkConstSection: genConstStmt(p, t)
|
||||||
of nkForStmt: internalError(t.info, "for statement not eliminated")
|
of nkForStmt: internalError(t.info, "for statement not eliminated")
|
||||||
of nkCaseStmt: genCaseStmt(p, t)
|
of nkCaseStmt: genCaseStmt(p, t)
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ proc mangleName(s: PSym): PRope =
|
||||||
case s.kind
|
case s.kind
|
||||||
of skProc, skMethod, skConverter, skConst:
|
of skProc, skMethod, skConverter, skConst:
|
||||||
result = toRope("@")
|
result = toRope("@")
|
||||||
of skVar, skResult:
|
of skVar, skResult, skLet:
|
||||||
if sfGlobal in s.flags: result = toRope("@")
|
if sfGlobal in s.flags: result = toRope("@")
|
||||||
else: result = toRope("%")
|
else: result = toRope("%")
|
||||||
of skForVar, skTemp, skParam, skType, skEnumField, skModule:
|
of skForVar, skTemp, skParam, skType, skEnumField, skModule:
|
||||||
|
|
|
||||||
|
|
@ -339,6 +339,7 @@ proc assignLocalVar(p: BProc, s: PSym) =
|
||||||
# for each module that uses them!
|
# for each module that uses them!
|
||||||
if s.loc.k == locNone:
|
if s.loc.k == locNone:
|
||||||
fillLoc(s.loc, locLocalVar, s.typ, mangleName(s), OnStack)
|
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))
|
app(p.s[cpsLocals], getTypeDesc(p.module, s.loc.t))
|
||||||
if sfRegister in s.flags: app(p.s[cpsLocals], " register")
|
if sfRegister in s.flags: app(p.s[cpsLocals], " register")
|
||||||
if (sfVolatile in s.flags) or (p.nestedTryStmts.len > 0):
|
if (sfVolatile in s.flags) or (p.nestedTryStmts.len > 0):
|
||||||
|
|
@ -473,7 +474,7 @@ proc cgsym(m: BModule, name: string): PRope =
|
||||||
if sym != nil:
|
if sym != nil:
|
||||||
case sym.kind
|
case sym.kind
|
||||||
of skProc, skMethod, skConverter: genProc(m, sym)
|
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)
|
of skType: discard getTypeDesc(m, sym.typ)
|
||||||
else: InternalError("cgsym: " & name)
|
else: InternalError("cgsym: " & name)
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
|
|
@ -785,18 +785,12 @@ proc generateDoc(d: PDoc, n: PNode) =
|
||||||
of nkMacroDef: genItem(d, n, n.sons[namePos], skMacro)
|
of nkMacroDef: genItem(d, n, n.sons[namePos], skMacro)
|
||||||
of nkTemplateDef: genItem(d, n, n.sons[namePos], skTemplate)
|
of nkTemplateDef: genItem(d, n, n.sons[namePos], skTemplate)
|
||||||
of nkConverterDef: genItem(d, n, n.sons[namePos], skConverter)
|
of nkConverterDef: genItem(d, n, n.sons[namePos], skConverter)
|
||||||
of nkVarSection:
|
of nkTypeSection, nkVarSection, nkLetSection, nkConstSection:
|
||||||
for i in countup(0, sonsLen(n) - 1):
|
for i in countup(0, sonsLen(n) - 1):
|
||||||
if n.sons[i].kind != nkCommentStmt:
|
if n.sons[i].kind != nkCommentStmt:
|
||||||
genItem(d, n.sons[i], n.sons[i].sons[0], skVar)
|
# order is always 'type var let const':
|
||||||
of nkConstSection:
|
genItem(d, n.sons[i], n.sons[i].sons[0],
|
||||||
for i in countup(0, sonsLen(n) - 1):
|
succ(skType, ord(n.kind)-ord(nkTypeSection)))
|
||||||
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)
|
|
||||||
of nkStmtList:
|
of nkStmtList:
|
||||||
for i in countup(0, sonsLen(n) - 1): generateDoc(d, n.sons[i])
|
for i in countup(0, sonsLen(n) - 1): generateDoc(d, n.sons[i])
|
||||||
of nkWhenStmt:
|
of nkWhenStmt:
|
||||||
|
|
@ -810,7 +804,7 @@ proc generateDoc(d: PDoc, n: PNode) =
|
||||||
|
|
||||||
proc genSection(d: PDoc, kind: TSymKind) =
|
proc genSection(d: PDoc, kind: TSymKind) =
|
||||||
const sectionNames: array[skModule..skTemplate, string] = [
|
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"
|
"Iterators", "Converters", "Macros", "Templates"
|
||||||
]
|
]
|
||||||
if d.section[kind] == nil: return
|
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
|
s = n.sons[0].sym
|
||||||
if s.loc.r == nil: InternalError(n.info, "genAddr: 3")
|
if s.loc.r == nil: InternalError(n.info, "genAddr: 3")
|
||||||
case s.kind
|
case s.kind
|
||||||
of skVar, skResult:
|
of skVar, skLet, skResult:
|
||||||
if mapType(n.typ) == etyObject:
|
if mapType(n.typ) == etyObject:
|
||||||
# make addr() a no-op:
|
# make addr() a no-op:
|
||||||
r.kind = etyNone
|
r.kind = etyNone
|
||||||
|
|
@ -866,7 +866,7 @@ proc genSym(p: var TProc, n: PNode, r: var TCompRes) =
|
||||||
if s.loc.r == nil:
|
if s.loc.r == nil:
|
||||||
InternalError(n.info, "symbol has no generated name: " & s.name.s)
|
InternalError(n.info, "symbol has no generated name: " & s.name.s)
|
||||||
case s.kind
|
case s.kind
|
||||||
of skVar, skParam, skTemp, skResult:
|
of skVar, skLet, skParam, skTemp, skResult:
|
||||||
var k = mapType(s.typ)
|
var k = mapType(s.typ)
|
||||||
if k == etyBaseIndex:
|
if k == etyBaseIndex:
|
||||||
r.kind = 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 nkBlockStmt: genBlock(p, n, r)
|
||||||
of nkIfStmt: genIfStmt(p, n, r)
|
of nkIfStmt: genIfStmt(p, n, r)
|
||||||
of nkWhileStmt: genWhileStmt(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 nkConstSection: genConstStmt(p, n, r)
|
||||||
of nkForStmt: internalError(n.info, "for statement not eliminated")
|
of nkForStmt: internalError(n.info, "for statement not eliminated")
|
||||||
of nkCaseStmt: genCaseStmt(p, n, r)
|
of nkCaseStmt: genCaseStmt(p, n, r)
|
||||||
|
|
|
||||||
|
|
@ -452,7 +452,7 @@ proc evalSym(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode =
|
||||||
case s.kind
|
case s.kind
|
||||||
of skProc, skConverter, skMacro:
|
of skProc, skConverter, skMacro:
|
||||||
result = s.getBody
|
result = s.getBody
|
||||||
of skVar, skForVar, skTemp, skResult:
|
of skVar, skLet, skForVar, skTemp, skResult:
|
||||||
if sfGlobal notin s.flags:
|
if sfGlobal notin s.flags:
|
||||||
result = evalVariable(c.tos, s, flags)
|
result = evalVariable(c.tos, s, flags)
|
||||||
else:
|
else:
|
||||||
|
|
@ -1195,7 +1195,7 @@ proc evalAux(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode =
|
||||||
of nkWhenStmt, nkIfStmt, nkIfExpr: result = evalIf(c, n)
|
of nkWhenStmt, nkIfStmt, nkIfExpr: result = evalIf(c, n)
|
||||||
of nkWhileStmt: result = evalWhile(c, n)
|
of nkWhileStmt: result = evalWhile(c, n)
|
||||||
of nkCaseStmt: result = evalCase(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 nkTryStmt: result = evalTry(c, n)
|
||||||
of nkRaiseStmt: result = evalRaise(c, n)
|
of nkRaiseStmt: result = evalRaise(c, n)
|
||||||
of nkReturnStmt: result = evalReturn(c, n)
|
of nkReturnStmt: result = evalReturn(c, n)
|
||||||
|
|
|
||||||
|
|
@ -92,7 +92,7 @@ type
|
||||||
errCannotInterpretNodeX, errFieldXNotFound, errInvalidConversionFromTypeX,
|
errCannotInterpretNodeX, errFieldXNotFound, errInvalidConversionFromTypeX,
|
||||||
errAssertionFailed, errCannotGenerateCodeForX, errXRequiresOneArgument,
|
errAssertionFailed, errCannotGenerateCodeForX, errXRequiresOneArgument,
|
||||||
errUnhandledExceptionX, errCyclicTree, errXisNoMacroOrTemplate,
|
errUnhandledExceptionX, errCyclicTree, errXisNoMacroOrTemplate,
|
||||||
errXhasSideEffects, errIteratorExpected, errWrongSymbolX,
|
errXhasSideEffects, errIteratorExpected, errLetNeedsInit, errWrongSymbolX,
|
||||||
errUser,
|
errUser,
|
||||||
warnCannotOpenFile,
|
warnCannotOpenFile,
|
||||||
warnOctalEscape, warnXIsNeverRead, warnXmightNotBeenInit,
|
warnOctalEscape, warnXIsNeverRead, warnXmightNotBeenInit,
|
||||||
|
|
@ -320,6 +320,7 @@ const
|
||||||
errXisNoMacroOrTemplate: "\'$1\' is no macro or template",
|
errXisNoMacroOrTemplate: "\'$1\' is no macro or template",
|
||||||
errXhasSideEffects: "\'$1\' can have side effects",
|
errXhasSideEffects: "\'$1\' can have side effects",
|
||||||
errIteratorExpected: "iterator within for loop context expected",
|
errIteratorExpected: "iterator within for loop context expected",
|
||||||
|
errLetNeedsInit: "'let' symbol requires an initialization",
|
||||||
errWrongSymbolX: "usage of \'$1\' is a user-defined error",
|
errWrongSymbolX: "usage of \'$1\' is a user-defined error",
|
||||||
errUser: "$1",
|
errUser: "$1",
|
||||||
warnCannotOpenFile: "cannot open \'$1\' [CannotOpenFile]",
|
warnCannotOpenFile: "cannot open \'$1\' [CannotOpenFile]",
|
||||||
|
|
|
||||||
|
|
@ -18,5 +18,5 @@ const
|
||||||
VersionPatch* = 13
|
VersionPatch* = 13
|
||||||
VersionAsString* = $VersionMajor & "." & $VersionMinor & "." & $VersionPatch
|
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 tkConverter: result = parseRoutine(p, nkConverterDef)
|
||||||
of tkType: result = parseSection(p, nkTypeSection, parseTypeDef)
|
of tkType: result = parseSection(p, nkTypeSection, parseTypeDef)
|
||||||
of tkConst: result = parseSection(p, nkConstSection, parseConstant)
|
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 tkWhen: result = parseIfOrWhen(p, nkWhenStmt)
|
||||||
of tkVar: result = parseSection(p, nkVarSection, parseVariable)
|
of tkVar: result = parseSection(p, nkVarSection, parseVariable)
|
||||||
of tkBind: result = parseBind(p)
|
of tkBind: result = parseBind(p)
|
||||||
|
|
|
||||||
|
|
@ -52,6 +52,7 @@ const
|
||||||
wImportcpp, wImportobjc, wError, wNoInit}
|
wImportcpp, wImportobjc, wError, wNoInit}
|
||||||
constPragmas* = {wImportc, wExportc, wHeader, wDeprecated, wMagic, wNodecl,
|
constPragmas* = {wImportc, wExportc, wHeader, wDeprecated, wMagic, wNodecl,
|
||||||
wExtern, wImportcpp, wImportobjc, wError}
|
wExtern, wImportcpp, wImportobjc, wError}
|
||||||
|
letPragmas* = varPragmas
|
||||||
procTypePragmas* = {FirstCallConv..LastCallConv, wVarargs, wNosideEffect,
|
procTypePragmas* = {FirstCallConv..LastCallConv, wVarargs, wNosideEffect,
|
||||||
wThread}
|
wThread}
|
||||||
allRoutinePragmas* = procPragmas + iteratorPragmas + lambdaPragmas
|
allRoutinePragmas* = procPragmas + iteratorPragmas + lambdaPragmas
|
||||||
|
|
|
||||||
|
|
@ -385,7 +385,7 @@ proc lsub(n: PNode): int =
|
||||||
of nkProcTy: result = lsons(n) + len("proc_")
|
of nkProcTy: result = lsons(n) + len("proc_")
|
||||||
of nkEnumTy: result = lsub(n.sons[0]) + lcomma(n, 1) + len("enum_")
|
of nkEnumTy: result = lsub(n.sons[0]) + lcomma(n, 1) + len("enum_")
|
||||||
of nkEnumFieldDef: result = lsons(n) + 3
|
of nkEnumFieldDef: result = lsons(n) + 3
|
||||||
of nkVarSection:
|
of nkVarSection, nkLetSection:
|
||||||
if sonsLen(n) > 1: result = maxLineLen + 1
|
if sonsLen(n) > 1: result = maxLineLen + 1
|
||||||
else: result = lsons(n) + len("var_")
|
else: result = lsons(n) + len("var_")
|
||||||
of nkReturnStmt: result = lsub(n.sons[0]) + len("return_")
|
of nkReturnStmt: result = lsub(n.sons[0]) + len("return_")
|
||||||
|
|
@ -650,7 +650,7 @@ proc gident(g: var TSrcGen, n: PNode) =
|
||||||
else:
|
else:
|
||||||
t = tkOpr
|
t = tkOpr
|
||||||
put(g, t, s)
|
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) =
|
proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
|
||||||
var
|
var
|
||||||
|
|
@ -825,7 +825,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
|
||||||
of nkDerefExpr:
|
of nkDerefExpr:
|
||||||
gsub(g, n.sons[0])
|
gsub(g, n.sons[0])
|
||||||
putWithSpace(g, tkOpr, "^")
|
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:
|
of nkAccQuoted:
|
||||||
put(g, tkAccent, "`")
|
put(g, tkAccent, "`")
|
||||||
if n.len > 0: gsub(g, n.sons[0])
|
if n.len > 0: gsub(g, n.sons[0])
|
||||||
|
|
@ -960,10 +960,11 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
|
||||||
initContext(a)
|
initContext(a)
|
||||||
incl(a.flags, rfInConstExpr)
|
incl(a.flags, rfInConstExpr)
|
||||||
gsection(g, n, a, tkConst, "const")
|
gsection(g, n, a, tkConst, "const")
|
||||||
of nkVarSection:
|
of nkVarSection, nkLetSection:
|
||||||
L = sonsLen(n)
|
L = sonsLen(n)
|
||||||
if L == 0: return
|
if L == 0: return
|
||||||
putWithSpace(g, tkVar, "var")
|
if n.kind == nkVarSection: putWithSpace(g, tkVar, "var")
|
||||||
|
else: putWithSpace(g, tkLet, "let")
|
||||||
if L > 1:
|
if L > 1:
|
||||||
gcoms(g)
|
gcoms(g)
|
||||||
indentNL(g)
|
indentNL(g)
|
||||||
|
|
@ -1084,7 +1085,8 @@ proc renderTree(n: PNode, renderFlags: TRenderFlags = {}): string =
|
||||||
gsub(g, n)
|
gsub(g, n)
|
||||||
result = g.buf
|
result = g.buf
|
||||||
|
|
||||||
proc renderModule(n: PNode, filename: string, renderFlags: TRenderFlags = {}) =
|
proc renderModule(n: PNode, filename: string,
|
||||||
|
renderFlags: TRenderFlags = {}) =
|
||||||
var
|
var
|
||||||
f: tfile
|
f: tfile
|
||||||
g: TSrcGen
|
g: TSrcGen
|
||||||
|
|
@ -1093,7 +1095,8 @@ proc renderModule(n: PNode, filename: string, renderFlags: TRenderFlags = {}) =
|
||||||
gsub(g, n.sons[i])
|
gsub(g, n.sons[i])
|
||||||
optNL(g)
|
optNL(g)
|
||||||
case n.sons[i].kind
|
case n.sons[i].kind
|
||||||
of nkTypeSection, nkConstSection, nkVarSection, nkCommentStmt: putNL(g)
|
of nkTypeSection, nkConstSection, nkVarSection, nkLetSection,
|
||||||
|
nkCommentStmt: putNL(g)
|
||||||
else: nil
|
else: nil
|
||||||
gcoms(g)
|
gcoms(g)
|
||||||
if optStdout in gGlobalOptions:
|
if optStdout in gGlobalOptions:
|
||||||
|
|
|
||||||
|
|
@ -531,17 +531,10 @@ proc process(c: PPassContext, n: PNode): PNode =
|
||||||
if n.sons[bodyPos].kind != nkEmpty or s.magic != mNone or
|
if n.sons[bodyPos].kind != nkEmpty or s.magic != mNone or
|
||||||
sfForward notin s.flags:
|
sfForward notin s.flags:
|
||||||
addInterfaceSym(w, s)
|
addInterfaceSym(w, s)
|
||||||
of nkVarSection:
|
of nkVarSection, nkLetSection, nkConstSection:
|
||||||
for i in countup(0, sonsLen(n) - 1):
|
for i in countup(0, sonsLen(n) - 1):
|
||||||
var a = n.sons[i]
|
var a = n.sons[i]
|
||||||
if a.kind == nkCommentStmt: continue
|
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")
|
|
||||||
addInterfaceSym(w, a.sons[0].sym)
|
addInterfaceSym(w, a.sons[0].sym)
|
||||||
of nkTypeSection:
|
of nkTypeSection:
|
||||||
for i in countup(0, sonsLen(n) - 1):
|
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)
|
result = newSymNode(s, n.info)
|
||||||
of skMacro: result = semMacroExpr(c, n, s)
|
of skMacro: result = semMacroExpr(c, n, s)
|
||||||
of skTemplate: result = semTemplateExpr(c, n, s)
|
of skTemplate: result = semTemplateExpr(c, n, s)
|
||||||
of skVar, skResult:
|
of skVar, skLet, skResult:
|
||||||
markUsed(n, s)
|
markUsed(n, s)
|
||||||
# if a proc accesses a global variable, it is not side effect free:
|
# if a proc accesses a global variable, it is not side effect free:
|
||||||
if sfGlobal in s.flags: incl(c.p.owner.flags, sfSideEffect)
|
if sfGlobal in s.flags: incl(c.p.owner.flags, sfSideEffect)
|
||||||
|
|
@ -372,6 +372,7 @@ proc isAssignable(c: PContext, n: PNode): TAssignableResult =
|
||||||
result = arNone
|
result = arNone
|
||||||
case n.kind
|
case n.kind
|
||||||
of nkSym:
|
of nkSym:
|
||||||
|
# don't list 'skLet' here:
|
||||||
if n.sym.kind in {skVar, skResult, skTemp}:
|
if n.sym.kind in {skVar, skResult, skTemp}:
|
||||||
if c.p.owner.id == n.sym.owner.id: result = arLocalLValue
|
if c.p.owner.id == n.sym.owner.id: result = arLocalLValue
|
||||||
else: result = arLValue
|
else: result = arLValue
|
||||||
|
|
|
||||||
|
|
@ -163,7 +163,7 @@ proc semGenericStmt(c: PContext, n: PNode,
|
||||||
for j in countup(0, L-2):
|
for j in countup(0, L-2):
|
||||||
a.sons[j] = semGenericStmt(c, a.sons[j], flags+{withinTypeDesc}, toBind)
|
a.sons[j] = semGenericStmt(c, a.sons[j], flags+{withinTypeDesc}, toBind)
|
||||||
a.sons[L-1] = semGenericStmtScope(c, a.sons[L-1], flags, 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):
|
for i in countup(0, sonsLen(n) - 1):
|
||||||
var a = n.sons[i]
|
var a = n.sons[i]
|
||||||
if a.kind == nkCommentStmt: continue
|
if a.kind == nkCommentStmt: continue
|
||||||
|
|
|
||||||
|
|
@ -223,14 +223,14 @@ proc semIdentDef(c: PContext, n: PNode, kind: TSymKind): PSym =
|
||||||
else:
|
else:
|
||||||
result = semIdentWithPragma(c, kind, n, {})
|
result = semIdentWithPragma(c, kind, n, {})
|
||||||
|
|
||||||
proc semVar(c: PContext, n: PNode): PNode =
|
proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
|
||||||
var b: PNode
|
var b: PNode
|
||||||
result = copyNode(n)
|
result = copyNode(n)
|
||||||
for i in countup(0, sonsLen(n)-1):
|
for i in countup(0, sonsLen(n)-1):
|
||||||
var a = n.sons[i]
|
var a = n.sons[i]
|
||||||
if gCmd == cmdIdeTools: suggestStmt(c, a)
|
if gCmd == cmdIdeTools: suggestStmt(c, a)
|
||||||
if a.kind == nkCommentStmt: continue
|
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)
|
checkMinSonsLen(a, 3)
|
||||||
var length = sonsLen(a)
|
var length = sonsLen(a)
|
||||||
var typ: PType
|
var typ: PType
|
||||||
|
|
@ -247,9 +247,11 @@ proc semVar(c: PContext, n: PNode): PNode =
|
||||||
else: typ = def.typ
|
else: typ = def.typ
|
||||||
else:
|
else:
|
||||||
def = ast.emptyNode
|
def = ast.emptyNode
|
||||||
|
if symkind == skLet: GlobalError(a.info, errLetNeedsInit)
|
||||||
|
|
||||||
# this can only happen for errornous var statements:
|
# this can only happen for errornous var statements:
|
||||||
if typ == nil: continue
|
if typ == nil: continue
|
||||||
if not typeAllowed(typ, skVar):
|
if not typeAllowed(typ, symkind):
|
||||||
GlobalError(a.info, errXisNoType, typeToString(typ))
|
GlobalError(a.info, errXisNoType, typeToString(typ))
|
||||||
var tup = skipTypes(typ, {tyGenericInst})
|
var tup = skipTypes(typ, {tyGenericInst})
|
||||||
if a.kind == nkVarTuple:
|
if a.kind == nkVarTuple:
|
||||||
|
|
@ -262,7 +264,7 @@ proc semVar(c: PContext, n: PNode): PNode =
|
||||||
b.sons[length-1] = def
|
b.sons[length-1] = def
|
||||||
addSon(result, b)
|
addSon(result, b)
|
||||||
for j in countup(0, length-3):
|
for j in countup(0, length-3):
|
||||||
var v = semIdentDef(c, a.sons[j], skVar)
|
var v = semIdentDef(c, a.sons[j], symkind)
|
||||||
addInterfaceDecl(c, v)
|
addInterfaceDecl(c, v)
|
||||||
if def != nil and def.kind != nkEmpty:
|
if def != nil and def.kind != nkEmpty:
|
||||||
# this is only needed for the evaluation pass:
|
# this is only needed for the evaluation pass:
|
||||||
|
|
@ -823,7 +825,8 @@ proc SemStmt(c: PContext, n: PNode): PNode =
|
||||||
of nkPragma, nkCommentStmt, nkNilLit, nkEmpty: nil
|
of nkPragma, nkCommentStmt, nkNilLit, nkEmpty: nil
|
||||||
else: localError(n.sons[j].info, errStmtInvalidAfterReturn)
|
else: localError(n.sons[j].info, errStmtInvalidAfterReturn)
|
||||||
of nkRaiseStmt: result = semRaise(c, n)
|
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 nkConstSection: result = semConst(c, n)
|
||||||
of nkTypeSection: result = SemTypeSection(c, n)
|
of nkTypeSection: result = SemTypeSection(c, n)
|
||||||
of nkIfStmt: result = SemIf(c, n)
|
of nkIfStmt: result = SemIf(c, n)
|
||||||
|
|
|
||||||
|
|
@ -107,7 +107,7 @@ proc analyseSym(c: PProcCtx, n: PNode): TThreadOwner =
|
||||||
result = c.mapping[v.id]
|
result = c.mapping[v.id]
|
||||||
if result != toUndefined: return
|
if result != toUndefined: return
|
||||||
case v.kind
|
case v.kind
|
||||||
of skVar, skResult:
|
of skVar, skLet, skResult:
|
||||||
result = toNil
|
result = toNil
|
||||||
if sfGlobal in v.flags:
|
if sfGlobal in v.flags:
|
||||||
if sfThread 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])
|
var a = analyse(c, n.sons[0])
|
||||||
if a != toMine: Message(n.info, warnDifferentHeaps)
|
if a != toMine: Message(n.info, warnDifferentHeaps)
|
||||||
result = toVoid
|
result = toVoid
|
||||||
of nkVarSection: result = analyseVarSection(c, n)
|
of nkVarSection, nkLetSection: result = analyseVarSection(c, n)
|
||||||
of nkConstSection: result = analyseConstSection(c, n)
|
of nkConstSection: result = analyseConstSection(c, n)
|
||||||
of nkTypeSection, nkCommentStmt: result = toVoid
|
of nkTypeSection, nkCommentStmt: result = toVoid
|
||||||
of nkIfStmt, nkWhileStmt, nkTryStmt, nkCaseStmt, nkStmtList, nkBlockStmt,
|
of nkIfStmt, nkWhileStmt, nkTryStmt, nkCaseStmt, nkStmtList, nkBlockStmt,
|
||||||
|
|
|
||||||
|
|
@ -242,6 +242,7 @@ proc semIdentWithPragma(c: PContext, kind: TSymKind, n: PNode,
|
||||||
# process pragmas later, because result.typ has not been set yet
|
# process pragmas later, because result.typ has not been set yet
|
||||||
of skField: pragma(c, result, n.sons[1], fieldPragmas)
|
of skField: pragma(c, result, n.sons[1], fieldPragmas)
|
||||||
of skVar: pragma(c, result, n.sons[1], varPragmas)
|
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)
|
of skConst: pragma(c, result, n.sons[1], constPragmas)
|
||||||
else: nil
|
else: nil
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
|
|
@ -294,7 +294,7 @@ proc introduceNewLocalVars(c: PTransf, n: PNode): PTransNode =
|
||||||
of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit:
|
of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit:
|
||||||
# nothing to be done for leaves:
|
# nothing to be done for leaves:
|
||||||
result = PTransNode(n)
|
result = PTransNode(n)
|
||||||
of nkVarSection:
|
of nkVarSection, nkLetSection:
|
||||||
result = transformVarSection(c, n)
|
result = transformVarSection(c, n)
|
||||||
else:
|
else:
|
||||||
result = newTransNode(n)
|
result = newTransNode(n)
|
||||||
|
|
@ -518,7 +518,7 @@ proc gatherVars(c: PTransf, n: PNode, marked: var TIntSet, owner: PSym,
|
||||||
var s = n.sym
|
var s = n.sym
|
||||||
var found = false
|
var found = false
|
||||||
case s.kind
|
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
|
of skTemp, skForVar, skParam, skResult: found = true
|
||||||
else: nil
|
else: nil
|
||||||
if found and owner.id != s.owner.id and not ContainsOrIncl(marked, s.id):
|
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:
|
of nkConstSection:
|
||||||
# do not replace ``const c = 3`` with ``const 3 = 3``
|
# do not replace ``const c = 3`` with ``const 3 = 3``
|
||||||
return transformConstSection(c, n)
|
return transformConstSection(c, n)
|
||||||
of nkVarSection:
|
of nkVarSection, nkLetSection:
|
||||||
if c.inlining > 0:
|
if c.inlining > 0:
|
||||||
# we need to copy the variables for multiple yield statements:
|
# we need to copy the variables for multiple yield statements:
|
||||||
result = transformVarSection(c, n)
|
result = transformVarSection(c, n)
|
||||||
|
|
|
||||||
|
|
@ -816,7 +816,7 @@ proc matchType*(a: PType, pattern: openArray[tuple[k:TTypeKind, i:int]],
|
||||||
result = a.kind == last
|
result = a.kind == last
|
||||||
|
|
||||||
proc typeAllowedAux(marker: var TIntSet, typ: PType, kind: TSymKind): bool =
|
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
|
# if we have already checked the type, return true, because we stop the
|
||||||
# evaluation if something is wrong:
|
# evaluation if something is wrong:
|
||||||
result = true
|
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
|
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
|
same type as the initializing expression. Variables are always initialized
|
||||||
|
|
||||||
with a default value if there is no initializing expression. The default
|
with a default value if there is no initializing expression. The default
|
||||||
value depends on the type and is always a zero in binary.
|
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]
|
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
|
Const section
|
||||||
~~~~~~~~~~~~~
|
~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
|
|
||||||
25
doc/tut1.txt
25
doc/tut1.txt
|
|
@ -213,6 +213,17 @@ constants:
|
||||||
z = y + 5 # computations are possible
|
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
|
Control flow statements
|
||||||
=======================
|
=======================
|
||||||
|
|
||||||
|
|
@ -227,7 +238,7 @@ If statement
|
||||||
The if statement is one way to branch the control flow:
|
The if statement is one way to branch the control flow:
|
||||||
|
|
||||||
.. code-block:: nimrod
|
.. code-block:: nimrod
|
||||||
var name = readLine(stdin)
|
let name = readLine(stdin)
|
||||||
if name == "":
|
if name == "":
|
||||||
echo("Poor soul, you lost your name?")
|
echo("Poor soul, you lost your name?")
|
||||||
elif name == "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:
|
a multi-branch:
|
||||||
|
|
||||||
.. code-block:: nimrod
|
.. code-block:: nimrod
|
||||||
var name = readLine(stdin)
|
let name = readLine(stdin)
|
||||||
case name
|
case name
|
||||||
of "":
|
of "":
|
||||||
echo("Poor soul, you lost your name?")
|
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
|
from strutils import parseInt
|
||||||
|
|
||||||
Echo("A number please: ")
|
Echo("A number please: ")
|
||||||
var n = parseInt(readLine(stdin))
|
let n = parseInt(readLine(stdin))
|
||||||
case n
|
case n
|
||||||
of 0..2, 4..7: Echo("The number is in the set: {0, 1, 2, 4, 5, 6, 7}")
|
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")
|
of 3, 8: Echo("The number is 3 or 8")
|
||||||
|
|
@ -410,7 +421,7 @@ the next iteration immediately:
|
||||||
|
|
||||||
.. code-block:: nimrod
|
.. code-block:: nimrod
|
||||||
while true:
|
while true:
|
||||||
var x = readLine(stdin)
|
let x = readLine(stdin)
|
||||||
if x == "": continue
|
if x == "": continue
|
||||||
Echo(x)
|
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
|
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
|
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
|
such a `forward declaration`:idx: is simple: just omit the ``=`` and the
|
||||||
body.
|
procedure's body.
|
||||||
|
|
||||||
|
|
||||||
Iterators
|
Iterators
|
||||||
|
|
@ -846,7 +857,7 @@ to mark them to be of another integer type:
|
||||||
|
|
||||||
|
|
||||||
.. code-block:: nimrod
|
.. code-block:: nimrod
|
||||||
var
|
let
|
||||||
x = 0 # x is of type ``int``
|
x = 0 # x is of type ``int``
|
||||||
y = 0'i8 # y is of type ``int8``
|
y = 0'i8 # y is of type ``int8``
|
||||||
z = 0'i64 # z is of type ``int64``
|
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
|
.. code-block:: nimrod
|
||||||
|
|
||||||
template withFile(f: expr, filename: string, mode: TFileMode,
|
template withFile(f: expr, filename: string, mode: TFileMode,
|
||||||
actions: stmt): stmt =
|
body: stmt): stmt =
|
||||||
block:
|
block:
|
||||||
var fn = filename
|
let fn = filename
|
||||||
var f: TFile
|
var f: TFile
|
||||||
if open(f, fn, mode):
|
if open(f, fn, mode):
|
||||||
try:
|
try:
|
||||||
actions
|
body
|
||||||
finally:
|
finally:
|
||||||
close(f)
|
close(f)
|
||||||
else:
|
else:
|
||||||
|
|
@ -596,10 +596,10 @@ via a special ``:`` syntax:
|
||||||
txt.writeln("line 1")
|
txt.writeln("line 1")
|
||||||
txt.writeln("line 2")
|
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
|
parameter. The ``withFile`` template contains boilerplate code and helps to
|
||||||
avoid a common bug: to forget to close the file. Note how the
|
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.
|
once.
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -37,8 +37,8 @@ type
|
||||||
nnkElifBranch, nnkExceptBranch, nnkElse, nnkMacroStmt,
|
nnkElifBranch, nnkExceptBranch, nnkElse, nnkMacroStmt,
|
||||||
nnkAsmStmt, nnkPragma, nnkIfStmt, nnkWhenStmt,
|
nnkAsmStmt, nnkPragma, nnkIfStmt, nnkWhenStmt,
|
||||||
nnkForStmt, nnkWhileStmt, nnkCaseStmt,
|
nnkForStmt, nnkWhileStmt, nnkCaseStmt,
|
||||||
nnkVarSection, nnkLetSection, nnkConstSection,
|
nnkTypeSection, nnkVarSection, nnkLetSection, nnkConstSection,
|
||||||
nnkConstDef, nnkTypeSection, nnkTypeDef,
|
nnkConstDef, nnkTypeDef,
|
||||||
nnkYieldStmt, nnkTryStmt, nnkFinally, nnkRaiseStmt,
|
nnkYieldStmt, nnkTryStmt, nnkFinally, nnkRaiseStmt,
|
||||||
nnkReturnStmt, nnkBreakStmt, nnkContinueStmt, nnkBlockStmt,
|
nnkReturnStmt, nnkBreakStmt, nnkContinueStmt, nnkBlockStmt,
|
||||||
nnkDiscardStmt, nnkStmtList, nnkImportStmt, nnkFromStmt,
|
nnkDiscardStmt, nnkStmtList, nnkImportStmt, nnkFromStmt,
|
||||||
|
|
|
||||||
|
|
@ -360,7 +360,8 @@ proc threadId*[TArg](t: var TThread[TArg]): TThreadId[TArg] {.inline.} =
|
||||||
result = addr(t)
|
result = addr(t)
|
||||||
|
|
||||||
proc myThreadId*[TArg](): TThreadId[TArg] =
|
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))
|
result = cast[TThreadId[TArg]](ThreadVarGetValue(globalsSlot))
|
||||||
|
|
||||||
when false:
|
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 =
|
pegLineError =
|
||||||
peg"{[^(]*} '(' {\d+} ', ' \d+ ') ' ('Error'/'Warning') ':' \s* {.*}"
|
peg"{[^(]*} '(' {\d+} ', ' \d+ ') ' ('Error'/'Warning') ':' \s* {.*}"
|
||||||
pegOtherError = peg"'Error:' \s* {.*}"
|
pegOtherError = peg"'Error:' \s* {.*}"
|
||||||
|
|
@ -111,10 +111,10 @@ var
|
||||||
pegOfInterest = pegLineError / pegOtherError
|
pegOfInterest = pegLineError / pegOtherError
|
||||||
|
|
||||||
proc callCompiler(cmdTemplate, filename, options: string): TSpec =
|
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],
|
var p = startProcess(command=c[0], args=c[1.. -1],
|
||||||
options={poStdErrToStdOut, poUseShell})
|
options={poStdErrToStdOut, poUseShell})
|
||||||
var outp = p.outputStream
|
let outp = p.outputStream
|
||||||
var suc = ""
|
var suc = ""
|
||||||
var err = ""
|
var err = ""
|
||||||
var x = newStringOfCap(120)
|
var x = newStringOfCap(120)
|
||||||
|
|
@ -222,7 +222,7 @@ proc cmpMsgs(r: var TResults, expected, given: TSpec, test: string) =
|
||||||
inc(r.passed)
|
inc(r.passed)
|
||||||
|
|
||||||
proc rejectSingleTest(r: var TResults, test, options: string) =
|
proc rejectSingleTest(r: var TResults, test, options: string) =
|
||||||
var test = test.addFileExt(".nim")
|
let test = test.addFileExt(".nim")
|
||||||
var t = extractFilename(test)
|
var t = extractFilename(test)
|
||||||
inc(r.total)
|
inc(r.total)
|
||||||
echo t
|
echo t
|
||||||
|
|
@ -240,10 +240,10 @@ proc reject(r: var TResults, dir, options: string) =
|
||||||
|
|
||||||
proc compile(r: var TResults, pattern, options: string) =
|
proc compile(r: var TResults, pattern, options: string) =
|
||||||
for test in os.walkFiles(pattern):
|
for test in os.walkFiles(pattern):
|
||||||
var t = extractFilename(test)
|
let t = extractFilename(test)
|
||||||
echo t
|
echo t
|
||||||
inc(r.total)
|
inc(r.total)
|
||||||
var expected = parseSpec(test)
|
let expected = parseSpec(test)
|
||||||
if expected.disabled:
|
if expected.disabled:
|
||||||
r.addResult(t, "", reIgnored)
|
r.addResult(t, "", reIgnored)
|
||||||
inc(r.skipped)
|
inc(r.skipped)
|
||||||
|
|
@ -253,11 +253,11 @@ proc compile(r: var TResults, pattern, options: string) =
|
||||||
if not given.err: inc(r.passed)
|
if not given.err: inc(r.passed)
|
||||||
|
|
||||||
proc compileSingleTest(r: var TResults, test, options: string) =
|
proc compileSingleTest(r: var TResults, test, options: string) =
|
||||||
var test = test.addFileExt(".nim")
|
let test = test.addFileExt(".nim")
|
||||||
var t = extractFilename(test)
|
let t = extractFilename(test)
|
||||||
inc(r.total)
|
inc(r.total)
|
||||||
echo t
|
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)
|
r.addResult(t, given.msg, if given.err: reFailure else: reSuccess)
|
||||||
if not given.err: inc(r.passed)
|
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
|
- 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
|
version 0.9.0
|
||||||
=============
|
=============
|
||||||
|
|
@ -11,18 +14,13 @@ version 0.9.0
|
||||||
escape analysis for string/seq seems to be easy to do too
|
escape analysis for string/seq seems to be easy to do too
|
||||||
- dead code elim for JS backend; 'of' operator for JS backend
|
- dead code elim for JS backend; 'of' operator for JS backend
|
||||||
- test the sort implementation again
|
- test the sort implementation again
|
||||||
- 'let x = y'
|
|
||||||
- const ptr/ref
|
- const ptr/ref
|
||||||
- unsigned ints and bignums; requires abstract integer literal type:
|
- unsigned ints and bignums; requires abstract integer literal type:
|
||||||
use tyInt+node for that
|
use tyInt+node for that
|
||||||
- implement the high level optimizer
|
- 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
|
- change overloading resolution
|
||||||
- implement closures; implement proper coroutines
|
- implement closures; implement proper coroutines
|
||||||
- implement ``partial`` pragma for partial evaluation
|
- 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
|
- we need to support iteration of 2 different data structures in parallel
|
||||||
- make exceptions compatible with C++ exceptions
|
- make exceptions compatible with C++ exceptions
|
||||||
- ``=`` should be overloadable; requires specialization for ``=``
|
- ``=`` should be overloadable; requires specialization for ``=``
|
||||||
|
|
@ -52,7 +50,6 @@ Bugs
|
||||||
- bug: stress testing basic method example (eval example)
|
- bug: stress testing basic method example (eval example)
|
||||||
without ``-d:release`` leaks memory; good way to figure out how a
|
without ``-d:release`` leaks memory; good way to figure out how a
|
||||||
fixed amount of stack can hold an arbitrary number of GC roots!
|
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
|
version 0.9.XX
|
||||||
|
|
|
||||||
|
|
@ -74,6 +74,7 @@ Language Additions
|
||||||
heart's content.
|
heart's content.
|
||||||
- ``bind`` (used for symbol binding in templates and generics) is now a
|
- ``bind`` (used for symbol binding in templates and generics) is now a
|
||||||
declarative statement.
|
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
|
- The slice assignment ``a[i..j] = b`` where ``a`` is a sequence or string
|
||||||
now supports *splicing*.
|
now supports *splicing*.
|
||||||
|
|
||||||
|
|
@ -114,7 +115,6 @@ Compiler Additions
|
||||||
Library Additions
|
Library Additions
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
- Added ``system.mainThreadId``.
|
|
||||||
- Added ``system.allocShared``, ``system.allocShared0``,
|
- Added ``system.allocShared``, ``system.allocShared0``,
|
||||||
``system.deallocShared``, ``system.reallocShared``.
|
``system.deallocShared``, ``system.reallocShared``.
|
||||||
- Slicing as implemented by the system module now supports *splicing*.
|
- Slicing as implemented by the system module now supports *splicing*.
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue