1
1
mirror of https://github.com/kanaka/mal.git synced 2024-09-20 10:07:45 +03:00
mal/nim/types.nim
2016-02-15 23:58:07 -06:00

152 lines
4.7 KiB
Nim

import tables, strutils
type
MalTypeKind* = enum Nil, True, False, Number, Symbol, String,
List, Vector, HashMap, Fun, MalFun, Atom
FunType = proc(a: varargs[MalType]): MalType
MalFunType* = ref object
fn*: FunType
ast*: MalType
params*: MalType
env*: Env
is_macro*: bool
MalType* = ref 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*: Table[string, MalType]
of Fun:
fun*: FunType
is_macro*: bool
of MalFun: malfun*: MalFunType
of Atom: val*: MalType
meta*: MalType
Env* = ref object
data*: Table[string, MalType]
outer*: Env
let nilObj* = MalType(kind: Nil)
let trueObj* = MalType(kind: True)
let 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 atom*(x: MalType): MalType =
result = MalType(kind: Atom)
result.val = x
proc list*(xs: varargs[MalType]): MalType {.procvar.} =
result = MalType(kind: List, list: newSeq[MalType](xs.len))
for i, x in xs: result.list[i] = x
proc vector*(xs: varargs[MalType]): MalType {.procvar.} =
result = MalType(kind: Vector, list: newSeq[MalType](xs.len))
for i, x in xs: result.list[i] = x
proc hash_map*(xs: varargs[MalType]): MalType {.procvar.} =
result = MalType(kind: HashMap, hash_map: initTable[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 macro_q*(x: MalType): bool =
if x.kind == Fun: result = x.is_macro
elif x.kind == MalFun: result = x.malfun.is_macro
else: raise newException(ValueError, "no function")
proc getFun*(x: MalType): FunType =
if x.kind == Fun: result = x.fun
elif x.kind == MalFun: result = x.malfun.fn
else: raise newException(ValueError, "no function")
proc fun*(x: proc(xs: varargs[MalType]): MalType, is_macro = false): MalType =
MalType(kind: Fun, fun: x, is_macro: is_macro)
proc malfun*(fn: auto, ast, params: MalType,
env: Env, is_macro = false): MalType =
MalType(kind: MalFun, malfun: MalFunType(fn: fn, ast: ast, params: params,
env: env, is_macro: is_macro))
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 seq_q*(xs: varargs[MalType]): MalType {.procvar.} =
boolObj xs[0].kind in {List, 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 nil_q*(xs: varargs[MalType]): MalType {.procvar.} =
boolObj xs[0].kind == Nil
proc true_q*(xs: varargs[MalType]): MalType {.procvar.} =
boolObj xs[0].kind == True
proc false_q*(xs: varargs[MalType]): MalType {.procvar.} =
boolObj xs[0].kind == False
proc string_q*(xs: varargs[MalType]): MalType {.procvar.} =
boolObj(xs[0].kind == String and xs[0].str[0] != '\xff')
proc symbol*(xs: varargs[MalType]): MalType {.procvar.} =
symbol(xs[0].str)
proc symbol_q*(xs: varargs[MalType]): MalType {.procvar.} =
boolObj xs[0].kind == Symbol
proc keyword*(xs: varargs[MalType]): MalType {.procvar.} =
keyword(xs[0].str)
proc keyword_q*(xs: varargs[MalType]): MalType {.procvar.} =
boolObj(xs[0].kind == String and xs[0].str[0] == '\xff')
proc atom*(xs: varargs[MalType]): MalType {.procvar.} =
atom(xs[0])
proc atom_q*(xs: varargs[MalType]): MalType {.procvar.} =
boolObj xs[0].kind == Atom
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 and
x.is_macro == y.is_macro
of MalFun: x.malfun == y.malfun
of Atom: x.val == y.val
proc equal*(xs: varargs[MalType]): MalType {.procvar.} =
boolObj xs[0] == xs[1]