Implement float range types
This commit is contained in:
parent
b503ca03f6
commit
a95316f78b
4 changed files with 144 additions and 88 deletions
|
|
@ -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",
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue