diff options
Diffstat (limited to 'compiler')
-rwxr-xr-x | compiler/ast.nim | 7 | ||||
-rwxr-xr-x | compiler/ecmasgen.nim | 346 | ||||
-rw-r--r-- | compiler/lambdalifting.nim | 2 | ||||
-rwxr-xr-x | compiler/magicsys.nim | 23 | ||||
-rwxr-xr-x | compiler/main.nim | 4 | ||||
-rwxr-xr-x | compiler/msgs.nim | 12 | ||||
-rwxr-xr-x | compiler/nimrod.nim | 9 | ||||
-rwxr-xr-x | compiler/semexprs.nim | 24 | ||||
-rwxr-xr-x | compiler/semfold.nim | 2 | ||||
-rwxr-xr-x | compiler/sigmatch.nim | 56 | ||||
-rwxr-xr-x | compiler/transf.nim | 4 |
11 files changed, 312 insertions, 177 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim index d14bef9f7..511d6f116 100755 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -334,12 +334,10 @@ type tfEnumHasHoles, # enum cannot be mapped into a range tfShallow, # type can be shallow copied on assignment tfThread, # proc type is marked as ``thread`` - tfUniIntLit # type represents literal value that could be either - # singed or unsigned integer (e.g. 100) - tfFromGeneric # type is an instantiation of a generic; this is needed + tfFromGeneric, # type is an instantiation of a generic; this is needed # because for instantiations of objects, structural # type equality has to be used - tfAll # type class requires all constraints to be met (default) + tfAll, # type class requires all constraints to be met (default) tfAny # type class requires any constraint to be met TTypeFlags* = set[TTypeFlag] @@ -587,6 +585,7 @@ type # for range types a nkRange node # for record types a nkRecord node # for enum types a list of symbols + # for tyInt it can be the int literal # else: unused destructor*: PSym # destructor. warning: nil here may not necessary # mean that there is no destructor. diff --git a/compiler/ecmasgen.nim b/compiler/ecmasgen.nim index 07754ee13..30a697d8e 100755 --- a/compiler/ecmasgen.nim +++ b/compiler/ecmasgen.nim @@ -22,11 +22,11 @@ proc ecmasgenPass*(): TPass type TEcmasGen = object of TPassContext - filename*: string - module*: PSym + filename: string + module: PSym BModule = ref TEcmasGen - TEcmasTypeKind = enum + TEcmasTypeKind = enum # necessary JS "types" etyNone, # no type etyNull, # null type etyProc, # proc type @@ -37,38 +37,42 @@ type etyObject, # Ecmascript's reference to an object etyBaseIndex # base + index needed TCompRes{.final.} = object - kind*: TEcmasTypeKind - com*: PRope # computation part - # address if this is a (address, index)-tuple - res*: PRope # result part; index if this is an - # (address, index)-tuple + kind: TEcmasTypeKind + com: PRope # computation part + # address if this is a (address, index)-tuple + res: PRope # result part; index if this is an + # (address, index)-tuple TBlock{.final.} = object - id*: int # the ID of the label; positive means that it - # has been used (i.e. the label should be emitted) - nestedTryStmts*: int # how many try statements is it nested into - isLoop: bool # whether it's a 'block' or 'while' + id: int # the ID of the label; positive means that it + # has been used (i.e. the label should be emitted) + nestedTryStmts: int # how many try statements is it nested into + isLoop: bool # whether it's a 'block' or 'while' TGlobals{.final.} = object - typeInfo*, code*: PRope - typeInfoGenerated*: TIntSet + typeInfo, code: PRope + forwarded: seq[PSym] + generatedSyms: TIntSet + typeInfoGenerated: TIntSet PGlobals = ref TGlobals TProc{.final.} = object - procDef*: PNode - prc*: PSym - data*: PRope - options*: TOptions - module*: BModule - globals*: PGlobals - BeforeRetNeeded*: bool - nestedTryStmts*: int - unique*: int - blocks*: seq[TBlock] + procDef: PNode + prc: PSym + data: PRope + options: TOptions + module: BModule + g: PGlobals + BeforeRetNeeded: bool + nestedTryStmts: int + unique: int + blocks: seq[TBlock] proc newGlobals(): PGlobals = new(result) + result.forwarded = @[] + result.generatedSyms = initIntSet() result.typeInfoGenerated = initIntSet() proc initCompRes(r: var TCompRes) = @@ -82,7 +86,7 @@ proc initProc(p: var TProc, globals: PGlobals, module: BModule, procDef: PNode, p.options = options p.module = module p.procDef = procDef - p.globals = globals + p.g = globals if procDef != nil: p.prc = procDef.sons[namePos].sym const @@ -97,7 +101,7 @@ proc mapType(typ: PType): TEcmasTypeKind = result = etyObject else: result = etyBaseIndex - of tyPointer: + of tyPointer: # treat a tyPointer like a typed pointer to an array of bytes result = etyInt of tyRange, tyDistinct, tyOrdinal, tyConst, tyMutable, tyIter, tyVarargs, @@ -196,12 +200,12 @@ proc genObjectFields(p: var TProc, typ: PType, n: PNode): PRope = proc genObjectInfo(p: var TProc, typ: PType, name: PRope) = var s = ropef("var $1 = {size: 0, kind: $2, base: null, node: null, " & "finalizer: null};$n", [name, toRope(ord(typ.kind))]) - prepend(p.globals.typeInfo, s) - appf(p.globals.typeInfo, "var NNI$1 = $2;$n", + prepend(p.g.typeInfo, s) + appf(p.g.typeInfo, "var NNI$1 = $2;$n", [toRope(typ.id), genObjectFields(p, typ, typ.n)]) - appf(p.globals.typeInfo, "$1.node = NNI$2;$n", [name, toRope(typ.id)]) + appf(p.g.typeInfo, "$1.node = NNI$2;$n", [name, toRope(typ.id)]) if (typ.kind == tyObject) and (typ.sons[0] != nil): - appf(p.globals.typeInfo, "$1.base = $2;$n", + appf(p.g.typeInfo, "$1.base = $2;$n", [name, genTypeInfo(p, typ.sons[0])]) proc genEnumInfo(p: var TProc, typ: PType, name: PRope) = @@ -221,18 +225,18 @@ proc genEnumInfo(p: var TProc, typ: PType, name: PRope) = "name: null, len: $2, sons: [$3]};$n", [toRope(typ.id), toRope(length), s]) s = ropef("var $1 = {size: 0, kind: $2, base: null, node: null, " & "finalizer: null};$n", [name, toRope(ord(typ.kind))]) - prepend(p.globals.typeInfo, s) - app(p.globals.typeInfo, n) - appf(p.globals.typeInfo, "$1.node = NNI$2;$n", [name, toRope(typ.id)]) + prepend(p.g.typeInfo, s) + app(p.g.typeInfo, n) + appf(p.g.typeInfo, "$1.node = NNI$2;$n", [name, toRope(typ.id)]) if typ.sons[0] != nil: - appf(p.globals.typeInfo, "$1.base = $2;$n", + appf(p.g.typeInfo, "$1.base = $2;$n", [name, genTypeInfo(p, typ.sons[0])]) proc genTypeInfo(p: var TProc, typ: PType): PRope = var t = typ if t.kind == tyGenericInst: t = lastSon(t) result = ropef("NTI$1", [toRope(t.id)]) - if ContainsOrIncl(p.globals.TypeInfoGenerated, t.id): return + if ContainsOrIncl(p.g.TypeInfoGenerated, t.id): return case t.kind of tyDistinct: result = genTypeInfo(p, typ.sons[0]) @@ -240,20 +244,20 @@ proc genTypeInfo(p: var TProc, typ: PType): PRope = var s = ropef( "var $1 = {size: 0,kind: $2,base: null,node: null,finalizer: null};$n", [result, toRope(ord(t.kind))]) - prepend(p.globals.typeInfo, s) + prepend(p.g.typeInfo, s) of tyVar, tyRef, tyPtr, tySequence, tyRange, tySet: var s = ropef( "var $1 = {size: 0,kind: $2,base: null,node: null,finalizer: null};$n", [result, toRope(ord(t.kind))]) - prepend(p.globals.typeInfo, s) - appf(p.globals.typeInfo, "$1.base = $2;$n", + prepend(p.g.typeInfo, s) + appf(p.g.typeInfo, "$1.base = $2;$n", [result, genTypeInfo(p, typ.sons[0])]) of tyArrayConstr, tyArray: var s = ropef( "var $1 = {size: 0,kind: $2,base: null,node: null,finalizer: null};$n", [result, toRope(ord(t.kind))]) - prepend(p.globals.typeInfo, s) - appf(p.globals.typeInfo, "$1.base = $2;$n", + prepend(p.g.typeInfo, s) + appf(p.g.typeInfo, "$1.base = $2;$n", [result, genTypeInfo(p, typ.sons[1])]) of tyEnum: genEnumInfo(p, t, result) of tyObject, tyTuple: genObjectInfo(p, t, result) @@ -261,10 +265,9 @@ proc genTypeInfo(p: var TProc, typ: PType): PRope = proc gen(p: var TProc, n: PNode, r: var TCompRes) proc genStmt(p: var TProc, n: PNode, r: var TCompRes) -proc useMagic(p: var TProc, ident: string) = - nil - # to implement - +proc genProc(oldProc: var TProc, prc: PSym, r: var TCompRes) +proc genConstant(p: var TProc, c: PSym, r: var TCompRes) + proc mergeExpr(a, b: PRope): PRope = if (a != nil): if b != nil: result = ropef("($1, $2)", [a, b]) @@ -280,6 +283,22 @@ proc mergeStmt(r: TCompRes): PRope = elif r.com == nil: result = r.res else: result = ropef("$1$2", [r.com, r.res]) +proc useMagic(p: var TProc, name: string) = + if name.len == 0: return + var s = magicsys.getCompilerProc(name) + if s != nil: + internalAssert s.kind in {skProc, skMethod, skConverter} + if not p.g.generatedSyms.containsOrIncl(s.id): + var r: TCompRes + genProc(p, s, r) + app(p.g.code, mergeStmt(r)) + else: + # we used to exclude the system module from this check, but for DLL + # generation support this sloppyness leads to hard to detect bugs, so + # we're picky here for the system module too: + if p.prc != nil: GlobalError(p.prc.info, errSystemNeeds, name) + else: rawMessage(errSystemNeeds, name) + proc genAnd(p: var TProc, a, b: PNode, r: var TCompRes) = var x, y: TCompRes gen(p, a, x) @@ -403,7 +422,7 @@ const # magic checked op; magic unchecked op; checked op; unchecked op proc binaryExpr(p: var TProc, n: PNode, r: var TCompRes, magic, frmt: string) = var x, y: TCompRes - if magic != "": useMagic(p, magic) + useMagic(p, magic) gen(p, n.sons[1], x) gen(p, n.sons[2], y) r.res = ropef(frmt, [x.res, y.res]) @@ -411,7 +430,7 @@ proc binaryExpr(p: var TProc, n: PNode, r: var TCompRes, magic, frmt: string) = proc binaryStmt(p: var TProc, n: PNode, r: var TCompRes, magic, frmt: string) = var x, y: TCompRes - if magic != "": useMagic(p, magic) + useMagic(p, magic) gen(p, n.sons[1], x) gen(p, n.sons[2], y) if x.com != nil: appf(r.com, "$1;$n", [x.com]) @@ -419,7 +438,7 @@ proc binaryStmt(p: var TProc, n: PNode, r: var TCompRes, magic, frmt: string) = appf(r.com, frmt, [x.res, y.res]) proc unaryExpr(p: var TProc, n: PNode, r: var TCompRes, magic, frmt: string) = - if magic != "": useMagic(p, magic) + useMagic(p, magic) gen(p, n.sons[1], r) r.res = ropef(frmt, [r.res]) @@ -527,11 +546,12 @@ proc genTryStmt(p: var TProc, n: PNode, r: var TCompRes) = if i > 1: app(epart, '}' & tnl) else: orExpr = nil + useMagic(p, "isObj") for j in countup(0, blen - 2): if (n.sons[i].sons[j].kind != nkType): InternalError(n.info, "genTryStmt") if orExpr != nil: app(orExpr, "||") - appf(orExpr, "($1.exc.m_type == $2)", + appf(orExpr, "isObj($1.exc.m_type, $2)", [safePoint, genTypeInfo(p, n.sons[i].sons[j].typ)]) if i > 1: app(epart, "else ") appf(epart, "if ($1.exc && $2) {$n", [safePoint, orExpr]) @@ -772,7 +792,7 @@ proc genSwap(p: var TProc, n: PNode, r: var TCompRes) = gen(p, n.sons[2], b) inc(p.unique) var tmp = ropef("Tmp$1", [toRope(p.unique)]) - case mapType(n.sons[1].typ) + case mapType(skipTypes(n.sons[1].typ, abstractVar)) of etyBaseIndex: inc(p.unique) var tmp2 = ropef("Tmp$1", [toRope(p.unique)]) @@ -785,24 +805,36 @@ proc genSwap(p: var TProc, n: PNode, r: var TCompRes) = if b.com != nil: appf(r.com, "$1;$n", [b.com]) appf(r.com, "var $1 = $2; $2 = $3; $3 = $1", [tmp, a.res, b.res]) +proc getFieldPosition(f: PNode): int = + case f.kind + of nkIntLit..nkUInt64Lit: result = int(f.intVal) + of nkSym: result = f.sym.position + else: InternalError(f.info, "genFieldPosition") + proc genFieldAddr(p: var TProc, n: PNode, r: var TCompRes) = var a: TCompRes r.kind = etyBaseIndex var b = if n.kind == nkHiddenAddr: n.sons[0] else: n gen(p, b.sons[0], a) - if b.sons[1].kind != nkSym: InternalError(b.sons[1].info, "genFieldAddr") - var f = b.sons[1].sym - if f.loc.r == nil: f.loc.r = mangleName(f) - r.res = makeCString(ropeToStr(f.loc.r)) + if skipTypes(b.sons[0].typ, abstractVarRange).kind == tyTuple: + r.res = makeCString("Field" & $getFieldPosition(b.sons[1])) + else: + if b.sons[1].kind != nkSym: InternalError(b.sons[1].info, "genFieldAddr") + var f = b.sons[1].sym + if f.loc.r == nil: f.loc.r = mangleName(f) + r.res = makeCString(ropeToStr(f.loc.r)) r.com = mergeExpr(a) proc genFieldAccess(p: var TProc, n: PNode, r: var TCompRes) = r.kind = etyNone gen(p, n.sons[0], r) - if n.sons[1].kind != nkSym: InternalError(n.sons[1].info, "genFieldAddr") - var f = n.sons[1].sym - if f.loc.r == nil: f.loc.r = mangleName(f) - r.res = ropef("$1.$2", [r.res, f.loc.r]) + if skipTypes(n.sons[0].typ, abstractVarRange).kind == tyTuple: + r.res = ropef("$1.Field$2", [r.res, getFieldPosition(n.sons[1]).toRope]) + else: + if n.sons[1].kind != nkSym: InternalError(n.sons[1].info, "genFieldAddr") + var f = n.sons[1].sym + if f.loc.r == nil: f.loc.r = mangleName(f) + r.res = ropef("$1.$2", [r.res, f.loc.r]) proc genCheckedFieldAddr(p: var TProc, n: PNode, r: var TCompRes) = genFieldAddr(p, n.sons[0], r) # XXX @@ -821,7 +853,7 @@ proc genArrayAddr(p: var TProc, n: PNode, r: var TCompRes) = var typ = skipTypes(n.sons[0].typ, abstractPtrs) if typ.kind in {tyArray, tyArrayConstr}: first = FirstOrd(typ.sons[0]) else: first = 0 - if (optBoundsCheck in p.options) and not isConstExpr(n.sons[1]): + if optBoundsCheck in p.options and not isConstExpr(n.sons[1]): useMagic(p, "chckIndx") b.res = ropef("chckIndx($1, $2, $3.length)-$2", [b.res, toRope(first), a.res]) @@ -831,7 +863,14 @@ proc genArrayAddr(p: var TProc, n: PNode, r: var TCompRes) = r.res = mergeExpr(b) proc genArrayAccess(p: var TProc, n: PNode, r: var TCompRes) = - genArrayAddr(p, n, r) + var ty = skipTypes(n.sons[0].typ, abstractVarRange) + if ty.kind in {tyRef, tyPtr}: ty = skipTypes(ty.sons[0], abstractVarRange) + case ty.kind + of tyArray, tyArrayConstr, tyOpenArray, tySequence, tyString, tyCString: + genArrayAddr(p, n, r) + of tyTuple: + genFieldAddr(p, n, r) + else: InternalError(n.info, "expr(nkBracketExpr, " & $ty.kind & ')') r.kind = etyNone r.res = ropef("$1[$2]", [r.com, r.res]) r.com = nil @@ -865,16 +904,23 @@ proc genAddr(p: var TProc, n: PNode, r: var TCompRes) = genCheckedFieldAddr(p, n, r) of nkDotExpr: genFieldAddr(p, n, r) - of nkBracketExpr: - genArrayAddr(p, n, r) + of nkBracketExpr: + var ty = skipTypes(n.sons[0].typ, abstractVarRange) + if ty.kind in {tyRef, tyPtr}: ty = skipTypes(ty.sons[0], abstractVarRange) + case ty.kind + of tyArray, tyArrayConstr, tyOpenArray, tySequence, tyString, tyCString: + genArrayAddr(p, n, r) + of tyTuple: + genFieldAddr(p, n, r) + else: InternalError(n.info, "expr(nkBracketExpr, " & $ty.kind & ')') else: InternalError(n.info, "genAddr") proc genSym(p: var TProc, n: PNode, r: var TCompRes) = var s = n.sym - if s.loc.r == nil: - InternalError(n.info, "symbol has no generated name: " & s.name.s) case s.kind of skVar, skLet, skParam, skTemp, skResult: + if s.loc.r == nil: + InternalError(n.info, "symbol has no generated name: " & s.name.s) var k = mapType(s.typ) if k == etyBaseIndex: r.kind = etyBaseIndex @@ -888,7 +934,28 @@ proc genSym(p: var TProc, n: PNode, r: var TCompRes) = r.res = ropef("$1[0]", [s.loc.r]) else: r.res = s.loc.r - else: r.res = s.loc.r + of skConst: + genConstant(p, s, r) + if s.loc.r == nil: + InternalError(n.info, "symbol has no generated name: " & s.name.s) + r.res = s.loc.r + of skProc, skConverter, skMethod: + discard mangleName(s) + r.res = s.loc.r + if lfNoDecl in s.loc.flags or s.magic != mNone or isGenericRoutine(s): nil + elif s.kind == skMethod and s.getBody.kind == nkEmpty: + # we cannot produce code for the dispatcher yet: + nil + elif sfForward in s.flags: + p.g.forwarded.add(s) + elif not p.g.generatedSyms.containsOrIncl(s.id): + var r2: TCompRes + genProc(p, s, r2) + app(p.g.code, mergeStmt(r2)) + else: + if s.loc.r == nil: + InternalError(n.info, "symbol has no generated name: " & s.name.s) + r.res = s.loc.r proc genDeref(p: var TProc, n: PNode, r: var TCompRes) = var a: TCompRes @@ -918,6 +985,7 @@ proc genCall(p: var TProc, n: PNode, r: var TCompRes) = genArgs(p, n, r) proc genEcho(p: var TProc, n: PNode, r: var TCompRes) = + useMagic(p, "rawEcho") app(r.res, "rawEcho") genArgs(p, n, r) @@ -974,8 +1042,9 @@ proc createVar(p: var TProc, typ: PType, indirect: bool): PRope = app(result, "]") of tyTuple: result = toRope("{") - var c = 0 - app(result, createRecordVarAux(p, t.n, c)) + for i in 0.. <t.sonslen: + if i > 0: app(result, ", ") + appf(result, "Field$1: $2", i.toRope, createVar(p, t.sons[i], false)) app(result, "}") of tyObject: result = toRope("{") @@ -1041,16 +1110,22 @@ proc genVarStmt(p: var TProc, n: PNode, r: var TCompRes) = genLineDir(p, a, r) genVarInit(p, v, a.sons[2], r) -proc genConstStmt(p: var TProc, n: PNode, r: var TCompRes) = - genLineDir(p, n, r) - for i in countup(0, sonsLen(n) - 1): - if n.sons[i].kind == nkCommentStmt: continue - assert(n.sons[i].kind == nkConstDef) - var c = n.sons[i].sons[0].sym - if (c.ast != nil) and (c.typ.kind in ConstantDataTypes) and - not (lfNoDecl in c.loc.flags): - genLineDir(p, n.sons[i], r) - genVarInit(p, c, c.ast, r) +proc genConstant(p: var TProc, c: PSym, r: var TCompRes) = + if lfNoDecl notin c.loc.flags and not p.g.generatedSyms.containsOrIncl(c.id): + genLineDir(p, c.ast, r) + genVarInit(p, c, c.ast, r) + +when false: + proc genConstStmt(p: var TProc, n: PNode, r: var TCompRes) = + genLineDir(p, n, r) + for i in countup(0, sonsLen(n) - 1): + if n.sons[i].kind == nkCommentStmt: continue + assert(n.sons[i].kind == nkConstDef) + var c = n.sons[i].sons[0].sym + if c.ast != nil and c.typ.kind in ConstantDataTypes and + lfNoDecl notin c.loc.flags: + genLineDir(p, n.sons[i], r) + genVarInit(p, c, c.ast, r) proc genNew(p: var TProc, n: PNode, r: var TCompRes) = var a: TCompRes @@ -1059,6 +1134,16 @@ proc genNew(p: var TProc, n: PNode, r: var TCompRes) = if a.com != nil: appf(r.com, "$1;$n", [a.com]) appf(r.com, "$1 = $2;$n", [a.res, createVar(p, t, true)]) +proc genNewSeq(p: var TProc, n: PNode, r: var TCompRes) = + var x, y: TCompRes + gen(p, n.sons[1], x) + gen(p, n.sons[2], y) + if x.com != nil: appf(r.com, "$1;$n", [x.com]) + if y.com != nil: appf(r.com, "$1;$n", [y.com]) + var t = skipTypes(n.sons[1].typ, abstractVar).sons[0] + appf(r.com, "$1 = new Array($2); for (var i=0;i<$2;++i) {$1[i]=$3;}", [ + x.res, y.res, createVar(p, t, false)]) + proc genOrd(p: var TProc, n: PNode, r: var TCompRes) = case skipTypes(n.sons[1].typ, abstractVar).kind of tyEnum, tyInt..tyInt64, tyChar: gen(p, n.sons[1], r) @@ -1102,6 +1187,25 @@ proc genRepr(p: var TProc, n: PNode, r: var TCompRes) = # XXX: internalError(n.info, "genRepr: Not implemented") +proc genOf(p: var TProc, n: PNode, r: var TCompRes) = + var x: TCompRes + let t = skipTypes(n.sons[2].typ, abstractVarRange+{tyRef, tyPtr}) + gen(p, n.sons[1], x) + if tfFinal in t.flags: + r.res = ropef("($1.m_type == $2)", [x.res, genTypeInfo(p, t)]) + else: + useMagic(p, "isObj") + r.res = ropef("isObj($1.m_type, $2)", [x.res, genTypeInfo(p, t)]) + r.com = mergeExpr(r.com, x.com) + +proc genReset(p: var TProc, n: PNode, r: var TCompRes) = + var x: TCompRes + useMagic(p, "genericReset") + gen(p, n.sons[1], x) + r.res = ropef("$1 = genericReset($1, $2)", [x.res, + genTypeInfo(p, n.sons[1].typ)]) + r.com = mergeExpr(r.com, x.com) + proc genMagic(p: var TProc, n: PNode, r: var TCompRes) = var a: TCompRes @@ -1171,7 +1275,9 @@ proc genMagic(p: var TProc, n: PNode, r: var TCompRes) = of mInSet: binaryExpr(p, n, r, "", "($1[$2] != undefined)") of mNLen..mNError: localError(n.info, errCannotGenerateCodeForX, n.sons[0].sym.name.s) - of mNewSeq: binaryStmt(p, n, r, "", "$1 = new Array($2)") + of mNewSeq: genNewSeq(p, n, r) + of mOf: genOf(p, n, r) + of mReset: genReset(p, n, r) of mEcho: genEcho(p, n, r) of mSlurp, mStaticExec: localError(n.info, errXMustBeCompileTime, n.sons[0].sym.name.s) @@ -1208,19 +1314,17 @@ proc genArrayConstr(p: var TProc, n: PNode, r: var TCompRes) = app(r.res, a.res) app(r.res, "]") -proc genRecordConstr(p: var TProc, n: PNode, r: var TCompRes) = +proc genTupleConstr(p: var TProc, n: PNode, r: var TCompRes) = var a: TCompRes - var i = 0 - var length = sonsLen(n) r.res = toRope("{") - while i < length: + for i in countup(0, sonsLen(n) - 1): if i > 0: app(r.res, ", ") - if (n.sons[i].kind != nkSym): - internalError(n.sons[i].info, "genRecordConstr") - gen(p, n.sons[i + 1], a) + var it = n.sons[i] + if it.kind == nkExprColonExpr: it = it.sons[1] + gen(p, it, a) r.com = mergeExpr(r.com, a.com) - appf(r.res, "$1: $2", [mangleName(n.sons[i].sym), a.res]) - inc(i, 2) + appf(r.res, "Field$1: $2", [i.toRope, a.res]) + r.res.app("}") proc genConv(p: var TProc, n: PNode, r: var TCompRes) = var dest = skipTypes(n.typ, abstractVarRange) @@ -1299,12 +1403,14 @@ proc genProc(oldProc: var TProc, prc: PSym, r: var TCompRes) = resultSym: PSym name, returnStmt, resultAsgn, header: PRope a: TCompRes - initProc(p, oldProc.globals, oldProc.module, prc.ast, prc.options) + #if gVerbosity >= 3: + # echo "BEGIN generating code for: " & prc.name.s + initProc(p, oldProc.g, oldProc.module, prc.ast, prc.options) returnStmt = nil resultAsgn = nil name = mangleName(prc) header = generateHeader(p, prc.typ) - if (prc.typ.sons[0] != nil) and not (sfPure in prc.flags): + if (prc.typ.sons[0] != nil) and sfPure notin prc.flags: resultSym = prc.ast.sons[resultPos].sym resultAsgn = ropef("var $1 = $2;$n", [mangleName(resultSym), createVar(p, resultSym.typ, isIndirect(resultSym))]) @@ -1315,6 +1421,8 @@ proc genProc(oldProc: var TProc, prc: PSym, r: var TCompRes) = r.com = ropef("function $1($2) {$n$3$4$5}$n", [name, header, resultAsgn, genProcBody(p, prc, r), returnStmt]) r.res = nil + #if gVerbosity >= 3: + # echo "END generated code for: " & prc.name.s proc genStmtListExpr(p: var TProc, n: PNode, r: var TCompRes) = var a: TCompRes @@ -1342,7 +1450,7 @@ proc genStmt(p: var TProc, n: PNode, r: var TCompRes) = of nkIfStmt: genIfStmt(p, n, r) of nkWhileStmt: genWhileStmt(p, n, r) of nkVarSection, nkLetSection: genVarStmt(p, n, r) - of nkConstSection: genConstStmt(p, n, r) + of nkConstSection: nil of nkForStmt, nkParForStmt: internalError(n.info, "for statement not eliminated") of nkCaseStmt: genCaseStmt(p, n, r) @@ -1358,20 +1466,14 @@ proc genStmt(p: var TProc, n: PNode, r: var TCompRes) = of nkTryStmt: genTryStmt(p, n, r) of nkRaiseStmt: genRaiseStmt(p, n, r) of nkTypeSection, nkCommentStmt, nkIteratorDef, nkIncludeStmt, nkImportStmt, - nkFromStmt, nkTemplateDef, nkMacroDef, nkPragma: - nil - of nkProcDef, nkMethodDef, nkConverterDef: - if (n.sons[genericParamsPos].kind == nkEmpty): - var prc = n.sons[namePos].sym - if lfNoDecl notin prc.loc.flags and prc.getBody.kind != nkEmpty: - genProc(p, prc, r) - else: - discard mangleName(prc) - else: + nkFromStmt, nkTemplateDef, nkMacroDef, nkPragma: nil + of nkProcDef, nkMethodDef, nkConverterDef: + var s = n.sons[namePos].sym + if {sfExportc, sfCompilerProc} * s.flags == {sfExportc}: + var r2: TCompRes + genSym(p, n.sons[namePos], r2) + else: genLineDir(p, n, r) - if n.sons[0].kind == nkSym: - if n.sons[0].sym.loc.r == nil: - n.sons[0].sym.loc.r = toRope(n.sons[0].sym.name.s) gen(p, n, r) app(r.res, ';' & tnl) @@ -1415,7 +1517,7 @@ proc gen(p: var TProc, n: PNode, r: var TCompRes) = genCall(p, n, r) of nkCurly: genSetConstr(p, n, r) of nkBracket: genArrayConstr(p, n, r) - of nkPar: genRecordConstr(p, n, r) + of nkPar: genTupleConstr(p, n, r) of nkHiddenStdConv, nkHiddenSubConv, nkConv: genConv(p, n, r) of nkAddr, nkHiddenAddr: genAddr(p, n, r) of nkDerefExpr, nkHiddenDeref: genDeref(p, n, r) @@ -1431,6 +1533,15 @@ 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 nkLambdaKinds: + let s = n.sons[namePos].sym + discard mangleName(s) + r.res = s.loc.r + if lfNoDecl in s.loc.flags or s.magic != mNone or isGenericRoutine(s): nil + elif not p.g.generatedSyms.containsOrIncl(s.id): + var r2: TCompRes + genProc(p, s, r2) + app(r.com, mergeStmt(r2)) of nkMetaNode: gen(p, n.sons[0], r) of nkType: r.res = genTypeInfo(p, n.typ) else: InternalError(n.info, "gen: unknown node type: " & $n.kind) @@ -1467,22 +1578,33 @@ proc myProcess(b: PPassContext, n: PNode): PNode = if m.module == nil: InternalError(n.info, "myProcess") initProc(p, globals, m, nil, m.module.options) genModule(p, n, r) - app(p.globals.code, p.data) - app(p.globals.code, mergeStmt(r)) + app(p.g.code, p.data) + app(p.g.code, mergeStmt(r)) proc myClose(b: PPassContext, n: PNode): PNode = if passes.skipCodegen(n): return n result = myProcess(b, n) var m = BModule(b) - if sfMainModule in m.module.flags: + if sfMainModule in m.module.flags: + for prc in globals.forwarded: + if not globals.generatedSyms.containsOrIncl(prc.id): + var + p: TProc + r: TCompRes + initProc(p, globals, m, nil, m.module.options) + genProc(p, prc, r) + app(p.g.code, mergeStmt(r)) + var disp = generateMethodDispatchers() for i in 0..sonsLen(disp)-1: - var - p: TProc - r: TCompRes - initProc(p, globals, m, nil, m.module.options) - genProc(p, disp.sons[i].sym, r) - app(p.globals.code, mergeStmt(r)) + let prc = disp.sons[i].sym + if not globals.generatedSyms.containsOrIncl(prc.id): + var + p: TProc + r: TCompRes + initProc(p, globals, m, nil, m.module.options) + genProc(p, prc, r) + app(p.g.code, mergeStmt(r)) # write the file: var code = con(globals.typeInfo, globals.code) diff --git a/compiler/lambdalifting.nim b/compiler/lambdalifting.nim index 5ab7c65ef..ab824b92a 100644 --- a/compiler/lambdalifting.nim +++ b/compiler/lambdalifting.nim @@ -510,6 +510,6 @@ proc liftLambdas(fn: PSym, body: PNode): PNode = proc liftLambdas*(n: PNode): PNode = assert n.kind in procDefs - if gCmd == cmdCompileToEcmaScript: return n var s = n.sons[namePos].sym + if gCmd == cmdCompileToEcmaScript: return s.getBody result = liftLambdas(s, s.getBody) diff --git a/compiler/magicsys.nim b/compiler/magicsys.nim index a69b40fbf..09c99c027 100755 --- a/compiler/magicsys.nim +++ b/compiler/magicsys.nim @@ -24,7 +24,7 @@ proc FinishSystem*(tab: TStrTable) proc getSysSym*(name: string): PSym # implementation -var +var gSysTypes: array[TTypeKind, PType] compilerprocs: TStrTable @@ -73,7 +73,26 @@ proc getSysType(kind: TTypeKind): PType = if result.kind != kind: InternalError("wanted: " & $kind & " got: " & $result.kind) if result == nil: InternalError("type not found: " & $kind) - + +when false: + var + intTypeCache: array[-5..64, PType] + + proc getIntLitType*(literal: PNode): PType = + # we cache some common integer literal types for performance: + let value = literal.intVal + if value >= low(intTypeCache) and value <= high(intTypeCache): + result = intTypeCache[value.int] + if result == nil: + let ti = getSysType(tyInt) + result = copyType(ti, ti.owner, false) + result.n = literal + intTypeCache[value.int] = result + else: + let ti = getSysType(tyInt) + result = copyType(ti, ti.owner, false) + result.n = literal + proc getCompilerProc(name: string): PSym = var ident = getIdent(name, hashIgnoreStyle(name)) result = StrTableGet(compilerprocs, ident) diff --git a/compiler/main.nim b/compiler/main.nim index 0675142fa..d3a40a32d 100755 --- a/compiler/main.nim +++ b/compiler/main.nim @@ -131,7 +131,9 @@ when has_LLVM_Backend: proc CommandCompileToEcmaScript = incl(gGlobalOptions, optSafeCode) setTarget(osEcmaScript, cpuEcmaScript) - initDefines() + #initDefines() + DefineSymbol("nimrod") # 'nimrod' is always defined + DefineSymbol("ecmascript") semanticPasses() registerPass(ecmasgenPass()) compileProject() diff --git a/compiler/msgs.nim b/compiler/msgs.nim index 0b79a68a2..efd83cfd9 100755 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -102,7 +102,7 @@ type warnSmallLshouldNotBeUsed, warnUnknownMagic, warnRedefinitionOfLabel, warnUnknownSubstitutionX, warnLanguageXNotSupported, warnCommentXIgnored, warnXisPassedToProcVar, warnAnalysisLoophole, - warnDifferentHeaps, warnWriteToForeignHeap, + warnDifferentHeaps, warnWriteToForeignHeap, warnImplicitNarrowing, warnUser, hintSuccess, hintSuccessX, hintLineTooLong, hintXDeclaredButNotUsed, hintConvToBaseNotNeeded, @@ -246,7 +246,7 @@ const errWrongNumberOfArguments: "wrong number of arguments", errXCannotBePassedToProcVar: "\'$1\' cannot be passed to a procvar", errXCannotBeInParamDecl: "$1 cannot be declared in parameter declaration", - errPragmaOnlyInHeaderOfProc: "pragmas are only in the header of a proc allowed", + errPragmaOnlyInHeaderOfProc: "pragmas are only allowed in the header of a proc", errImplOfXNotAllowed: "implementation of \'$1\' is not allowed", errImplOfXexpected: "implementation of \'$1\' expected", errNoSymbolToBorrowFromFound: "no symbol to borrow from found", @@ -270,7 +270,7 @@ const errInvalidParamKindX: "invalid param kind: \'$1\'", errDefaultArgumentInvalid: "default argument invalid", errNamedParamHasToBeIdent: "named parameter has to be an identifier", - errNoReturnTypeForX: "no return type for $1 allowed", + errNoReturnTypeForX: "no return type allowed for $1", errConvNeedsOneArg: "a type conversion needs exactly one argument", errInvalidPragmaX: "invalid pragma: $1", errXNotAllowedHere: "$1 not allowed here", @@ -345,6 +345,7 @@ const warnAnalysisLoophole: "thread analysis incomplete due to unkown call '$1' [AnalysisLoophole]", warnDifferentHeaps: "possible inconsistency of thread local heaps [DifferentHeaps]", warnWriteToForeignHeap: "write to foreign heap [WriteToForeignHeap]", + warnImplicitNarrowing: "implicit narrowing conversion: '$1'", warnUser: "$1 [User]", hintSuccess: "operation successful [Success]", hintSuccessX: "operation successful ($# lines compiled; $# sec total; $#) [SuccessX]", @@ -362,13 +363,14 @@ const hintUser: "$1 [User]"] const - WarningsToStr*: array[0..16, string] = ["CannotOpenFile", "OctalEscape", + WarningsToStr*: array[0..17, string] = ["CannotOpenFile", "OctalEscape", "XIsNeverRead", "XmightNotBeenInit", "Deprecated", "ConfigDeprecated", "SmallLshouldNotBeUsed", "UnknownMagic", "RedefinitionOfLabel", "UnknownSubstitutionX", "LanguageXNotSupported", "CommentXIgnored", "XisPassedToProcVar", - "AnalysisLoophole", "DifferentHeaps", "WriteToForeignHeap", "User"] + "AnalysisLoophole", "DifferentHeaps", "WriteToForeignHeap", + "ImplicitNarrowing,", "User"] HintsToStr*: array[0..13, string] = ["Success", "SuccessX", "LineTooLong", "XDeclaredButNotUsed", "ConvToBaseNotNeeded", "ConvFromXtoItselfNotNeeded", diff --git a/compiler/nimrod.nim b/compiler/nimrod.nim index 6328c3ae3..1bd6698a7 100755 --- a/compiler/nimrod.nim +++ b/compiler/nimrod.nim @@ -98,9 +98,14 @@ proc HandleCmdLine() = formatFloat(epochTime() - start, ffDecimal, 3), formatSize(getTotalMem())]) if optRun in gGlobalOptions: - var ex = quoteIfContainsWhite( + if gCmd == cmdCompileToEcmaScript: + var ex = quoteIfContainsWhite( + completeCFilePath(changeFileExt(gProjectFull, "js").prependCurDir)) + execExternalProgram("node " & ex & ' ' & arguments) + else: + var ex = quoteIfContainsWhite( changeFileExt(gProjectFull, exeExt).prependCurDir) - execExternalProgram(ex & ' ' & arguments) + execExternalProgram(ex & ' ' & arguments) #GC_disableMarkAndSweep() diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 00acbbe65..501b7ed72 100755 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -1285,20 +1285,6 @@ proc semMacroStmt(c: PContext, n: PNode, semCheck = true): PNode = GlobalError(n.info, errInvalidExpressionX, renderTree(a, {renderNoComments})) -proc uniIntType(kind: TTypeKind): PType = - result = getSysType(kind).copyType(getCurrOwner(), true) - result.flags.incl(tfUniIntLit) - -template memoize(e: expr): expr = - var `*guard` {.global.} = false - var `*memo` {.global.} : type(e) - - if not `*guard`: - `*memo` = e - `*guard` = true - - `*memo` - proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = result = n if gCmd == cmdIdeTools: suggestExpr(c, n) @@ -1319,15 +1305,9 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = if result.typ == nil: let i = result.intVal if i >= low(int32) and i <= high(int32): - if i >= 0: - result.typ = uniIntType(tyInt).memoize - else: - result.typ = getSysType(tyInt) + result.typ = getSysType(tyInt) else: - if i >= 0: - result.typ = uniIntType(tyInt64).memoize - else: - result.typ = getSysType(tyInt64) + result.typ = getSysType(tyInt64) of nkInt8Lit: if result.typ == nil: result.typ = getSysType(tyInt8) of nkInt16Lit: diff --git a/compiler/semfold.nim b/compiler/semfold.nim index f67e58e2f..66d7e98fc 100755 --- a/compiler/semfold.nim +++ b/compiler/semfold.nim @@ -13,7 +13,7 @@ import strutils, lists, options, ast, astalgo, trees, treetab, nimsets, times, nversion, platform, math, msgs, os, condsyms, idents, renderer, types, - commands + commands, magicsys proc getConstExpr*(m: PSym, n: PNode): PNode # evaluates the constant expression or returns nil if it is no constant diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 7e985e981..7a5d959df 100755 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -159,16 +159,29 @@ proc concreteType(mapping: TIdTable, t: PType): PType = proc handleRange(f, a: PType, min, max: TTypeKind): TTypeRelation = if a.kind == f.kind: result = isEqual - else: + else: var k = skipTypes(a, {tyRange}).kind if k == f.kind: result = isSubtype - elif f.kind == tyInt and k in {tyInt..tyInt32}: result = isIntConv - elif f.kind == tyUInt and k in {tyUInt..tyUInt32}: result = isIntConv - elif f.kind in {tyUInt..tyUInt64} and k == tyInt and tfUniIntLit in a.flags: + elif k == tyInt: + # and a.n != nil and a.n.intVal >= firstOrd(f) and + # a.n.intVal <= lastOrd(f): + # integer literal in the proper range; we want ``i16 + 4`` to stay an + # ``int16`` operation so we declare the ``4`` pseudo-equal to int16 result = isIntConv elif k >= min and k <= max: result = isConvertible else: result = isNone - + #elif f.kind == tyInt and k in {tyInt..tyInt32}: result = isIntConv + #elif f.kind == tyUInt and k in {tyUInt..tyUInt32}: result = isIntConv + +proc isConvertibleToRange(f, a: PType): bool = + # be less picky for tyRange, as that it is used for array indexing: + if f.kind in {tyInt..tyInt64, tyUInt..tyUInt64} and + a.kind in {tyInt..tyInt64, tyUInt..tyUInt64}: + result = true + elif f.kind in {tyFloat..tyFloat128} and + a.kind in {tyFloat..tyFloat128}: + result = true + proc handleFloatRange(f, a: PType): TTypeRelation = if a.kind == f.kind: result = isEqual @@ -227,10 +240,10 @@ proc matchTypeClass(mapping: var TIdTable, f, a: PType): TTypeRelation = else: nil if tfAny in f.flags: - if match == true: + if match: return isGeneric else: - if match == false: + if not match: return isNone # if the loop finished without returning, either all constraints matched @@ -287,9 +300,9 @@ proc typeRel(mapping: var TIdTable, f, a: PType): TTypeRelation = if a.kind == tyGenericInst and skipTypes(f, {tyVar}).kind notin { tyGenericBody, tyGenericInvokation, - tyGenericParam, tyTypeClass }: + tyGenericParam, tyTypeClass}: return typeRel(mapping, f, lastSon(a)) - if a.kind == tyVar and f.kind != tyVar: + if a.kind == tyVar and f.kind != tyVar: return typeRel(mapping, f, a.sons[0]) case f.kind of tyEnum: @@ -302,18 +315,20 @@ proc typeRel(mapping: var TIdTable, f, a: PType): TTypeRelation = if a.kind == f.kind: result = typeRel(mapping, base(a), base(f)) if result < isGeneric: result = isNone - elif skipTypes(f, {tyRange}).kind == a.kind: + elif skipTypes(f, {tyRange}).kind == a.kind: + result = isIntConv + elif isConvertibleToRange(skipTypes(f, {tyRange}), a): result = isConvertible # a convertible to f of tyInt: result = handleRange(f, a, tyInt8, tyInt32) of tyInt8: result = handleRange(f, a, tyInt8, tyInt8) of tyInt16: result = handleRange(f, a, tyInt8, tyInt16) - of tyInt32: result = handleRange(f, a, tyInt, tyInt32) + of tyInt32: result = handleRange(f, a, tyInt8, tyInt32) of tyInt64: result = handleRange(f, a, tyInt, tyInt64) - of tyUInt: result = handleRange(f, a, tyUInt8, tyUInt32) - of tyUInt8: result = handleRange(f, a, tyUInt8, tyUInt8) - of tyUInt16: result = handleRange(f, a, tyUInt8, tyUInt16) - of tyUInt32: result = handleRange(f, a, tyUInt, tyUInt32) - of tyUInt64: result = handleRange(f, a, tyUInt, tyUInt64) + of tyUInt: result = handleRange(f, a, tyUInt8, tyUInt32) + of tyUInt8: result = handleRange(f, a, tyUInt8, tyUInt8) + of tyUInt16: result = handleRange(f, a, tyUInt8, tyUInt16) + of tyUInt32: result = handleRange(f, a, tyUInt8, tyUInt32) + of tyUInt64: result = handleRange(f, a, tyUInt, tyUInt64) of tyFloat: result = handleFloatRange(f, a) of tyFloat32: result = handleFloatRange(f, a) of tyFloat64: result = handleFloatRange(f, a) @@ -789,12 +804,3 @@ proc matches*(c: PContext, n, nOrig: PNode, m: var TCandidate) = # use default value: setSon(m.call, formal.position + 1, copyTree(formal.ast)) inc(f) - - when false: - if sfSystemModule notin c.module.flags: - if fileInfoIdx("temp.nim") == c.module.info.fileIndex: - echo "########################" - echo m.call.renderTree - for i in 1..m.call.len-1: - debug m.call[i].typ - diff --git a/compiler/transf.nim b/compiler/transf.nim index f6e87e828..7c2353c54 100755 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -12,7 +12,7 @@ # # * inlines iterators # * inlines constants -# * performes contant folding +# * performes constant folding # * converts "continue" to "break" # * introduces method dispatchers # * performs lambda lifting for closure support @@ -401,7 +401,7 @@ proc transformConv(c: PTransf, n: PNode): PTransNode = result = transformSons(c, n) else: # generate a range check: - if (dest.kind == tyInt64) or (source.kind == tyInt64): + if dest.kind == tyInt64 or source.kind == tyInt64: result = newTransNode(nkChckRange64, n, 3) else: result = newTransNode(nkChckRange, n, 3) |