mirror of
https://github.com/kanaka/mal.git
synced 2024-11-13 11:23:59 +03:00
132 lines
4.4 KiB
Forth
132 lines
4.4 KiB
Forth
module Env
|
|
|
|
open Types
|
|
|
|
let makeEmpty () = Env()
|
|
|
|
let ofList lst =
|
|
let env = makeEmpty ()
|
|
let accumulate (e : Env) (k, v) = e.Add(k, v); e
|
|
List.fold accumulate env lst
|
|
|
|
let set (env : EnvChain) key node =
|
|
match env with
|
|
| head::_ -> head.[key] <- node
|
|
| _ -> raise <| Error.noEnvironment ()
|
|
|
|
let rec find (chain : EnvChain) key =
|
|
match chain with
|
|
| [] -> None
|
|
| env::rest ->
|
|
match env.TryGetValue(key) with
|
|
| true, v -> Some(v)
|
|
| false, _ -> find rest key
|
|
|
|
let get chain key =
|
|
match find chain key with
|
|
| Some(v) -> v
|
|
| None -> raise <| Error.symbolNotFound key
|
|
|
|
let private getNextValue =
|
|
let counter = ref 0
|
|
fun () -> System.Threading.Interlocked.Increment(counter)
|
|
|
|
let makeBuiltInFunc f =
|
|
BuiltInFunc(Node.NIL, getNextValue (), f)
|
|
|
|
let makeFunc f body binds env =
|
|
Func(Node.NIL, getNextValue (), f, body, binds, env)
|
|
|
|
let makeMacro f body binds env =
|
|
Macro(Node.NIL, getNextValue (), f, body, binds, env)
|
|
|
|
let makeRootEnv () =
|
|
let wrap name f = name, makeBuiltInFunc f
|
|
let env =
|
|
[ wrap "+" Core.add
|
|
wrap "-" Core.subtract
|
|
wrap "*" Core.multiply
|
|
wrap "/" Core.divide
|
|
wrap "list" Core.list
|
|
wrap "list?" Core.isList
|
|
wrap "empty?" Core.isEmpty
|
|
wrap "count" Core.count
|
|
wrap "=" Core.eq
|
|
wrap "<" Core.lt
|
|
wrap "<=" Core.le
|
|
wrap ">=" Core.ge
|
|
wrap ">" Core.gt
|
|
wrap "time-ms" Core.time_ms
|
|
wrap "pr-str" Core.pr_str
|
|
wrap "str" Core.str
|
|
wrap "prn" Core.prn
|
|
wrap "println" Core.println
|
|
wrap "read-string" Core.read_str
|
|
wrap "slurp" Core.slurp
|
|
wrap "cons" Core.cons
|
|
wrap "concat" Core.concat
|
|
wrap "nth" Core.nth
|
|
wrap "first" Core.first
|
|
wrap "rest" Core.rest
|
|
wrap "throw" Core.throw
|
|
wrap "map" Core.map
|
|
wrap "apply" Core.apply
|
|
wrap "nil?" (Core.isConst Node.NIL)
|
|
wrap "true?" (Core.isConst Node.TRUE)
|
|
wrap "false?" (Core.isConst Node.FALSE)
|
|
wrap "symbol?" Core.isSymbol
|
|
wrap "symbol" Core.symbol
|
|
wrap "string?" Core.isString
|
|
wrap "keyword?" Core.isKeyword
|
|
wrap "keyword" Core.keyword
|
|
wrap "number?" Core.isNumber
|
|
wrap "fn?" Core.isFn
|
|
wrap "macro?" Core.isMacro
|
|
wrap "sequential?" Core.isSequential
|
|
wrap "vector?" Core.isVector
|
|
wrap "vector" Core.vector
|
|
wrap "map?" Core.isMap
|
|
wrap "hash-map" Core.hashMap
|
|
wrap "assoc" Core.assoc
|
|
wrap "dissoc" Core.dissoc
|
|
wrap "get" Core.get
|
|
wrap "contains?" Core.contains
|
|
wrap "keys" Core.keys
|
|
wrap "vals" Core.vals
|
|
wrap "atom" (Core.atom getNextValue)
|
|
wrap "atom?" Core.isAtom
|
|
wrap "deref" Core.deref
|
|
wrap "reset!" Core.reset
|
|
wrap "swap!" Core.swap
|
|
wrap "conj" Core.conj
|
|
wrap "seq" Core.seq
|
|
wrap "meta" Core.meta
|
|
wrap "with-meta" Core.withMeta ]
|
|
|> ofList
|
|
[ env ]
|
|
|
|
let makeNew outer symbols nodes =
|
|
let env = (makeEmpty ())::outer
|
|
let rec loop symbols nodes =
|
|
match symbols, nodes with
|
|
| [Symbol("&"); Symbol(s)], nodes ->
|
|
set env s (Node.makeList nodes)
|
|
env
|
|
| Symbol("&")::_, _ -> raise <| Error.onlyOneSymbolAfterAmp ()
|
|
| Symbol(s)::symbols, n::nodes ->
|
|
set env s n
|
|
loop symbols nodes
|
|
| [], [] -> env
|
|
| _, [] -> raise <| Error.notEnoughValues ()
|
|
| [], _ -> raise <| Error.tooManyValues ()
|
|
| _, _ -> raise <| Error.errExpectedX "symbol"
|
|
loop symbols nodes
|
|
|
|
(* Active Patterns to help with pattern matching nodes *)
|
|
let inline (|IsMacro|_|) env = function
|
|
| List(_, Symbol(sym)::rest) ->
|
|
match find env sym with
|
|
| Some(Macro(_, _, _, _, _, _) as m) -> Some(IsMacro m, rest)
|
|
| _ -> None
|
|
| _ -> None
|