Implement float range types

This commit is contained in:
cooldome 2018-04-26 23:47:51 +01:00
commit a95316f78b
4 changed files with 144 additions and 88 deletions

View file

@ -46,7 +46,8 @@ type
errInvalidArgForX, errStmtHasNoEffect, errXExpectsTypeOrValue, errInvalidArgForX, errStmtHasNoEffect, errXExpectsTypeOrValue,
errXExpectsArrayType, errIteratorCannotBeInstantiated, errExprXAmbiguous, errXExpectsArrayType, errIteratorCannotBeInstantiated, errExprXAmbiguous,
errConstantDivisionByZero, errOrdinalTypeExpected, errConstantDivisionByZero, errOrdinalTypeExpected,
errOrdinalOrFloatTypeExpected, errOverOrUnderflow, errOrdinalOrFloatTypeExpected, errFloatTypeExpected, errStringTypeExpected,
errOverOrUnderflow,
errCannotEvalXBecauseIncompletelyDefined, errChrExpectsRange0_255, errCannotEvalXBecauseIncompletelyDefined, errChrExpectsRange0_255,
errDynlibRequiresExportc, errUndeclaredFieldX, errNilAccess, errDynlibRequiresExportc, errUndeclaredFieldX, errNilAccess,
errIndexOutOfBounds, errIndexTypesDoNotMatch, errBracketsInvalidForType, errIndexOutOfBounds, errIndexTypesDoNotMatch, errBracketsInvalidForType,
@ -219,6 +220,8 @@ const
errConstantDivisionByZero: "division by zero", errConstantDivisionByZero: "division by zero",
errOrdinalTypeExpected: "ordinal type expected", errOrdinalTypeExpected: "ordinal type expected",
errOrdinalOrFloatTypeExpected: "ordinal or float type expected", errOrdinalOrFloatTypeExpected: "ordinal or float type expected",
errFloatTypeExpected: "float type expected",
errStringTypeExpected: "string type expected",
errOverOrUnderflow: "over- or underflow", errOverOrUnderflow: "over- or underflow",
errCannotEvalXBecauseIncompletelyDefined: "cannot evaluate '$1' because type is not defined completely", errCannotEvalXBecauseIncompletelyDefined: "cannot evaluate '$1' because type is not defined completely",
errChrExpectsRange0_255: "\'chr\' expects an int in the range 0..255", errChrExpectsRange0_255: "\'chr\' expects an int in the range 0..255",

View file

@ -205,8 +205,8 @@ proc semRangeAux(c: PContext, n: PNode, prev: PType): PType =
if not hasUnknownTypes: if not hasUnknownTypes:
if not sameType(rangeT[0].skipTypes({tyRange}), rangeT[1].skipTypes({tyRange})): if not sameType(rangeT[0].skipTypes({tyRange}), rangeT[1].skipTypes({tyRange})):
localError(n.info, errPureTypeMismatch) localError(n.info, errPureTypeMismatch)
elif not rangeT[0].isOrdinalType: elif not rangeT[0].isOrdinalType and rangeT[0].kind notin tyFloat..tyFloat128:
localError(n.info, errOrdinalTypeExpected) localError(n.info, errOrdinalOrFloatTypeExpected)
elif enumHasHoles(rangeT[0]): elif enumHasHoles(rangeT[0]):
localError(n.info, errEnumXHasHoles, rangeT[0].sym.name.s) localError(n.info, errEnumXHasHoles, rangeT[0].sym.name.s)

View file

@ -628,20 +628,27 @@ proc procTypeRel(c: var TCandidate, f, a: PType): TTypeRelation =
else: discard else: discard
proc typeRangeRel(f, a: PType): TTypeRelation {.noinline.} = proc typeRangeRel(f, a: PType): TTypeRelation {.noinline.} =
let template check_range_in(t: typedesc): untyped =
a0 = firstOrd(a) let
a1 = lastOrd(a) a0 = firstValue[t](a)
f0 = firstOrd(f) a1 = lastValue[t](a)
f1 = lastOrd(f) f0 = firstValue[t](f)
if a0 == f0 and a1 == f1: f1 = lastValue[t](f)
result = isEqual if a0 == f0 and a1 == f1:
elif a0 >= f0 and a1 <= f1: result = isEqual
result = isConvertible elif a0 >= f0 and a1 <= f1:
elif a0 <= f1 and f0 <= a1: result = isConvertible
# X..Y and C..D overlap iff (X <= D and C <= Y) elif a0 <= f1 and f0 <= a1:
result = isConvertible # X..Y and C..D overlap iff (X <= D and C <= Y)
result = isConvertible
else:
result = isNone
if f.isOrdinalType:
check_range_in(BiggestInt)
else: else:
result = isNone check_range_in(BiggestFloat)
proc matchUserTypeClass*(m: var TCandidate; ff, a: PType): PType = proc matchUserTypeClass*(m: var TCandidate; ff, a: PType): PType =
var var

View file

@ -86,14 +86,33 @@ proc isPureObject*(typ: PType): bool =
t = t.sons[0].skipTypes(skipPtrs) t = t.sons[0].skipTypes(skipPtrs)
result = t.sym != nil and sfPure in t.sym.flags result = t.sym != nil and sfPure in t.sym.flags
proc getOrdValue*(n: PNode): BiggestInt = proc getValue*[T:BiggestInt|BiggestFloat|string](n: PNode): T =
## get value of liternal node
case n.kind case n.kind
of nkCharLit..nkUInt64Lit: result = n.intVal of nkNilLit: reset(result)
of nkNilLit: result = 0 of nkHiddenStdConv: result = getValue[T](n.sons[1])
of nkHiddenStdConv: result = getOrdValue(n.sons[1])
else: else:
localError(n.info, errOrdinalTypeExpected) when T is BiggestInt:
result = 0 case n.kind
of nkCharLit..nkUInt64Lit: result = n.intVal
else:
localError(n.info, errOrdinalTypeExpected)
result = 0
elif T is BiggestFloat:
case n.kind
of nkFloatLiterals: result = n.floatVal
else:
localError(n.info, errFloatTypeExpected)
result = NaN
else:
case n.kind:
of nkStrLit..nkTripleStrLit: result = n.strVal
else:
localError(n.info, errStringTypeExpected)
result = nil
proc getOrdValue*(n: PNode): BiggestInt {.inline.} =
getValue[BiggestInt](n)
proc isIntLit*(t: PType): bool {.inline.} = proc isIntLit*(t: PType): bool {.inline.} =
result = t.kind == tyInt and t.n != nil and t.n.kind == nkIntLit result = t.kind == tyInt and t.n != nil and t.n.kind == nkIntLit
@ -587,79 +606,106 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
result = typeToStr[t.kind] result = typeToStr[t.kind]
result.addTypeFlags(t) result.addTypeFlags(t)
proc firstOrd*(t: PType): BiggestInt = proc firstValue*[T:BiggestInt|BiggestFloat](t: PType): T =
case t.kind case t.kind:
of tyBool, tyChar, tySequence, tyOpenArray, tyString, tyVarargs, tyProxy: of tyVar: result = firstValue[T](t.sons[0])
result = 0 of tyGenericInst, tyDistinct, tyTypeDesc, tyAlias:
of tySet, tyVar: result = firstOrd(t.sons[0]) result = firstValue[T](lastSon(t))
of tyArray: result = firstOrd(t.sons[0]) of tyRange:
of tyRange: assert(t.n != nil) # range directly given:
assert(t.n != nil) # range directly given: assert(t.n.kind == nkRange)
assert(t.n.kind == nkRange) result = getValue[T](t.n.sons[0])
result = getOrdValue(t.n.sons[0])
of tyInt:
if platform.intSize == 4: result = - (2147483646) - 2
else: result = 0x8000000000000000'i64
of tyInt8: result = - 128
of tyInt16: result = - 32768
of tyInt32: result = - 2147483646 - 2
of tyInt64: result = 0x8000000000000000'i64
of tyUInt..tyUInt64: result = 0
of tyEnum:
# if basetype <> nil then return firstOrd of basetype
if sonsLen(t) > 0 and t.sons[0] != nil:
result = firstOrd(t.sons[0])
else: else:
assert(t.n.sons[0].kind == nkSym) when T is BiggestInt:
result = t.n.sons[0].sym.position case t.kind:
of tyGenericInst, tyDistinct, tyTypeDesc, tyAlias: of tyBool, tyChar, tySequence, tyOpenArray, tyString, tyVarargs, tyProxy:
result = firstOrd(lastSon(t)) result = 0
of tyOrdinal: of tySet, tyVar: result = firstValue[T](t.sons[0])
if t.len > 0: result = firstOrd(lastSon(t)) of tyArray: result = firstValue[T](t.sons[0])
else: internalError("invalid kind for first(" & $t.kind & ')') of tyInt:
else: if platform.intSize == 4: result = - (2147483646) - 2
internalError("invalid kind for first(" & $t.kind & ')') else: result = 0x8000000000000000'i64
result = 0 of tyInt8: result = - 128
of tyInt16: result = - 32768
of tyInt32: result = - 2147483646 - 2
of tyInt64: result = 0x8000000000000000'i64
of tyUInt..tyUInt64: result = 0
of tyEnum:
# if basetype <> nil then return firstOrd of basetype
if sonsLen(t) > 0 and t.sons[0] != nil:
result = firstValue[T](t.sons[0])
else:
assert(t.n.sons[0].kind == nkSym)
result = t.n.sons[0].sym.position
of tyOrdinal:
if t.len > 0: result = firstValue[T](lastSon(t))
else: internalError("invalid kind for first(" & $t.kind & ')')
else:
internalError("invalid kind for first(" & $t.kind & ')')
result = 0
proc lastOrd*(t: PType; fixedUnsigned = false): BiggestInt = elif T is BiggestFloat:
case t.kind:
of tyFloat..tyFloat128: result = -Inf
else:
internalError("invalid kind for first(" & $t.kind & ')')
result = NaN
proc firstOrd*(t: PType): BiggestInt {.inline.} =
firstValue[BiggestInt](t)
proc lastValue*[T:BiggestInt|BiggestFloat](t: PType; fixedUnsigned = false): T =
case t.kind case t.kind
of tyBool: result = 1 of tyVar: result = lastValue[T](t.sons[0])
of tyChar: result = 255 of tyGenericInst, tyDistinct, tyTypeDesc, tyAlias:
of tySet, tyVar: result = lastOrd(t.sons[0]) result = lastValue[T](lastSon(t))
of tyArray: result = lastOrd(t.sons[0])
of tyRange: of tyRange:
assert(t.n != nil) # range directly given: assert(t.n != nil) # range directly given:
assert(t.n.kind == nkRange) assert(t.n.kind == nkRange)
result = getOrdValue(t.n.sons[1]) result = getValue[T](t.n.sons[1])
of tyInt:
if platform.intSize == 4: result = 0x7FFFFFFF
else: result = 0x7FFFFFFFFFFFFFFF'i64
of tyInt8: result = 0x0000007F
of tyInt16: result = 0x00007FFF
of tyInt32: result = 0x7FFFFFFF
of tyInt64: result = 0x7FFFFFFFFFFFFFFF'i64
of tyUInt:
if platform.intSize == 4: result = 0xFFFFFFFF
elif fixedUnsigned: result = 0xFFFFFFFFFFFFFFFF'i64
else: result = 0x7FFFFFFFFFFFFFFF'i64
of tyUInt8: result = 0xFF
of tyUInt16: result = 0xFFFF
of tyUInt32: result = 0xFFFFFFFF
of tyUInt64:
if fixedUnsigned: result = 0xFFFFFFFFFFFFFFFF'i64
else: result = 0x7FFFFFFFFFFFFFFF'i64
of tyEnum:
assert(t.n.sons[sonsLen(t.n) - 1].kind == nkSym)
result = t.n.sons[sonsLen(t.n) - 1].sym.position
of tyGenericInst, tyDistinct, tyTypeDesc, tyAlias:
result = lastOrd(lastSon(t))
of tyProxy: result = 0
of tyOrdinal:
if t.len > 0: result = lastOrd(lastSon(t))
else: internalError("invalid kind for last(" & $t.kind & ')')
else: else:
internalError("invalid kind for last(" & $t.kind & ')') when T is BiggestInt:
result = 0 case t.kind
of tyBool: result = 1
of tyChar: result = 255
of tySet, tyArray: result = lastValue[T](t.sons[0])
of tyInt:
if platform.intSize == 4: result = 0x7FFFFFFF
else: result = 0x7FFFFFFFFFFFFFFF'i64
of tyInt8: result = 0x0000007F
of tyInt16: result = 0x00007FFF
of tyInt32: result = 0x7FFFFFFF
of tyInt64: result = 0x7FFFFFFFFFFFFFFF'i64
of tyUInt:
if platform.intSize == 4: result = 0xFFFFFFFF
elif fixedUnsigned: result = 0xFFFFFFFFFFFFFFFF'i64
else: result = 0x7FFFFFFFFFFFFFFF'i64
of tyUInt8: result = 0xFF
of tyUInt16: result = 0xFFFF
of tyUInt32: result = 0xFFFFFFFF
of tyUInt64:
if fixedUnsigned: result = 0xFFFFFFFFFFFFFFFF'i64
else: result = 0x7FFFFFFFFFFFFFFF'i64
of tyEnum:
assert(t.n.sons[sonsLen(t.n) - 1].kind == nkSym)
result = t.n.sons[sonsLen(t.n) - 1].sym.position
of tyProxy: result = 0
of tyOrdinal:
if t.len > 0: result = lastValue[T](lastSon(t))
else: internalError("invalid kind for last(" & $t.kind & ')')
else:
internalError("invalid kind for last(" & $t.kind & ')')
result = 0
elif T is BiggestFloat:
case t.kind:
of tyFloat..tyFloat128: result = Inf
else:
internalError("invalid kind for first(" & $t.kind & ')')
result = NaN
proc lastOrd*(t: PType; fixedUnsigned = false): BiggestInt {.inline.}=
lastValue[BiggestInt](t, fixedUnsigned)
proc lengthOrd*(t: PType): BiggestInt = proc lengthOrd*(t: PType): BiggestInt =
case t.kind case t.kind