From f61164c77c5c21a32b58ad61c868bd8ff6a4a79e Mon Sep 17 00:00:00 2001 From: jsdelfino Date: Mon, 26 Oct 2009 05:13:06 +0000 Subject: 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 --- cpp/sca/modules/atom/atom-test.cpp | 72 +++++++++++++++++++++++++++++------- cpp/sca/modules/atom/atom.hpp | 50 +++++++++++++------------ cpp/sca/modules/eval/Makefile.am | 3 ++ cpp/sca/modules/eval/driver.hpp | 4 +- cpp/sca/modules/eval/environment.hpp | 42 +++++++++++++-------- cpp/sca/modules/eval/eval-shell.cpp | 2 +- cpp/sca/modules/eval/eval-test.cpp | 22 +++++++---- cpp/sca/modules/eval/eval.hpp | 31 ++++++++-------- cpp/sca/modules/eval/primitive.hpp | 5 ++- cpp/sca/modules/eval/read.hpp | 5 ++- cpp/sca/modules/json/json-test.cpp | 57 ++++++++++++++++++++-------- cpp/sca/modules/json/json.hpp | 62 ++++++++++++++++++++++++------- 12 files changed, 245 insertions(+), 110 deletions(-) (limited to 'cpp/sca/modules') 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("\n" "" "\n"); -bool testATOMEntry() { +std::string incompleteEntry("" + "item" + "" + "Orange" + "3.55" + "" + "" + ""); + +std::string completedEntry("\n" + "" + "item" + "" + "" + "" + "Orange" + "3.55" + "" + "" + "\n"); + +bool testEntry() { { const list i = list() << element << "item" << (list() << element << "name" << std::string("Apple")) << (list() << element << "price" << std::string("$2.99")); const list a = mklist(std::string("item"), std::string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b"), i); std::ostringstream os; - writeATOMEntry(atomWriter, &os, a); + writeEntry(writer, &os, a); assert(os.str() == itemEntry); } { - const list a = readATOMEntry(mklist(itemEntry)); + const list a = readEntry(mklist(itemEntry)); std::ostringstream os; - writeATOMEntry(atomWriter, &os, a); + writeEntry(writer, &os, a); assert(os.str() == itemEntry); } + { + const list a = readEntry(mklist(incompleteEntry)); + std::ostringstream os; + writeEntry(writer, &os, a); + assert(os.str() == completedEntry); + } return true; } @@ -100,16 +128,16 @@ std::string itemFeed("\n" "" "\n"); -bool testATOMFeed() { +bool testFeed() { { std::ostringstream os; - writeATOMFeed(atomWriter, &os, mklist("Feed", "1234")); + writeFeed(writer, &os, mklist("Feed", "1234")); assert(os.str() == emptyFeed); } { - const list a = readATOMFeed(mklist(emptyFeed)); + const list a = readFeed(mklist(emptyFeed)); std::ostringstream os; - writeATOMFeed(atomWriter, &os, a); + writeFeed(writer, &os, a); assert(os.str() == emptyFeed); } { @@ -124,25 +152,41 @@ bool testATOMFeed() { << (list() << element << "price" << "$3.55"))); const list a = cons("Feed", cons("1234", i)); std::ostringstream os; - writeATOMFeed(atomWriter, &os, a); + writeFeed(writer, &os, a); assert(os.str() == itemFeed); } { - const list a = readATOMFeed(mklist(itemFeed)); + const list i = list() + << (list() << "item" << "cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b" + << valueToElement(list() << "item" + << (list() << "name" << "Apple") + << (list() << "price" << "$2.99"))) + << (list() << "item" << "cart-53d67a61-aa5e-4e5e-8401-39edeba8b83c" + << valueToElement(list() << "item" + << (list() << "name" << "Orange") + << (list() << "price" << "$3.55"))); + const list a = cons("Feed", cons("1234", i)); std::ostringstream os; - writeATOMFeed(atomWriter, &os, a); + writeFeed(writer, &os, a); + assert(os.str() == itemFeed); + } + { + const list a = readFeed(mklist(itemFeed)); + std::ostringstream os; + writeFeed(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 atomEntry(const list& e) { - const list t = filter(selector(mklist(element, "title")), e); - const list i = filter(selector(mklist(element, "id")), e); - const list c = filter(selector(mklist(element, "content")), e); - return mklist(elementValue(car(t)), elementValue(car(i)), cadr(elementChildren(car(c)))); +const list entry(const list& e) { + const list lt = filter(selector(mklist(element, "title")), e); + const value t = isNil(lt)? value(std::string("")) : elementValue(car(lt)); + const list li = filter(selector(mklist(element, "id")), e); + const value i = isNil(li)? value(std::string("")) : elementValue(car(li)); + const list lc = filter(selector(mklist(element, "content")), e); + return mklist(t, i, cadr(elementChildren(car(lc)))); } /** * Convert a list of elements to a list of values representing ATOM entries. */ -const list atomEntries(const list& e) { +const list entries(const list& e) { if (isNil(e)) return list(); - return cons(atomEntry(car(e)), atomEntries(cdr(e))); + return cons(entry(car(e)), entries(cdr(e))); } /** * Convert a list of strings to a list of values representing an ATOM entry. */ -const failable, std::string> readATOMEntry(const list& ilist) { +const failable, std::string> readEntry(const list& ilist) { const list 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, std::string> readATOMFeed(const list& ilist) { +const failable, std::string> readFeed(const list& ilist) { const list f = readXML(ilist); if (isNil(f)) return std::string("Empty feed"); @@ -75,14 +78,14 @@ const failable, std::string> readATOMFeed(const list& i const list e = filter(selector(mklist(element, "entry")), car(f)); if (isNil(e)) return mklist(elementValue(car(t)), elementValue(car(i))); - return cons(elementValue(car(t)), cons(elementValue(car(i)), atomEntries(e))); + return cons(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 atomEntryElement(const list& l) { +const list entryElement(const list& l) { return list() << element << "entry" << (list() << attribute << "xmlns" << "http://www.w3.org/2005/Atom") << (list() << element << "title" << (list() << attribute << "type" << "text") << car(l)) @@ -94,30 +97,30 @@ const list atomEntryElement(const list& l) { /** * Convert a list of values representing ATOM entries to a list of elements. */ -const list atomEntriesElements(const list& l) { +const list entriesElements(const list& l) { if (isNil(l)) return list(); - return cons(atomEntryElement(car(l)), atomEntriesElements(cdr(l))); + return cons(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 const failable writeATOMEntry(const lambda& reduce, const R& initial, const list& l) { - return writeXML(reduce, initial, mklist(atomEntryElement(l))); +template const failable writeEntry(const lambda& reduce, const R& initial, const list& l) { + return writeXML(reduce, initial, mklist(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 writeATOMList(const list& listSoFar, const std::string& s) { +const list writeStrings(const list& listSoFar, const std::string& s) { return cons(s, listSoFar); } -const failable, std::string> writeATOMEntry(const list& l) { - const failable, std::string> ls = writeATOMEntry >(writeATOMList, list(), l); +const failable, std::string> writeEntry(const list& l) { + const failable, std::string> ls = writeEntry >(writeStrings, list(), l); if (!hasValue(ls)) return ls; return reverse(list(ls)); @@ -127,14 +130,14 @@ const failable, std::string> writeATOMEntry(const list& * 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 const failable writeATOMFeed(const lambda& reduce, const R& initial, const list& l) { +template const failable writeFeed(const lambda& reduce, const R& initial, const list& l) { const list f = list() << element << "feed" << (list() << attribute << "xmlns" << "http://www.w3.org/2005/Atom") << (list() << element << "title" << (list() << attribute << "type" << "text") << car(l)) << (list() << element << "id" << cadr(l)); if (isNil(cddr(l))) return writeXML(reduce, initial, mklist(f)); - const list fe = append(f, atomEntriesElements(cddr(l))); + const list fe = append(f, entriesElements(cddr(l))); return writeXML(reduce, initial, mklist(fe)); } @@ -142,13 +145,14 @@ template const failable writeATOMFeed(const lambda, std::string> writeATOMFeed(const list& l) { - const failable, std::string> ls = writeATOMFeed >(writeATOMList, list(), l); +const failable, std::string> writeFeed(const list& l) { + const failable, std::string> ls = writeFeed >(writeStrings, list(), l); if (!hasValue(ls)) return ls; return reverse(list(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); @@ -70,5 +71,6 @@ const bool evalDriverRun(std::istream& in, std::ostream& out) { return true; } +} } #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 Frame; typedef list Env; const value trueSymbol("true"); @@ -130,28 +130,37 @@ const value assignmentValue(const value& exp) { return car(cdr(cdr((list )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& vars, const list& 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()>(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; } @@ -177,5 +186,6 @@ const value lookupVariableValue(const value& var, const Env& env) { return lookupEnvLoop(var, 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(); @@ -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("+", 2, 3); Env env = setupEnvironment(); - const value r = eval(exp, env); + const value r = evalApply(exp, env); assert(r == value(5)); return true; } @@ -159,17 +166,18 @@ bool testEvalRun() { return true; } +} } 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 operands(const value& exp) { const list listOfValues(const list exps, Env& env) { if(isNil(exps)) return list (); - 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 seq) { const value evalSequence(const list& 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 applyOperandValues = eval(applyOperand(exp), env); - return applyProcedure(eval(applyOperat(exp), env), applyOperandValues); + list applyOperandValues = evalApply(applyOperand(exp), env); + return applyProcedure(evalApply(applyOperat(exp), env), applyOperandValues); } if(isApplication(exp)) { list 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("'"); @@ -189,5 +189,6 @@ const value makeLambda(const list& parameters, const list& body) { return cons(lambdaSymbol, cons(parameters, 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(")")); const value leftParenthesis(mklist("(")); @@ -179,5 +179,6 @@ const value read(std::istream& in) { return nextToken; } +} } #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 cr = mklist(mklist (attribute, "name", std::string("jdoe")), cons(element, cons("address", ad)), cons(element, cons("account", ac))); const list c = mklist(cons(element, cons("customer", cr))); std::ostringstream os; - writeJSON(cx, jsonWriter, &os, c); + write(cx, jsonWriter, &os, c); assert(os.str() == "{\"customer\":{\"name\":\"jdoe\",\"address\":{\"city\":\"san francisco\",\"state\":\"ca\"},\"account\":{\"id\":\"1234\",\"balance\":1000}}}"); } { const list phones = mklist (std::string("408-1234"), std::string("650-1234")); - const list l = mklist (mklist (element, "phones", phones), mklist (attribute, "lastName", std::string("test\ttab")), mklist (attribute, "firstName", std::string("test1"))); + const list l = mklist (mklist (element, "phones", phones), mklist (element, "lastName", std::string("test\ttab")), mklist (element, "firstName", std::string("test1"))); std::ostringstream os; - writeJSON(cx, jsonWriter, &os, l); + write(cx, jsonWriter, &os, l); assert(os.str() == "{\"phones\":[\"408-1234\",\"650-1234\"],\"lastName\":\"test\\u0009tab\",\"firstName\":\"test1\"}"); std::istringstream is(os.str()); const list il = streamList(is); - const list r = readJSON(cx, il); + const list 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 e = readJSON(cx, mklist(lm)); - const list v = elementsToValues(e); - - assert(assoc("id", v) == mklist("id", 1)); - assert(assoc("method", v) == mklist("method", std::string("system.listMethods"))); - assert(assoc("params", v) == mklist("params", list())); + { + const std::string lm("{\"id\": 1, \"method\": \"system.listMethods\", \"params\": []}"); + const list e = read(cx, mklist(lm)); + const list v = elementsToValues(e); + assert(assoc("id", v) == mklist("id", 1)); + assert(assoc("method", v) == mklist("method", std::string("system.listMethods"))); + assert(assoc("params", v) == mklist("params", list())); + } + { + const std::string i("{\"id\":3,\"result\":[{\"price\":\"$2.99\",\"name\":\"Apple\"},{\"price\":\"$3.55\",\"name\":\"Orange\"},{\"price\":\"$1.55\",\"name\":\"Pear\"}]}"); + const list 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 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 e = read(cx, mklist(i)); + std::ostringstream os; + write(write(cx, e), os); + assert(os.str() == i); + const list v = elementsToValues(e); + const list r = valuesToElements(v); + assert(r == e); + } + { + const list r = mklist(mklist("id", 1), mklist("result", mklist(std::string("Service.get"), std::string("Service.getTotal")))); + const list 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 jsPropertiesToValues(const JSONContext& cx, const list& 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 (mklist (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 consumeJSON(const JSONContext& cx, JSONParser* parser, const list& ilist) { +failable consume(const JSONContext& cx, JSONParser* parser, const list& 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, std::string> readJSON(const JSONContext& cx, const list& ilist) { +const failable, std::string> read(const JSONContext& cx, const list& ilist) { jsval val; JSONParser* parser = JS_BeginJSONParse(cx, &val); if(parser == NULL) return std::string("JS_BeginJSONParse failed"); - const failable consumed = consumeJSON(cx, parser, ilist); + const failable consumed = consume(cx, parser, ilist); if(!JS_FinishJSONParse(cx, parser, JSVAL_NULL)) return std::string("JS_FinishJSONParse failed"); @@ -234,6 +235,36 @@ JSObject* valuesToJSElements(const JSONContext& cx, JSObject* a, const list& l) { + if(isNil(l)) + return false; + const value v = car(l); + if(isList(v)) { + const list 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& l) { + const jsval valueToJSVal(const JSONContext& cx, const value& val); + if(isNil(l)) + return o; + const list 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. */ @@ -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 writeList(const JSONContext& cx, const list class JSONWriteContext { +template class WriteContext { public: - JSONWriteContext(const JSONContext& cx, const lambda& reduce, const R& accum) : cx(cx), reduce(reduce), accum(accum) { + WriteContext(const JSONContext& cx, const lambda& reduce, const R& accum) : cx(cx), reduce(reduce), accum(accum) { } const JSONContext& cx; const lambda reduce; @@ -310,7 +343,7 @@ public: * Called by JS_Stringify to write JSON out. */ template JSBool writeCallback(const jschar *buf, uint32 len, void *data) { - JSONWriteContext& wcx = *(static_cast*> (data)); + WriteContext& wcx = *(static_cast*> (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 JSBool writeCallback(const jschar *buf, uint32 len, void *d /** * Convert a list of values to a JSON document. */ -template const failable writeJSON(const JSONContext& cx, const lambda& reduce, const R& initial, const list& l) { +template const failable write(const JSONContext& cx, const lambda& reduce, const R& initial, const list& l) { JSObject* o = JS_NewObject(cx, NULL, NULL, NULL); jsval val = OBJECT_TO_JSVAL(o); const failable w = writeList(cx, l, o); if (!hasValue(w)) return std::string(w); - JSONWriteContext wcx(cx, reduce, initial); + WriteContext wcx(cx, reduce, initial); if (!JS_Stringify(cx, &val, NULL, JSVAL_NULL, writeCallback, &wcx)) return std::string("JS_Stringify failed"); return wcx.accum; @@ -335,17 +368,18 @@ template const failable writeJSON(const JSONContext& /** * Convert a list of values to a list of strings representing a JSON document. */ -const list writeJSONList(const list& listSoFar, const std::string& s) { +const list writeStrings(const list& listSoFar, const std::string& s) { return cons(s, listSoFar); } -const failable, std::string> writeJSON(const JSONContext& cx, const list& l) { - const failable, std::string> ls = writeJSON >(cx, writeJSONList, list(), l); +const failable, std::string> write(const JSONContext& cx, const list& l) { + const failable, std::string> ls = write >(cx, writeStrings, list(), l); if (!hasValue(ls)) return ls; return reverse(list(ls)); } +} } #endif /* tuscany_json_hpp */ -- cgit v1.2.3