implemented a[^1] notation
This commit is contained in:
parent
36b6bfaf78
commit
5d63ecb3a4
13 changed files with 209 additions and 50 deletions
|
|
@ -529,7 +529,7 @@ type
|
|||
TMagic* = enum # symbols that require compiler magic:
|
||||
mNone,
|
||||
mDefined, mDefinedInScope, mCompiles,
|
||||
mLow, mHigh, mSizeOf, mTypeTrait, mIs, mOf, mAddr, mTypeOf,
|
||||
mLow, mHigh, mSizeOf, mTypeTrait, mIs, mOf, mAddr, mTypeOf, mRoof,
|
||||
mEcho, mShallowCopy, mSlurp, mStaticExec,
|
||||
mParseExprToAst, mParseStmtToAst, mExpandToAst, mQuoteAst,
|
||||
mUnaryLt, mInc, mDec, mOrd, mNew, mNewFinalize, mNewSeq, mLengthOpenArray,
|
||||
|
|
|
|||
|
|
@ -113,7 +113,7 @@ proc genMergeInfo*(m: BModule): PRope =
|
|||
s.add("*/")
|
||||
result = s.toRope
|
||||
|
||||
template `^`(pos: expr): expr = L.buf[pos]
|
||||
template `^`(pos: int): expr = L.buf[pos]
|
||||
|
||||
proc skipWhite(L: var TBaseLexer) =
|
||||
var pos = L.bufpos
|
||||
|
|
|
|||
|
|
@ -131,11 +131,10 @@ proc semNodeKindConstraints*(p: PNode): PNode =
|
|||
result.strVal.add(ppEof)
|
||||
|
||||
type
|
||||
TSideEffectAnalysis = enum
|
||||
TSideEffectAnalysis* = enum
|
||||
seUnknown, seSideEffect, seNoSideEffect
|
||||
|
||||
proc checkForSideEffects(n: PNode): TSideEffectAnalysis =
|
||||
# XXX is 'raise' a side effect?
|
||||
proc checkForSideEffects*(n: PNode): TSideEffectAnalysis =
|
||||
case n.kind
|
||||
of nkCallKinds:
|
||||
# only calls can produce side effects:
|
||||
|
|
@ -162,6 +161,8 @@ proc checkForSideEffects(n: PNode): TSideEffectAnalysis =
|
|||
# an atom cannot produce a side effect:
|
||||
result = seNoSideEffect
|
||||
else:
|
||||
# assume no side effect:
|
||||
result = seNoSideEffect
|
||||
for i in 0 .. <n.len:
|
||||
let ret = checkForSideEffects(n.sons[i])
|
||||
if ret == seSideEffect: return ret
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ type
|
|||
|
||||
POptionEntry* = ref TOptionEntry
|
||||
PProcCon* = ref TProcCon
|
||||
TProcCon*{.final.} = object # procedure context; also used for top-level
|
||||
TProcCon* = object # procedure context; also used for top-level
|
||||
# statements
|
||||
owner*: PSym # the symbol this context belongs to
|
||||
resultSym*: PSym # the result symbol (if we are in a proc)
|
||||
|
|
@ -36,6 +36,7 @@ type
|
|||
# in standalone ``except`` and ``finally``
|
||||
next*: PProcCon # used for stacking procedure contexts
|
||||
wasForwarded*: bool # whether the current proc has a separate header
|
||||
bracketExpr*: PNode # current bracket expression (for ^ support)
|
||||
|
||||
TInstantiationPair* = object
|
||||
genericSym*: PSym
|
||||
|
|
|
|||
|
|
@ -1133,19 +1133,20 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
|||
## returns nil if not a built-in subscript operator; also called for the
|
||||
## checking of assignments
|
||||
if sonsLen(n) == 1:
|
||||
var x = semDeref(c, n)
|
||||
let x = semDeref(c, n)
|
||||
if x == nil: return nil
|
||||
result = newNodeIT(nkDerefExpr, x.info, x.typ)
|
||||
result.add(x[0])
|
||||
return
|
||||
checkMinSonsLen(n, 2)
|
||||
n.sons[0] = semExprWithType(c, n.sons[0])
|
||||
var arr = skipTypes(n.sons[0].typ, {tyGenericInst, tyVar, tyPtr, tyRef})
|
||||
let arr = skipTypes(n.sons[0].typ, {tyGenericInst, tyVar, tyPtr, tyRef})
|
||||
case arr.kind
|
||||
of tyArray, tyOpenArray, tyVarargs, tyArrayConstr, tySequence, tyString,
|
||||
tyCString:
|
||||
if n.len != 2: return nil
|
||||
n.sons[0] = makeDeref(n.sons[0])
|
||||
c.p.bracketExpr = n.sons[0]
|
||||
for i in countup(1, sonsLen(n) - 1):
|
||||
n.sons[i] = semExprWithType(c, n.sons[i],
|
||||
flags*{efInTypeof, efDetermineType})
|
||||
|
|
@ -1166,6 +1167,7 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
|||
of tyTuple:
|
||||
checkSonsLen(n, 2)
|
||||
n.sons[0] = makeDeref(n.sons[0])
|
||||
c.p.bracketExpr = n.sons[0]
|
||||
# [] operator for tuples requires constant expression:
|
||||
n.sons[1] = semConstExpr(c, n.sons[1])
|
||||
if skipTypes(n.sons[1].typ, {tyGenericInst, tyRange, tyOrdinal}).kind in
|
||||
|
|
@ -1176,13 +1178,16 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
|||
else:
|
||||
localError(n.info, errIndexTypesDoNotMatch)
|
||||
result = n
|
||||
else: discard
|
||||
else:
|
||||
c.p.bracketExpr = n.sons[0]
|
||||
|
||||
proc semArrayAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
let oldBracketExpr = c.p.bracketExpr
|
||||
result = semSubscript(c, n, flags)
|
||||
if result == nil:
|
||||
# overloaded [] operator:
|
||||
result = semExpr(c, buildOverloadedSubscripts(n, getIdent"[]"))
|
||||
c.p.bracketExpr = oldBracketExpr
|
||||
|
||||
proc propertyWriteAccess(c: PContext, n, nOrig, a: PNode): PNode =
|
||||
var id = considerQuotedIdent(a[1])
|
||||
|
|
@ -1249,11 +1254,15 @@ proc semAsgn(c: PContext, n: PNode): PNode =
|
|||
of nkBracketExpr:
|
||||
# a[i] = x
|
||||
# --> `[]=`(a, i, x)
|
||||
let oldBracketExpr = c.p.bracketExpr
|
||||
a = semSubscript(c, a, {efLValue})
|
||||
if a == nil:
|
||||
result = buildOverloadedSubscripts(n.sons[0], getIdent"[]=")
|
||||
add(result, n[1])
|
||||
return semExprNoType(c, result)
|
||||
result = semExprNoType(c, result)
|
||||
c.p.bracketExpr = oldBracketExpr
|
||||
return result
|
||||
c.p.bracketExpr = oldBracketExpr
|
||||
of nkCurlyExpr:
|
||||
# a{i} = x --> `{}=`(a, i, x)
|
||||
result = buildOverloadedSubscripts(n.sons[0], getIdent"{}=")
|
||||
|
|
|
|||
|
|
@ -130,6 +130,11 @@ proc semLocals(c: PContext, n: PNode): PNode =
|
|||
result.add(a)
|
||||
|
||||
proc semShallowCopy(c: PContext, n: PNode, flags: TExprFlags): PNode
|
||||
|
||||
proc isStrangeArray(t: PType): bool =
|
||||
let t = t.skipTypes(abstractInst)
|
||||
result = t.kind == tyArray and t.firstOrd != 0
|
||||
|
||||
proc magicsAfterOverloadResolution(c: PContext, n: PNode,
|
||||
flags: TExprFlags): PNode =
|
||||
case n[0].sym.magic
|
||||
|
|
@ -153,4 +158,29 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode,
|
|||
of mProcCall:
|
||||
result = n
|
||||
result.typ = n[1].typ
|
||||
of mRoof:
|
||||
# error correction:
|
||||
result = n.sons[1]
|
||||
if c.p.bracketExpr.isNil:
|
||||
localError(n.info, "no surrounding array access context for '^'")
|
||||
elif c.p.bracketExpr.checkForSideEffects != seNoSideEffect:
|
||||
localError(n.info, "invalid context for '^' as '$#' has side effects" %
|
||||
renderTree(c.p.bracketExpr))
|
||||
elif c.p.bracketExpr.typ.isStrangeArray:
|
||||
localError(n.info, "invalid context for '^' as len!=high+1 for '$#'" %
|
||||
renderTree(c.p.bracketExpr))
|
||||
else:
|
||||
# ^x is rewritten to: len(a)-x
|
||||
let lenExpr = newNodeI(nkCall, n.info)
|
||||
lenExpr.add newIdentNode(getIdent"len", n.info)
|
||||
lenExpr.add c.p.bracketExpr
|
||||
let lenExprB = semExprWithType(c, lenExpr)
|
||||
if lenExprB.typ.isNil or not isOrdinalType(lenExprB.typ):
|
||||
localError(n.info, "'$#' has to be of an ordinal type for '^'" %
|
||||
renderTree(lenExpr))
|
||||
else:
|
||||
result = newNodeIT(nkCall, n.info, getSysType(tyInt))
|
||||
result.add newSymNode(createMagic("-", mSubI), n.info)
|
||||
result.add lenExprB
|
||||
result.add n.sons[1]
|
||||
else: result = n
|
||||
|
|
|
|||
|
|
@ -590,7 +590,7 @@ proc firstOrd(t: PType): BiggestInt =
|
|||
of tyUInt..tyUInt64: result = 0
|
||||
of tyEnum:
|
||||
# if basetype <> nil then return firstOrd of basetype
|
||||
if (sonsLen(t) > 0) and (t.sons[0] != nil):
|
||||
if sonsLen(t) > 0 and t.sons[0] != nil:
|
||||
result = firstOrd(t.sons[0])
|
||||
else:
|
||||
assert(t.n.sons[0].kind == nkSym)
|
||||
|
|
|
|||
|
|
@ -222,8 +222,8 @@ type
|
|||
set*{.magic: "Set".}[T] ## Generic type to construct bit sets.
|
||||
|
||||
type
|
||||
Slice* {.final, pure.}[T] = object ## builtin slice type
|
||||
a*, b*: T ## the bounds
|
||||
Slice*[T] = object ## builtin slice type
|
||||
a*, b*: T ## the bounds
|
||||
|
||||
when defined(nimalias):
|
||||
{.deprecated: [TSlice: Slice].}
|
||||
|
|
@ -3247,4 +3247,12 @@ proc procCall*(x: expr) {.magic: "ProcCall".} =
|
|||
## procCall someMethod(a, b)
|
||||
discard
|
||||
|
||||
proc `^`*(x: int): int {.noSideEffect, magic: "Roof".} =
|
||||
## builtin `roof`:idx: operator that can be used for convenient array access.
|
||||
## ``a[^x]`` is rewritten to ``a[a.len-x]``. However currently the ``a``
|
||||
## expression must not have side effects for this to compile. Note that since
|
||||
## this is a builtin, it automatically works for all kinds of
|
||||
## overloaded ``[]`` or ``[]=`` accessors.
|
||||
discard
|
||||
|
||||
{.pop.} #{.push warning[GcMem]: off.}
|
||||
|
|
|
|||
36
tests/array/troof1.nim
Normal file
36
tests/array/troof1.nim
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
discard """
|
||||
output: '''@[2, 3, 4]321
|
||||
9.0 4.0
|
||||
(a: 1.0, b: 2.0, c: 8.0)2.0'''
|
||||
"""
|
||||
|
||||
proc foo[T](x, y: T): T = x
|
||||
|
||||
var a = @[1, 2, 3, 4]
|
||||
var b: array[3, array[2, float]] = [[1.0,2], [3.0,4], [8.0,9]]
|
||||
echo a[1.. ^1], a[^2], a[^3], a[^4]
|
||||
echo b[^1][^1], " ", (b[^2]).foo(b[^1])[^1]
|
||||
|
||||
type
|
||||
MyArray = object
|
||||
a, b, c: float
|
||||
|
||||
var
|
||||
ma = MyArray(a: 1.0, b: 2.0, c: 3.0)
|
||||
|
||||
proc len(x: MyArray): int = 3
|
||||
|
||||
proc `[]=`(x: var MyArray; idx: range[0..2]; val: float) =
|
||||
case idx
|
||||
of 0: x.a = val
|
||||
of 1: x.b = val
|
||||
of 2: x.c = val
|
||||
|
||||
proc `[]`(x: var MyArray; idx: range[0..2]): float =
|
||||
case idx
|
||||
of 0: result = x.a
|
||||
of 1: result = x.b
|
||||
of 2: result = x.c
|
||||
|
||||
ma[^1] = 8.0
|
||||
echo ma, ma[^2]
|
||||
10
tests/array/troof2.nim
Normal file
10
tests/array/troof2.nim
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
discard """
|
||||
errormsg: "invalid context for '^' as 'foo()' has side effects"
|
||||
line: "9"
|
||||
"""
|
||||
|
||||
proc foo(): seq[int] =
|
||||
echo "ha"
|
||||
|
||||
let f = foo()[^1]
|
||||
|
||||
8
tests/array/troof3.nim
Normal file
8
tests/array/troof3.nim
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
discard """
|
||||
errormsg: "invalid context for '^' as len!=high+1 for 'a'"
|
||||
line: "8"
|
||||
"""
|
||||
|
||||
var a: array[1..3, string]
|
||||
|
||||
echo a[^1]
|
||||
37
tests/array/troof4.nim
Normal file
37
tests/array/troof4.nim
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
discard """
|
||||
errormsg: "no surrounding array access context for '^'"
|
||||
line: "37"
|
||||
"""
|
||||
|
||||
proc foo[T](x, y: T): T = x
|
||||
|
||||
var a = @[1, 2, 3, 4]
|
||||
var b: array[3, array[2, float]] = [[1.0,2], [3.0,4], [8.0,9]]
|
||||
echo a[1.. ^1], a[^2], a[^3], a[^4]
|
||||
echo b[^1][^1], " ", (b[^2]).foo(b[^1])[^1]
|
||||
|
||||
type
|
||||
MyArray = object
|
||||
a, b, c: float
|
||||
|
||||
var
|
||||
ma = MyArray(a: 1.0, b: 2.0, c: 3.0)
|
||||
|
||||
proc len(x: MyArray): int = 3
|
||||
|
||||
proc `[]=`(x: var MyArray; idx: range[0..2]; val: float) =
|
||||
case idx
|
||||
of 0: x.a = val
|
||||
of 1: x.b = val
|
||||
of 2: x.c = val
|
||||
|
||||
proc `[]`(x: var MyArray; idx: range[0..2]): float =
|
||||
case idx
|
||||
of 0: result = x.a
|
||||
of 1: result = x.b
|
||||
of 2: result = x.c
|
||||
|
||||
ma[^1] = 8.0
|
||||
echo ma, ma[^2]
|
||||
|
||||
echo(^1)
|
||||
19
web/news.txt
19
web/news.txt
|
|
@ -42,6 +42,22 @@ News
|
|||
structure; for immediate macro parameters ``nkCall('addr', 'x')`` is
|
||||
produced instead of ``nkAddr('x')``.
|
||||
- ``concept`` is now a keyword and is used instead of ``generic``.
|
||||
- The ``inc``, ``dec``, ``+=``, ``-=`` builtins now produces OverflowError
|
||||
exceptions. This means code like the following:
|
||||
|
||||
.. code-block:: nim
|
||||
var x = low(T)
|
||||
while x <= high(T):
|
||||
echo x
|
||||
inc x
|
||||
|
||||
Needs to be replaced by something like this:
|
||||
|
||||
.. code-block:: nim
|
||||
var x = low(T).int
|
||||
while x <= high(T).int:
|
||||
echo x.T
|
||||
inc x
|
||||
|
||||
|
||||
Language Additions
|
||||
|
|
@ -84,6 +100,9 @@ News
|
|||
varOrConst(x) # "var"
|
||||
varOrConst(45) # "const"
|
||||
|
||||
- Array and seq indexing can now use the builtin ``^`` operator to access
|
||||
things from backwards: ``a[^1]`` is like Python's ``a[-1]``.
|
||||
|
||||
|
||||
Library additions
|
||||
-----------------
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue