# # # 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>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 =