Skip to content

Commit

Permalink
added system.typeof operation; fixes #9093
Browse files Browse the repository at this point in the history
  • Loading branch information
Araq committed Oct 24, 2018
1 parent e7e7522 commit 963292f
Show file tree
Hide file tree
Showing 5 changed files with 47 additions and 4 deletions.
3 changes: 3 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@

- Added `or` for `NimNode` in `macros`.

- Added `system.typeof` for more control over how `type` expressions
can be deduced.

### Library changes


Expand Down
1 change: 1 addition & 0 deletions compiler/condsyms.nim
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ proc initDefines*(symbols: StringTableRef) =
defineSymbol("nimNoNilSeqs2")
defineSymbol("nimHasUserErrors")
defineSymbol("nimUncheckedArrayTyp")
defineSymbol("nimHasTypeof")

defineSymbol("nimHasNilSeqs")
for f in low(Feature)..high(Feature):
Expand Down
16 changes: 16 additions & 0 deletions compiler/semtypes.nim
Original file line number Diff line number Diff line change
Expand Up @@ -1414,6 +1414,20 @@ proc semTypeof(c: PContext; n: PNode; prev: PType): PType =
fixupTypeOf(c, prev, t)
result = t.typ

proc semTypeof2(c: PContext; n: PNode; prev: PType): PType =
openScope(c)
var m = BiggestInt 1 # typeOfIter
if n.len == 3:
let mode = semConstExpr(c, n[2])
if mode.kind != nkIntLit:
localError(c.config, n.info, "typeof: cannot evaluate 'mode' parameter at compile-time")
else:
m = mode.intVal
let t = semExprWithType(c, n[1], if m == 1: {efInTypeof} else: {})
closeScope(c)
fixupTypeOf(c, prev, t)
result = t.typ

proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
result = nil
inc c.inTypeContext
Expand Down Expand Up @@ -1494,6 +1508,8 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
elif op.id == ord(wType):
checkSonsLen(n, 2, c.config)
result = semTypeof(c, n[1], prev)
elif op.s == "typeof" and n[0].kind == nkSym and n[0].sym.magic == mTypeof:
result = semTypeOf2(c, n, prev)
else:
if c.inGenericContext > 0 and n.kind == nkCall:
result = makeTypeFromExpr(c, n.copyTree)
Expand Down
22 changes: 18 additions & 4 deletions lib/pure/collections/sequtils.nim
Original file line number Diff line number Diff line change
Expand Up @@ -673,10 +673,16 @@ template mapIt*(s: typed, op: untyped): untyped =
## nums = @[1, 2, 3, 4]
## strings = nums.mapIt($(4 * it))
## assert strings == @["4", "8", "12", "16"]
type outType = type((
block:
var it{.inject.}: type(items(s));
op))
when defined(nimHasTypeof):
type outType = typeof((
block:
var it{.inject.}: typeof(items(s), typeOfIter);
op), typeOfProc)
else:
type outType = type((
block:
var it{.inject.}: type(items(s));
op))
when compiles(s.len):
block: # using a block avoids https://github.com/nim-lang/Nim/issues/8580

Expand Down Expand Up @@ -1135,5 +1141,13 @@ when isMainModule:
A, B
doAssert mapIt(X, $it) == @["A", "B"]

block:
# bug #9093
let inp = "a:b,c:d"

let outp = inp.split(",").mapIt(it.split(":"))
doAssert outp == @[@["a", "b"], @["c", "d"]]


when not defined(testing):
echo "Finished doc tests"
9 changes: 9 additions & 0 deletions lib/system.nim
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,15 @@ else:
## Cannot be overloaded.
discard

when defined(nimHasTypeof):
type
TypeOfMode* = enum ## Possible modes of `typeof`.
typeOfProc, ## Prefer the interpretation that means `x` is a proc call.
typeOfIter ## Prefer the interpretation that means `x` is an iterator call.
proc typeof*(x: untyped; mode = typeOfIter): typeDesc {.magic: "TypeOf", noSideEffect, compileTime.} =
## Builtin 'typeof' operation for accessing the type of an expression. Since version 0.20.0.
discard

proc `not`*(x: bool): bool {.magic: "Not", noSideEffect.}
## Boolean not; returns true iff ``x == false``.

Expand Down

0 comments on commit 963292f

Please sign in to comment.