changed integer promotion rules; added math.fmod

This commit is contained in:
Araq
2012-06-28 08:33:25 +02:00
parent b5d34242ca
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
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.

View File

@@ -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)

View File

@@ -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",

View File

@@ -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:

View File

@@ -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

View File

@@ -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

View File

@@ -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)

View File

@@ -188,7 +188,7 @@ type
Tid* {.importc: "id_t", header: "<sys/types.h>".} = int
Tino* {.importc: "ino_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
TOff* {.importc: "off_t", header: "<sys/types.h>".} = int64
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 ceil*(x: float): float {.importc: "ceil", nodecl.}
proc fmod*(x, y: float): float {.importc: "fmod", header: "<math.h>".}
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) =

View File

@@ -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()

View File

@@ -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".}

View File

@@ -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)

View File

@@ -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``