src/GuileHandler.h
branchv_0
changeset 23 6ee7a9e311e9
parent 20 dccbfd273a5a
child 26 421608ecc12a
--- a/src/GuileHandler.h	Tue May 07 01:03:21 2019 +0200
+++ b/src/GuileHandler.h	Sun May 26 19:46:47 2019 +0200
@@ -20,6 +20,7 @@
 #include <memory>
 #include <string>
 #include <vector>
+#include <map>
 #include <iostream>
 #include <sstream>
 #include <locale>
@@ -39,6 +40,7 @@
 #include <relpipe/cli/RelpipeCLIException.h>
 
 #include "Configuration.h"
+#include "GuileException.h"
 
 namespace relpipe {
 namespace tr {
@@ -59,6 +61,7 @@
 	RelationConfiguration* currentRelationConfiguration = nullptr;
 	vector<AttributeMetadata> currentReaderMetadata;
 	vector<writer::AttributeMetadata> currentWriterMetadata;
+	std::map<string_t, string_t> currenVariablesMapping;
 	integer_t currentAttributeIndex = 0;
 	boolean_t includeCurrentRecord = false;
 
@@ -70,13 +73,51 @@
 			});
 	}
 
+	void generateVariableMappings() {
+		currenVariablesMapping.clear();
+		for (AttributeMetadata m : currentReaderMetadata) currenVariablesMapping[m.getAttributeName()] = L"";
+		for (writer::AttributeMetadata m : currentWriterMetadata) currenVariablesMapping[m.attributeName] = L"";
+
+		for (std::pair<string_t, string_t> m : currenVariablesMapping) {
+			currenVariablesMapping[m.first] = escapeAwkVariableName(m.first);
+		}
+	}
+
 	/**
 	 * @param attributeName name from relational pipe
 	 * @return variable name in Guile
 	 */
 	string_t a2v(const string_t& attributeName) {
-		// TODO: escape spaces and special characters
-		return L"$" + attributeName;
+		if (currenVariablesMapping.find(attributeName) != currenVariablesMapping.end()) return currenVariablesMapping[attributeName];
+		else throw GuileException(L"Unable to find value in currenVariablesMapping");
+	}
+
+	template <typename K, typename V> bool containsValue(std::map<K, V> map, V value) { // TODO: common function (Guile, AWK)
+		for (std::pair<K, V> p : map) if (p.second == value) return true;
+		return false;
+	}
+
+	string_t escapeAwkVariableName(const string_t& attributeName, bool addPrefix = true) {
+		std::wregex badCharacters(L"\\s");
+		string_t name = std::regex_replace(attributeName, badCharacters, L"-");
+
+		if (addPrefix) name = L"$" + name; // $ = standard attribute-variable prefix
+
+		if (containsValue(currenVariablesMapping, name)) return escapeAwkVariableName(L"$" + name, false); // $ = different prefix added to distinguish two attributes with ambiguous names
+		else return name;
+
+	}
+
+	void debugVariableMapping(const string_t& relationName) {
+		relationalWriter->startRelation(relationName + L".variableMapping",{
+			{L"attribute", writer::TypeId::STRING},
+			{L"variable", writer::TypeId::STRING},
+		}, true);
+
+		for (std::pair<string_t, string_t> m : currenVariablesMapping) {
+			relationalWriter->writeAttribute(m.first);
+			relationalWriter->writeAttribute(m.second);
+		}
 	}
 
 	SCM toGuileSymbol(const string_t& name) {
@@ -233,6 +274,10 @@
 			add(currentReaderMetadata, currentWriterMetadata);
 		}
 
+		generateVariableMappings();
+
+		if (currentRelationConfiguration->debugVariableMapping) debugVariableMapping(name);
+
 		if (!currentRelationConfiguration || !currentRelationConfiguration->drop) relationalWriter->startRelation(name, currentWriterMetadata, true);
 
 		if (currentRelationConfiguration) {