Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ on:
- 'tests/**'
- 'unchained.nimble'
- '.github/workflows/ci.yml'
branches:
- 'master'
pull_request:
paths:
- 'examples/**'
Expand Down
3 changes: 3 additions & 0 deletions changelog.org
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
* v0.4.7
- support ~range[T]~ types. Previously caused error when determining
associated "unit"
* v0.4.6
- fix parsing of single runes, i.e. when doing ~defUnit(Ω•m⁻¹)~ the
parser would try to parse the Ω as a single ~char~ and not a unicode rune
Expand Down
16 changes: 16 additions & 0 deletions src/unchained/macro_utils.nim
Original file line number Diff line number Diff line change
Expand Up @@ -75,13 +75,29 @@ proc resolveTypeFromGenericInst(n: NimNode): NimNode =
# simply leave as is
result = n

proc resolveFromRange*(n: NimNode): NimNode =
## Resolves the underlying type of a `range[T]`.
##
## In the end we call `getType.repr` on the literal (or constant) that defines
## the lower range:
## BracketExpr
## Sym "range"
## Infix
## Ident ".."
## FloatLit 0.0
## FloatLit 1.0
let typ = n.getTypeInst
doAssert typ[0].repr == "range", "ntyRange is not a range type? " & $typ.treerepr
result = typ[1][1].getType

proc getUnitTypeImpl*(n: NimNode): NimNode =
case n.typeKind
of ntyAlias: result = n.resolveTypeFromAlias()
of ntyDistinct: result = n.resolveTypeFromDistinct()
of ntyTypeDesc: result = n.resolveTypeFromTypeDesc()
of ntyGenericInst: result = n.resolveTypeFromGenericInst()
of ntyFloat32, ntyFloat64, ntyFloat: result = n
of ntyRange: result = n.resolveFromRange()
of ntyUserTypeClass:
## NOTE: Attempting to resolve a type from such an implicit generic doesn't
## work properly. See tests/tResolveImplicitQuantity.nim
Expand Down
38 changes: 30 additions & 8 deletions src/unchained/parse_units.nim
Original file line number Diff line number Diff line change
Expand Up @@ -193,13 +193,16 @@ proc tryLookupUnitType*(tab: UnitTable, n: NimNode): Option[UnitProduct] =
## In that case, we can just return it instead of parsing it again.
## This is especially useful for predefined aliases like `N = Newton = KiloGram•Meter•Second⁻²`
## as we otherwise fully resolve it to the long format.
proc inSupportedBaseType(s: string): bool =
result = s in ["FloatType", "float32", "float", "float64", "int", "int64", "UnitLess"]

proc fromTab(tab: UnitTable, nStr: string): Option[UnitProduct] =
if tab.isUserDefined(nStr):
if inSupportedBaseType(nStr):
result = some(initUnitProduct())
elif tab.isUserDefined(nStr):
result = some(tab.getUserDefined(nStr))
elif nStr in tab:
result = some(tab[nStr].toUnitInstance(assignPrefix = false).toUnitProduct())
elif nStr in ["FloatType", "float32", "float", "float64", "int", "int64", "UnitLess"]:
result = some(initUnitProduct())

case n.kind
of nnkIdent:
Expand All @@ -210,14 +213,33 @@ proc tryLookupUnitType*(tab: UnitTable, n: NimNode): Option[UnitProduct] =
let nTyp = n.getTypeInst
var nStr: string
case nTyp.kind
of nnkBracketExpr: nStr = nTyp[1].strVal
of nnkBracketExpr:
case nTyp.len
of 1: nStr = nTyp[1].strVal
of 2: # might be a range type, e.g.:
# BracketExpr
# Sym "range"
# Infix
# Ident ".."
# FloatLit 0.0
# FloatLit 1.0
# or a `nnkBracketExpr[typedesc, foo]`
if nTyp[0].kind in [nnkSym, nnkIdent] and nTyp[0].strVal == "range":
# check if range is in supported types
let rangeTyp = nTyp[1][1].getType
nStr = rangeTyp.repr
elif nTyp[0].kind in [nnkSym, nnkIdent] and nTyp[0].strVal.normalize == "typedesc":
doAssert nTyp[1].kind in [nnkSym, nnkIdent], "Typedesc argument is not a symbol: " & $nTyp.treerepr
nStr = nTyp[1].strVal
else:
error("Unexpected type: " & $nTyp.treerepr & " for input: " & $n.treerepr)
else:
error("Unexpected type: " & $nTyp.treerepr & " for input: " & $n.treerepr)
of nnkDistinctTy: nStr = nTyp[1].strVal
of nnkSym: nStr = nTyp.strVal
else: error("Invalid node for type : " & nTyp.repr)
if nStr in ["FloatType", "float32", "float", "float64", "int", "int64", "UnitLess"]:
result = some(initUnitProduct())
else:
result = fromTab(tab, nStr)

result = fromTab(tab, nStr)
of nnkTypeOfExpr:
result = tab.tryLookupUnitType(n[0])
else:
Expand Down
12 changes: 12 additions & 0 deletions tests/tunchained.nim
Original file line number Diff line number Diff line change
Expand Up @@ -1057,6 +1057,18 @@ suite "Unchained - Bug issues":
let x = 5.Ω•m⁻¹
check typeof(x) is Ω•m⁻¹

test "Range types work":
block IntRange:
let x: range[0 .. 10] = 5
let y = 123.kg
check typeof(x * y) is kg
check typeof(y / x) is kg
block FloatRange:
let x: range[0.0 .. 1.0] = 0.5
let y = 123.kg
check typeof(x * y) is kg
check typeof(y / x) is kg

suite "Utils":
test "Power w/ static integer exponents for floats":
let x = 5
Expand Down
2 changes: 1 addition & 1 deletion unchained.nimble
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ task installTestDeps, "Install dependencies to run tests in CI":
task test, "Runs the test":
exec "nim c -r tests/tunchained.nim"
exec "nim c -r tests/tresolveAlias.nim"
when not defined(windows): # For some reason in CI in this repo lapack isn't found using msys2 (works in ggplotnim)
when defined(linux): # For some reason in CI in this repo lapack isn't found using msys2 (works in ggplotnim)
exec "nim c -r -d:nolapack examples/bethe_bloch.nim"
exec "nim c -r examples/custom_unit_system.nim"

Expand Down
Loading