summary refs log tree commit diff stats
path: root/nimlib/pure/variants.nim
diff options
context:
space:
mode:
Diffstat (limited to 'nimlib/pure/variants.nim')
-rwxr-xr-xnimlib/pure/variants.nim181
1 files changed, 181 insertions, 0 deletions
diff --git a/nimlib/pure/variants.nim b/nimlib/pure/variants.nim
new file mode 100755
index 000000000..f661f81a6
--- /dev/null
+++ b/nimlib/pure/variants.nim
@@ -0,0 +1,181 @@
+#
+#
+#            Nimrod's Runtime Library
+#        (c) Copyright 2009 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module implements Nimrod's support for the ``variant`` datatype.
+## `TVariant` shows how the flexibility of dynamic typing is achieved
+## within a static type system. 
+
+type
+  TVarType* = enum
+    vtNone,
+    vtBool, 
+    vtChar,
+    vtEnum,
+    vtInt,
+    vtFloat,
+    vtString,
+    vtSet,
+    vtSeq,
+    vtDict
+  TVariant* {.final.} = object of TObject
+    case vtype: TVarType
+    of vtNone: nil
+    of vtBool, vtChar, vtEnum, vtInt: vint: int64
+    of vtFloat: vfloat: float64
+    of vtString: vstring: string
+    of vtSet, vtSeq: q: seq[TVariant]
+    of vtDict: d: seq[tuple[key, val: TVariant]]
+    
+iterator objectFields*[T](x: T, skipInherited: bool): tuple[
+  key: string, val: TVariant] {.magic: "ObjectFields"}
+
+proc `<>`*(x: ordinal): TVariant =
+  result.kind = vtEnum
+  result.vint = x
+
+proc `<>`*(x: biggestInt): TVariant =
+  result.kind = vtInt
+  result.vint = x
+
+proc `<>`*(x: char): TVariant =
+  result.kind = vtChar
+  result.vint = ord(x)
+
+proc `<>`*(x: bool): TVariant =
+  result.kind = vtBool
+  result.vint = ord(x)
+
+proc `<>`*(x: biggestFloat): TVariant =
+  result.kind = vtFloat
+  result.vfloat = x
+
+proc `<>`*(x: string): TVariant =
+  result.kind = vtString
+  result.vstring = x
+
+proc `<>`*[T](x: openArray[T]): TVariant =
+  result.kind = vtSeq
+  newSeq(result.q, x.len)
+  for i in 0..x.len-1: result.q[i] = <>x[i]
+
+proc `<>`*[T](x: set[T]): TVariant =
+  result.kind = vtSet
+  result.q = @[]
+  for a in items(x): result.q.add(<>a)
+
+proc `<>`* [T: object](x: T): TVariant {.magic: "ToVariant".}
+  ## this converts a value to a variant ("boxing")
+
+proc `><`*[T](v: TVariant, typ: T): T {.magic: "FromVariant".}
+
+[<>5, <>67, <>"hallo"]
+myVar><int
+
+  
+proc `==`* (x, y: TVariant): bool =
+  if x.vtype == y.vtype:
+    case x.vtype
+    of vtNone: result = true
+    of vtBool, vtChar, vtEnum, vtInt: result = x.vint == y.vint
+    of vtFloat: result = x.vfloat == y.vfloat
+    of vtString: result = x.vstring == y.vstring
+    of vtSet:
+      # complicated! We check that each a in x also occurs in y and that the
+      # counts are identical:
+      if x.q.len == y.q.len:
+        for a in items(x.q):
+          block inner:
+            for b in items(y.q):
+              if a == b: break inner
+            return false
+        result = true
+    of vtSeq:
+      if x.q.len == y.q.len:
+        for i in 0..x.q.len-1:
+          if x.q[i] != y.q[i]: return false
+        result = true
+    of vtDict:
+      # it is an ordered dict:
+      if x.d.len == y.d.len:
+        for i in 0..x.d.len-1:
+          if x.d[i].key != y.d[i].key: return false
+          if x.d[i].val != y.d[i].val: return false
+        result = true
+
+proc `[]`* (a, b: TVariant): TVariant =
+  case a.vtype
+  of vtSeq:
+    if b.vtype in {vtBool, vtChar, vtEnum, vtInt}:
+      result = a.q[b.vint]
+    else:
+      variantError()
+  of vtDict:
+    for i in 0..a.d.len-1:
+      if a.d[i].key == b: return a.d[i].val
+    if b.vtype in {vtBool, vtChar, vtEnum, vtInt}:
+      result = a.d[b.vint].val
+    variantError()
+  else: variantError()
+
+proc `[]=`* (a, b, c: TVariant) =
+  case a.vtype
+  of vtSeq:
+    if b.vtype in {vtBool, vtChar, vtEnum, vtInt}:
+      a.q[b.vint] = b
+    else:
+      variantError()
+  of vtDict:
+    for i in 0..a.d.len-1:
+      if a.d[i].key == b:
+        a.d[i].val = c
+        return
+    if b.vtype in {vtBool, vtChar, vtEnum, vtInt}:
+      a.d[b.vint].val = c
+    variantError()
+  else: variantError()
+  
+proc `[]`* (a: TVariant, b: int): TVariant {.inline} = return a[<>b]
+proc `[]`* (a: TVariant, b: string): TVariant {.inline} = return a[<>b]
+proc `[]=`* (a: TVariant, b: int, c: TVariant) {.inline} = a[<>b] = c
+proc `[]=`* (a: TVariant, b: string, c: TVariant) {.inline} = a[<>b] = c
+
+proc `+`* (x, y: TVariant): TVariant =
+  case x.vtype
+  of vtBool, vtChar, vtEnum, vtInt:
+    if y.vtype == x.vtype:
+      result.vtype = x.vtype
+      result.vint = x.vint + y.vint
+    else:
+      case y.vtype
+      of vtBool, vtChar, vtEnum, vtInt:
+        
+    
+    
+    vint: int64
+  of vtFloat: vfloat: float64
+  of vtString: vstring: string
+  of vtSet, vtSeq: q: seq[TVariant]
+  of vtDict: d: seq[tuple[key, val: TVariant]]
+
+proc `-`* (x, y: TVariant): TVariant
+proc `*`* (x, y: TVariant): TVariant
+proc `/`* (x, y: TVariant): TVariant
+proc `div`* (x, y: TVariant): TVariant
+proc `mod`* (x, y: TVariant): TVariant
+proc `&`* (x, y: TVariant): TVariant
+proc `$`* (x: TVariant): string =
+  # uses JS notation
+  
+proc parseVariant*(s: string): TVariant
+proc `<`* (x, y: TVariant): bool
+proc `<=`* (x, y: TVariant): bool
+
+proc hash*(x: TVariant): int =
+  
+