changed integer promotion rules; added math.fmod

This commit is contained in:
Araq 2012-06-28 08:33:25 +02:00
commit 2900ceae35
13 changed files with 83 additions and 71 deletions

View file

@ -334,12 +334,10 @@ type
tfEnumHasHoles, # enum cannot be mapped into a range tfEnumHasHoles, # enum cannot be mapped into a range
tfShallow, # type can be shallow copied on assignment tfShallow, # type can be shallow copied on assignment
tfThread, # proc type is marked as ``thread`` tfThread, # proc type is marked as ``thread``
tfUniIntLit # type represents literal value that could be either tfFromGeneric, # type is an instantiation of a generic; this is needed
# singed or unsigned integer (e.g. 100)
tfFromGeneric # type is an instantiation of a generic; this is needed
# because for instantiations of objects, structural # because for instantiations of objects, structural
# type equality has to be used # 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 tfAny # type class requires any constraint to be met
TTypeFlags* = set[TTypeFlag] TTypeFlags* = set[TTypeFlag]
@ -587,6 +585,7 @@ type
# for range types a nkRange node # for range types a nkRange node
# for record types a nkRecord node # for record types a nkRecord node
# for enum types a list of symbols # for enum types a list of symbols
# for tyInt it can be the int literal
# else: unused # else: unused
destructor*: PSym # destructor. warning: nil here may not necessary destructor*: PSym # destructor. warning: nil here may not necessary
# mean that there is no destructor. # mean that there is no destructor.

View file

@ -74,6 +74,25 @@ proc getSysType(kind: TTypeKind): PType =
InternalError("wanted: " & $kind & " got: " & $result.kind) InternalError("wanted: " & $kind & " got: " & $result.kind)
if result == nil: InternalError("type not found: " & $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 = proc getCompilerProc(name: string): PSym =
var ident = getIdent(name, hashIgnoreStyle(name)) var ident = getIdent(name, hashIgnoreStyle(name))
result = StrTableGet(compilerprocs, ident) result = StrTableGet(compilerprocs, ident)

View file

@ -102,7 +102,7 @@ type
warnSmallLshouldNotBeUsed, warnUnknownMagic, warnRedefinitionOfLabel, warnSmallLshouldNotBeUsed, warnUnknownMagic, warnRedefinitionOfLabel,
warnUnknownSubstitutionX, warnLanguageXNotSupported, warnCommentXIgnored, warnUnknownSubstitutionX, warnLanguageXNotSupported, warnCommentXIgnored,
warnXisPassedToProcVar, warnAnalysisLoophole, warnXisPassedToProcVar, warnAnalysisLoophole,
warnDifferentHeaps, warnWriteToForeignHeap, warnDifferentHeaps, warnWriteToForeignHeap, warnImplicitNarrowing,
warnUser, warnUser,
hintSuccess, hintSuccessX, hintSuccess, hintSuccessX,
hintLineTooLong, hintXDeclaredButNotUsed, hintConvToBaseNotNeeded, hintLineTooLong, hintXDeclaredButNotUsed, hintConvToBaseNotNeeded,
@ -345,6 +345,7 @@ const
warnAnalysisLoophole: "thread analysis incomplete due to unkown call '$1' [AnalysisLoophole]", warnAnalysisLoophole: "thread analysis incomplete due to unkown call '$1' [AnalysisLoophole]",
warnDifferentHeaps: "possible inconsistency of thread local heaps [DifferentHeaps]", warnDifferentHeaps: "possible inconsistency of thread local heaps [DifferentHeaps]",
warnWriteToForeignHeap: "write to foreign heap [WriteToForeignHeap]", warnWriteToForeignHeap: "write to foreign heap [WriteToForeignHeap]",
warnImplicitNarrowing: "implicit narrowing conversion: '$1'",
warnUser: "$1 [User]", warnUser: "$1 [User]",
hintSuccess: "operation successful [Success]", hintSuccess: "operation successful [Success]",
hintSuccessX: "operation successful ($# lines compiled; $# sec total; $#) [SuccessX]", hintSuccessX: "operation successful ($# lines compiled; $# sec total; $#) [SuccessX]",
@ -362,13 +363,14 @@ const
hintUser: "$1 [User]"] hintUser: "$1 [User]"]
const const
WarningsToStr*: array[0..16, string] = ["CannotOpenFile", "OctalEscape", WarningsToStr*: array[0..17, string] = ["CannotOpenFile", "OctalEscape",
"XIsNeverRead", "XmightNotBeenInit", "XIsNeverRead", "XmightNotBeenInit",
"Deprecated", "ConfigDeprecated", "Deprecated", "ConfigDeprecated",
"SmallLshouldNotBeUsed", "UnknownMagic", "SmallLshouldNotBeUsed", "UnknownMagic",
"RedefinitionOfLabel", "UnknownSubstitutionX", "LanguageXNotSupported", "RedefinitionOfLabel", "UnknownSubstitutionX", "LanguageXNotSupported",
"CommentXIgnored", "XisPassedToProcVar", "CommentXIgnored", "XisPassedToProcVar",
"AnalysisLoophole", "DifferentHeaps", "WriteToForeignHeap", "User"] "AnalysisLoophole", "DifferentHeaps", "WriteToForeignHeap",
"ImplicitNarrowing,", "User"]
HintsToStr*: array[0..13, string] = ["Success", "SuccessX", "LineTooLong", HintsToStr*: array[0..13, string] = ["Success", "SuccessX", "LineTooLong",
"XDeclaredButNotUsed", "ConvToBaseNotNeeded", "ConvFromXtoItselfNotNeeded", "XDeclaredButNotUsed", "ConvToBaseNotNeeded", "ConvFromXtoItselfNotNeeded",

View file

@ -1285,20 +1285,6 @@ proc semMacroStmt(c: PContext, n: PNode, semCheck = true): PNode =
GlobalError(n.info, errInvalidExpressionX, GlobalError(n.info, errInvalidExpressionX,
renderTree(a, {renderNoComments})) 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 = proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
result = n result = n
if gCmd == cmdIdeTools: suggestExpr(c, n) if gCmd == cmdIdeTools: suggestExpr(c, n)
@ -1319,13 +1305,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
if result.typ == nil: if result.typ == nil:
let i = result.intVal let i = result.intVal
if i >= low(int32) and i <= high(int32): 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: else:
result.typ = getSysType(tyInt64) result.typ = getSysType(tyInt64)
of nkInt8Lit: of nkInt8Lit:

View file

@ -13,7 +13,7 @@
import import
strutils, lists, options, ast, astalgo, trees, treetab, nimsets, times, strutils, lists, options, ast, astalgo, trees, treetab, nimsets, times,
nversion, platform, math, msgs, os, condsyms, idents, renderer, types, nversion, platform, math, msgs, os, condsyms, idents, renderer, types,
commands commands, magicsys
proc getConstExpr*(m: PSym, n: PNode): PNode proc getConstExpr*(m: PSym, n: PNode): PNode
# evaluates the constant expression or returns nil if it is no constant # evaluates the constant expression or returns nil if it is no constant

View file

@ -162,12 +162,25 @@ proc handleRange(f, a: PType, min, max: TTypeKind): TTypeRelation =
else: else:
var k = skipTypes(a, {tyRange}).kind var k = skipTypes(a, {tyRange}).kind
if k == f.kind: result = isSubtype if k == f.kind: result = isSubtype
elif f.kind == tyInt and k in {tyInt..tyInt32}: result = isIntConv elif k == tyInt:
elif f.kind == tyUInt and k in {tyUInt..tyUInt32}: result = isIntConv # and a.n != nil and a.n.intVal >= firstOrd(f) and
elif f.kind in {tyUInt..tyUInt64} and k == tyInt and tfUniIntLit in a.flags: # 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 result = isIntConv
elif k >= min and k <= max: result = isConvertible elif k >= min and k <= max: result = isConvertible
else: result = isNone 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 = proc handleFloatRange(f, a: PType): TTypeRelation =
if a.kind == f.kind: if a.kind == f.kind:
@ -227,10 +240,10 @@ proc matchTypeClass(mapping: var TIdTable, f, a: PType): TTypeRelation =
else: nil else: nil
if tfAny in f.flags: if tfAny in f.flags:
if match == true: if match:
return isGeneric return isGeneric
else: else:
if match == false: if not match:
return isNone return isNone
# if the loop finished without returning, either all constraints matched # if the loop finished without returning, either all constraints matched
@ -287,7 +300,7 @@ proc typeRel(mapping: var TIdTable, f, a: PType): TTypeRelation =
if a.kind == tyGenericInst and if a.kind == tyGenericInst and
skipTypes(f, {tyVar}).kind notin { skipTypes(f, {tyVar}).kind notin {
tyGenericBody, tyGenericInvokation, tyGenericBody, tyGenericInvokation,
tyGenericParam, tyTypeClass }: tyGenericParam, tyTypeClass}:
return typeRel(mapping, f, lastSon(a)) 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]) return typeRel(mapping, f, a.sons[0])
@ -303,16 +316,18 @@ proc typeRel(mapping: var TIdTable, f, a: PType): TTypeRelation =
result = typeRel(mapping, base(a), base(f)) result = typeRel(mapping, base(a), base(f))
if result < isGeneric: result = isNone 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 result = isConvertible # a convertible to f
of tyInt: result = handleRange(f, a, tyInt8, tyInt32) of tyInt: result = handleRange(f, a, tyInt8, tyInt32)
of tyInt8: result = handleRange(f, a, tyInt8, tyInt8) of tyInt8: result = handleRange(f, a, tyInt8, tyInt8)
of tyInt16: result = handleRange(f, a, tyInt8, tyInt16) 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 tyInt64: result = handleRange(f, a, tyInt, tyInt64)
of tyUInt: result = handleRange(f, a, tyUInt8, tyUInt32) of tyUInt: result = handleRange(f, a, tyUInt8, tyUInt32)
of tyUInt8: result = handleRange(f, a, tyUInt8, tyUInt8) of tyUInt8: result = handleRange(f, a, tyUInt8, tyUInt8)
of tyUInt16: result = handleRange(f, a, tyUInt8, tyUInt16) of tyUInt16: result = handleRange(f, a, tyUInt8, tyUInt16)
of tyUInt32: result = handleRange(f, a, tyUInt, tyUInt32) of tyUInt32: result = handleRange(f, a, tyUInt8, tyUInt32)
of tyUInt64: result = handleRange(f, a, tyUInt, tyUInt64) of tyUInt64: result = handleRange(f, a, tyUInt, tyUInt64)
of tyFloat: result = handleFloatRange(f, a) of tyFloat: result = handleFloatRange(f, a)
of tyFloat32: result = handleFloatRange(f, a) of tyFloat32: result = handleFloatRange(f, a)
@ -789,12 +804,3 @@ proc matches*(c: PContext, n, nOrig: PNode, m: var TCandidate) =
# use default value: # use default value:
setSon(m.call, formal.position + 1, copyTree(formal.ast)) setSon(m.call, formal.position + 1, copyTree(formal.ast))
inc(f) 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

View file

@ -12,7 +12,7 @@
# #
# * inlines iterators # * inlines iterators
# * inlines constants # * inlines constants
# * performes contant folding # * performes constant folding
# * converts "continue" to "break" # * converts "continue" to "break"
# * introduces method dispatchers # * introduces method dispatchers
# * performs lambda lifting for closure support # * performs lambda lifting for closure support
@ -401,7 +401,7 @@ proc transformConv(c: PTransf, n: PNode): PTransNode =
result = transformSons(c, n) result = transformSons(c, n)
else: else:
# generate a range check: # 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) result = newTransNode(nkChckRange64, n, 3)
else: else:
result = newTransNode(nkChckRange, n, 3) result = newTransNode(nkChckRange, n, 3)

View file

@ -188,7 +188,7 @@ type
Tid* {.importc: "id_t", header: "<sys/types.h>".} = int Tid* {.importc: "id_t", header: "<sys/types.h>".} = int
Tino* {.importc: "ino_t", header: "<sys/types.h>".} = int Tino* {.importc: "ino_t", header: "<sys/types.h>".} = int
TKey* {.importc: "key_t", header: "<sys/types.h>".} = int TKey* {.importc: "key_t", header: "<sys/types.h>".} = int
TMode* {.importc: "mode_t", header: "<sys/types.h>".} = int TMode* {.importc: "mode_t", header: "<sys/types.h>".} = cint
TNlink* {.importc: "nlink_t", header: "<sys/types.h>".} = int TNlink* {.importc: "nlink_t", header: "<sys/types.h>".} = int
TOff* {.importc: "off_t", header: "<sys/types.h>".} = int64 TOff* {.importc: "off_t", header: "<sys/types.h>".} = int64
TPid* {.importc: "pid_t", header: "<sys/types.h>".} = int TPid* {.importc: "pid_t", header: "<sys/types.h>".} = int

View file

@ -188,6 +188,8 @@ when not defined(ECMAScript):
proc floor*(x: float): float {.importc: "floor", nodecl.} proc floor*(x: float): float {.importc: "floor", nodecl.}
proc ceil*(x: float): float {.importc: "ceil", nodecl.} proc ceil*(x: float): float {.importc: "ceil", nodecl.}
proc fmod*(x, y: float): float {.importc: "fmod", header: "<math.h>".}
else: else:
proc mathrandom(): float {.importc: "Math.random", nodecl.} proc mathrandom(): float {.importc: "Math.random", nodecl.}
proc floor*(x: float): float {.importc: "Math.floor", nodecl.} proc floor*(x: float): float {.importc: "Math.floor", nodecl.}
@ -230,8 +232,11 @@ else:
var y = exp(2.0*x) var y = exp(2.0*x)
return (y-1.0)/(y+1.0) 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 type
TRunningStat* = object ## an accumulator for statistical data TRunningStat* {.pure,final.} = object ## an accumulator for statistical data
n*: int ## number of pushed data n*: int ## number of pushed data
sum*, min*, max*, mean*: float ## self-explaining sum*, min*, max*, mean*: float ## self-explaining
oldM, oldS, newS: float oldM, oldS, newS: float

View file

@ -23,7 +23,7 @@ when defined(posix):
const const
PROT_READ = 1 # page can be read PROT_READ = 1 # page can be read
PROT_WRITE = 2 # page can be written 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): when defined(macosx) or defined(bsd):
const MAP_ANONYMOUS = 0x1000 const MAP_ANONYMOUS = 0x1000

View file

@ -14,9 +14,9 @@
{.push hints:off} {.push hints:off}
proc c_strcmp(a, b: CString): cint {.nodecl, noSideEffect, importc: "strcmp".} 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".} 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_strlen(a: CString): int {.nodecl, noSideEffect, importc: "strlen".}
proc c_memset(p: pointer, value: cint, size: int) {.nodecl, importc: "memset".} proc c_memset(p: pointer, value: cint, size: int) {.nodecl, importc: "memset".}

View file

@ -199,8 +199,8 @@ proc Open(f: var TFile, filename: string,
var p: pointer = fopen(filename, FormatOpen[mode]) var p: pointer = fopen(filename, FormatOpen[mode])
result = (p != nil) result = (p != nil)
f = cast[TFile](p) f = cast[TFile](p)
if bufSize > 0: if bufSize > 0 and bufSize <= high(cint):
if setvbuf(f, nil, IOFBF, bufSize) != 0'i32: if setvbuf(f, nil, IOFBF, bufSize.cint) != 0'i32:
raise newException(EOutOfMemory, "out of memory") raise newException(EOutOfMemory, "out of memory")
elif bufSize == 0: elif bufSize == 0:
discard setvbuf(f, nil, IONBF, 0) discard setvbuf(f, nil, IONBF, 0)

View file

@ -11,6 +11,7 @@ New pragmas:
- ``borrow`` needs to take type classes into account - ``borrow`` needs to take type classes into account
- make templates hygienic by default: try to gensym() everything in the 'block' - make templates hygienic by default: try to gensym() everything in the 'block'
of a template; find a better solution for gensym instead of `*ident` 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 - make use of ``tyIter`` to fix the implicit items/pairs issue
- ``=`` should be overloadable; requires specialization for ``=`` - ``=`` should be overloadable; requires specialization for ``=``
- optimize genericAssign in the code generator - optimize genericAssign in the code generator
@ -21,8 +22,7 @@ New pragmas:
- implement "closure tuple consists of a single 'ref'" optimization - implement "closure tuple consists of a single 'ref'" optimization
- document 'do' notation - document 'do' notation
- unsigned ints and bignums; requires abstract integer literal type: - finish support for unsigned ints
use tyInt+node for that
- rethink the syntax: distinction between expr and stmt is unfortunate; - rethink the syntax: distinction between expr and stmt is unfortunate;
indentation handling is quite complex too; problem with exception handling 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 is that often the scope of ``try`` is wrong and apart from that ``try`` is
@ -100,6 +100,7 @@ Library
Low priority Low priority
------------ ------------
- bignums
- change how comments are part of the AST - change how comments are part of the AST
- ``with proc `+`(x, y: T): T`` for generic code - ``with proc `+`(x, y: T): T`` for generic code
- new feature: ``distinct T with operations`` - new feature: ``distinct T with operations``