22#include < exception>
33#include < iostream>
44#include < loguru.hpp>
5+ #include < map>
56#include < numeric>
67#include < vector>
78#include " memory.hpp"
89#include " scheme.hpp"
910
1011namespace scm {
1112
13+ /* *
14+ * Helper function to get the keys of any std::map as a vector
15+ * @tparam TYPE_KEY the type of the keys
16+ * @tparam TYPE_VALUE the type of the values
17+ * @param inputMap the map from which to get the keys
18+ * @returns a vector<TYPE_KEY> of all keys of inputMap
19+ */
20+ template <typename TYPE_KEY, typename TYPE_VALUE>
21+ std::vector<TYPE_KEY> getKeys (std::map<TYPE_KEY, TYPE_VALUE> const & inputMap)
22+ {
23+ std::vector<TYPE_KEY> keys;
24+ for (auto const & element : inputMap) {
25+ keys.push_back (element.first );
26+ }
27+ return keys;
28+ }
29+
1230/* *
1331 * Copy constructor for the Environment class
1432 * @param env the environment to copy
@@ -20,56 +38,36 @@ Environment::Environment(const Environment& env)
2038}
2139
2240/* *
23- * Get a binding of the given string key in the specified Environment
41+ * Get the value of a binding of a given string key in the specified Environment
2442 * @param env the environment in which to look
2543 * @param key the key to look out for
26- * @returns The found binding in form con(key, value) or NULL if none was found
44+ * @returns The found variable
2745 */
28- Object* getBinding (Environment& env, std::string& key)
46+ Object* getVariable (Environment& env, std::string& key)
2947{
30- Environment* currentEnv = &env;
31- while (currentEnv != NULL ) {
32- auto lambda = [key](Object* binding) { return (getStringValue (getCar (binding)) == key); };
33- auto found = std::find_if (currentEnv->bindings .begin (), currentEnv->bindings .end (), lambda);
34- if (found != currentEnv->bindings .end ()) {
35- return *found;
48+ Environment* currentEnvPtr = &env;
49+ while (currentEnvPtr != NULL ) {
50+ std::map<std::string, Object*>::iterator found = currentEnvPtr->bindings .find (key);
51+ if (found != currentEnvPtr->bindings .end ()) {
52+ return currentEnvPtr->bindings .at (key);
3653 }
3754 else {
38- currentEnv = currentEnv ->parentEnv ;
55+ currentEnvPtr = currentEnvPtr ->parentEnv ;
3956 }
4057 }
4158 return NULL ;
4259}
4360
44- /* *
45- * Get a binding of the given symbol Object key in the specified Environment
46- * @overload
47- */
48- Object* getBinding (Environment& env, Object* key)
49- {
50- std::string keyStr = getStringValue (key);
51- return getBinding (env, keyStr);
52- }
53-
54- /* *
55- * Get the value of a binding of a given string key in the specified Environment
56- * @param env the environment in which to look
57- * @param key the key to look out for
58- * @returns The found variable
59- */
60- Object* getVariable (Environment& env, std::string& key)
61- {
62- Object* binding{getBinding (env, key)};
63- return (binding != NULL ) ? getCdr (binding) : NULL ;
64- }
65-
6661/* *
6762 * Get the value of a binding of a given symbol Object key in the specified Environment
6863 * @overload
6964 */
7065Object* getVariable (Environment& env, Object* key)
7166{
72- std::string keyStr = getStringValue (key);
67+ if (!hasTag (key, TAG_SYMBOL)) {
68+ schemeThrow (" values can only be bound to symbols" );
69+ }
70+ std::string keyStr{getStringValue (key)};
7371 return getVariable (env, keyStr);
7472}
7573
@@ -79,30 +77,23 @@ Object* getVariable(Environment& env, Object* key)
7977 * @param key the key of the binding
8078 * @param value the value of the binding
8179 */
80+ void define (Environment& env, std::string& key, Object* value)
81+ {
82+ DLOG_IF_F (INFO, LOG_ENVIRONMENT, " define %s := %s" , key.c_str (), toString (value).c_str ());
83+ env.bindings [key] = value;
84+ }
85+
86+ /* *
87+ * Define a new binding in the given environment, takes an Object* as key.
88+ * @overload
89+ */
8290void define (Environment& env, Object* key, Object* value)
8391{
84- DLOG_IF_F (
85- INFO, LOG_ENVIRONMENT, " define %s := %s" , toString (key).c_str (), toString (value).c_str ());
86- auto currentDefinition = getBinding (env, key);
87- // if binding doesn't exist yet create a new one
88- if (currentDefinition == NULL ) {
89- DLOG_IF_F (INFO,
90- LOG_ENVIRONMENT,
91- " define new variable %s := %s" ,
92- toString (key).c_str (),
93- toString (value).c_str ());
94- Object* definition{newCons (key, value)};
95- env.bindings .push_back (definition);
96- }
97- // if binding does exist set the old value to the new value
98- else {
99- DLOG_IF_F (INFO,
100- LOG_ENVIRONMENT,
101- " redefine variable %s := %s" ,
102- toString (key).c_str (),
103- toString (value).c_str ());
104- std::get<ConsValue>(currentDefinition->value ).cdr = value;
92+ if (!hasTag (key, TAG_SYMBOL)) {
93+ schemeThrow (" values can only be bound to symbols" );
10594 }
95+ std::string keyStr{getStringValue (key)};
96+ define (env, keyStr, value);
10697}
10798
10899/* *
@@ -121,64 +112,60 @@ void set(Environment& env, Object* key, Object* value)
121112 };
122113}
123114
115+ /* *
116+ * Print all bindings of an environment that fulfill a certain condition.
117+ * @param env the environment from which to get the bindings
118+ * @param checkFunction a function that's called on each element to determine whether it should be
119+ * printed or not
120+ * @param maxNameLength the longest variable name in the environment, for spacing purposes
121+ */
122+ void printCategory (Environment& env, std::function<bool (Object*)> checkFunction, int maxNameLength)
123+ {
124+ for (auto & binding : env.bindings ) {
125+ if (checkFunction (binding.second )) {
126+ std::string name = binding.first ;
127+ std::cout << name;
128+ for (int i{0 }; i < maxNameLength - name.size (); i++) {
129+ std::cout << ' ' ;
130+ }
131+ std::cout << " := " ;
132+ if (hasTag (binding.second , TAG_FUNC_USER)) {
133+ std::cout << toString (getUserFunctionArgList (binding.second ));
134+ }
135+ else if (isOneOf (binding.second , {TAG_FUNC_BUILTIN, TAG_SYNTAX})) {
136+ std::cout << getBuiltinFuncHelpText (binding.second )
137+ .substr (0 , getBuiltinFuncHelpText (binding.second ).find (' \n ' ));
138+ }
139+ else {
140+ std::cout << toString (binding.second );
141+ }
142+ std::cout << " \n " ;
143+ }
144+ }
145+ }
146+
124147/* *
125148 * Prints all bindings of a given environment in a formatted form.
126149 * @param env the environment to print
127150 */
128151void printEnv (Environment& env)
129152{
130153 // get longest variable name for spacing purposes
131- int longestVariableNameLength = std::accumulate (
132- env.bindings .begin (), env.bindings .end (), 0 , [](int longestLength, Object* binding) {
133- return (getStringValue (getCar (binding)).size () > longestLength)
134- ? getStringValue (getCar (binding)).size ()
135- : longestLength;
154+ std::vector<std::string> keys{getKeys (env.bindings )};
155+ int longestVariableNameLength =
156+ std::accumulate (keys.begin (), keys.end (), 0 , [](int longestLength, std::string& binding) {
157+ return (binding.size () > longestLength) ? binding.size () : longestLength;
136158 });
137159
138160 std::cout << " ======== SYNTAX ========\n " ;
139- for (auto binding : env.bindings ) {
140- if (hasTag (getCdr (binding), TAG_SYNTAX)) {
141- std::string name = getStringValue (getCar (binding));
142- std::cout << toString (getCar (binding));
143- for (int i{0 }; i < longestVariableNameLength - name.size (); i++) {
144- std::cout << ' ' ;
145- }
146- std::cout << " := " << toString (getCdr (binding)) << " \n " ;
147- }
148- }
161+ std::function<bool (Object*)> lambda = [](Object* obj) { return hasTag (obj, TAG_SYNTAX); };
162+ printCategory (env, lambda, longestVariableNameLength);
149163 std::cout << " ======== FUNCTIONS ========\n " ;
150- for (auto binding : env.bindings ) {
151- if (hasTag (getCdr (binding), TAG_FUNC_BUILTIN)) {
152- std::string name = getStringValue (getCar (binding));
153- std::cout << toString (getCar (binding));
154- for (int i{0 }; i < longestVariableNameLength - name.size (); i++) {
155- std::cout << ' ' ;
156- }
157- std::cout << " := " << toString (getCdr (binding)) << " \n " ;
158- }
159- }
160- for (auto binding : env.bindings ) {
161- if (hasTag (getCdr (binding), TAG_FUNC_USER)) {
162- std::string name = getStringValue (getCar (binding));
163- std::cout << toString (getCar (binding));
164- for (int i{0 }; i < longestVariableNameLength - name.size (); i++) {
165- std::cout << ' ' ;
166- }
167- std::cout << " := function args: " << toString (getUserFunctionArgList (getCdr (binding)))
168- << " \n " ;
169- }
170- }
164+ lambda = [](Object* obj) { return isOneOf (obj, {TAG_FUNC_BUILTIN, TAG_FUNC_USER}); };
165+ printCategory (env, lambda, longestVariableNameLength);
171166 std::cout << " ======== VARIABLES ========\n " ;
172- for (auto binding : env.bindings ) {
173- if (!isOneOf (getCdr (binding), {TAG_FUNC_BUILTIN, TAG_FUNC_USER, TAG_SYNTAX})) {
174- std::string name = getStringValue (getCar (binding));
175- std::cout << toString (getCar (binding));
176- for (int i{0 }; i < longestVariableNameLength - name.size (); i++) {
177- std::cout << ' ' ;
178- }
179- std::cout << " := " << toString (getCdr (binding)) << " \n " ;
180- }
181- }
167+ lambda = [](Object* obj) { return !isOneOf (obj, {TAG_FUNC_BUILTIN, TAG_FUNC_USER, TAG_SYNTAX}); };
168+ printCategory (env, lambda, longestVariableNameLength);
182169 std::cout << " ===========================\n " ;
183170}
184171} // namespace scm
0 commit comments