diff options
author | Araq <rumpf_a@web.de> | 2011-10-07 09:02:08 +0200 |
---|---|---|
committer | Araq <rumpf_a@web.de> | 2011-10-07 09:02:08 +0200 |
commit | 42516c0086faa41c0d8613759ebc263bd1e989e9 (patch) | |
tree | a858aebc4e2a786256b8b52457745ec8904d0c91 /compiler | |
parent | e9b7d5e68eeeb6d468d407437502fd1c178adc43 (diff) | |
download | Nim-42516c0086faa41c0d8613759ebc263bd1e989e9.tar.gz |
code generator supports constant sequences; more consistent compile time evaluation
Diffstat (limited to 'compiler')
-rwxr-xr-x | compiler/ast.nim | 6 | ||||
-rwxr-xr-x | compiler/ccgexprs.nim | 25 | ||||
-rwxr-xr-x | compiler/ccgstmts.nim | 3 | ||||
-rwxr-xr-x | compiler/ecmasgen.nim | 1 | ||||
-rwxr-xr-x | compiler/evals.nim | 16 | ||||
-rwxr-xr-x | compiler/sem.nim | 23 | ||||
-rwxr-xr-x | compiler/semexprs.nim | 44 | ||||
-rwxr-xr-x | compiler/semfold.nim | 20 | ||||
-rwxr-xr-x | compiler/semstmts.nim | 41 | ||||
-rwxr-xr-x | compiler/transf.nim | 24 | ||||
-rwxr-xr-x | compiler/types.nim | 2 |
11 files changed, 123 insertions, 82 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim index 775f679df..b33d99554 100755 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -559,9 +559,11 @@ const tyBool, tyChar, tyEnum, tyArray, tyObject, tySet, tyTuple, tyRange, tyPtr, tyRef, tyVar, tySequence, tyProc, tyPointer, - tyOpenArray, tyString, tyCString, tyInt..tyInt64, tyFloat..tyFloat128} + tyOpenArray, tyString, tyCString, tyInt..tyInt64, tyFloat..tyFloat128, + tyUInt..tyUInt64} - ConstantDataTypes*: TTypeKinds = {tyArray, tySet, tyTuple} + ConstantDataTypes*: TTypeKinds = {tyArrayConstr, tyArray, tySet, + tyTuple, tySequence} ExportableSymKinds* = {skVar, skConst, skProc, skMethod, skType, skIterator, skMacro, skTemplate, skConverter, skStub} PersistentNodeFlags*: TNodeFlags = {nfBase2, nfBase8, nfBase16, nfAllConst} diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 409dd51c2..826832438 100755 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -1831,6 +1831,7 @@ proc expr(p: BProc, e: PNode, d: var TLoc) = if sym.loc.r == nil or sym.loc.t == nil: InternalError(e.info, "expr: proc not init " & sym.name.s) putLocIntoDest(p, d, sym.loc) + of nkMetaNode: expr(p, e.sons[0], d) else: InternalError(e.info, "expr(" & $e.kind & "); unknown node kind") proc genNamedConstExpr(p: BProc, n: PNode): PRope = @@ -1845,6 +1846,24 @@ proc genConstSimpleList(p: BProc, n: PNode): PRope = if length > 0: app(result, genNamedConstExpr(p, n.sons[length - 1])) appf(result, "}$n") +proc genConstSeq(p: BProc, n: PNode, t: PType): PRope = + var data = ropef("{{$1, $1}", n.len.toRope) + for i in countup(0, n.len - 1): + appf(data, ",$1$n", [genConstExpr(p, n.sons[i])]) + data.app("}") + + inc(p.labels) + result = con("CNSTSEQ", p.labels.toRope) + + appcg(p.module, cfsData, + "NIM_CONST struct {$n" & + " #TGenericSeq Sup;$n" & + " $1 data[$2];$n" & + "} $3 = $4;$n", [ + getTypeDesc(p.module, t.sons[0]), n.len.toRope, result, data]) + + result = ropef("(($1)&$2)", [getTypeDesc(p.module, t), result]) + proc genConstExpr(p: BProc, n: PNode): PRope = case n.Kind of nkHiddenStdConv, nkHiddenSubConv: @@ -1855,7 +1874,11 @@ proc genConstExpr(p: BProc, n: PNode): PRope = result = genRawSetData(cs, int(getSize(n.typ))) of nkBracket, nkPar: # XXX: tySequence! - result = genConstSimpleList(p, n) + var t = skipTypes(n.typ, abstractInst) + if t.kind == tySequence: + result = genConstSeq(p, n, t) + else: + result = genConstSimpleList(p, n) else: var d: TLoc initLocExpr(p, n, d) diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index f982f2c22..bf3d6aea1 100755 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -67,7 +67,8 @@ proc genConstStmt(p: BProc, t: PNode) = var c = it.sons[0].sym if sfFakeConst in c.flags: genSingleVar(p, it) - elif c.typ.kind in ConstantDataTypes and not (lfNoDecl in c.loc.flags): + elif c.typ.kind in ConstantDataTypes and not (lfNoDecl in c.loc.flags) and + c.ast.len != 0: # generate the data: fillLoc(c.loc, locData, c.typ, mangleName(c), OnUnknown) if sfImportc in c.flags: diff --git a/compiler/ecmasgen.nim b/compiler/ecmasgen.nim index 42643b39e..7ad4dbd8b 100755 --- a/compiler/ecmasgen.nim +++ b/compiler/ecmasgen.nim @@ -1426,6 +1426,7 @@ proc gen(p: var TProc, n: PNode, r: var TCompRes) = of nkCStringToString: convCStrToStr(p, n, r) of nkStmtListExpr: genStmtListExpr(p, n, r) of nkEmpty: nil + of nkMetaNode: gen(p, n.sons[0], r) else: InternalError(n.info, "gen: unknown node type: " & $n.kind) var globals: PGlobals diff --git a/compiler/evals.nim b/compiler/evals.nim index a61d687ef..1d443a404 100755 --- a/compiler/evals.nim +++ b/compiler/evals.nim @@ -43,7 +43,7 @@ const evalMaxIterations = 500_000 # max iterations of all loops evalMaxRecDepth = 10_000 # max recursion depth for evaluation -# Much better: use a timeout! -> Wether code compiles depends on the machine +# other idea: use a timeout! -> Wether code compiles depends on the machine # the compiler runs on then! Bad idea! proc newStackFrame*(): PStackFrame = @@ -754,17 +754,15 @@ proc evalRepr(c: PEvalContext, n: PNode): PNode = if isSpecial(result): return result = newStrNodeT(renderTree(result, {renderNoComments}), n) -proc isEmpty(n: PNode): bool = - result = (n != nil) and (n.kind == nkEmpty) +proc isEmpty(n: PNode): bool = + result = n != nil and n.kind == nkEmpty # The lexer marks multi-line strings as residing at the line where they # are closed. This function returns the line where the string begins # Maybe the lexer should mark both the beginning and the end of expressions, # then this function could be removed. proc stringStartingLine(s: PNode): int = - var totalLines = 0 - for ln in splitLines(s.strVal): inc totalLines - result = s.info.line - totalLines + result = s.info.line - countLines(s.strVal) proc evalParseExpr(c: PEvalContext, n: Pnode): Pnode = var code = evalAux(c, n.sons[1], {}) @@ -1069,9 +1067,6 @@ proc evalAux(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode = dec(gNestedEvals) if gNestedEvals <= 0: stackTrace(c, n, errTooManyIterations) case n.kind # atoms: - of nkMetaNode: - result = copyTree(n.sons[0]) - result.typ = n.typ of nkEmpty: result = n of nkSym: result = evalSym(c, n, flags) of nkType..nkNilLit: result = copyNode(n) # end of atoms @@ -1131,6 +1126,9 @@ proc evalAux(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode = nkTypeSection, nkTemplateDef, nkConstSection, nkIteratorDef, nkConverterDef, nkIncludeStmt, nkImportStmt, nkFromStmt: nil + of nkMetaNode: + result = copyTree(n.sons[0]) + result.typ = n.typ of nkIdentDefs, nkCast, nkYieldStmt, nkAsmStmt, nkForStmt, nkPragmaExpr, nkLambda, nkContinueStmt, nkIdent: stackTrace(c, n, errCannotInterpretNodeX, $n.kind) diff --git a/compiler/sem.nim b/compiler/sem.nim index 78a04f744..dcbdac157 100755 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -55,25 +55,26 @@ proc ParamsTypeCheck(c: PContext, typ: PType) {.inline.} = GlobalError(typ.n.info, errXisNoType, typeToString(typ)) proc semConstExpr(c: PContext, n: PNode): PNode = - result = semExprWithType(c, n) - if result == nil: - GlobalError(n.info, errConstExprExpected) - return - result = getConstExpr(c.module, result) - if result == nil: GlobalError(n.info, errConstExprExpected) - -proc semAndEvalConstExpr(c: PContext, n: PNode): PNode = var e = semExprWithType(c, n) if e == nil: GlobalError(n.info, errConstExprExpected) return nil result = getConstExpr(c.module, e) - if result == nil: - #writeln(output, renderTree(n)); + if result == nil: result = evalConstExpr(c.module, e) if result == nil or result.kind == nkEmpty: GlobalError(n.info, errConstExprExpected) - + when false: + result = semExprWithType(c, n) + if result == nil: + GlobalError(n.info, errConstExprExpected) + return + result = getConstExpr(c.module, result) + if result == nil: GlobalError(n.info, errConstExprExpected) + +proc semAndEvalConstExpr(c: PContext, n: PNode): PNode = + result = semConstExpr(c, n) + include seminst, semcall proc typeMismatch(n: PNode, formal, actual: PType) = diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index e720cf055..356f1c196 100755 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -9,10 +9,6 @@ # this module does the semantic checking for expressions -const - ConstAbstractTypes = {tyNil, tyChar, tyInt..tyInt64, tyFloat..tyFloat128, - tyArrayConstr, tyTuple, tySet} - proc semTemplateExpr(c: PContext, n: PNode, s: PSym, semCheck = true): PNode = markUsed(n, s) pushInfoContext(n.info) @@ -49,6 +45,11 @@ proc semExprNoDeref(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = proc semSymGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode = result = symChoice(c, n, s) +proc inlineConst(n: PNode, s: PSym): PNode {.inline.} = + result = copyTree(s.ast) + result.typ = s.typ + result.info = n.info + proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode = case s.kind of skProc, skMethod, skIterator, skConverter: @@ -56,24 +57,25 @@ proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode = getModule(s).id != c.module.id: LocalError(n.info, errXCannotBePassedToProcVar, s.name.s) result = symChoice(c, n, s) - of skConst: - # - # Consider:: - # const x = [] - # proc p(a: openarray[int]) - # proc q(a: openarray[char]) - # p(x) - # q(x) - # - # It is clear that ``[]`` means two totally different things. Thus, we - # copy `x`'s AST into each context, so that the type fixup phase can - # deal with two different ``[]``. - # + of skConst: markUsed(n, s) - if s.typ.kind in ConstAbstractTypes: - result = copyTree(s.ast) - result.typ = s.typ - result.info = n.info + case skipTypes(s.typ, abstractInst).kind + of tyNil, tyChar, tyInt..tyInt64, tyFloat..tyFloat128, + tyTuple, tySet, tyUInt..tyUInt64: + result = inlineConst(n, s) + of tyArrayConstr, tySequence: + # Consider:: + # const x = [] + # proc p(a: openarray[int]) + # proc q(a: openarray[char]) + # p(x) + # q(x) + # + # It is clear that ``[]`` means two totally different things. Thus, we + # copy `x`'s AST into each context, so that the type fixup phase can + # deal with two different ``[]``. + if s.ast.len == 0: result = inlineConst(n, s) + else: result = newSymNode(s, n.info) else: result = newSymNode(s, n.info) of skMacro: result = semMacroExpr(c, n, s) diff --git a/compiler/semfold.nim b/compiler/semfold.nim index 570656a39..77d84b6f8 100755 --- a/compiler/semfold.nim +++ b/compiler/semfold.nim @@ -181,10 +181,8 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode = result.info = n.info of mConStrStr: result = newStrNodeT(getStrOrChar(a) & getStrOrChar(b), n) of mInSet: result = newIntNodeT(Ord(inSet(a, b)), n) - of mRepr: - # BUGFIX: we cannot eval mRepr here. But this means that it is not - # available for interpretation. I don't know how to fix this. - #result := newStrNodeT(renderTree(a, {@set}[renderNoComments]), n); + of mRepr: + # BUGFIX: we cannot eval mRepr here for reasons that I forgot. of mIntToStr, mInt64ToStr: result = newStrNodeT($(getOrdValue(a)), n) of mBoolToStr: if getOrdValue(a) == 0: result = newStrNodeT("false", n) @@ -324,7 +322,7 @@ proc getConstExpr(m: PSym, n: PNode): PNode = var s = n.sym if s.kind == skEnumField: result = newIntNodeT(s.position, n) - elif (s.kind == skConst): + elif s.kind == skConst: case s.magic of mIsMainModule: result = newIntNodeT(ord(sfMainModule in m.flags), n) of mCompileDate: result = newStrNodeT(times.getDateStr(), n) @@ -370,10 +368,14 @@ proc getConstExpr(m: PSym, n: PNode): PNode = of mLow: result = newIntNodeT(firstOrd(n.sons[1].typ), n) of mHigh: - if not (skipTypes(n.sons[1].typ, abstractVar).kind in - {tyOpenArray, tySequence, tyString}): - result = newIntNodeT(lastOrd(skipTypes(n.sons[1].typ, abstractVar)), - n) + if skipTypes(n.sons[1].typ, abstractVar).kind notin + {tyOpenArray, tySequence, tyString}: + result = newIntNodeT(lastOrd(skipTypes(n[1].typ, abstractVar)), n) + else: + var a = n.sons[1] + if a.kind == nkBracket: + # we can optimize it away: + result = newIntNodeT(sonsLen(a)-1, n) of mLengthOpenArray: var a = n.sons[1] if a.kind == nkBracket: diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index decc8a2d7..c00b68bb5 100755 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -280,22 +280,33 @@ proc semConst(c: PContext, n: PNode): PNode = var typ: PType = nil if a.sons[1].kind != nkEmpty: typ = semTypeNode(c, a.sons[1], nil) - var e = semExprWithType(c, a.sons[2]) - if e == nil: GlobalError(a.sons[2].info, errConstExprExpected) - var def = getConstExpr(c.module, e) - if def == nil: - v.flags.incl(sfFakeConst) - def = evalConstExpr(c.module, e) - if def == nil or def.kind == nkEmpty: def = e - # check type compatibility between def.typ and typ: - if typ != nil: - def = fitRemoveHiddenConv(c, typ, def) - else: - typ = def.typ - if not typeAllowed(typ, skConst): - v.flags.incl(sfFakeConst) - if not typeAllowed(typ, skVar): + when true: + var def = semConstExpr(c, a.sons[2]) + if def == nil: GlobalError(a.sons[2].info, errConstExprExpected) + # check type compatibility between def.typ and typ: + if typ != nil: + def = fitRemoveHiddenConv(c, typ, def) + else: + typ = def.typ + if not typeAllowed(typ, skConst): GlobalError(a.info, errXisNoType, typeToString(typ)) + else: + var e = semExprWithType(c, a.sons[2]) + if e == nil: GlobalError(a.sons[2].info, errConstExprExpected) + var def = getConstExpr(c.module, e) + if def == nil: + v.flags.incl(sfFakeConst) + def = evalConstExpr(c.module, e) + if def == nil or def.kind == nkEmpty: def = e + # check type compatibility between def.typ and typ: + if typ != nil: + def = fitRemoveHiddenConv(c, typ, def) + else: + typ = def.typ + if not typeAllowed(typ, skConst): + v.flags.incl(sfFakeConst) + if not typeAllowed(typ, skVar): + GlobalError(a.info, errXisNoType, typeToString(typ)) v.typ = typ v.ast = def # no need to copy addInterfaceDecl(c, v) diff --git a/compiler/transf.nim b/compiler/transf.nim index 482332f38..9c67165e3 100755 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -161,7 +161,6 @@ proc newAsgnStmt(c: PTransf, le: PNode, ri: PTransNode): PTransNode = proc transformSymAux(c: PTransf, n: PNode): PNode = var b: PNode - if (n.kind != nkSym): internalError(n.info, "transformSym") var tc = c.transCon if sfBorrow in n.sym.flags: # simply exchange the symbol: @@ -176,14 +175,15 @@ proc transformSymAux(c: PTransf, n: PNode): PNode = if result != nil: return tc = tc.next result = b - case b.sym.kind - of skConst, skEnumField: - if sfFakeConst notin b.sym.flags: - if skipTypes(b.sym.typ, abstractInst).kind notin ConstantDataTypes: - result = getConstExpr(c.module, b) - if result == nil: InternalError(b.info, "transformSym: const") - else: - nil + when false: + case b.sym.kind + of skConst, skEnumField: + if sfFakeConst notin b.sym.flags: + if skipTypes(b.sym.typ, abstractInst).kind notin ConstantDataTypes: + result = getConstExpr(c.module, b) + if result == nil: InternalError(b.info, "transformSym: const") + else: + nil proc transformSym(c: PTransf, n: PNode): PTransNode = result = PTransNode(transformSymAux(c, n)) @@ -360,7 +360,7 @@ proc transformConv(c: PTransf, n: PNode): PTransNode = var dest = skipTypes(n.typ, abstractVarRange) var source = skipTypes(n.sons[1].typ, abstractVarRange) case dest.kind - of tyInt..tyInt64, tyEnum, tyChar, tyBool: + of tyInt..tyInt64, tyEnum, tyChar, tyBool, tyUInt..tyUInt64: if not isOrdinalType(source): # XXX int64 -> float conversion? result = transformSons(c, n) @@ -659,7 +659,7 @@ proc transformCall(c: PTransf, n: PNode): PTransNode = proc transform(c: PTransf, n: PNode): PTransNode = case n.kind of nkSym: - return transformSym(c, n) + result = transformSym(c, n) of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit: # nothing to be done for leaves: result = PTransNode(n) @@ -719,7 +719,7 @@ proc transform(c: PTransf, n: PNode): PTransNode = else: result = transformSons(c, n) var cnst = getConstExpr(c.module, PNode(result)) - if cnst != nil: + if cnst != nil and (cnst.kind != nkBracket or cnst.len == 0): result = PTransNode(cnst) # do not miss an optimization proc processTransf(context: PPassContext, n: PNode): PNode = diff --git a/compiler/types.nim b/compiler/types.nim index 144f4052e..cc1281b6e 100755 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -762,7 +762,7 @@ proc typeAllowedAux(marker: var TIntSet, typ: PType, kind: TSymKind): bool = of tyOpenArray, tyVarargs: result = (kind == skParam) and typeAllowedAux(marker, t.sons[0], skVar) of tySequence: - result = (kind != skConst) and typeAllowedAux(marker, t.sons[0], skVar) or + result = typeAllowedAux(marker, t.sons[0], skVar) or t.sons[0].kind == tyEmpty of tyArray: result = typeAllowedAux(marker, t.sons[1], skVar) or |