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:
|
TMagic* = enum # symbols that require compiler magic:
|
||||||
mNone,
|
mNone,
|
||||||
mDefined, mDefinedInScope, mCompiles,
|
mDefined, mDefinedInScope, mCompiles,
|
||||||
mLow, mHigh, mSizeOf, mTypeTrait, mIs, mOf, mAddr, mTypeOf,
|
mLow, mHigh, mSizeOf, mTypeTrait, mIs, mOf, mAddr, mTypeOf, mRoof,
|
||||||
mEcho, mShallowCopy, mSlurp, mStaticExec,
|
mEcho, mShallowCopy, mSlurp, mStaticExec,
|
||||||
mParseExprToAst, mParseStmtToAst, mExpandToAst, mQuoteAst,
|
mParseExprToAst, mParseStmtToAst, mExpandToAst, mQuoteAst,
|
||||||
mUnaryLt, mInc, mDec, mOrd, mNew, mNewFinalize, mNewSeq, mLengthOpenArray,
|
mUnaryLt, mInc, mDec, mOrd, mNew, mNewFinalize, mNewSeq, mLengthOpenArray,
|
||||||
|
|
|
||||||
|
|
@ -94,7 +94,7 @@ proc writeIntSet(a: IntSet, s: var string) =
|
||||||
encodeVInt(x, s)
|
encodeVInt(x, s)
|
||||||
inc i
|
inc i
|
||||||
s.add('}')
|
s.add('}')
|
||||||
|
|
||||||
proc genMergeInfo*(m: BModule): PRope =
|
proc genMergeInfo*(m: BModule): PRope =
|
||||||
if optSymbolFiles notin gGlobalOptions: return nil
|
if optSymbolFiles notin gGlobalOptions: return nil
|
||||||
var s = "/*\tNIM_merge_INFO:"
|
var s = "/*\tNIM_merge_INFO:"
|
||||||
|
|
@ -113,7 +113,7 @@ proc genMergeInfo*(m: BModule): PRope =
|
||||||
s.add("*/")
|
s.add("*/")
|
||||||
result = s.toRope
|
result = s.toRope
|
||||||
|
|
||||||
template `^`(pos: expr): expr = L.buf[pos]
|
template `^`(pos: int): expr = L.buf[pos]
|
||||||
|
|
||||||
proc skipWhite(L: var TBaseLexer) =
|
proc skipWhite(L: var TBaseLexer) =
|
||||||
var pos = L.bufpos
|
var pos = L.bufpos
|
||||||
|
|
@ -132,7 +132,7 @@ proc skipUntilCmd(L: var TBaseLexer) =
|
||||||
of CR: pos = nimlexbase.handleCR(L, pos)
|
of CR: pos = nimlexbase.handleCR(L, pos)
|
||||||
of LF: pos = nimlexbase.handleLF(L, pos)
|
of LF: pos = nimlexbase.handleLF(L, pos)
|
||||||
of '\0': break
|
of '\0': break
|
||||||
of '/':
|
of '/':
|
||||||
if ^(pos+1) == '*' and ^(pos+2) == '\t':
|
if ^(pos+1) == '*' and ^(pos+2) == '\t':
|
||||||
inc pos, 3
|
inc pos, 3
|
||||||
break
|
break
|
||||||
|
|
@ -145,7 +145,7 @@ proc atEndMark(buf: cstring, pos: int): bool =
|
||||||
while s < NimMergeEndMark.len and buf[pos+s] == NimMergeEndMark[s]: inc s
|
while s < NimMergeEndMark.len and buf[pos+s] == NimMergeEndMark[s]: inc s
|
||||||
result = s == NimMergeEndMark.len
|
result = s == NimMergeEndMark.len
|
||||||
|
|
||||||
proc readVerbatimSection(L: var TBaseLexer): PRope =
|
proc readVerbatimSection(L: var TBaseLexer): PRope =
|
||||||
var pos = L.bufpos
|
var pos = L.bufpos
|
||||||
var buf = L.buf
|
var buf = L.buf
|
||||||
var r = newStringOfCap(30_000)
|
var r = newStringOfCap(30_000)
|
||||||
|
|
@ -162,7 +162,7 @@ proc readVerbatimSection(L: var TBaseLexer): PRope =
|
||||||
of '\0':
|
of '\0':
|
||||||
internalError("ccgmerge: expected: " & NimMergeEndMark)
|
internalError("ccgmerge: expected: " & NimMergeEndMark)
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
if atEndMark(buf, pos):
|
if atEndMark(buf, pos):
|
||||||
inc pos, NimMergeEndMark.len
|
inc pos, NimMergeEndMark.len
|
||||||
break
|
break
|
||||||
|
|
@ -181,7 +181,7 @@ proc readKey(L: var TBaseLexer, result: var string) =
|
||||||
if buf[pos] != ':': internalError("ccgmerge: ':' expected")
|
if buf[pos] != ':': internalError("ccgmerge: ':' expected")
|
||||||
L.bufpos = pos + 1 # skip ':'
|
L.bufpos = pos + 1 # skip ':'
|
||||||
|
|
||||||
proc newFakeType(id: int): PType =
|
proc newFakeType(id: int): PType =
|
||||||
new(result)
|
new(result)
|
||||||
result.id = id
|
result.id = id
|
||||||
|
|
||||||
|
|
@ -227,8 +227,8 @@ proc processMergeInfo(L: var TBaseLexer, m: BModule) =
|
||||||
|
|
||||||
when not defined(nimhygiene):
|
when not defined(nimhygiene):
|
||||||
{.pragma: inject.}
|
{.pragma: inject.}
|
||||||
|
|
||||||
template withCFile(cfilename: string, body: stmt) {.immediate.} =
|
template withCFile(cfilename: string, body: stmt) {.immediate.} =
|
||||||
var s = llStreamOpen(cfilename, fmRead)
|
var s = llStreamOpen(cfilename, fmRead)
|
||||||
if s == nil: return
|
if s == nil: return
|
||||||
var L {.inject.}: TBaseLexer
|
var L {.inject.}: TBaseLexer
|
||||||
|
|
@ -239,7 +239,7 @@ template withCFile(cfilename: string, body: stmt) {.immediate.} =
|
||||||
if ^L.bufpos == '\0': break
|
if ^L.bufpos == '\0': break
|
||||||
body
|
body
|
||||||
closeBaseLexer(L)
|
closeBaseLexer(L)
|
||||||
|
|
||||||
proc readMergeInfo*(cfilename: string, m: BModule) =
|
proc readMergeInfo*(cfilename: string, m: BModule) =
|
||||||
## reads the merge meta information into `m`.
|
## reads the merge meta information into `m`.
|
||||||
withCFile(cfilename):
|
withCFile(cfilename):
|
||||||
|
|
@ -257,7 +257,7 @@ proc readMergeSections(cfilename: string, m: var TMergeSections) =
|
||||||
## reads the merge sections into `m`.
|
## reads the merge sections into `m`.
|
||||||
withCFile(cfilename):
|
withCFile(cfilename):
|
||||||
readKey(L, k)
|
readKey(L, k)
|
||||||
if k == "NIM_merge_INFO":
|
if k == "NIM_merge_INFO":
|
||||||
discard
|
discard
|
||||||
elif ^L.bufpos == '*' and ^(L.bufpos+1) == '/':
|
elif ^L.bufpos == '*' and ^(L.bufpos+1) == '/':
|
||||||
inc(L.bufpos, 2)
|
inc(L.bufpos, 2)
|
||||||
|
|
@ -283,7 +283,7 @@ proc mergeRequired*(m: BModule): bool =
|
||||||
#echo "not empty: ", i, " ", ropeToStr(m.s[i])
|
#echo "not empty: ", i, " ", ropeToStr(m.s[i])
|
||||||
return true
|
return true
|
||||||
for i in low(TCProcSection)..high(TCProcSection):
|
for i in low(TCProcSection)..high(TCProcSection):
|
||||||
if m.initProc.s(i) != nil:
|
if m.initProc.s(i) != nil:
|
||||||
#echo "not empty: ", i, " ", ropeToStr(m.initProc.s[i])
|
#echo "not empty: ", i, " ", ropeToStr(m.initProc.s[i])
|
||||||
return true
|
return true
|
||||||
|
|
||||||
|
|
@ -291,7 +291,7 @@ proc mergeFiles*(cfilename: string, m: BModule) =
|
||||||
## merges the C file with the old version on hard disc.
|
## merges the C file with the old version on hard disc.
|
||||||
var old: TMergeSections
|
var old: TMergeSections
|
||||||
readMergeSections(cfilename, old)
|
readMergeSections(cfilename, old)
|
||||||
# do the merge; old section before new section:
|
# do the merge; old section before new section:
|
||||||
for i in low(TCFileSection)..high(TCFileSection):
|
for i in low(TCFileSection)..high(TCFileSection):
|
||||||
m.s[i] = con(old.f[i], m.s[i])
|
m.s[i] = con(old.f[i], m.s[i])
|
||||||
for i in low(TCProcSection)..high(TCProcSection):
|
for i in low(TCProcSection)..high(TCProcSection):
|
||||||
|
|
|
||||||
|
|
@ -131,11 +131,10 @@ proc semNodeKindConstraints*(p: PNode): PNode =
|
||||||
result.strVal.add(ppEof)
|
result.strVal.add(ppEof)
|
||||||
|
|
||||||
type
|
type
|
||||||
TSideEffectAnalysis = enum
|
TSideEffectAnalysis* = enum
|
||||||
seUnknown, seSideEffect, seNoSideEffect
|
seUnknown, seSideEffect, seNoSideEffect
|
||||||
|
|
||||||
proc checkForSideEffects(n: PNode): TSideEffectAnalysis =
|
proc checkForSideEffects*(n: PNode): TSideEffectAnalysis =
|
||||||
# XXX is 'raise' a side effect?
|
|
||||||
case n.kind
|
case n.kind
|
||||||
of nkCallKinds:
|
of nkCallKinds:
|
||||||
# only calls can produce side effects:
|
# only calls can produce side effects:
|
||||||
|
|
@ -162,6 +161,8 @@ proc checkForSideEffects(n: PNode): TSideEffectAnalysis =
|
||||||
# an atom cannot produce a side effect:
|
# an atom cannot produce a side effect:
|
||||||
result = seNoSideEffect
|
result = seNoSideEffect
|
||||||
else:
|
else:
|
||||||
|
# assume no side effect:
|
||||||
|
result = seNoSideEffect
|
||||||
for i in 0 .. <n.len:
|
for i in 0 .. <n.len:
|
||||||
let ret = checkForSideEffects(n.sons[i])
|
let ret = checkForSideEffects(n.sons[i])
|
||||||
if ret == seSideEffect: return ret
|
if ret == seSideEffect: return ret
|
||||||
|
|
|
||||||
|
|
@ -9,13 +9,13 @@
|
||||||
|
|
||||||
## This module contains the data structures for the semantic checking phase.
|
## This module contains the data structures for the semantic checking phase.
|
||||||
|
|
||||||
import
|
import
|
||||||
strutils, lists, intsets, options, lexer, ast, astalgo, trees, treetab,
|
strutils, lists, intsets, options, lexer, ast, astalgo, trees, treetab,
|
||||||
wordrecg,
|
wordrecg,
|
||||||
ropes, msgs, platform, os, condsyms, idents, renderer, types, extccomp, math,
|
ropes, msgs, platform, os, condsyms, idents, renderer, types, extccomp, math,
|
||||||
magicsys, nversion, nimsets, parser, times, passes, rodread, vmdef
|
magicsys, nversion, nimsets, parser, times, passes, rodread, vmdef
|
||||||
|
|
||||||
type
|
type
|
||||||
TOptionEntry* = object of lists.TListEntry # entries to put on a
|
TOptionEntry* = object of lists.TListEntry # entries to put on a
|
||||||
# stack for pragma parsing
|
# stack for pragma parsing
|
||||||
options*: TOptions
|
options*: TOptions
|
||||||
|
|
@ -26,7 +26,7 @@ type
|
||||||
|
|
||||||
POptionEntry* = ref TOptionEntry
|
POptionEntry* = ref TOptionEntry
|
||||||
PProcCon* = ref TProcCon
|
PProcCon* = ref TProcCon
|
||||||
TProcCon*{.final.} = object # procedure context; also used for top-level
|
TProcCon* = object # procedure context; also used for top-level
|
||||||
# statements
|
# statements
|
||||||
owner*: PSym # the symbol this context belongs to
|
owner*: PSym # the symbol this context belongs to
|
||||||
resultSym*: PSym # the result symbol (if we are in a proc)
|
resultSym*: PSym # the result symbol (if we are in a proc)
|
||||||
|
|
@ -36,12 +36,13 @@ type
|
||||||
# in standalone ``except`` and ``finally``
|
# in standalone ``except`` and ``finally``
|
||||||
next*: PProcCon # used for stacking procedure contexts
|
next*: PProcCon # used for stacking procedure contexts
|
||||||
wasForwarded*: bool # whether the current proc has a separate header
|
wasForwarded*: bool # whether the current proc has a separate header
|
||||||
|
bracketExpr*: PNode # current bracket expression (for ^ support)
|
||||||
|
|
||||||
TInstantiationPair* = object
|
TInstantiationPair* = object
|
||||||
genericSym*: PSym
|
genericSym*: PSym
|
||||||
inst*: PInstantiation
|
inst*: PInstantiation
|
||||||
|
|
||||||
TExprFlag* = enum
|
TExprFlag* = enum
|
||||||
efLValue, efWantIterator, efInTypeof, efWantStmt, efDetermineType,
|
efLValue, efWantIterator, efInTypeof, efWantStmt, efDetermineType,
|
||||||
efAllowDestructor, efWantValue, efOperand, efNoSemCheck
|
efAllowDestructor, efWantValue, efOperand, efNoSemCheck
|
||||||
TExprFlags* = set[TExprFlag]
|
TExprFlags* = set[TExprFlag]
|
||||||
|
|
@ -57,7 +58,7 @@ type
|
||||||
# this is used so that generic instantiations
|
# this is used so that generic instantiations
|
||||||
# can access private object fields
|
# can access private object fields
|
||||||
instCounter*: int # to prevent endless instantiations
|
instCounter*: int # to prevent endless instantiations
|
||||||
|
|
||||||
ambiguousSymbols*: IntSet # ids of all ambiguous symbols (cannot
|
ambiguousSymbols*: IntSet # ids of all ambiguous symbols (cannot
|
||||||
# store this info in the syms themselves!)
|
# store this info in the syms themselves!)
|
||||||
inTypeClass*: int # > 0 if we are in a user-defined type class
|
inTypeClass*: int # > 0 if we are in a user-defined type class
|
||||||
|
|
@ -95,7 +96,7 @@ type
|
||||||
instDeepCopy*: proc (c: PContext; dc: PSym; t: PType;
|
instDeepCopy*: proc (c: PContext; dc: PSym; t: PType;
|
||||||
info: TLineInfo): PSym {.nimcall.}
|
info: TLineInfo): PSym {.nimcall.}
|
||||||
|
|
||||||
|
|
||||||
proc makeInstPair*(s: PSym, inst: PInstantiation): TInstantiationPair =
|
proc makeInstPair*(s: PSym, inst: PInstantiation): TInstantiationPair =
|
||||||
result.genericSym = s
|
result.genericSym = s
|
||||||
result.inst = inst
|
result.inst = inst
|
||||||
|
|
@ -127,7 +128,7 @@ proc popOwner*()
|
||||||
|
|
||||||
var gOwners*: seq[PSym] = @[]
|
var gOwners*: seq[PSym] = @[]
|
||||||
|
|
||||||
proc getCurrOwner(): PSym =
|
proc getCurrOwner(): PSym =
|
||||||
# owner stack (used for initializing the
|
# owner stack (used for initializing the
|
||||||
# owner field of syms)
|
# owner field of syms)
|
||||||
# the documentation comment always gets
|
# the documentation comment always gets
|
||||||
|
|
@ -135,19 +136,19 @@ proc getCurrOwner(): PSym =
|
||||||
# BUGFIX: global array is needed!
|
# BUGFIX: global array is needed!
|
||||||
result = gOwners[high(gOwners)]
|
result = gOwners[high(gOwners)]
|
||||||
|
|
||||||
proc pushOwner(owner: PSym) =
|
proc pushOwner(owner: PSym) =
|
||||||
add(gOwners, owner)
|
add(gOwners, owner)
|
||||||
|
|
||||||
proc popOwner() =
|
proc popOwner() =
|
||||||
var length = len(gOwners)
|
var length = len(gOwners)
|
||||||
if length > 0: setLen(gOwners, length - 1)
|
if length > 0: setLen(gOwners, length - 1)
|
||||||
else: internalError("popOwner")
|
else: internalError("popOwner")
|
||||||
|
|
||||||
proc lastOptionEntry(c: PContext): POptionEntry =
|
proc lastOptionEntry(c: PContext): POptionEntry =
|
||||||
result = POptionEntry(c.optionStack.tail)
|
result = POptionEntry(c.optionStack.tail)
|
||||||
|
|
||||||
proc pushProcCon*(c: PContext, owner: PSym) {.inline.} =
|
proc pushProcCon*(c: PContext, owner: PSym) {.inline.} =
|
||||||
if owner == nil:
|
if owner == nil:
|
||||||
internalError("owner is nil")
|
internalError("owner is nil")
|
||||||
return
|
return
|
||||||
var x: PProcCon
|
var x: PProcCon
|
||||||
|
|
@ -158,7 +159,7 @@ proc pushProcCon*(c: PContext, owner: PSym) {.inline.} =
|
||||||
|
|
||||||
proc popProcCon*(c: PContext) {.inline.} = c.p = c.p.next
|
proc popProcCon*(c: PContext) {.inline.} = c.p = c.p.next
|
||||||
|
|
||||||
proc newOptionEntry(): POptionEntry =
|
proc newOptionEntry(): POptionEntry =
|
||||||
new(result)
|
new(result)
|
||||||
result.options = gOptions
|
result.options = gOptions
|
||||||
result.defaultCC = ccDefault
|
result.defaultCC = ccDefault
|
||||||
|
|
@ -182,8 +183,8 @@ proc newContext(module: PSym): PContext =
|
||||||
|
|
||||||
proc inclSym(sq: var TSymSeq, s: PSym) =
|
proc inclSym(sq: var TSymSeq, s: PSym) =
|
||||||
var L = len(sq)
|
var L = len(sq)
|
||||||
for i in countup(0, L - 1):
|
for i in countup(0, L - 1):
|
||||||
if sq[i].id == s.id: return
|
if sq[i].id == s.id: return
|
||||||
setLen(sq, L + 1)
|
setLen(sq, L + 1)
|
||||||
sq[L] = s
|
sq[L] = s
|
||||||
|
|
||||||
|
|
@ -193,20 +194,20 @@ proc addConverter*(c: PContext, conv: PSym) =
|
||||||
proc addPattern*(c: PContext, p: PSym) =
|
proc addPattern*(c: PContext, p: PSym) =
|
||||||
inclSym(c.patterns, p)
|
inclSym(c.patterns, p)
|
||||||
|
|
||||||
proc newLib(kind: TLibKind): PLib =
|
proc newLib(kind: TLibKind): PLib =
|
||||||
new(result)
|
new(result)
|
||||||
result.kind = kind #initObjectSet(result.syms)
|
result.kind = kind #initObjectSet(result.syms)
|
||||||
|
|
||||||
proc addToLib(lib: PLib, sym: PSym) =
|
proc addToLib(lib: PLib, sym: PSym) =
|
||||||
#if sym.annex != nil and not isGenericRoutine(sym):
|
#if sym.annex != nil and not isGenericRoutine(sym):
|
||||||
# LocalError(sym.info, errInvalidPragma)
|
# LocalError(sym.info, errInvalidPragma)
|
||||||
sym.annex = lib
|
sym.annex = lib
|
||||||
|
|
||||||
proc makePtrType(c: PContext, baseType: PType): PType =
|
proc makePtrType(c: PContext, baseType: PType): PType =
|
||||||
result = newTypeS(tyPtr, c)
|
result = newTypeS(tyPtr, c)
|
||||||
addSonSkipIntLit(result, baseType.assertNotNil)
|
addSonSkipIntLit(result, baseType.assertNotNil)
|
||||||
|
|
||||||
proc makeVarType(c: PContext, baseType: PType): PType =
|
proc makeVarType(c: PContext, baseType: PType): PType =
|
||||||
result = newTypeS(tyVar, c)
|
result = newTypeS(tyVar, c)
|
||||||
addSonSkipIntLit(result, baseType.assertNotNil)
|
addSonSkipIntLit(result, baseType.assertNotNil)
|
||||||
|
|
||||||
|
|
@ -286,7 +287,7 @@ proc errorNode*(c: PContext, n: PNode): PNode =
|
||||||
result = newNodeI(nkEmpty, n.info)
|
result = newNodeI(nkEmpty, n.info)
|
||||||
result.typ = errorType(c)
|
result.typ = errorType(c)
|
||||||
|
|
||||||
proc fillTypeS(dest: PType, kind: TTypeKind, c: PContext) =
|
proc fillTypeS(dest: PType, kind: TTypeKind, c: PContext) =
|
||||||
dest.kind = kind
|
dest.kind = kind
|
||||||
dest.owner = getCurrOwner()
|
dest.owner = getCurrOwner()
|
||||||
dest.size = - 1
|
dest.size = - 1
|
||||||
|
|
@ -311,13 +312,13 @@ proc illFormedAst*(n: PNode) =
|
||||||
proc illFormedAstLocal*(n: PNode) =
|
proc illFormedAstLocal*(n: PNode) =
|
||||||
localError(n.info, errIllFormedAstX, renderTree(n, {renderNoComments}))
|
localError(n.info, errIllFormedAstX, renderTree(n, {renderNoComments}))
|
||||||
|
|
||||||
proc checkSonsLen*(n: PNode, length: int) =
|
proc checkSonsLen*(n: PNode, length: int) =
|
||||||
if sonsLen(n) != length: illFormedAst(n)
|
if sonsLen(n) != length: illFormedAst(n)
|
||||||
|
|
||||||
proc checkMinSonsLen*(n: PNode, length: int) =
|
proc checkMinSonsLen*(n: PNode, length: int) =
|
||||||
if sonsLen(n) < length: illFormedAst(n)
|
if sonsLen(n) < length: illFormedAst(n)
|
||||||
|
|
||||||
proc isTopLevel*(c: PContext): bool {.inline.} =
|
proc isTopLevel*(c: PContext): bool {.inline.} =
|
||||||
result = c.currentScope.depthLevel <= 2
|
result = c.currentScope.depthLevel <= 2
|
||||||
|
|
||||||
proc experimentalMode*(c: PContext): bool {.inline.} =
|
proc experimentalMode*(c: PContext): bool {.inline.} =
|
||||||
|
|
|
||||||
|
|
@ -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
|
## returns nil if not a built-in subscript operator; also called for the
|
||||||
## checking of assignments
|
## checking of assignments
|
||||||
if sonsLen(n) == 1:
|
if sonsLen(n) == 1:
|
||||||
var x = semDeref(c, n)
|
let x = semDeref(c, n)
|
||||||
if x == nil: return nil
|
if x == nil: return nil
|
||||||
result = newNodeIT(nkDerefExpr, x.info, x.typ)
|
result = newNodeIT(nkDerefExpr, x.info, x.typ)
|
||||||
result.add(x[0])
|
result.add(x[0])
|
||||||
return
|
return
|
||||||
checkMinSonsLen(n, 2)
|
checkMinSonsLen(n, 2)
|
||||||
n.sons[0] = semExprWithType(c, n.sons[0])
|
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
|
case arr.kind
|
||||||
of tyArray, tyOpenArray, tyVarargs, tyArrayConstr, tySequence, tyString,
|
of tyArray, tyOpenArray, tyVarargs, tyArrayConstr, tySequence, tyString,
|
||||||
tyCString:
|
tyCString:
|
||||||
if n.len != 2: return nil
|
if n.len != 2: return nil
|
||||||
n.sons[0] = makeDeref(n.sons[0])
|
n.sons[0] = makeDeref(n.sons[0])
|
||||||
|
c.p.bracketExpr = n.sons[0]
|
||||||
for i in countup(1, sonsLen(n) - 1):
|
for i in countup(1, sonsLen(n) - 1):
|
||||||
n.sons[i] = semExprWithType(c, n.sons[i],
|
n.sons[i] = semExprWithType(c, n.sons[i],
|
||||||
flags*{efInTypeof, efDetermineType})
|
flags*{efInTypeof, efDetermineType})
|
||||||
|
|
@ -1166,6 +1167,7 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
of tyTuple:
|
of tyTuple:
|
||||||
checkSonsLen(n, 2)
|
checkSonsLen(n, 2)
|
||||||
n.sons[0] = makeDeref(n.sons[0])
|
n.sons[0] = makeDeref(n.sons[0])
|
||||||
|
c.p.bracketExpr = n.sons[0]
|
||||||
# [] operator for tuples requires constant expression:
|
# [] operator for tuples requires constant expression:
|
||||||
n.sons[1] = semConstExpr(c, n.sons[1])
|
n.sons[1] = semConstExpr(c, n.sons[1])
|
||||||
if skipTypes(n.sons[1].typ, {tyGenericInst, tyRange, tyOrdinal}).kind in
|
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:
|
else:
|
||||||
localError(n.info, errIndexTypesDoNotMatch)
|
localError(n.info, errIndexTypesDoNotMatch)
|
||||||
result = n
|
result = n
|
||||||
else: discard
|
else:
|
||||||
|
c.p.bracketExpr = n.sons[0]
|
||||||
|
|
||||||
proc semArrayAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
proc semArrayAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
|
let oldBracketExpr = c.p.bracketExpr
|
||||||
result = semSubscript(c, n, flags)
|
result = semSubscript(c, n, flags)
|
||||||
if result == nil:
|
if result == nil:
|
||||||
# overloaded [] operator:
|
# overloaded [] operator:
|
||||||
result = semExpr(c, buildOverloadedSubscripts(n, getIdent"[]"))
|
result = semExpr(c, buildOverloadedSubscripts(n, getIdent"[]"))
|
||||||
|
c.p.bracketExpr = oldBracketExpr
|
||||||
|
|
||||||
proc propertyWriteAccess(c: PContext, n, nOrig, a: PNode): PNode =
|
proc propertyWriteAccess(c: PContext, n, nOrig, a: PNode): PNode =
|
||||||
var id = considerQuotedIdent(a[1])
|
var id = considerQuotedIdent(a[1])
|
||||||
|
|
@ -1249,11 +1254,15 @@ proc semAsgn(c: PContext, n: PNode): PNode =
|
||||||
of nkBracketExpr:
|
of nkBracketExpr:
|
||||||
# a[i] = x
|
# a[i] = x
|
||||||
# --> `[]=`(a, i, x)
|
# --> `[]=`(a, i, x)
|
||||||
|
let oldBracketExpr = c.p.bracketExpr
|
||||||
a = semSubscript(c, a, {efLValue})
|
a = semSubscript(c, a, {efLValue})
|
||||||
if a == nil:
|
if a == nil:
|
||||||
result = buildOverloadedSubscripts(n.sons[0], getIdent"[]=")
|
result = buildOverloadedSubscripts(n.sons[0], getIdent"[]=")
|
||||||
add(result, n[1])
|
add(result, n[1])
|
||||||
return semExprNoType(c, result)
|
result = semExprNoType(c, result)
|
||||||
|
c.p.bracketExpr = oldBracketExpr
|
||||||
|
return result
|
||||||
|
c.p.bracketExpr = oldBracketExpr
|
||||||
of nkCurlyExpr:
|
of nkCurlyExpr:
|
||||||
# a{i} = x --> `{}=`(a, i, x)
|
# a{i} = x --> `{}=`(a, i, x)
|
||||||
result = buildOverloadedSubscripts(n.sons[0], getIdent"{}=")
|
result = buildOverloadedSubscripts(n.sons[0], getIdent"{}=")
|
||||||
|
|
|
||||||
|
|
@ -130,6 +130,11 @@ proc semLocals(c: PContext, n: PNode): PNode =
|
||||||
result.add(a)
|
result.add(a)
|
||||||
|
|
||||||
proc semShallowCopy(c: PContext, n: PNode, flags: TExprFlags): PNode
|
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,
|
proc magicsAfterOverloadResolution(c: PContext, n: PNode,
|
||||||
flags: TExprFlags): PNode =
|
flags: TExprFlags): PNode =
|
||||||
case n[0].sym.magic
|
case n[0].sym.magic
|
||||||
|
|
@ -153,4 +158,29 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode,
|
||||||
of mProcCall:
|
of mProcCall:
|
||||||
result = n
|
result = n
|
||||||
result.typ = n[1].typ
|
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
|
else: result = n
|
||||||
|
|
|
||||||
|
|
@ -590,7 +590,7 @@ proc firstOrd(t: PType): BiggestInt =
|
||||||
of tyUInt..tyUInt64: result = 0
|
of tyUInt..tyUInt64: result = 0
|
||||||
of tyEnum:
|
of tyEnum:
|
||||||
# if basetype <> nil then return firstOrd of basetype
|
# 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])
|
result = firstOrd(t.sons[0])
|
||||||
else:
|
else:
|
||||||
assert(t.n.sons[0].kind == nkSym)
|
assert(t.n.sons[0].kind == nkSym)
|
||||||
|
|
|
||||||
|
|
@ -222,8 +222,8 @@ type
|
||||||
set*{.magic: "Set".}[T] ## Generic type to construct bit sets.
|
set*{.magic: "Set".}[T] ## Generic type to construct bit sets.
|
||||||
|
|
||||||
type
|
type
|
||||||
Slice* {.final, pure.}[T] = object ## builtin slice type
|
Slice*[T] = object ## builtin slice type
|
||||||
a*, b*: T ## the bounds
|
a*, b*: T ## the bounds
|
||||||
|
|
||||||
when defined(nimalias):
|
when defined(nimalias):
|
||||||
{.deprecated: [TSlice: Slice].}
|
{.deprecated: [TSlice: Slice].}
|
||||||
|
|
@ -3247,4 +3247,12 @@ proc procCall*(x: expr) {.magic: "ProcCall".} =
|
||||||
## procCall someMethod(a, b)
|
## procCall someMethod(a, b)
|
||||||
discard
|
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.}
|
{.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
|
structure; for immediate macro parameters ``nkCall('addr', 'x')`` is
|
||||||
produced instead of ``nkAddr('x')``.
|
produced instead of ``nkAddr('x')``.
|
||||||
- ``concept`` is now a keyword and is used instead of ``generic``.
|
- ``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
|
Language Additions
|
||||||
|
|
@ -84,6 +100,9 @@ News
|
||||||
varOrConst(x) # "var"
|
varOrConst(x) # "var"
|
||||||
varOrConst(45) # "const"
|
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
|
Library additions
|
||||||
-----------------
|
-----------------
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue