summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rwxr-xr-xcompiler/ast.nim2
-rwxr-xr-xcompiler/semexprs.nim205
-rwxr-xr-xcompiler/semstmts.nim67
-rwxr-xr-xinstall.sh6
-rwxr-xr-xlib/impure/zipfiles.nim6
-rwxr-xr-xlib/system.nim11
-rwxr-xr-xweb/news.txt3
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.