implemented 'let' statement

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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