code generator supports constant sequences; more consistent compile time evaluation
This commit is contained in:
parent
e9b7d5e68e
commit
42516c0086
18 changed files with 180 additions and 137 deletions
|
|
@ -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}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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) =
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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 =
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue