Skip to content

Commit 847da7d

Browse files
use map for environment bindings
1 parent 335ef6e commit 847da7d

File tree

4 files changed

+98
-107
lines changed

4 files changed

+98
-107
lines changed

src/environment.cpp

Lines changed: 87 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,31 @@
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

1011
namespace 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
*/
7065
Object* 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+
*/
8290
void 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
*/
128151
void 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

src/environment.hpp

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#pragma once
2-
#include <vector>
2+
#include <map>
33
#include "scheme.hpp"
44

55
namespace scm {
@@ -12,23 +12,25 @@ namespace scm {
1212
*/
1313
class Environment {
1414
private:
15-
std::vector<scm::Object*> bindings;
15+
std::map<std::string, Object*> bindings;
1616
Environment* parentEnv;
1717

1818
public:
1919
Environment(Environment* parent = NULL) : parentEnv(parent){};
2020
Environment(const Environment& obj);
2121
~Environment() = default;
2222
friend void set(Environment& env, Object* key, Object* value);
23-
friend void define(Environment& env, Object* key, Object* value);
23+
friend void define(Environment& env, std::string& key, Object* value);
24+
friend void printCategory(Environment& env,
25+
std::function<bool(Object*)> checkFunction,
26+
int maxNameLength);
2427
friend void printEnv(Environment& env);
25-
friend Object* getBinding(Environment& env, Object* key);
26-
friend Object* getBinding(Environment& env, std::string& key);
2728
friend Object* getVariable(Environment& env, Object* key);
2829
friend Object* getVariable(Environment& env, std::string& key);
2930
};
3031

3132
void define(Environment& env, Object* key, Object* value);
33+
void define(Environment& env, std::string& key, Object* value);
3234
void set(Environment& env, Object* key, Object* value);
3335
void printEnv(Environment& env);
3436
Object* getVariable(Environment& env, Object* key);

src/scheme.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ int getBuiltinFuncNArgs(Object* obj);
124124
std::string getBuiltinFuncHelpText(Object* obj);
125125
Object* getUserFunctionBodyList(Object* obj);
126126
Object* getUserFunctionArgList(Object* obj);
127+
std::string getBuiltinFuncHelpText(Object* obj);
127128
Environment* getUserFunctionParentEnv(Object* obj);
128129
bool hasTag(Object* obj, ObjectTypeTag tag);
129130
bool isString(Object* obj);

src/setup.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#include "setup.hpp"
22
#include <iostream>
3+
#include <loguru.hpp>
34
#include "environment.hpp"
45
#include "memory.hpp"
56
#include "scheme.hpp"
@@ -21,7 +22,7 @@ void defineNewSyntax(Environment& env,
2122
std::string helpText)
2223
{
2324
Object* func{newSyntax(name, nArgs, tag, helpText)};
24-
define(env, newSymbol(name), func);
25+
define(env, name, func);
2526
}
2627

2728
/**
@@ -39,7 +40,7 @@ void defineNewBuiltinFunction(Environment& env,
3940
std::string helpText)
4041
{
4142
Object* func{newBuiltinFunction(name, nArgs, tag, helpText)};
42-
define(env, newSymbol(name), func);
43+
define(env, name, func);
4344
}
4445

4546
/**

0 commit comments

Comments
 (0)