diff --git a/compiler/ast.nim b/compiler/ast.nim index d14bef9f70..511d6f116a 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/magicsys.nim b/compiler/magicsys.nim index a69b40fbfb..09c99c027e 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/msgs.nim b/compiler/msgs.nim index 0b79a68a26..53438c7222 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, @@ -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/semexprs.nim b/compiler/semexprs.nim index 00acbbe655..501b7ed720 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 f67e58e2f3..66d7e98fc0 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 7e985e9815..7a5d959dfd 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 f6e87e8282..7c2353c54c 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) diff --git a/lib/posix/posix.nim b/lib/posix/posix.nim index ca29f5fccf..ff121777ed 100755 --- a/lib/posix/posix.nim +++ b/lib/posix/posix.nim @@ -188,7 +188,7 @@ type Tid* {.importc: "id_t", header: "".} = int Tino* {.importc: "ino_t", header: "".} = int TKey* {.importc: "key_t", header: "".} = int - TMode* {.importc: "mode_t", header: "".} = int + TMode* {.importc: "mode_t", header: "".} = cint TNlink* {.importc: "nlink_t", header: "".} = int TOff* {.importc: "off_t", header: "".} = int64 TPid* {.importc: "pid_t", header: "".} = int diff --git a/lib/pure/math.nim b/lib/pure/math.nim index 6f3135d133..5876711654 100755 --- a/lib/pure/math.nim +++ b/lib/pure/math.nim @@ -188,6 +188,8 @@ when not defined(ECMAScript): proc floor*(x: float): float {.importc: "floor", nodecl.} proc ceil*(x: float): float {.importc: "ceil", nodecl.} + proc fmod*(x, y: float): float {.importc: "fmod", header: "".} + else: proc mathrandom(): float {.importc: "Math.random", nodecl.} proc floor*(x: float): float {.importc: "Math.floor", nodecl.} @@ -230,10 +232,13 @@ else: var y = exp(2.0*x) return (y-1.0)/(y+1.0) +proc `mod`*(x, y: float): float = + result = if y == 0.0: x else: x - y * (x/y).floor + type - TRunningStat* = object ## an accumulator for statistical data - n*: int ## number of pushed data - sum*, min*, max*, mean*: float ## self-explaining + TRunningStat* {.pure,final.} = object ## an accumulator for statistical data + n*: int ## number of pushed data + sum*, min*, max*, mean*: float ## self-explaining oldM, oldS, newS: float proc push*(s: var TRunningStat, x: float) = diff --git a/lib/system/alloc.nim b/lib/system/alloc.nim index 981dac9779..ba172373d5 100755 --- a/lib/system/alloc.nim +++ b/lib/system/alloc.nim @@ -23,7 +23,7 @@ when defined(posix): const PROT_READ = 1 # page can be read PROT_WRITE = 2 # page can be written - MAP_PRIVATE = 2 # Changes are private + MAP_PRIVATE = 2'i32 # Changes are private when defined(macosx) or defined(bsd): const MAP_ANONYMOUS = 0x1000 @@ -40,7 +40,7 @@ when defined(posix): proc osAllocPages(size: int): pointer {.inline.} = result = mmap(nil, size, PROT_READ or PROT_WRITE, - MAP_PRIVATE or MAP_ANONYMOUS, -1, 0) + MAP_PRIVATE or MAP_ANONYMOUS, -1, 0) if result == nil or result == cast[pointer](-1): raiseOutOfMem() diff --git a/lib/system/ansi_c.nim b/lib/system/ansi_c.nim index e328f70990..3376b94135 100755 --- a/lib/system/ansi_c.nim +++ b/lib/system/ansi_c.nim @@ -14,9 +14,9 @@ {.push hints:off} proc c_strcmp(a, b: CString): cint {.nodecl, noSideEffect, importc: "strcmp".} -proc c_memcmp(a, b: CString, size: cint): cint {. +proc c_memcmp(a, b: CString, size: int): cint {. nodecl, noSideEffect, importc: "memcmp".} -proc c_memcpy(a, b: CString, size: cint) {.nodecl, importc: "memcpy".} +proc c_memcpy(a, b: CString, size: int) {.nodecl, importc: "memcpy".} proc c_strlen(a: CString): int {.nodecl, noSideEffect, importc: "strlen".} proc c_memset(p: pointer, value: cint, size: int) {.nodecl, importc: "memset".} diff --git a/lib/system/sysio.nim b/lib/system/sysio.nim index adcb32b42f..15f87896a1 100755 --- a/lib/system/sysio.nim +++ b/lib/system/sysio.nim @@ -199,8 +199,8 @@ proc Open(f: var TFile, filename: string, var p: pointer = fopen(filename, FormatOpen[mode]) result = (p != nil) f = cast[TFile](p) - if bufSize > 0: - if setvbuf(f, nil, IOFBF, bufSize) != 0'i32: + if bufSize > 0 and bufSize <= high(cint): + if setvbuf(f, nil, IOFBF, bufSize.cint) != 0'i32: raise newException(EOutOfMemory, "out of memory") elif bufSize == 0: discard setvbuf(f, nil, IONBF, 0) diff --git a/todo.txt b/todo.txt index c77b8680fe..a33afe3624 100755 --- a/todo.txt +++ b/todo.txt @@ -11,6 +11,7 @@ New pragmas: - ``borrow`` needs to take type classes into account - make templates hygienic by default: try to gensym() everything in the 'block' of a template; find a better solution for gensym instead of `*ident` +- introduce ``;`` to the parser - make use of ``tyIter`` to fix the implicit items/pairs issue - ``=`` should be overloadable; requires specialization for ``=`` - optimize genericAssign in the code generator @@ -21,8 +22,7 @@ New pragmas: - implement "closure tuple consists of a single 'ref'" optimization - document 'do' notation -- unsigned ints and bignums; requires abstract integer literal type: - use tyInt+node for that +- finish support for unsigned ints - rethink the syntax: distinction between expr and stmt is unfortunate; indentation handling is quite complex too; problem with exception handling is that often the scope of ``try`` is wrong and apart from that ``try`` is @@ -100,6 +100,7 @@ Library Low priority ------------ +- bignums - change how comments are part of the AST - ``with proc `+`(x, y: T): T`` for generic code - new feature: ``distinct T with operations``