aboutsummaryrefslogtreecommitdiff
path: root/nim/types.nim
blob: 278ae1b61bb548a5f8eae074a820c7478d2f3e79 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
import tables, strutils

type
  MalTypeKind* = enum Nil, True, False, Number, Symbol, String,
    List, Vector, HashMap, Fun, MalFun

  MalFunType* = ref object
    fn*:     proc(a: varargs[MalType]): MalType
    ast*:    MalType
    params*: MalType
    env*:    Env

  MalType* = object
    case kind*: MalTypeKind
    of Nil, True, False: nil
    of Number:           number*:   int
    of String, Symbol:   str*:      string
    of List, Vector:     list*:     seq[MalType]
    of HashMap:          hash_map*: TableRef[string, MalType]
    of Fun:              fun*:      proc(xs: varargs[MalType]): MalType
    of MalFun:           malfun*:   MalFunType

  Env* = ref object
    data*: Table[string, MalType]
    outer*: Env

# Convenience procs
const nilObj* = MalType(kind: Nil)
const trueObj* = MalType(kind: True)
const falseObj* = MalType(kind: False)

proc number*(x: int): MalType = MalType(kind: Number, number: x)

proc symbol*(x: string): MalType = MalType(kind: Symbol, str: x)

proc str*(x: string): MalType {.procvar.} = MalType(kind: String, str: x)

proc keyword*(x: string): MalType = MalType(kind: String, str: "\xff" & x)

proc list*(xs: varargs[MalType]): MalType {.procvar.} =
  result = MalType(kind: List, list: @[])
  for x in xs: result.list.add x

proc vector*(xs: varargs[MalType]): MalType {.procvar.} =
  result = MalType(kind: Vector, list: @[])
  for x in xs: result.list.add x

proc hash_map*(xs: varargs[MalType]): MalType {.procvar.} =
  result = MalType(kind: HashMap, hash_map: newTable[string, MalType]())
  for i in countup(0, xs.high, 2):
    let s = case xs[i].kind
    of String: "\"" & xs[i].str & "\""
    else: xs[i].str
    result.hash_map[s] = xs[i+1]

proc fun*(x: proc(xs: varargs[MalType]): MalType): MalType = MalType(kind: Fun, fun: x)

proc malfun*(fn: auto, ast, params: MalType,
  env: Env): MalType =
  MalType(kind: MalFun,
    malfun: MalFunType(fn: fn, ast: ast, params: params, env: env))

proc boolObj(b: bool): MalType =
  if b: trueObj else: falseObj

proc list_q*(xs: varargs[MalType]): MalType {.procvar.} =
  boolObj xs[0].kind == List

proc vector_q*(xs: varargs[MalType]): MalType {.procvar.} =
  boolObj xs[0].kind == Vector

proc hash_map_q*(xs: varargs[MalType]): MalType {.procvar.} =
  boolObj xs[0].kind == HashMap

proc empty_q*(xs: varargs[MalType]): MalType {.procvar.} =
  boolObj xs[0].list.len == 0

proc count*(xs: varargs[MalType]): MalType {.procvar.} =
  number if xs[0].kind == Nil: 0 else: xs[0].list.len

proc `==`*(x, y: MalType): bool =
  if not (x.kind in {List, Vector} and y.kind in {List, Vector}):
    if x.kind != y.kind: return false
  result = case x.kind
  of Nil, True, False: true
  of Number:         x.number   == y.number
  of Symbol, String: x.str      == y.str
  of List, Vector:   x.list     == y.list
  of HashMap:        x.hash_map == y.hash_map
  of Fun:            x.fun      == y.fun
  of MalFun:         x.malfun   == y.malfun

proc equal*(xs: varargs[MalType]): MalType {.procvar.} =
  boolObj xs[0] == xs[1]