From 99c71cae9fe53e9db7ae6b90b5be576d9aad7f28 Mon Sep 17 00:00:00 2001 From: Steve Kemp Date: Tue, 22 Nov 2022 06:30:27 +0200 Subject: [PATCH] Moved (env) from the core to the builtin package. This will close #99, once complete. --- builtins/builtins.go | 29 +++++++++++++++++++++++++++++ builtins/builtins_test.go | 38 ++++++++++++++++++++++++++++++++++++++ builtins/help.txt | 4 ++++ eval/specials.go | 27 --------------------------- 4 files changed, 71 insertions(+), 27 deletions(-) diff --git a/builtins/builtins.go b/builtins/builtins.go index 890040f..1fa137e 100644 --- a/builtins/builtins.go +++ b/builtins/builtins.go @@ -111,6 +111,7 @@ func PopulateEnvironment(env *env.Environment) { env.Set("date", &primitive.Procedure{F: dateFn, Help: helpMap["date"]}) env.Set("directory:entries", &primitive.Procedure{F: directoryEntriesFn, Help: helpMap["directory:entries"]}) env.Set("directory?", &primitive.Procedure{F: directoryFn, Help: helpMap["directory?"], Args: []primitive.Symbol{primitive.Symbol("path")}}) + env.Set("env", &primitive.Procedure{F: envFn, Help: helpMap["env"], Args: []primitive.Symbol{}}) env.Set("eq", &primitive.Procedure{F: eqFn, Help: helpMap["eq"], Args: []primitive.Symbol{primitive.Symbol("a"), primitive.Symbol("b")}}) env.Set("error", &primitive.Procedure{F: errorFn, Help: helpMap["error"], Args: []primitive.Symbol{primitive.Symbol("message")}}) env.Set("exists?", &primitive.Procedure{F: existsFn, Help: helpMap["exists?"], Args: []primitive.Symbol{primitive.Symbol("path")}}) @@ -458,6 +459,34 @@ func divideFn(env *env.Environment, args []primitive.Primitive) primitive.Primit return primitive.Number(v) } +// envFn returns registered "things" from our environment +func envFn(env *env.Environment, args []primitive.Primitive) primitive.Primitive { + // create a new list + var c primitive.List + + for key, val := range env.Items() { + + v := val.(primitive.Primitive) + + tmp := primitive.NewHash() + tmp.Set(":name", primitive.String(key)) + tmp.Set(":value", v) + + // Is this a procedure? If so + // add the help-text + proc, ok := v.(*primitive.Procedure) + if ok { + if len(proc.Help) > 0 { + tmp.Set(":help", primitive.String(proc.Help)) + } + } + + c = append(c, tmp) + } + + return c +} + // eqFn implements "eq" func eqFn(env *env.Environment, args []primitive.Primitive) primitive.Primitive { if len(args) != 2 { diff --git a/builtins/builtins_test.go b/builtins/builtins_test.go index 9277328..4f341d6 100644 --- a/builtins/builtins_test.go +++ b/builtins/builtins_test.go @@ -944,6 +944,44 @@ func TestEnsureHelpPresent(t *testing.T) { } } +// TestEnv tests env +func TestEnv(t *testing.T) { + + // Load our standard library + st := stdlib.Contents() + std := string(st) + + // Create a new interpreter + l := eval.New(std + "\n") + + env := env.New() + l.Evaluate(env) + + // No arguments + out := envFn(env, []primitive.Primitive{}) + + // Will lead to a list + e, ok := out.(primitive.List) + if !ok { + t.Fatalf("expected list, got %v", out) + } + + // Ensure our list of items contains only hashes. + for _, x := range e { + + // Get the hash + _, ok2 := x.(primitive.Hash) + if !ok2 { + t.Fatalf("env should have a list of hashes, found element %v", x) + } + + } + + if len(e) < 100 { + t.Fatalf("expected a lot of entries, got %d", len(e)) + } +} + // TestEq tests "eq" (non-numerical equality) func TestEq(t *testing.T) { diff --git a/builtins/help.txt b/builtins/help.txt index 2b09644..a5b11fc 100644 --- a/builtins/help.txt +++ b/builtins/help.txt @@ -105,6 +105,10 @@ path, recursively. It is a helper function used to implement directory:walk See also: directory:walk, glob %% +env + +env returns all the registered symbols from the environment, as a list of hashes. +%% eq eq returns true if the two values supplied as parameters have the same type, and string representation. diff --git a/eval/specials.go b/eval/specials.go index ead0849..ee92dfc 100644 --- a/eval/specials.go +++ b/eval/specials.go @@ -90,33 +90,6 @@ func (ev *Eval) evalSpecialForm(name string, args []primitive.Primitive, e *env. } return ret, true - case "env": - - // create a new list - var c primitive.List - - for key, val := range e.Items() { - - v := val.(primitive.Primitive) - - tmp := primitive.NewHash() - tmp.Set(":name", primitive.String(key)) - tmp.Set(":value", v) - - // Is this a procedure? If so - // add the help-text - proc, ok := v.(*primitive.Procedure) - if ok { - if len(proc.Help) > 0 { - tmp.Set(":help", primitive.String(proc.Help)) - } - } - - c = append(c, tmp) - } - - return c, true - case "eval": if len(args) != 1 { return primitive.ArityError(), true