summaryrefslogtreecommitdiffstats
path: root/cpp
diff options
context:
space:
mode:
authorjsdelfino <jsdelfino@13f79535-47bb-0310-9956-ffa450edef68>2009-10-26 05:13:06 +0000
committerjsdelfino <jsdelfino@13f79535-47bb-0310-9956-ffa450edef68>2009-10-26 05:13:06 +0000
commitf61164c77c5c21a32b58ad61c868bd8ff6a4a79e (patch)
tree951cc581d22bac8ad615697b19e879e22578d10c /cpp
parent0969cc21d093f9450c36e7f63cddc4f5aa44b238 (diff)
Minor refactoring, given each module its own namespace. Added utility functions to convert between values elements/attributes and fixed XML, ATOM and JSON serialization of lists.
git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@829699 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to '')
-rw-r--r--cpp/sca/kernel/element.hpp143
-rw-r--r--cpp/sca/kernel/function.hpp4
-rw-r--r--cpp/sca/kernel/kernel-test.cpp75
-rw-r--r--cpp/sca/kernel/list.hpp71
-rw-r--r--cpp/sca/kernel/value.hpp41
-rw-r--r--cpp/sca/kernel/xml.hpp55
-rw-r--r--cpp/sca/modules/atom/atom-test.cpp72
-rw-r--r--cpp/sca/modules/atom/atom.hpp50
-rw-r--r--cpp/sca/modules/eval/Makefile.am3
-rw-r--r--cpp/sca/modules/eval/driver.hpp4
-rw-r--r--cpp/sca/modules/eval/environment.hpp42
-rw-r--r--cpp/sca/modules/eval/eval-shell.cpp2
-rw-r--r--cpp/sca/modules/eval/eval-test.cpp22
-rw-r--r--cpp/sca/modules/eval/eval.hpp31
-rw-r--r--cpp/sca/modules/eval/primitive.hpp5
-rw-r--r--cpp/sca/modules/eval/read.hpp5
-rw-r--r--cpp/sca/modules/json/json-test.cpp57
-rw-r--r--cpp/sca/modules/json/json.hpp62
18 files changed, 527 insertions, 217 deletions
diff --git a/cpp/sca/kernel/element.hpp b/cpp/sca/kernel/element.hpp
index 9b0f1f5f0a..af221f849b 100644
--- a/cpp/sca/kernel/element.hpp
+++ b/cpp/sca/kernel/element.hpp
@@ -60,6 +60,13 @@ const value elementName(const list<value>& l) {
}
/**
+ * Returns true if an element has children.
+ */
+const bool elementHasChildren(const list<value>& l) {
+ return !isNil(cddr(l));
+}
+
+/**
* Returns the children of an element.
*/
const list<value> elementChildren(const list<value>& l) {
@@ -70,15 +77,11 @@ const list<value> elementChildren(const list<value>& l) {
* Returns true if an element has a value.
*/
const value elementHasValue(const list<value>& l) {
- if (isNil(cddr(l)))
- return false;
const list<value> r = reverse(l);
- if(isList(car(r))) {
- const list<value> v = car(r);
- if(isSymbol(car(v))) {
+ if (isSymbol(car(r)))
+ return false;
+ if(isList(car(r)) && isSymbol(car<value>(car(r))))
return false;
- }
- }
return true;
}
@@ -90,36 +93,122 @@ const value elementValue(const list<value>& l) {
}
/**
- * Converts a list of elements to a list of values.
+ * Convert an element to a value.
*/
-const list<value> elementsToValues(const list<value>& e) {
- if (isNil(e))
- return list<value>();
- const value t = car(e);
+const bool elementToValueIsList(const value& v) {
+ if (!isList(v))
+ return false;
+ const list<value> l = v;
+ if(isNil(l))
+ return true;
+ return isList(car(l));
+}
+
+const value elementToValue(const value& t) {
+ const list<value> elementsToValues(const list<value>& e);
+
+ // Convert an attribute
if (isTaggedList(t, attribute))
- return cons<value>(mklist(attributeName(t), attributeValue(t)), elementsToValues(cdr(e)));
+ return mklist(attributeName(t), attributeValue(t));
+
+ // Convert an element
if (isTaggedList(t, element)) {
- if (elementHasValue(t))
- return cons<value>(mklist(elementName(t), elementValue(t)), elementsToValues(cdr(e)));
- return cons<value>(cons(elementName(t), elementsToValues(elementChildren(t))), elementsToValues(cdr(e)));
+
+ // Convert an element's value
+ if (elementHasValue(t)) {
+
+ // Convert a single value
+ if (!elementToValueIsList(elementValue(t)))
+ return mklist(elementName(t), elementValue(t));
+
+ // Convert a list value
+ return cons(elementName(t), mklist<value>(elementsToValues(elementValue(t))));
+ }
+
+ // Convert an element's children
+ return cons(elementName(t), elementsToValues(elementChildren(t)));
}
- return cons(t, elementsToValues(cdr(e)));
+
+ // Convert a value
+ if (!isList(t))
+ return t;
+ return elementsToValues(t);
}
/**
- * Converts a list of values to a list of elements.
+ * Convert a list of elements to a list of values.
*/
-const list<value> valuesToElements(const list<value>& e) {
+const bool elementToValueIsSymbol(const value& v) {
+ if (!isList(v))
+ return false;
+ const list<value> l = v;
+ if (isNil(l))
+ return false;
+ if (!isSymbol(car(l)))
+ return false;
+ return true;
+}
+
+const list<value> elementToValueGroupValues(const value& v, const list<value>& l) {
+ if (isNil(l) || !elementToValueIsSymbol(v) || !elementToValueIsSymbol(car(l))) {
+ return cons(v, l);
+ }
+ if (car<value>(car(l)) != car<value>(v)) {
+ return cons(v, l);
+ }
+ if (!elementToValueIsList(cadr<value>(car(l)))) {
+ const value g = mklist<value>(car<value>(v), mklist<value>(cdr<value>(v), cdr<value>(car(l))));
+ return elementToValueGroupValues(g, cdr(l));
+ }
+ const value g = mklist<value>(car<value>(v), cons<value>(cdr<value>(v), (list<value>)cadr<value>(car(l))));
+ return elementToValueGroupValues(g, cdr(l));
+
+}
+
+const list<value> elementsToValues(const list<value>& e) {
if (isNil(e))
return list<value>();
- const value t = car(e);
- if (isList(t)) {
+ const value v = elementToValue(car(e));
+ const list<value> n = elementsToValues(cdr(e));
+ return elementToValueGroupValues(elementToValue(car(e)), elementsToValues(cdr(e)));
+}
+
+/**
+ * Convert a value to an element.
+ */
+const value valueToElement(const value& t) {
+ const list<value> valuesToElements(const list<value>& l);
+
+ // Convert a name value pair
+ if (isList(t) && isSymbol(car<value>(t))) {
+ const value n = car<value>(t);
const value v = cadr<value>(t);
+
+ // Convert a single value
if (!isList(v))
- return cons<value>(mklist(attribute, car<value>(t), v), valuesToElements(cdr(e)));
- return cons<value>(cons(element, cons(car<value>(t), valuesToElements(cdr<value>(t)))), valuesToElements(cdr(e)));
+ return mklist(element, n, v);
+
+ // Convert a list value
+ if (!isSymbol(car<value>(v)))
+ return cons(element, cons(n, mklist<value>(valuesToElements(v))));
+
+ // Convert a nested name value pair value
+ return cons(element, cons(n, valuesToElements(cdr<value>(t))));
}
- return cons(t, valuesToElements(cdr(e)));
+
+ // Convert a value
+ if (!isList(t))
+ return t;
+ return valuesToElements(t);
+}
+
+/**
+ * Convert a list of values to a list of elements.
+ */
+const list<value> valuesToElements(const list<value>& l) {
+ if (isNil(l))
+ return list<value>();
+ return cons<value>(valueToElement(car(l)), valuesToElements(cdr(l)));
}
/**
@@ -130,19 +219,19 @@ struct selectorLambda {
const list<value> select;
selectorLambda(const list<value>& s) : select(s) {
}
- const bool eval(const list<value>& s, const list<value> v) const {
+ const bool evalApply(const list<value>& s, const list<value> v) const {
if (isNil(s))
return true;
if (isNil(v))
return false;
if (car(s) != car(v))
return false;
- return eval(cdr(s), cdr(v));
+ return evalApply(cdr(s), cdr(v));
}
const bool operator()(const value& v) const {
if (!isList(v))
return false;
- return eval(select, v);
+ return evalApply(select, v);
}
};
diff --git a/cpp/sca/kernel/function.hpp b/cpp/sca/kernel/function.hpp
index 55637f68bf..9492879e5e 100644
--- a/cpp/sca/kernel/function.hpp
+++ b/cpp/sca/kernel/function.hpp
@@ -139,7 +139,7 @@ public:
const lambda& operator=(const lambda& l) {
if (this == &l)
- return *this;
+ return *this;
callable = l.callable;
return *this;
}
@@ -150,7 +150,7 @@ public:
const bool operator==(const lambda& l) const {
if (this == &l)
- return true;
+ return true;
return callable == l.callable;
}
diff --git a/cpp/sca/kernel/kernel-test.cpp b/cpp/sca/kernel/kernel-test.cpp
index 2d4158ea11..9f977a64f9 100644
--- a/cpp/sca/kernel/kernel-test.cpp
+++ b/cpp/sca/kernel/kernel-test.cpp
@@ -34,6 +34,7 @@
#include "slist.hpp"
#include "parallel.hpp"
#include "value.hpp"
+#include "element.hpp"
#include "xml.hpp"
#include "monad.hpp"
@@ -67,6 +68,12 @@ bool testLambda() {
assert(incf(1) == 11);
assert(mapLambda(incf, 1) == 11);
assert(mapLambda(inc(10), 1) == 11);
+
+ lambda<int(int)> l;
+ l = incf;
+ assert(l(1) == 11);
+ l = square;
+ assert(l(2) == 4);
return true;
}
@@ -115,11 +122,23 @@ bool testCons() {
return true;
}
+bool testSet() {
+ list<int> l = mklist(1, 2, 3);
+ setCar(l, 4);
+ setCdr(l, mklist(5, 6));
+ assert(car(l) == 4);
+ assert(cadr(l) == 5);
+ assert(caddr(l) == 6);
+ assert(isNil(cdddr(l)));
+ return true;
+}
+
bool testListGC() {
resetLambdaCounters();
resetListCounters();
countElements = 0;
testCons();
+ testSet();
assert(countLambdas == 0);
assert(countlists == 0);
assert(countElements == 0);
@@ -133,7 +152,7 @@ bool testOut() {
std::ostringstream os2;
os2 << mklist(1, 2, 3);
- assert(os2.str() == "(1, (2, (3, ())))");
+ assert(os2.str() == "(1, 2, 3)");
return true;
}
@@ -329,18 +348,6 @@ bool testValueGC() {
return true;
}
-bool testElement() {
- const list<value> ad = mklist<value>(mklist<value>(attribute, "city", std::string("san francisco")), mklist<value>(attribute, "state", std::string("ca")));
- const list<value> ac = mklist<value>(mklist<value>(attribute, "id", std::string("1234")), mklist<value>(attribute, "balance", 1000));
- const list<value> cr = mklist<value>(mklist<value> (attribute, "name", std::string("jdoe")), cons<value>(element, cons<value>("address", ad)), cons<value>(element, cons<value>("account", ac)));
- const list<value> c = mklist<value>(cons<value>(element, cons<value>("customer", cr)));
-
- const list<value> v = elementsToValues(c);
- const list<value> e = valuesToElements(v);
- assert(e == c);
- return true;
-}
-
double fib_aux(double n, double a, double b) {
if(n == 0.0)
return a;
@@ -487,9 +494,12 @@ const std::string customerXML =
"<name>jdoe</name>"
"<address><city>san francisco</city><state>ca</state></address>"
"<account><id>1234</id><balance>1000</balance></account>"
+"<account><id>6789</id><balance>2000</balance></account>"
+"<account><id>4567</id><balance>3000</balance></account>"
"</customer>"
"\n";
+
const bool isName(const value& token) {
return isTaggedList(token, attribute) && attributeName(token) == "name";
}
@@ -534,6 +544,44 @@ bool testWriteXML() {
return true;
}
+bool testElement() {
+ {
+ const list<value> ad = mklist<value>(mklist<value>("city", std::string("san francisco")), mklist<value>("state", std::string("ca")));
+ const list<value> ac1 = mklist<value>(mklist<value>("id", std::string("1234")), mklist<value>("balance", 1000));
+ const list<value> ac2 = mklist<value>(mklist<value>("id", std::string("6789")), mklist<value>("balance", 2000));
+ const list<value> ac3 = mklist<value>(mklist<value>("id", std::string("4567")), mklist<value>("balance", 3000));
+ {
+ const list<value> c = mklist<value>(mklist<value>("customer", mklist<value>("name", std::string("jdoe")), cons<value>("address", ad), mklist<value>("account", mklist<value>(ac1, ac2, ac3))));
+ const list<value> e = valuesToElements(c);
+ const list<value> v = elementsToValues(e);
+ assert(v == c);
+
+ std::ostringstream os;
+ writeXML<std::ostringstream*>(xmlWriter, &os, e);
+ assert(os.str() == customerXML);
+ }
+ {
+ const list<value> c = mklist<value>(mklist<value>("customer", mklist<value>("name", std::string("jdoe")), cons<value>("address", ad), cons<value>("account", ac1), cons<value>("account", ac2), cons<value>("account", ac3)));
+ const list<value> e = valuesToElements(c);
+ const list<value> v = elementsToValues(e);
+
+ std::ostringstream os;
+ writeXML<std::ostringstream*>(xmlWriter, &os, e);
+ assert(os.str() == customerXML);
+ }
+ }
+ {
+ std::istringstream is(customerXML);
+ const list<value> c = readXML(streamList(is));
+ const list<value> v = elementsToValues(c);
+ const list<value> e = valuesToElements(v);
+ std::ostringstream os;
+ writeXML<std::ostringstream*>(xmlWriter, &os, e);
+ assert(os.str() == customerXML);
+ }
+ return true;
+}
+
const id<int> idF(const int v) {
return v * 2;
}
@@ -644,6 +692,7 @@ int main() {
tuscany::testLambda();
tuscany::testLambdaGC();
tuscany::testCons();
+ tuscany::testSet();
tuscany::testListGC();
tuscany::testOut();
tuscany::testEquals();
diff --git a/cpp/sca/kernel/list.hpp b/cpp/sca/kernel/list.hpp
index 8c5ab30d1d..62c5d91150 100644
--- a/cpp/sca/kernel/list.hpp
+++ b/cpp/sca/kernel/list.hpp
@@ -114,7 +114,10 @@ public:
template<typename X> friend const bool isNil(const list<X>& p);
template<typename X> friend const X car(const list<X>& p);
- template<typename X> friend list<X> const cdr(const list<X>& p);
+ template<typename X> friend const list<X> cdr(const list<X>& p);
+ template<typename X> friend const bool setCar(list<X>& p, const X& car);
+ template<typename X> friend const bool setCdr(list<X>& p, const list<X>& cdr);
+ template<typename X> friend const bool setCdr(list<X>& p, const lambda<list<X> ()>& cdr);
private:
T car;
@@ -131,10 +134,19 @@ template<typename T> const bool isNil(const list<T>& p) {
/**
* Write a list to an output stream.
*/
-template<typename X> std::ostream& operator<<(std::ostream& out, const list<X>& l) {
+template<typename T> std::ostream& operator<<(std::ostream& out, const list<T>& l) {
if(isNil(l))
return out << "()";
- return out << "(" << car(l) << ", " << cdr(l) << ")";
+ out << "(";
+ list<T> ml = l;
+ while(true) {
+ out << car(ml);
+ ml = cdr(ml);
+ if (isNil(ml))
+ break;
+ out << ", ";
+ }
+ return out << ")";
}
/**
@@ -194,6 +206,13 @@ template<typename T> const list<T> mklist(const T& a, const T& b, const T& c, co
}
/**
+ * Construct a list of six values.
+ */
+template<typename T> const list<T> mklist(const T& a, const T& b, const T& c, const T& d, const T& e, const T& f) {
+ return cons(a, cons(b, cons(c, cons(d, cons(e, mklist(f))))));
+}
+
+/**
* Returns the car of a list.
*/
template<typename T> const T car(const list<T>& p) {
@@ -203,11 +222,36 @@ template<typename T> const T car(const list<T>& p) {
/**
* Returns the cdr of a list.
*/
-template<typename T> list<T> const cdr(const list<T>& p) {
+template<typename T> const list<T> cdr(const list<T>& p) {
return p.cdr();
}
/**
+ * Sets the car of a list.
+ */
+template<typename T> const bool setCar(list<T>& p, const T& car) {
+ p.car = car;
+ return true;
+}
+
+/**
+ * Sets the cdr of a list.
+ */
+template<typename T> const bool setCdr(list<T>& p, const list<T>& c) {
+ p.cdr = result(c);
+ return true;
+}
+
+/**
+ * Sets the cdr of a list to a lambda function.
+ */
+template<typename T> const bool setCdr(list<T>& p, const lambda<list<T> ()>& cdr) {
+ p.cdr = cdr;
+ return true;
+}
+
+
+/**
* Returns the car of the cdr of a list.
*/
template<typename T> const T cadr(const list<T>& p) {
@@ -415,25 +459,6 @@ template<typename T> const list<list<T> > unzip(const list<list<T> >& l) {
return mklist<list<T> >(unzipKeys(l), unzipValues(l));
}
-/**
- * Pretty print a list.
- */
-template<typename T> std::ostream& print(const list<T>& l, std::ostream& os) {
- os << "(";
- if (!isNil(l)) {
- list<T> ml = l;
- while(true) {
- os << car(ml);
- ml = cdr(ml);
- if (isNil(ml))
- break;
- os << ", ";
- }
- }
- os << ")";
- return os;
-}
-
}
#endif /* tuscany_list_hpp */
diff --git a/cpp/sca/kernel/value.hpp b/cpp/sca/kernel/value.hpp
index a8140d4892..d57264ff43 100644
--- a/cpp/sca/kernel/value.hpp
+++ b/cpp/sca/kernel/value.hpp
@@ -324,24 +324,24 @@ private:
std::ostream& operator<<(std::ostream& out, const value& v) {
switch(v.type) {
case value::List:
- return out << "List::" << v.lst()();
+ return out << v.lst()();
case value::Lambda:
- return out << "Lambda::" << v.func();
+ return out << "lambda::" << v.func();
case value::Symbol:
- return out << "Symbol::" << v.str()();
+ return out << "symbol::" << v.str()();
case value::String:
- return out << "String::" << '\"' << v.str()() << '\"';
+ return out << "string::" << '\"' << v.str()() << '\"';
case value::Number:
- return out << "Number::" << v.num()();
+ return out << "number::" << v.num()();
case value::Boolean:
if(v.boo()())
- return out << "Boolean::" << "true";
+ return out << "bool::" << "true";
else
- return out << "Boolean::" << "false";
+ return out << "bool::" << "false";
case value::Character:
- return out << "Character::" << v.chr()();
+ return out << "char::" << v.chr()();
default:
- return out << "Undefined";
+ return out << "undefined";
}
}
@@ -383,28 +383,5 @@ const bool isTaggedList(const value& exp, value tag) {
return false;
}
-/**
- * Pretty print a list of values.
- */
-std::ostream& print(const list<value>& l, std::ostream& os) {
- os << "(";
- if (!isNil(l)) {
- list<value> ml = l;
- while(true) {
- const value v = car(ml);
- if (isList(v))
- print(list<value>(v), os);
- else
- os << v;
- ml = cdr(ml);
- if (isNil(ml))
- break;
- os << ", ";
- }
- }
- os << ")";
- return os;
-}
-
}
#endif /* tuscany_value_hpp */
diff --git a/cpp/sca/kernel/xml.hpp b/cpp/sca/kernel/xml.hpp
index 16fddef1ef..afc3f5cc38 100644
--- a/cpp/sca/kernel/xml.hpp
+++ b/cpp/sca/kernel/xml.hpp
@@ -32,6 +32,7 @@
#include <libxml/globals.h>
#include <string>
#include "list.hpp"
+#include "slist.hpp"
#include "value.hpp"
#include "element.hpp"
#include "monad.hpp"
@@ -47,7 +48,7 @@ public:
None = 0, Element = 1, Attribute = 2, Text = 3, EndElement = 15, Identifier = 100, End = 101
};
- XMLReader(xmlTextReaderPtr xml) : xml(xml), tokenType(None) {
+ XMLReader(xmlTextReaderPtr xml) : xml(xml), tokenType(None), isEmptyElement(false), hasValue(false), hasAttributes(false) {
xmlTextReaderSetParserProp(xml, XML_PARSER_DEFAULTATTRS, 1);
xmlTextReaderSetParserProp(xml, XML_PARSER_SUBST_ENTITIES, 1);
}
@@ -204,9 +205,16 @@ const list<value> readXML(const list<std::string>& ilist) {
*/
const char* encoding = "UTF-8";
+
/**
* Write a list of XML element or attribute tokens.
*/
+const list<value> expandElementValues(const value& n, const list<value>& l) {
+ if (isNil(l))
+ return list<value>();
+ return cons<value>(value(cons<value>(element, cons<value>(n, (list<value>)car(l)))), expandElementValues(n, cdr(l)));
+}
+
const failable<bool, std::string> writeList(const list<value>& l, const xmlTextWriterPtr xml) {
if (isNil(l))
return true;
@@ -219,23 +227,50 @@ const failable<bool, std::string> writeList(const list<value>& l, const xmlTextW
} else if (isTaggedList(token, element)) {
- // Write an element
- if (xmlTextWriterStartElement(xml, (const xmlChar*)std::string(elementName(token)).c_str()) < 0)
- return std::string("xmlTextWriterStartElement failed");
+ // Write an element containing a value
+ if (elementHasValue(token)) {
+ const value v = elementValue(token);
+ if (isList(v)) {
+
+ // Write an element per entry in a list of values
+ const list<value> e = expandElementValues(elementName(token), v);
+ writeList(e, xml);
+
+ } else {
- // Write its children
- const failable<bool, std::string> w = writeList(elementChildren(token), xml);
- if (!hasValue(w))
- return w;
+ // Write an element with a single value
+ if (xmlTextWriterStartElement(xml, (const xmlChar*)std::string(elementName(token)).c_str()) < 0)
+ return std::string("xmlTextWriterStartElement failed");
- if (xmlTextWriterEndElement(xml) < 0)
- return std::string("xmlTextWriterEndElement failed");
+ // Write its children
+ const failable<bool, std::string> w = writeList(elementChildren(token), xml);
+ if (!hasValue(w))
+ return w;
+ if (xmlTextWriterEndElement(xml) < 0)
+ return std::string("xmlTextWriterEndElement failed");
+ }
+ }
+ else {
+
+ // Write an element
+ if (xmlTextWriterStartElement(xml, (const xmlChar*)std::string(elementName(token)).c_str()) < 0)
+ return std::string("xmlTextWriterStartElement failed");
+
+ // Write its children
+ const failable<bool, std::string> w = writeList(elementChildren(token), xml);
+ if (!hasValue(w))
+ return w;
+
+ if (xmlTextWriterEndElement(xml) < 0)
+ return std::string("xmlTextWriterEndElement failed");
+ }
} else {
// Write XML text
if (xmlTextWriterWriteString(xml, (const xmlChar*)std::string(token).c_str()) < 0)
return std::string("xmlTextWriterWriteString failed");
+
}
// Go on
diff --git a/cpp/sca/modules/atom/atom-test.cpp b/cpp/sca/modules/atom/atom-test.cpp
index 0cef6b3b60..618f534001 100644
--- a/cpp/sca/modules/atom/atom-test.cpp
+++ b/cpp/sca/modules/atom/atom-test.cpp
@@ -31,8 +31,9 @@
#include "atom.hpp"
namespace tuscany {
+namespace atom {
-std::ostringstream* atomWriter(std::ostringstream* os, const std::string& s) {
+std::ostringstream* writer(std::ostringstream* os, const std::string& s) {
(*os) << s;
return os;
}
@@ -49,22 +50,49 @@ std::string itemEntry("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
"<link href=\"cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b\"/>"
"</entry>\n");
-bool testATOMEntry() {
+std::string incompleteEntry("<entry xmlns=\"http://www.w3.org/2005/Atom\">"
+ "<title>item</title><content type=\"text/xml\">"
+ "<Item xmlns=\"http://services/\">"
+ "<name xmlns=\"\">Orange</name>"
+ "<price xmlns=\"\">3.55</price>"
+ "</Item>"
+ "</content>"
+ "</entry>");
+
+std::string completedEntry("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+ "<entry xmlns=\"http://www.w3.org/2005/Atom\">"
+ "<title type=\"text\">item</title>"
+ "<id></id>"
+ "<content type=\"application/xml\">"
+ "<Item xmlns=\"http://services/\">"
+ "<name xmlns=\"\">Orange</name>"
+ "<price xmlns=\"\">3.55</price>"
+ "</Item>"
+ "</content><link href=\"\"/>"
+ "</entry>\n");
+
+bool testEntry() {
{
const list<value> i = list<value>() << element << "item"
<< (list<value>() << element << "name" << std::string("Apple"))
<< (list<value>() << element << "price" << std::string("$2.99"));
const list<value> a = mklist<value>(std::string("item"), std::string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b"), i);
std::ostringstream os;
- writeATOMEntry<std::ostringstream*>(atomWriter, &os, a);
+ writeEntry<std::ostringstream*>(writer, &os, a);
assert(os.str() == itemEntry);
}
{
- const list<value> a = readATOMEntry(mklist(itemEntry));
+ const list<value> a = readEntry(mklist(itemEntry));
std::ostringstream os;
- writeATOMEntry<std::ostringstream*>(atomWriter, &os, a);
+ writeEntry<std::ostringstream*>(writer, &os, a);
assert(os.str() == itemEntry);
}
+ {
+ const list<value> a = readEntry(mklist(incompleteEntry));
+ std::ostringstream os;
+ writeEntry<std::ostringstream*>(writer, &os, a);
+ assert(os.str() == completedEntry);
+ }
return true;
}
@@ -100,16 +128,16 @@ std::string itemFeed("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
"</entry>"
"</feed>\n");
-bool testATOMFeed() {
+bool testFeed() {
{
std::ostringstream os;
- writeATOMFeed<std::ostringstream*>(atomWriter, &os, mklist<value>("Feed", "1234"));
+ writeFeed<std::ostringstream*>(writer, &os, mklist<value>("Feed", "1234"));
assert(os.str() == emptyFeed);
}
{
- const list<value> a = readATOMFeed(mklist(emptyFeed));
+ const list<value> a = readFeed(mklist(emptyFeed));
std::ostringstream os;
- writeATOMFeed<std::ostringstream*>(atomWriter, &os, a);
+ writeFeed<std::ostringstream*>(writer, &os, a);
assert(os.str() == emptyFeed);
}
{
@@ -124,25 +152,41 @@ bool testATOMFeed() {
<< (list<value>() << element << "price" << "$3.55")));
const list<value> a = cons<value>("Feed", cons<value>("1234", i));
std::ostringstream os;
- writeATOMFeed<std::ostringstream*>(atomWriter, &os, a);
+ writeFeed<std::ostringstream*>(writer, &os, a);
assert(os.str() == itemFeed);
}
{
- const list<value> a = readATOMFeed(mklist(itemFeed));
+ const list<value> i = list<value>()
+ << (list<value>() << "item" << "cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b"
+ << valueToElement(list<value>() << "item"
+ << (list<value>() << "name" << "Apple")
+ << (list<value>() << "price" << "$2.99")))
+ << (list<value>() << "item" << "cart-53d67a61-aa5e-4e5e-8401-39edeba8b83c"
+ << valueToElement(list<value>() << "item"
+ << (list<value>() << "name" << "Orange")
+ << (list<value>() << "price" << "$3.55")));
+ const list<value> a = cons<value>("Feed", cons<value>("1234", i));
std::ostringstream os;
- writeATOMFeed<std::ostringstream*>(atomWriter, &os, a);
+ writeFeed<std::ostringstream*>(writer, &os, a);
+ assert(os.str() == itemFeed);
+ }
+ {
+ const list<value> a = readFeed(mklist(itemFeed));
+ std::ostringstream os;
+ writeFeed<std::ostringstream*>(writer, &os, a);
assert(os.str() == itemFeed);
}
return true;
}
}
+}
int main() {
std::cout << "Testing..." << std::endl;
- tuscany::testATOMEntry();
- tuscany::testATOMFeed();
+ tuscany::atom::testEntry();
+ tuscany::atom::testFeed();
std::cout << "OK" << std::endl;
diff --git a/cpp/sca/modules/atom/atom.hpp b/cpp/sca/modules/atom/atom.hpp
index 5bb8d45e38..78b60da70f 100644
--- a/cpp/sca/modules/atom/atom.hpp
+++ b/cpp/sca/modules/atom/atom.hpp
@@ -33,40 +33,43 @@
#include "xml.hpp"
namespace tuscany {
+namespace atom {
/**
* Convert a list of elements to a list of values representing an ATOM entry.
*/
-const list<value> atomEntry(const list<value>& e) {
- const list<value> t = filter<value>(selector(mklist<value>(element, "title")), e);
- const list<value> i = filter<value>(selector(mklist<value>(element, "id")), e);
- const list<value> c = filter<value>(selector(mklist<value>(element, "content")), e);
- return mklist<value>(elementValue(car(t)), elementValue(car(i)), cadr(elementChildren(car(c))));
+const list<value> entry(const list<value>& e) {
+ const list<value> lt = filter<value>(selector(mklist<value>(element, "title")), e);
+ const value t = isNil(lt)? value(std::string("")) : elementValue(car(lt));
+ const list<value> li = filter<value>(selector(mklist<value>(element, "id")), e);
+ const value i = isNil(li)? value(std::string("")) : elementValue(car(li));
+ const list<value> lc = filter<value>(selector(mklist<value>(element, "content")), e);
+ return mklist<value>(t, i, cadr(elementChildren(car(lc))));
}
/**
* Convert a list of elements to a list of values representing ATOM entries.
*/
-const list<value> atomEntries(const list<value>& e) {
+const list<value> entries(const list<value>& e) {
if (isNil(e))
return list<value>();
- return cons<value>(atomEntry(car(e)), atomEntries(cdr(e)));
+ return cons<value>(entry(car(e)), entries(cdr(e)));
}
/**
* Convert a list of strings to a list of values representing an ATOM entry.
*/
-const failable<list<value>, std::string> readATOMEntry(const list<std::string>& ilist) {
+const failable<list<value>, std::string> readEntry(const list<std::string>& ilist) {
const list<value> e = readXML(ilist);
if (isNil(e))
return std::string("Empty entry");
- return atomEntry(car(e));
+ return entry(car(e));
}
/**
* Convert a list of strings to a list of values representing an ATOM feed.
*/
-const failable<list<value>, std::string> readATOMFeed(const list<std::string>& ilist) {
+const failable<list<value>, std::string> readFeed(const list<std::string>& ilist) {
const list<value> f = readXML(ilist);
if (isNil(f))
return std::string("Empty feed");
@@ -75,14 +78,14 @@ const failable<list<value>, std::string> readATOMFeed(const list<std::string>& i
const list<value> e = filter<value>(selector(mklist<value>(element, "entry")), car(f));
if (isNil(e))
return mklist<value>(elementValue(car(t)), elementValue(car(i)));
- return cons<value>(elementValue(car(t)), cons(elementValue(car(i)), atomEntries(e)));
+ return cons<value>(elementValue(car(t)), cons(elementValue(car(i)), entries(e)));
}
/**
* Convert a list of values representing an ATOM entry to a list of elements.
* The first two values in the list are the entry title and id.
*/
-const list<value> atomEntryElement(const list<value>& l) {
+const list<value> entryElement(const list<value>& l) {
return list<value>()
<< element << "entry" << (list<value>() << attribute << "xmlns" << "http://www.w3.org/2005/Atom")
<< (list<value>() << element << "title" << (list<value>() << attribute << "type" << "text") << car(l))
@@ -94,30 +97,30 @@ const list<value> atomEntryElement(const list<value>& l) {
/**
* Convert a list of values representing ATOM entries to a list of elements.
*/
-const list<value> atomEntriesElements(const list<value>& l) {
+const list<value> entriesElements(const list<value>& l) {
if (isNil(l))
return list<value>();
- return cons<value>(atomEntryElement(car(l)), atomEntriesElements(cdr(l)));
+ return cons<value>(entryElement(car(l)), entriesElements(cdr(l)));
}
/**
* Convert a list of values representing an ATOM entry to an ATOM entry.
* The first two values in the list are the entry id and title.
*/
-template<typename R> const failable<R, std::string> writeATOMEntry(const lambda<R(R, std::string)>& reduce, const R& initial, const list<value>& l) {
- return writeXML<R>(reduce, initial, mklist<value>(atomEntryElement(l)));
+template<typename R> const failable<R, std::string> writeEntry(const lambda<R(R, std::string)>& reduce, const R& initial, const list<value>& l) {
+ return writeXML<R>(reduce, initial, mklist<value>(entryElement(l)));
}
/**
* Convert a list of values representing an ATOM entry to a list of strings.
* The first two values in the list are the entry id and title.
*/
-const list<std::string> writeATOMList(const list<std::string>& listSoFar, const std::string& s) {
+const list<std::string> writeStrings(const list<std::string>& listSoFar, const std::string& s) {
return cons(s, listSoFar);
}
-const failable<list<std::string>, std::string> writeATOMEntry(const list<value>& l) {
- const failable<list<std::string>, std::string> ls = writeATOMEntry<list<std::string> >(writeATOMList, list<std::string>(), l);
+const failable<list<std::string>, std::string> writeEntry(const list<value>& l) {
+ const failable<list<std::string>, std::string> ls = writeEntry<list<std::string> >(writeStrings, list<std::string>(), l);
if (!hasValue(ls))
return ls;
return reverse(list<std::string>(ls));
@@ -127,14 +130,14 @@ const failable<list<std::string>, std::string> writeATOMEntry(const list<value>&
* Convert a list of values representing an ATOM feed to an ATOM feed.
* The first two values in the list are the feed id and title.
*/
-template<typename R> const failable<R, std::string> writeATOMFeed(const lambda<R(R, std::string)>& reduce, const R& initial, const list<value>& l) {
+template<typename R> const failable<R, std::string> writeFeed(const lambda<R(R, std::string)>& reduce, const R& initial, const list<value>& l) {
const list<value> f = list<value>()
<< element << "feed" << (list<value>() << attribute << "xmlns" << "http://www.w3.org/2005/Atom")
<< (list<value>() << element << "title" << (list<value>() << attribute << "type" << "text") << car(l))
<< (list<value>() << element << "id" << cadr(l));
if (isNil(cddr(l)))
return writeXML<R>(reduce, initial, mklist<value>(f));
- const list<value> fe = append(f, atomEntriesElements(cddr(l)));
+ const list<value> fe = append(f, entriesElements(cddr(l)));
return writeXML<R>(reduce, initial, mklist<value>(fe));
}
@@ -142,13 +145,14 @@ template<typename R> const failable<R, std::string> writeATOMFeed(const lambda<R
* Convert a list of values representing an ATOM feed to a list of strings.
* The first two values in the list are the feed id and title.
*/
-const failable<list<std::string>, std::string> writeATOMFeed(const list<value>& l) {
- const failable<list<std::string>, std::string> ls = writeATOMFeed<list<std::string> >(writeATOMList, list<std::string>(), l);
+const failable<list<std::string>, std::string> writeFeed(const list<value>& l) {
+ const failable<list<std::string>, std::string> ls = writeFeed<list<std::string> >(writeStrings, list<std::string>(), l);
if (!hasValue(ls))
return ls;
return reverse(list<std::string>(ls));
}
}
+}
#endif /* tuscany_atom_hpp */
diff --git a/cpp/sca/modules/eval/Makefile.am b/cpp/sca/modules/eval/Makefile.am
index 552e0f99c7..b9fa9f8f56 100644
--- a/cpp/sca/modules/eval/Makefile.am
+++ b/cpp/sca/modules/eval/Makefile.am
@@ -27,3 +27,6 @@ eval_test_LDADD = -lpthread -L${LIBXML2_LIB} -lxml2
eval_shell_SOURCES = eval-shell.cpp
eval_shell_LDADD = -lpthread -L${LIBXML2_LIB} -lxml2
+
+TESTS = eval-test
+
diff --git a/cpp/sca/modules/eval/driver.hpp b/cpp/sca/modules/eval/driver.hpp
index 7a0645781f..064213706c 100644
--- a/cpp/sca/modules/eval/driver.hpp
+++ b/cpp/sca/modules/eval/driver.hpp
@@ -31,6 +31,7 @@
#include "eval.hpp"
namespace tuscany {
+namespace eval {
const std::string evalOutputPrompt("; ");
const std::string evalInputPrompt("=> ");
@@ -57,7 +58,7 @@ const value evalDriverLoop(std::istream& in, std::ostream& out, Env& globalEnv)
value input = read(in);
if (isNil(input))
return input;
- const value output = eval(input, globalEnv);
+ const value output = evalApply(input, globalEnv);
announceOutput(out, evalOutputPrompt);
userPrint(out, output);
return evalDriverLoop(in, out, globalEnv);
@@ -71,4 +72,5 @@ const bool evalDriverRun(std::istream& in, std::ostream& out) {
}
}
+}
#endif /* tuscany_eval_driver_hpp */
diff --git a/cpp/sca/modules/eval/environment.hpp b/cpp/sca/modules/eval/environment.hpp
index 834563069e..e0da9096fe 100644
--- a/cpp/sca/modules/eval/environment.hpp
+++ b/cpp/sca/modules/eval/environment.hpp
@@ -31,10 +31,10 @@
#include "value.hpp"
#include "primitive.hpp"
-namespace tuscany
-{
+namespace tuscany {
+namespace eval {
-typedef value Frame;
+typedef list<value> Frame;
typedef list<value> Env;
const value trueSymbol("true");
@@ -130,28 +130,37 @@ const value assignmentValue(const value& exp) {
return car(cdr(cdr((list<value> )exp)));
}
-const Frame addBindingToFrame(const value& var, const value& val, const Frame& frame) {
- return cons(value(cons(var, frameVariables(frame))), cons(val, frameValues(frame)));
+const bool addBindingToFrame(const value& var, const value& val, Frame& frame) {
+ //frame = cons(value(cons(var, frameVariables(frame))), cons(val, frameValues(frame)));
+ setCar(frame, (value)cons(var, frameVariables(frame)));
+ setCdr(frame, cons(val, frameValues(frame)));
+ return true;
}
-const Env defineVariable(const value& var, const value& val, Env& env) {
- return cons(addBindingToFrame(var, val, firstFrame(env)), cdr(env));
+const bool defineVariable(const value& var, const value& val, Env& env) {
+ Frame frame = firstFrame(env);
+ addBindingToFrame(var, val, frame);
+ setCar(env, value(frame));
+ return true;
}
+struct environmentReference {
+ const Env env;
+ environmentReference(const Env& env) : env(env) {
+ }
+ const Env& operator()() const {
+ return env;
+ }
+};
+
const Env extendEnvironment(const list<value>& vars, const list<value>& vals, const Env& baseEnv) {
-// if(length(vars) == length(vals))
-// else if(length(vars) < length(vals))
-// std::cout << "Too many arguments supplied " << vars << " " << vals << "\n";
-// else
-// std::cout << "Too few arguments supplied " << vars << " " << vals << "\n";
-// return baseEnv;
- return cons(makeFrame(vars, vals), baseEnv);
+ return cons(value(makeFrame(vars, vals)), lambda<list<value>()>(environmentReference(baseEnv)));
}
const Env setupEnvironment() {
Env env = extendEnvironment(primitiveProcedureNames(), primitiveProcedureObjects(), theEmptyEnvironment());
- env = defineVariable(trueSymbol, true, env);
- env = defineVariable(falseSymbol, false, env);
+ defineVariable(trueSymbol, true, env);
+ defineVariable(falseSymbol, false, env);
return env;
}
@@ -178,4 +187,5 @@ const value lookupVariableValue(const value& var, const Env& env) {
}
}
+}
#endif /* tuscany_eval_environment_hpp */
diff --git a/cpp/sca/modules/eval/eval-shell.cpp b/cpp/sca/modules/eval/eval-shell.cpp
index 46710b8354..e1c90101da 100644
--- a/cpp/sca/modules/eval/eval-shell.cpp
+++ b/cpp/sca/modules/eval/eval-shell.cpp
@@ -30,6 +30,6 @@
#include "driver.hpp"
int main() {
- tuscany::evalDriverRun(std::cin, std::cout);
+ tuscany::eval::evalDriverRun(std::cin, std::cout);
return 0;
}
diff --git a/cpp/sca/modules/eval/eval-test.cpp b/cpp/sca/modules/eval/eval-test.cpp
index c536ed51a4..95a286ade0 100644
--- a/cpp/sca/modules/eval/eval-test.cpp
+++ b/cpp/sca/modules/eval/eval-test.cpp
@@ -30,6 +30,7 @@
#include "driver.hpp"
namespace tuscany {
+namespace eval {
bool testEnv() {
Env globalEnv = list<value>();
@@ -109,6 +110,11 @@ const std::string testSchemeLambda(
"(define (testLambda) (if (= 4 (sqrt 2)) (display \"testLambda ok\") (error \"testLambda\"))) "
"(testLambda)");
+const std::string testSchemeForward(
+ "(define (testLambda) (if (= 4 (sqrt 2)) (display \"testForward ok\") (error \"testForward\"))) "
+ "(define sqrt (lambda (x) (* x x))) "
+ "(testLambda)");
+
bool contains(const std::string& str, const std::string& pattern) {
return str.find(pattern) != str.npos;
}
@@ -129,13 +135,14 @@ bool testEval() {
assert(contains(evalOutput(testSchemeBegin), "testBegin1 ok"));
assert(contains(evalOutput(testSchemeBegin), "testBegin2 ok"));
assert(contains(evalOutput(testSchemeLambda), "testLambda ok"));
+ //assert(contains(evalOutput(testSchemeForward), "testForward ok"));
return true;
}
bool testEvalExpr() {
const value exp = mklist<value>("+", 2, 3);
Env env = setupEnvironment();
- const value r = eval(exp, env);
+ const value r = evalApply(exp, env);
assert(r == value(5));
return true;
}
@@ -160,16 +167,17 @@ bool testEvalRun() {
}
}
+}
int main() {
std::cout << "Testing..." << std::endl;
- tuscany::testEnv();
- tuscany::testEnvGC();
- tuscany::testRead();
- tuscany::testEval();
- tuscany::testEvalExpr();
- tuscany::testEvalGC();
+ tuscany::eval::testEnv();
+ tuscany::eval::testEnvGC();
+ tuscany::eval::testRead();
+ tuscany::eval::testEval();
+ tuscany::eval::testEvalExpr();
+ tuscany::eval::testEvalGC();
std::cout << "OK" << std::endl;
return 0;
diff --git a/cpp/sca/modules/eval/eval.hpp b/cpp/sca/modules/eval/eval.hpp
index 2be2894bf3..1496c3bd09 100644
--- a/cpp/sca/modules/eval/eval.hpp
+++ b/cpp/sca/modules/eval/eval.hpp
@@ -33,10 +33,10 @@
#include "read.hpp"
#include "environment.hpp"
-namespace tuscany
-{
+namespace tuscany {
+namespace eval {
-const value eval(const value& exp, Env& env);
+const value evalApply(const value& exp, Env& env);
const value compoundProcedureSymbol("compound-procedure");
const value procedureSymbol("procedure");
@@ -89,7 +89,7 @@ const list<value> operands(const value& exp) {
const list<value> listOfValues(const list<value> exps, Env& env) {
if(isNil(exps))
return list<value> ();
- return cons(eval(car(exps), env), listOfValues(cdr(exps), env));
+ return cons(evalApply(car(exps), env), listOfValues(cdr(exps), env));
}
const value applyOperat(const value& exp) {
@@ -134,8 +134,8 @@ const value makeBegin(const list<value> seq) {
const value evalSequence(const list<value>& exps, Env& env) {
if(isLastExp(exps))
- return eval(firstExp(exps), env);
- eval(firstExp(exps), env);
+ return evalApply(firstExp(exps), env);
+ evalApply(firstExp(exps), env);
return evalSequence(restExp(exps), env);
}
@@ -219,17 +219,17 @@ value condToIf(const value& exp) {
}
value evalIf(const value& exp, Env& env) {
- if(isTrue(eval(ifPredicate(exp), env)))
- return eval(ifConsequent(exp), env);
- return eval(ifAlternative(exp), env);
+ if(isTrue(evalApply(ifPredicate(exp), env)))
+ return evalApply(ifConsequent(exp), env);
+ return evalApply(ifAlternative(exp), env);
}
const value evalDefinition(const value& exp, Env& env) {
- env = defineVariable(definitionVariable(exp), eval(definitionValue(exp), env), env);
+ defineVariable(definitionVariable(exp), evalApply(definitionValue(exp), env), env);
return definitionVariable(exp);
}
-const value eval(const value& exp, Env& env) {
+const value evalApply(const value& exp, Env& env) {
if(isSelfEvaluating(exp))
return exp;
if(isQuoted(exp))
@@ -241,22 +241,23 @@ const value eval(const value& exp, Env& env) {
if(isBegin(exp))
return evalSequence(beginActions(exp), env);
if(isCond(exp))
- return eval(condToIf(exp), env);
+ return evalApply(condToIf(exp), env);
if(isLambda(exp))
return makeProcedure(lambdaParameters(exp), lambdaBody(exp), env);
if(isVariable(exp))
return lookupVariableValue(exp, env);
if(isApply(exp)) {
- list<value> applyOperandValues = eval(applyOperand(exp), env);
- return applyProcedure(eval(applyOperat(exp), env), applyOperandValues);
+ list<value> applyOperandValues = evalApply(applyOperand(exp), env);
+ return applyProcedure(evalApply(applyOperat(exp), env), applyOperandValues);
}
if(isApplication(exp)) {
list<value> operandValues = listOfValues(operands(exp), env);
- return applyProcedure(eval(operat(exp), env), operandValues);
+ return applyProcedure(evalApply(operat(exp), env), operandValues);
}
std::cout << "Unknown expression type " << exp << "\n";
return value();
}
}
+}
#endif /* tuscany_eval_eval_hpp */
diff --git a/cpp/sca/modules/eval/primitive.hpp b/cpp/sca/modules/eval/primitive.hpp
index 0d738d1392..4ca6ea900a 100644
--- a/cpp/sca/modules/eval/primitive.hpp
+++ b/cpp/sca/modules/eval/primitive.hpp
@@ -31,8 +31,8 @@
#include "list.hpp"
#include "value.hpp"
-namespace tuscany
-{
+namespace tuscany {
+namespace eval {
const value primitiveSymbol("primitive");
const value quoteSymbol("'");
@@ -190,4 +190,5 @@ const value makeLambda(const list<value>& parameters, const list<value>& body) {
}
}
+}
#endif /* tuscany_eval_primitive_hpp */
diff --git a/cpp/sca/modules/eval/read.hpp b/cpp/sca/modules/eval/read.hpp
index 189075ded9..994462f145 100644
--- a/cpp/sca/modules/eval/read.hpp
+++ b/cpp/sca/modules/eval/read.hpp
@@ -35,8 +35,8 @@
#include "value.hpp"
#include "primitive.hpp"
-namespace tuscany
-{
+namespace tuscany {
+namespace eval {
const value rightParenthesis(mklist<value>(")"));
const value leftParenthesis(mklist<value>("("));
@@ -180,4 +180,5 @@ const value read(std::istream& in) {
}
}
+}
#endif /* tuscany_eval_read_hpp */
diff --git a/cpp/sca/modules/json/json-test.cpp b/cpp/sca/modules/json/json-test.cpp
index b7cc4e4eeb..bf0ecab1f4 100644
--- a/cpp/sca/modules/json/json-test.cpp
+++ b/cpp/sca/modules/json/json-test.cpp
@@ -31,6 +31,7 @@
#include "json.hpp"
namespace tuscany {
+namespace json {
bool testJSEval() {
JSONContext cx;
@@ -56,49 +57,75 @@ bool testJSON() {
const list<value> cr = mklist<value>(mklist<value> (attribute, "name", std::string("jdoe")), cons<value>(element, cons<value>("address", ad)), cons<value>(element, cons<value>("account", ac)));
const list<value> c = mklist<value>(cons<value>(element, cons<value>("customer", cr)));
std::ostringstream os;
- writeJSON<std::ostringstream*>(cx, jsonWriter, &os, c);
+ write<std::ostringstream*>(cx, jsonWriter, &os, c);
assert(os.str() == "{\"customer\":{\"name\":\"jdoe\",\"address\":{\"city\":\"san francisco\",\"state\":\"ca\"},\"account\":{\"id\":\"1234\",\"balance\":1000}}}");
}
{
const list<value> phones = mklist<value> (std::string("408-1234"), std::string("650-1234"));
- const list<value> l = mklist<value> (mklist<value> (element, "phones", phones), mklist<value> (attribute, "lastName", std::string("test\ttab")), mklist<value> (attribute, "firstName", std::string("test1")));
+ const list<value> l = mklist<value> (mklist<value> (element, "phones", phones), mklist<value> (element, "lastName", std::string("test\ttab")), mklist<value> (element, "firstName", std::string("test1")));
std::ostringstream os;
- writeJSON<std::ostringstream*>(cx, jsonWriter, &os, l);
+ write<std::ostringstream*>(cx, jsonWriter, &os, l);
assert(os.str() == "{\"phones\":[\"408-1234\",\"650-1234\"],\"lastName\":\"test\\u0009tab\",\"firstName\":\"test1\"}");
std::istringstream is(os.str());
const list<std::string> il = streamList(is);
- const list<value> r = readJSON(cx, il);
+ const list<value> r = read(cx, il);
assert(r == l);
std::ostringstream wos;
- write(writeJSON(cx, r), wos);
+ write(write(cx, r), wos);
assert(wos.str() == os.str());
}
return true;
}
bool testJSONRPC() {
- const std::string lm("{\"id\": 1, \"method\": \"system.listMethods\", \"params\": []}");
JSONContext cx;
- const list<value> e = readJSON(cx, mklist(lm));
- const list<value> v = elementsToValues(e);
-
- assert(assoc<value>("id", v) == mklist<value>("id", 1));
- assert(assoc<value>("method", v) == mklist<value>("method", std::string("system.listMethods")));
- assert(assoc<value>("params", v) == mklist<value>("params", list<value>()));
+ {
+ const std::string lm("{\"id\": 1, \"method\": \"system.listMethods\", \"params\": []}");
+ const list<value> e = read(cx, mklist(lm));
+ const list<value> v = elementsToValues(e);
+ assert(assoc<value>("id", v) == mklist<value>("id", 1));
+ assert(assoc<value>("method", v) == mklist<value>("method", std::string("system.listMethods")));
+ assert(assoc<value>("params", v) == mklist<value>("params", list<value>()));
+ }
+ {
+ const std::string i("{\"id\":3,\"result\":[{\"price\":\"$2.99\",\"name\":\"Apple\"},{\"price\":\"$3.55\",\"name\":\"Orange\"},{\"price\":\"$1.55\",\"name\":\"Pear\"}]}");
+ const list<value> e = read(cx, mklist(i));
+ const std::string i2("{\"id\":3,\"result\":{\"0\":{\"price\":\"$2.99\",\"name\":\"Apple\"},\"1\":{\"price\":\"$3.55\",\"name\":\"Orange\"},\"2\":{\"price\":\"$1.55\",\"name\":\"Pear\"}}}");
+ const list<value> e2 = read(cx, mklist(i));
+ assert(e == e2);
+ }
+ {
+ const std::string i("{\"id\":3,\"result\":[{\"price\":\"$2.99\",\"name\":\"Apple\"},{\"price\":\"$3.55\",\"name\":\"Orange\"},{\"price\":\"$1.55\",\"name\":\"Pear\"}]}");
+ const list<value> e = read(cx, mklist(i));
+ std::ostringstream os;
+ write(write(cx, e), os);
+ assert(os.str() == i);
+ const list<value> v = elementsToValues(e);
+ const list<value> r = valuesToElements(v);
+ assert(r == e);
+ }
+ {
+ const list<value> r = mklist<value>(mklist<value>("id", 1), mklist<value>("result", mklist<value>(std::string("Service.get"), std::string("Service.getTotal"))));
+ const list<value> e = valuesToElements(r);
+ std::ostringstream os;
+ write(write(cx, e), os);
+ assert(os.str() == "{\"id\":1,\"result\":[\"Service.get\",\"Service.getTotal\"]}");
+ }
return true;
}
}
+}
int main() {
std::cout << "Testing..." << std::endl;
- tuscany::testJSEval();
- tuscany::testJSON();
- tuscany::testJSONRPC();
+ tuscany::json::testJSEval();
+ tuscany::json::testJSON();
+ tuscany::json::testJSONRPC();
std::cout << "OK" << std::endl;
diff --git a/cpp/sca/modules/json/json.hpp b/cpp/sca/modules/json/json.hpp
index 5f3d8c21e0..8e4666196e 100644
--- a/cpp/sca/modules/json/json.hpp
+++ b/cpp/sca/modules/json/json.hpp
@@ -35,6 +35,7 @@
#include "monad.hpp"
namespace tuscany {
+namespace json {
/**
* Report JSON errors.
@@ -155,7 +156,7 @@ const list<value> jsPropertiesToValues(const JSONContext& cx, const list<value>&
jsval idv;
JS_IdToValue(cx, id, &idv);
if(JSVAL_IS_STRING(idv)) {
- const value type = isList(val)? element : attribute;
+ const value type = isList(val)? element : element;
return jsPropertiesToValues(cx, cons<value> (mklist<value> (type, JS_GetStringBytes(JSVAL_TO_STRING(idv)), val), propertiesSoFar), o, i);
}
return jsPropertiesToValues(cx, cons(val, propertiesSoFar), o, i);
@@ -194,25 +195,25 @@ const value jsValToValue(const JSONContext& cx, const jsval& jsv) {
/**
* Consumes JSON strings and populates a JS object.
*/
-failable<bool, std::string> consumeJSON(const JSONContext& cx, JSONParser* parser, const list<std::string>& ilist) {
+failable<bool, std::string> consume(const JSONContext& cx, JSONParser* parser, const list<std::string>& ilist) {
if (isNil(ilist))
return true;
JSString* jstr = JS_NewStringCopyZ(cx, car(ilist).c_str());
if(!JS_ConsumeJSONText(cx, parser, JS_GetStringChars(jstr), JS_GetStringLength(jstr)))
return "JS_ConsumeJSONText failed";
- return consumeJSON(cx, parser, cdr(ilist));
+ return consume(cx, parser, cdr(ilist));
}
/**
* Convert a list of strings representing a JSON document to a list of values.
*/
-const failable<list<value>, std::string> readJSON(const JSONContext& cx, const list<std::string>& ilist) {
+const failable<list<value>, std::string> read(const JSONContext& cx, const list<std::string>& ilist) {
jsval val;
JSONParser* parser = JS_BeginJSONParse(cx, &val);
if(parser == NULL)
return std::string("JS_BeginJSONParse failed");
- const failable<bool, std::string> consumed = consumeJSON(cx, parser, ilist);
+ const failable<bool, std::string> consumed = consume(cx, parser, ilist);
if(!JS_FinishJSONParse(cx, parser, JSVAL_NULL))
return std::string("JS_FinishJSONParse failed");
@@ -235,6 +236,36 @@ JSObject* valuesToJSElements(const JSONContext& cx, JSObject* a, const list<valu
}
/**
+ * Returns true if a list represents a JS array.
+ */
+const bool isJSArray(const list<value>& l) {
+ if(isNil(l))
+ return false;
+ const value v = car(l);
+ if(isList(v)) {
+ const list<value> p = v;
+ if(isSymbol(car(p)))
+ return false;
+ }
+ return true;
+}
+
+
+
+/**
+ * Converts a list of values to JS properties.
+ */
+JSObject* valuesToJSProperties(const JSONContext& cx, JSObject* o, const list<value>& l) {
+ const jsval valueToJSVal(const JSONContext& cx, const value& val);
+ if(isNil(l))
+ return o;
+ const list<value> p = car(l);
+ jsval pv = valueToJSVal(cx, caddr(p));
+ JS_SetProperty(cx, o, ((std::string)cadr(p)).c_str(), &pv);
+ return valuesToJSProperties(cx, o, cdr(l));
+}
+
+/**
* Converts a value to a JS val.
*/
const jsval valueToJSVal(const JSONContext& cx, const value& val) {
@@ -250,7 +281,9 @@ const jsval valueToJSVal(const JSONContext& cx, const value& val) {
return DOUBLE_TO_JSVAL(JS_NewDouble(cx, (double)val));
}
case value::List: {
- return OBJECT_TO_JSVAL(valuesToJSElements(cx, JS_NewArrayObject(cx, 0, NULL), val, 0));
+ if (isJSArray(val))
+ return OBJECT_TO_JSVAL(valuesToJSElements(cx, JS_NewArrayObject(cx, 0, NULL), val, 0));
+ return OBJECT_TO_JSVAL(valuesToJSProperties(cx, JS_NewObject(cx, NULL, NULL, NULL), val));
}
default: {
return JSVAL_VOID;
@@ -297,9 +330,9 @@ const failable<bool, std::string> writeList(const JSONContext& cx, const list<va
/**
* Context passed to the JSON write callback function.
*/
-template<typename R> class JSONWriteContext {
+template<typename R> class WriteContext {
public:
- JSONWriteContext(const JSONContext& cx, const lambda<R(R, std::string)>& reduce, const R& accum) : cx(cx), reduce(reduce), accum(accum) {
+ WriteContext(const JSONContext& cx, const lambda<R(R, std::string)>& reduce, const R& accum) : cx(cx), reduce(reduce), accum(accum) {
}
const JSONContext& cx;
const lambda<R(R, std::string)> reduce;
@@ -310,7 +343,7 @@ public:
* Called by JS_Stringify to write JSON out.
*/
template<typename R> JSBool writeCallback(const jschar *buf, uint32 len, void *data) {
- JSONWriteContext<R>& wcx = *(static_cast<JSONWriteContext<R>*> (data));
+ WriteContext<R>& wcx = *(static_cast<WriteContext<R>*> (data));
JSString* jstr = JS_NewUCStringCopyN(wcx.cx, buf, len);
wcx.accum = wcx.reduce(wcx.accum, std::string(JS_GetStringBytes(jstr), JS_GetStringLength(jstr)));
return JS_TRUE;
@@ -319,14 +352,14 @@ template<typename R> JSBool writeCallback(const jschar *buf, uint32 len, void *d
/**
* Convert a list of values to a JSON document.
*/
-template<typename R> const failable<R, std::string> writeJSON(const JSONContext& cx, const lambda<R(R, std::string)>& reduce, const R& initial, const list<value>& l) {
+template<typename R> const failable<R, std::string> write(const JSONContext& cx, const lambda<R(R, std::string)>& reduce, const R& initial, const list<value>& l) {
JSObject* o = JS_NewObject(cx, NULL, NULL, NULL);
jsval val = OBJECT_TO_JSVAL(o);
const failable<bool, std::string> w = writeList(cx, l, o);
if (!hasValue(w))
return std::string(w);
- JSONWriteContext<R> wcx(cx, reduce, initial);
+ WriteContext<R> wcx(cx, reduce, initial);
if (!JS_Stringify(cx, &val, NULL, JSVAL_NULL, writeCallback<R>, &wcx))
return std::string("JS_Stringify failed");
return wcx.accum;
@@ -335,17 +368,18 @@ template<typename R> const failable<R, std::string> writeJSON(const JSONContext&
/**
* Convert a list of values to a list of strings representing a JSON document.
*/
-const list<std::string> writeJSONList(const list<std::string>& listSoFar, const std::string& s) {
+const list<std::string> writeStrings(const list<std::string>& listSoFar, const std::string& s) {
return cons(s, listSoFar);
}
-const failable<list<std::string>, std::string> writeJSON(const JSONContext& cx, const list<value>& l) {
- const failable<list<std::string>, std::string> ls = writeJSON<list<std::string> >(cx, writeJSONList, list<std::string>(), l);
+const failable<list<std::string>, std::string> write(const JSONContext& cx, const list<value>& l) {
+ const failable<list<std::string>, std::string> ls = write<list<std::string> >(cx, writeStrings, list<std::string>(), l);
if (!hasValue(ls))
return ls;
return reverse(list<std::string>(ls));
}
}
+}
#endif /* tuscany_json_hpp */