diff options
-rwxr-xr-x | compiler/ast.nim | 2 | ||||
-rwxr-xr-x | compiler/semexprs.nim | 205 | ||||
-rwxr-xr-x | compiler/semstmts.nim | 67 | ||||
-rwxr-xr-x | install.sh | 6 | ||||
-rwxr-xr-x | lib/impure/zipfiles.nim | 6 | ||||
-rwxr-xr-x | lib/system.nim | 11 | ||||
-rwxr-xr-x | web/news.txt | 3 |
7 files changed, 158 insertions, 142 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim index ae8680c6b..905576655 100755 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -310,7 +310,7 @@ type TMagic* = enum # symbols that require compiler magic: mNone, mDefined, mDefinedInScope, mLow, mHigh, mSizeOf, mIs, - mEcho, mCreateThread, + mEcho, mCreateThread, mShallowCopy, mUnaryLt, mSucc, mPred, mInc, mDec, mOrd, mNew, mNewFinalize, mNewSeq, mLengthOpenArray, mLengthStr, mLengthArray, mLengthSeq, mIncl, mExcl, mCard, mChr, mGCref, diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index dac72c2f0..67ad158f4 100755 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -397,7 +397,7 @@ proc analyseIfAddressTakenInCall(c: PContext, n: PNode) = const FakeVarParams = {mNew, mNewFinalize, mInc, ast.mDec, mIncl, mExcl, mSetLengthStr, mSetLengthSeq, mAppendStrCh, mAppendStrStr, mSwap, - mAppendSeqElem, mNewSeq, mReset} + mAppendSeqElem, mNewSeq, mReset, mShallowCopy} checkMinSonsLen(n, 1) var t = n.sons[0].typ if (n.sons[0].kind == nkSym) and (n.sons[0].sym.magic in FakeVarParams): @@ -505,72 +505,25 @@ proc semEcho(c: PContext, n: PNode): PNode = var arg = semExprWithType(c, n.sons[i]) n.sons[i] = semExpr(c, buildStringify(c, arg)) result = n + +proc buildEchoStmt(c: PContext, n: PNode): PNode = + # we MUST not check 'n' for semantics again here! + result = newNodeI(nkCall, n.info) + var e = StrTableGet(magicsys.systemModule.Tab, getIdent"echo") + if e == nil: GlobalError(n.info, errSystemNeeds, "echo") + addSon(result, newSymNode(e)) + var arg = buildStringify(c, n) + # problem is: implicit '$' is not checked for semantics yet. So we give up + # and check 'arg' for semantics again: + addSon(result, semExpr(c, arg)) -proc lookUpForDefined(c: PContext, i: PIdent, onlyCurrentScope: bool): PSym = - if onlyCurrentScope: - result = SymtabLocalGet(c.tab, i) - else: - result = SymtabGet(c.Tab, i) # no need for stub loading - -proc LookUpForDefined(c: PContext, n: PNode, onlyCurrentScope: bool): PSym = - case n.kind - of nkIdent: - result = LookupForDefined(c, n.ident, onlyCurrentScope) - of nkDotExpr: - result = nil - if onlyCurrentScope: return - checkSonsLen(n, 2) - var m = LookupForDefined(c, n.sons[0], onlyCurrentScope) - if (m != nil) and (m.kind == skModule): - if (n.sons[1].kind == nkIdent): - var ident = n.sons[1].ident - if m == c.module: - result = StrTableGet(c.tab.stack[ModuleTablePos], ident) - else: - result = StrTableGet(m.tab, ident) - else: - GlobalError(n.sons[1].info, errIdentifierExpected, "") - of nkAccQuoted: - result = lookupForDefined(c, considerAcc(n), onlyCurrentScope) - of nkSym: - result = n.sym - else: - GlobalError(n.info, errIdentifierExpected, renderTree(n)) - result = nil - -proc semDefined(c: PContext, n: PNode, onlyCurrentScope: bool): PNode = - checkSonsLen(n, 2) - # we replace this node by a 'true' or 'false' node: - result = newIntNode(nkIntLit, 0) - if LookUpForDefined(c, n.sons[1], onlyCurrentScope) != nil: - result.intVal = 1 - elif not onlyCurrentScope and (n.sons[1].kind == nkIdent) and - condsyms.isDefined(n.sons[1].ident): - result.intVal = 1 - result.info = n.info - result.typ = getSysType(tyBool) - -proc setMs(n: PNode, s: PSym): PNode = - result = n - n.sons[0] = newSymNode(s) - n.sons[0].info = n.info - -proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode = - # this is a hotspot in the compiler! - result = n - case s.magic # magics that need special treatment - of mDefined: result = semDefined(c, setMs(n, s), false) - of mDefinedInScope: result = semDefined(c, setMs(n, s), true) - of mLow: result = semLowHigh(c, setMs(n, s), mLow) - of mHigh: result = semLowHigh(c, setMs(n, s), mHigh) - of mSizeOf: result = semSizeof(c, setMs(n, s)) - of mIs: result = semIs(c, setMs(n, s)) - of mEcho: result = semEcho(c, setMs(n, s)) - of mCreateThread: - result = semDirectOp(c, n, flags) - if semthreads.needsGlobalAnalysis(): - c.threadEntries.add(result) - else: result = semDirectOp(c, n, flags) +proc semExprNoType(c: PContext, n: PNode): PNode = + result = semExpr(c, n) + if result.typ != nil and result.typ.kind != tyStmt: + if gCmd == cmdInteractive: + result = buildEchoStmt(c, result) + else: + localError(n.info, errDiscardValue) proc isTypeExpr(n: PNode): bool = case n.kind @@ -784,6 +737,126 @@ proc semArrayAccess(c: PContext, n: PNode, flags: TExprFlags): PNode = # overloaded [] operator: result = semExpr(c, buildOverloadedSubscripts(n, inAsgn=false)) +proc propertyWriteAccess(c: PContext, n, a: PNode): PNode = + var id = considerAcc(a[1]) + result = newNodeI(nkCall, n.info) + addSon(result, newIdentNode(getIdent(id.s & '='), n.info)) + # a[0] is already checked for semantics, that does ``builtinFieldAccess`` + # this is ugly. XXX Semantic checking should use the ``nfSem`` flag for + # nodes? + addSon(result, a[0]) + addSon(result, semExpr(c, n[1])) + result = semDirectCallAnalyseEffects(c, result, {}) + if result != nil: + fixAbstractType(c, result) + analyseIfAddressTakenInCall(c, result) + else: + globalError(n.Info, errUndeclaredFieldX, id.s) + +proc semAsgn(c: PContext, n: PNode): PNode = + checkSonsLen(n, 2) + var a = n.sons[0] + case a.kind + of nkDotExpr: + # r.f = x + # --> `f=` (r, x) + a = builtinFieldAccess(c, a, {efLValue}) + if a == nil: + return propertyWriteAccess(c, n, n[0]) + of nkBracketExpr: + # a[i..j] = x + # --> `[..]=`(a, i, j, x) + a = semSubscript(c, a, {efLValue}) + if a == nil: + result = buildOverloadedSubscripts(n.sons[0], inAsgn=true) + add(result, n[1]) + return semExprNoType(c, result) + else: + a = semExprWithType(c, a, {efLValue}) + n.sons[0] = a + n.sons[1] = semExprWithType(c, n.sons[1]) + var le = a.typ + if skipTypes(le, {tyGenericInst}).kind != tyVar and IsAssignable(a) == arNone: + # Direct assignment to a discriminant is allowed! + localError(a.info, errXCannotBeAssignedTo, + renderTree(a, {renderNoComments})) + else: + n.sons[1] = fitNode(c, le, n.sons[1]) + fixAbstractType(c, n) + result = n + +proc lookUpForDefined(c: PContext, i: PIdent, onlyCurrentScope: bool): PSym = + if onlyCurrentScope: + result = SymtabLocalGet(c.tab, i) + else: + result = SymtabGet(c.Tab, i) # no need for stub loading + +proc LookUpForDefined(c: PContext, n: PNode, onlyCurrentScope: bool): PSym = + case n.kind + of nkIdent: + result = LookupForDefined(c, n.ident, onlyCurrentScope) + of nkDotExpr: + result = nil + if onlyCurrentScope: return + checkSonsLen(n, 2) + var m = LookupForDefined(c, n.sons[0], onlyCurrentScope) + if (m != nil) and (m.kind == skModule): + if (n.sons[1].kind == nkIdent): + var ident = n.sons[1].ident + if m == c.module: + result = StrTableGet(c.tab.stack[ModuleTablePos], ident) + else: + result = StrTableGet(m.tab, ident) + else: + GlobalError(n.sons[1].info, errIdentifierExpected, "") + of nkAccQuoted: + result = lookupForDefined(c, considerAcc(n), onlyCurrentScope) + of nkSym: + result = n.sym + else: + GlobalError(n.info, errIdentifierExpected, renderTree(n)) + result = nil + +proc semDefined(c: PContext, n: PNode, onlyCurrentScope: bool): PNode = + checkSonsLen(n, 2) + # we replace this node by a 'true' or 'false' node: + result = newIntNode(nkIntLit, 0) + if LookUpForDefined(c, n.sons[1], onlyCurrentScope) != nil: + result.intVal = 1 + elif not onlyCurrentScope and (n.sons[1].kind == nkIdent) and + condsyms.isDefined(n.sons[1].ident): + result.intVal = 1 + result.info = n.info + result.typ = getSysType(tyBool) + +proc setMs(n: PNode, s: PSym): PNode = + result = n + n.sons[0] = newSymNode(s) + n.sons[0].info = n.info + +proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode = + # this is a hotspot in the compiler! + result = n + case s.magic # magics that need special treatment + of mDefined: result = semDefined(c, setMs(n, s), false) + of mDefinedInScope: result = semDefined(c, setMs(n, s), true) + of mLow: result = semLowHigh(c, setMs(n, s), mLow) + of mHigh: result = semLowHigh(c, setMs(n, s), mHigh) + of mSizeOf: result = semSizeof(c, setMs(n, s)) + of mIs: result = semIs(c, setMs(n, s)) + of mEcho: result = semEcho(c, setMs(n, s)) + of mCreateThread: + result = semDirectOp(c, n, flags) + if semthreads.needsGlobalAnalysis(): + c.threadEntries.add(result) + of mShallowCopy: + checkSonsLen(n, 3) + result = newNodeI(nkFastAsgn, n.info) + result.add(n[1]) + result.add(n[2]) + result = semAsgn(c, result) + else: result = semDirectOp(c, n, flags) + proc semIfExpr(c: PContext, n: PNode): PNode = result = n checkMinSonsLen(n, 2) diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 62eb52ac1..2e328d730 100755 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -8,25 +8,6 @@ # ## this module does the semantic checking of statements - -proc buildEchoStmt(c: PContext, n: PNode): PNode = - # we MUST not check 'n' for semantics again here! - result = newNodeI(nkCall, n.info) - var e = StrTableGet(magicsys.systemModule.Tab, getIdent"echo") - if e == nil: GlobalError(n.info, errSystemNeeds, "echo") - addSon(result, newSymNode(e)) - var arg = buildStringify(c, n) - # problem is: implicit '$' is not checked for semantics yet. So we give up - # and check 'arg' for semantics again: - addSon(result, semExpr(c, arg)) - -proc semExprNoType(c: PContext, n: PNode): PNode = - result = semExpr(c, n) - if result.typ != nil and result.typ.kind != tyStmt: - if gCmd == cmdInteractive: - result = buildEchoStmt(c, result) - else: - localError(n.info, errDiscardValue) proc semCommand(c: PContext, n: PNode): PNode = result = semExprNoType(c, n) @@ -170,54 +151,6 @@ proc semCase(c: PContext, n: PNode): PNode = localError(n.info, errNotAllCasesCovered) closeScope(c.tab) -proc propertyWriteAccess(c: PContext, n, a: PNode): PNode = - var id = considerAcc(a[1]) - result = newNodeI(nkCall, n.info) - addSon(result, newIdentNode(getIdent(id.s & '='), n.info)) - # a[0] is already checked for semantics, that does ``builtinFieldAccess`` - # this is ugly. XXX Semantic checking should use the ``nfSem`` flag for - # nodes? - addSon(result, a[0]) - addSon(result, semExpr(c, n[1])) - result = semDirectCallAnalyseEffects(c, result, {}) - if result != nil: - fixAbstractType(c, result) - analyseIfAddressTakenInCall(c, result) - else: - globalError(n.Info, errUndeclaredFieldX, id.s) - -proc semAsgn(c: PContext, n: PNode): PNode = - checkSonsLen(n, 2) - var a = n.sons[0] - case a.kind - of nkDotExpr: - # r.f = x - # --> `f=` (r, x) - a = builtinFieldAccess(c, a, {efLValue}) - if a == nil: - return propertyWriteAccess(c, n, n[0]) - of nkBracketExpr: - # a[i..j] = x - # --> `[..]=`(a, i, j, x) - a = semSubscript(c, a, {efLValue}) - if a == nil: - result = buildOverloadedSubscripts(n.sons[0], inAsgn=true) - add(result, n[1]) - return semExprNoType(c, result) - else: - a = semExprWithType(c, a, {efLValue}) - n.sons[0] = a - n.sons[1] = semExprWithType(c, n.sons[1]) - var le = a.typ - if skipTypes(le, {tyGenericInst}).kind != tyVar and IsAssignable(a) == arNone: - # Direct assignment to a discriminant is allowed! - localError(a.info, errXCannotBeAssignedTo, - renderTree(a, {renderNoComments})) - else: - n.sons[1] = fitNode(c, le, n.sons[1]) - fixAbstractType(c, n) - result = n - proc SemReturn(c: PContext, n: PNode): PNode = var restype: PType diff --git a/install.sh b/install.sh index 3fe865df6..4ac8d5215 100755 --- a/install.sh +++ b/install.sh @@ -223,6 +223,8 @@ if [ $# -eq 1 ] ; then chmod 644 $libdir/pure/cookies.nim cp lib/pure/dynlib.nim $libdir/pure/dynlib.nim || exit 1 chmod 644 $libdir/pure/dynlib.nim + cp lib/pure/encodings.nim $libdir/pure/encodings.nim || exit 1 + chmod 644 $libdir/pure/encodings.nim cp lib/pure/gentabs.nim $libdir/pure/gentabs.nim || exit 1 chmod 644 $libdir/pure/gentabs.nim cp lib/pure/hashes.nim $libdir/pure/hashes.nim || exit 1 @@ -267,6 +269,8 @@ if [ $# -eq 1 ] ; then chmod 644 $libdir/pure/redis.nim cp lib/pure/regexprs.nim $libdir/pure/regexprs.nim || exit 1 chmod 644 $libdir/pure/regexprs.nim + cp lib/pure/romans.nim $libdir/pure/romans.nim || exit 1 + chmod 644 $libdir/pure/romans.nim cp lib/pure/ropes.nim $libdir/pure/ropes.nim || exit 1 chmod 644 $libdir/pure/ropes.nim cp lib/pure/scgi.nim $libdir/pure/scgi.nim || exit 1 @@ -307,8 +311,6 @@ if [ $# -eq 1 ] ; then chmod 644 $libdir/impure/db_sqlite.nim cp lib/impure/dialogs.nim $libdir/impure/dialogs.nim || exit 1 chmod 644 $libdir/impure/dialogs.nim - cp lib/impure/encodings.nim $libdir/impure/encodings.nim || exit 1 - chmod 644 $libdir/impure/encodings.nim cp lib/impure/graphics.nim $libdir/impure/graphics.nim || exit 1 chmod 644 $libdir/impure/graphics.nim cp lib/impure/osinfo_posix.nim $libdir/impure/osinfo_posix.nim || exit 1 diff --git a/lib/impure/zipfiles.nim b/lib/impure/zipfiles.nim index c60847d48..62fe210d2 100755 --- a/lib/impure/zipfiles.nim +++ b/lib/impure/zipfiles.nim @@ -113,9 +113,9 @@ type PZipFileStream* = ref TZipFileStream ## a reader stream of a file within a zip archive -proc fsClose(s: PZipFileStream) = zip_fclose(s.f) -proc fsReadData(s: PZipFileStream, buffer: pointer, bufLen: int): int = - result = zip_fread(s.f, buffer, bufLen) +proc fsClose(s: PStream) = zip_fclose(PZipFileStream(s).f) +proc fsReadData(s: PStream, buffer: pointer, bufLen: int): int = + result = zip_fread(PZipFileStream(s).f, buffer, bufLen) proc newZipFileStream(f: PZipFile): PZipFileStream = new(result) diff --git a/lib/system.nim b/lib/system.nim index 1837959c7..af948265f 100755 --- a/lib/system.nim +++ b/lib/system.nim @@ -801,18 +801,25 @@ proc add *[T](x: var seq[T], y: openArray[T]) {.noSideEffect.} = setLen(x, xl + y.len) for i in 0..high(y): x[xl+i] = y[i] +proc shallowCopy*[T](x: var T, y: T) {.noSideEffect, magic: "ShallowCopy".} + ## use this instead of `=` for a `shallow copy`:idx:. The shallow copy + ## only changes the semantics for sequences and strings (and types which + ## contain those). Be careful with the changed semantics though! There + ## is a reason why the default assignment does a deep copy of sequences + ## and strings. + proc del*[T](x: var seq[T], i: int) {.noSideEffect.} = ## deletes the item at index `i` by putting ``x[high(x)]`` into position `i`. ## This is an O(1) operation. var xl = x.len - x[i] = x[xl-1] + shallowCopy(x[i], x[xl-1]) setLen(x, xl-1) proc delete*[T](x: var seq[T], i: int) {.noSideEffect.} = ## deletes the item at index `i` by moving ``x[i+1..]`` by one position. ## This is an O(n) operation. var xl = x.len - for j in i..xl-2: x[j] = x[j+1] + for j in i..xl-2: shallowCopy(x[j], x[j+1]) setLen(x, xl-1) proc insert*[T](x: var seq[T], item: T, i = 0) {.noSideEffect.} = diff --git a/web/news.txt b/web/news.txt index a0825e0cb..d0ae451b5 100755 --- a/web/news.txt +++ b/web/news.txt @@ -94,7 +94,8 @@ Additions - The compiler now supports array, sequence and string slicing. - Added ``system.newStringOfCap``. - Added ``system.raiseHook``. -- Added ``system.writeFile ``. +- Added ``system.writeFile``. +- Added ``system.shallowCopy``. - ``system.echo`` is guaranteed to be thread-safe. - Case statement branches support constant sets for programming convenience. |