diff options
-rw-r--r-- | cpp/sca/kernel/element.hpp | 143 | ||||
-rw-r--r-- | cpp/sca/kernel/function.hpp | 4 | ||||
-rw-r--r-- | cpp/sca/kernel/kernel-test.cpp | 75 | ||||
-rw-r--r-- | cpp/sca/kernel/list.hpp | 71 | ||||
-rw-r--r-- | cpp/sca/kernel/value.hpp | 41 | ||||
-rw-r--r-- | cpp/sca/kernel/xml.hpp | 55 | ||||
-rw-r--r-- | cpp/sca/modules/atom/atom-test.cpp | 72 | ||||
-rw-r--r-- | cpp/sca/modules/atom/atom.hpp | 50 | ||||
-rw-r--r-- | cpp/sca/modules/eval/Makefile.am | 3 | ||||
-rw-r--r-- | cpp/sca/modules/eval/driver.hpp | 4 | ||||
-rw-r--r-- | cpp/sca/modules/eval/environment.hpp | 42 | ||||
-rw-r--r-- | cpp/sca/modules/eval/eval-shell.cpp | 2 | ||||
-rw-r--r-- | cpp/sca/modules/eval/eval-test.cpp | 22 | ||||
-rw-r--r-- | cpp/sca/modules/eval/eval.hpp | 31 | ||||
-rw-r--r-- | cpp/sca/modules/eval/primitive.hpp | 5 | ||||
-rw-r--r-- | cpp/sca/modules/eval/read.hpp | 5 | ||||
-rw-r--r-- | cpp/sca/modules/json/json-test.cpp | 57 | ||||
-rw-r--r-- | cpp/sca/modules/json/json.hpp | 62 |
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 */ |