Merge lp:~zorba-coders/zorba/feature-json_parser into lp:zorba

Proposed by Paul J. Lucas
Status: Merged
Approved by: Paul J. Lucas
Approved revision: 10650
Merged at revision: 10662
Proposed branch: lp:~zorba-coders/zorba/feature-json_parser
Merge into: lp:zorba
Diff against target: 6765 lines (+5533/-73)
164 files modified
ChangeLog (+1/-0)
include/zorba/diagnostic.h (+4/-1)
include/zorba/internal/ztd.h (+2/-1)
include/zorba/pregenerated/diagnostic_list.h (+34/-0)
modules/ExternalModules.conf (+1/-1)
modules/com/zorba-xquery/www/modules/CMakeLists.txt (+4/-0)
modules/com/zorba-xquery/www/modules/converters/json-options.xsd (+60/-0)
modules/com/zorba-xquery/www/modules/converters/json.xq (+260/-0)
modules/com/zorba-xquery/www/modules/pregenerated/errors.xq (+69/-1)
src/context/static_context.cpp (+7/-0)
src/context/static_context.h (+1/-0)
src/diagnostics/diagnostic.cpp (+3/-0)
src/diagnostics/diagnostic_en.xml (+65/-0)
src/diagnostics/pregenerated/diagnostic_list.cpp (+51/-0)
src/diagnostics/pregenerated/dict_en.cpp (+19/-0)
src/diagnostics/qname.cpp (+6/-0)
src/functions/library.cpp (+2/-0)
src/functions/pregenerated/func_json.cpp (+87/-0)
src/functions/pregenerated/func_json.h (+79/-0)
src/functions/pregenerated/function_enum.h (+2/-0)
src/runtime/CMakeLists.txt (+3/-0)
src/runtime/full_text/ft_match.cpp (+2/-3)
src/runtime/json/common.cpp (+62/-0)
src/runtime/json/common.h (+120/-0)
src/runtime/json/json_impl.cpp (+217/-0)
src/runtime/json/jsonml_array.cpp (+285/-0)
src/runtime/json/jsonml_array.h (+41/-0)
src/runtime/json/pregenerated/json.cpp (+94/-0)
src/runtime/json/pregenerated/json.h (+114/-0)
src/runtime/json/snelson.cpp (+515/-0)
src/runtime/json/snelson.h (+41/-0)
src/runtime/spec/json/json.xml (+52/-0)
src/runtime/spec/mappings.xml (+4/-0)
src/runtime/visitors/pregenerated/planiter_visitor.h (+10/-0)
src/runtime/visitors/pregenerated/printer_visitor.cpp (+29/-0)
src/runtime/visitors/pregenerated/printer_visitor.h (+6/-0)
src/unit_tests/CMakeLists.txt (+2/-0)
src/unit_tests/json_parser.cpp (+636/-0)
src/unit_tests/unit_test_list.h (+1/-0)
src/unit_tests/unit_tests.cpp (+1/-0)
src/util/CMakeLists.txt (+2/-0)
src/util/json_parser.cpp (+662/-0)
src/util/json_parser.h (+570/-0)
src/util/mem_streambuf.cpp (+119/-0)
src/util/mem_streambuf.h (+108/-0)
src/util/omanip.h (+205/-57)
src/util/oseparator.h (+17/-5)
src/util/stl_util.h (+51/-2)
src/util/string_util.h (+2/-1)
test/rbkt/ExpQueryResults/zorba/json/json-jsonml_array-parse-01.xml.res (+1/-0)
test/rbkt/ExpQueryResults/zorba/json/json-jsonml_array-parse-02.xml.res (+4/-0)
test/rbkt/ExpQueryResults/zorba/json/json-jsonml_array-parse-03.xml.res (+1/-0)
test/rbkt/ExpQueryResults/zorba/json/json-jsonml_array-parse-04.xml.res (+7/-0)
test/rbkt/ExpQueryResults/zorba/json/json-jsonml_array-parse-05.xml.res (+1/-0)
test/rbkt/ExpQueryResults/zorba/json/json-jsonml_array-parse-wikipedia.xml.res (+10/-0)
test/rbkt/ExpQueryResults/zorba/json/json-jsonml_array-serialize-01.xml.res (+1/-0)
test/rbkt/ExpQueryResults/zorba/json/json-jsonml_array-serialize-02.xml.res (+1/-0)
test/rbkt/ExpQueryResults/zorba/json/json-jsonml_array-serialize-03.xml.res (+1/-0)
test/rbkt/ExpQueryResults/zorba/json/json-jsonml_array-serialize-indent-wikipedia.xml.res (+11/-0)
test/rbkt/ExpQueryResults/zorba/json/json-jsonml_array-serialize-none-wikipedia.xml.res (+1/-0)
test/rbkt/ExpQueryResults/zorba/json/json-jsonml_array-serialize-some-wikipedia.xml.res (+1/-0)
test/rbkt/ExpQueryResults/zorba/json/json-snelson-null-handling.xml.res (+3/-0)
test/rbkt/ExpQueryResults/zorba/json/json-snelson-numbers-and-decimals.xml.res (+7/-0)
test/rbkt/ExpQueryResults/zorba/json/json-snelson-parse-array-01.xml.res (+3/-0)
test/rbkt/ExpQueryResults/zorba/json/json-snelson-parse-array-02.xml.res (+3/-0)
test/rbkt/ExpQueryResults/zorba/json/json-snelson-parse-array-03.xml.res (+3/-0)
test/rbkt/ExpQueryResults/zorba/json/json-snelson-parse-array-04.xml.res (+3/-0)
test/rbkt/ExpQueryResults/zorba/json/json-snelson-parse-array-05.xml.res (+4/-0)
test/rbkt/ExpQueryResults/zorba/json/json-snelson-parse-array-06.xml.res (+8/-0)
test/rbkt/ExpQueryResults/zorba/json/json-snelson-parse-array-07.xml.res (+10/-0)
test/rbkt/ExpQueryResults/zorba/json/json-snelson-parse-array-08.xml.res (+6/-0)
test/rbkt/ExpQueryResults/zorba/json/json-snelson-parse-example.xml.res (+14/-0)
test/rbkt/ExpQueryResults/zorba/json/json-snelson-parse-object-01.xml.res (+3/-0)
test/rbkt/ExpQueryResults/zorba/json/json-snelson-parse-object-02.xml.res (+4/-0)
test/rbkt/ExpQueryResults/zorba/json/json-snelson-parse-object-03.xml.res (+8/-0)
test/rbkt/ExpQueryResults/zorba/json/json-snelson-parse-object-04.xml.res (+6/-0)
test/rbkt/ExpQueryResults/zorba/json/json-snelson-parse-serialize.xml.res (+3/-0)
test/rbkt/ExpQueryResults/zorba/json/json-snelson-serialize-array-01.xml.res (+1/-0)
test/rbkt/ExpQueryResults/zorba/json/json-snelson-serialize-array-02.xml.res (+1/-0)
test/rbkt/ExpQueryResults/zorba/json/json-snelson-serialize-array-03.xml.res (+1/-0)
test/rbkt/ExpQueryResults/zorba/json/json-snelson-serialize-array-04.xml.res (+1/-0)
test/rbkt/ExpQueryResults/zorba/json/json-snelson-serialize-array-05.xml.res (+1/-0)
test/rbkt/ExpQueryResults/zorba/json/json-snelson-serialize-array-12.xml.res (+1/-0)
test/rbkt/ExpQueryResults/zorba/json/json-snelson-serialize-indent-example.xml.res (+11/-0)
test/rbkt/ExpQueryResults/zorba/json/json-snelson-serialize-none-example.xml.res (+1/-0)
test/rbkt/ExpQueryResults/zorba/json/json-snelson-serialize-object-01.xml.res (+1/-0)
test/rbkt/ExpQueryResults/zorba/json/json-snelson-serialize-object-02.xml.res (+1/-0)
test/rbkt/ExpQueryResults/zorba/json/json-snelson-serialize-object-03.xml.res (+1/-0)
test/rbkt/ExpQueryResults/zorba/json/json-snelson-serialize-parse.xml.res (+1/-0)
test/rbkt/ExpQueryResults/zorba/json/json-snelson-serialize-some-example.xml.res (+1/-0)
test/rbkt/ExpQueryResults/zorba/json/json-snelson-uncommon-chars.xml.res (+3/-0)
test/rbkt/ExpQueryResults/zorba/json/json-snelson-utf-8.xml.res (+3/-0)
test/rbkt/Queries/zorba/json/json-invalid-option-parameter.spec (+1/-0)
test/rbkt/Queries/zorba/json/json-invalid-option-parameter.xq (+10/-0)
test/rbkt/Queries/zorba/json/json-jsonml_array-parse-01.xq (+9/-0)
test/rbkt/Queries/zorba/json/json-jsonml_array-parse-02.xq (+14/-0)
test/rbkt/Queries/zorba/json/json-jsonml_array-parse-03.xq (+18/-0)
test/rbkt/Queries/zorba/json/json-jsonml_array-parse-04.xq (+27/-0)
test/rbkt/Queries/zorba/json/json-jsonml_array-parse-05.xq (+66/-0)
test/rbkt/Queries/zorba/json/json-jsonml_array-parse-06.spec (+1/-0)
test/rbkt/Queries/zorba/json/json-jsonml_array-parse-06.xq (+10/-0)
test/rbkt/Queries/zorba/json/json-jsonml_array-parse-wikipedia.xq (+23/-0)
test/rbkt/Queries/zorba/json/json-jsonml_array-serialize-01.xq (+10/-0)
test/rbkt/Queries/zorba/json/json-jsonml_array-serialize-02.xq (+13/-0)
test/rbkt/Queries/zorba/json/json-jsonml_array-serialize-03.xq (+10/-0)
test/rbkt/Queries/zorba/json/json-jsonml_array-serialize-indent-wikipedia.xq (+20/-0)
test/rbkt/Queries/zorba/json/json-jsonml_array-serialize-none-wikipedia.xq (+19/-0)
test/rbkt/Queries/zorba/json/json-jsonml_array-serialize-some-wikipedia.xq (+20/-0)
test/rbkt/Queries/zorba/json/json-snelson-invalid-json.spec (+1/-0)
test/rbkt/Queries/zorba/json/json-snelson-invalid-json.xq (+9/-0)
test/rbkt/Queries/zorba/json/json-snelson-null-handling.xq (+5/-0)
test/rbkt/Queries/zorba/json/json-snelson-numbers-and-decimals.xq (+10/-0)
test/rbkt/Queries/zorba/json/json-snelson-parse-array-01.xq (+5/-0)
test/rbkt/Queries/zorba/json/json-snelson-parse-array-02.xq (+5/-0)
test/rbkt/Queries/zorba/json/json-snelson-parse-array-03.xq (+5/-0)
test/rbkt/Queries/zorba/json/json-snelson-parse-array-04.xq (+5/-0)
test/rbkt/Queries/zorba/json/json-snelson-parse-array-05.xq (+5/-0)
test/rbkt/Queries/zorba/json/json-snelson-parse-array-06.xq (+7/-0)
test/rbkt/Queries/zorba/json/json-snelson-parse-array-07.xq (+5/-0)
test/rbkt/Queries/zorba/json/json-snelson-parse-array-08.xq (+7/-0)
test/rbkt/Queries/zorba/json/json-snelson-parse-empty.spec (+1/-0)
test/rbkt/Queries/zorba/json/json-snelson-parse-empty.xq (+5/-0)
test/rbkt/Queries/zorba/json/json-snelson-parse-example.xq (+20/-0)
test/rbkt/Queries/zorba/json/json-snelson-parse-object-01.xq (+5/-0)
test/rbkt/Queries/zorba/json/json-snelson-parse-object-02.xq (+5/-0)
test/rbkt/Queries/zorba/json/json-snelson-parse-object-03.xq (+7/-0)
test/rbkt/Queries/zorba/json/json-snelson-parse-object-04.xq (+12/-0)
test/rbkt/Queries/zorba/json/json-snelson-parse-serialize.xq (+8/-0)
test/rbkt/Queries/zorba/json/json-snelson-serialize-array-01.xq (+8/-0)
test/rbkt/Queries/zorba/json/json-snelson-serialize-array-02.xq (+8/-0)
test/rbkt/Queries/zorba/json/json-snelson-serialize-array-03.xq (+8/-0)
test/rbkt/Queries/zorba/json/json-snelson-serialize-array-04.xq (+8/-0)
test/rbkt/Queries/zorba/json/json-snelson-serialize-array-05.xq (+9/-0)
test/rbkt/Queries/zorba/json/json-snelson-serialize-array-06.spec (+1/-0)
test/rbkt/Queries/zorba/json/json-snelson-serialize-array-06.xq (+8/-0)
test/rbkt/Queries/zorba/json/json-snelson-serialize-array-07.spec (+1/-0)
test/rbkt/Queries/zorba/json/json-snelson-serialize-array-07.xq (+8/-0)
test/rbkt/Queries/zorba/json/json-snelson-serialize-array-08.spec (+1/-0)
test/rbkt/Queries/zorba/json/json-snelson-serialize-array-08.xq (+8/-0)
test/rbkt/Queries/zorba/json/json-snelson-serialize-array-09.spec (+1/-0)
test/rbkt/Queries/zorba/json/json-snelson-serialize-array-09.xq (+8/-0)
test/rbkt/Queries/zorba/json/json-snelson-serialize-array-10.spec (+1/-0)
test/rbkt/Queries/zorba/json/json-snelson-serialize-array-10.xq (+8/-0)
test/rbkt/Queries/zorba/json/json-snelson-serialize-array-11.spec (+1/-0)
test/rbkt/Queries/zorba/json/json-snelson-serialize-array-11.xq (+8/-0)
test/rbkt/Queries/zorba/json/json-snelson-serialize-array-12.xq (+11/-0)
test/rbkt/Queries/zorba/json/json-snelson-serialize-comment-node.spec (+1/-0)
test/rbkt/Queries/zorba/json/json-snelson-serialize-comment-node.xq (+5/-0)
test/rbkt/Queries/zorba/json/json-snelson-serialize-indent-example.xq (+24/-0)
test/rbkt/Queries/zorba/json/json-snelson-serialize-invalid-value-for-attribute.spec (+1/-0)
test/rbkt/Queries/zorba/json/json-snelson-serialize-invalid-value-for-attribute.xq (+8/-0)
test/rbkt/Queries/zorba/json/json-snelson-serialize-none-example.xq (+19/-0)
test/rbkt/Queries/zorba/json/json-snelson-serialize-object-01.xq (+8/-0)
test/rbkt/Queries/zorba/json/json-snelson-serialize-object-02.xq (+9/-0)
test/rbkt/Queries/zorba/json/json-snelson-serialize-object-03.xq (+12/-0)
test/rbkt/Queries/zorba/json/json-snelson-serialize-parse.xq (+5/-0)
test/rbkt/Queries/zorba/json/json-snelson-serialize-some-example.xq (+24/-0)
test/rbkt/Queries/zorba/json/json-snelson-serialize-type-value-missing.spec (+1/-0)
test/rbkt/Queries/zorba/json/json-snelson-serialize-type-value-missing.xq (+8/-0)
test/rbkt/Queries/zorba/json/json-snelson-uncommon-chars.xq (+5/-0)
test/rbkt/Queries/zorba/json/json-snelson-utf-8.xq (+5/-0)
test/unit/CMakeLists.txt (+1/-0)
test/update/Queries/zorba/store/sc3.spec (+2/-0)
test/update/Queries/zorba/store/sc3_ex3.xq (+1/-1)
To merge this branch: bzr merge lp:~zorba-coders/zorba/feature-json_parser
Reviewer Review Type Date Requested Status
Sorin Marian Nasoi Approve
William Candillon Needs Fixing
Paul J. Lucas Approve
Matthias Brantner Pending
Review via email: mp+92900@code.launchpad.net

This proposal supersedes a proposal from 2012-02-08.

Commit message

New JSON parser and module.

Description of the change

New JSON parser and module.
Fixed the missing quote in the documentation.
Added checking of stream state for manipulators.
All bugs fixed.
Yet another bug fixed.
I think I've finally got it.

To post a comment you must log in.
Revision history for this message
Sorin Marian Nasoi (sorin.marian.nasoi) wrote : Posted in a previous version of this proposal

I have resubmitted the merge proposal after committing the fix for the JSON tests.

Revision history for this message
William Candillon (wcandillon) wrote : Posted in a previous version of this proposal

The documentation is missing some examples.
The example section at http://docs.basex.org/wiki/JSON_Module is a good place to get inspired.

Why A chars have a backslash in error code descriptions:
ZJSE0001 if \a $xml is not a document or element node.
ZJSE0002 if \a $xml contains an element that is missing a required attribute.
ZJSE0003 if \a $xml contains an attribute having an illegal value.
ZJSE0004 if \a $xml contains an illegal element.
ZJSE0005 if \a $xml contains an illegal child element for a JSON type.
ZJSE0006 if \a $xml contains an illegal child element.
ZJSE0007 if \a $xml contains an illegal text node.
ZJSE0008 if \a $xml contains an illegal value for a JSON type.

review: Needs Fixing
Revision history for this message
Paul J. Lucas (paul-lucas) wrote : Posted in a previous version of this proposal

The \a is the doxygen way to say the following thing is an argument and should be italicized.

Revision history for this message
William Candillon (wcandillon) wrote : Posted in a previous version of this proposal

Doesn't seem to work for xqdoc

Revision history for this message
Paul J. Lucas (paul-lucas) : Posted in a previous version of this proposal
review: Approve
Revision history for this message
William Candillon (wcandillon) wrote : Posted in a previous version of this proposal

The module works great.
There is room for improvement regarding its documentation.
"There are many ways to represent JSON data in XML" -> There are two ways to represent JSON data in XML:
- bullet 1 (John Snelson's format)
- bullet 2 (JSON)
Then add two examples, you can take some inspiration at http://docs.basex.org/wiki/JSON_Module

For parse#1, add a small example.
For parse#2, add two small examples and some description of what is excepted for the option element (which namespace, example of schema instance instance)
For serialize#1, please elaborate on what the following means: "Serializes an XDM into JSON using one of the representations described above." and add two small examples.
For serialize#2, same comment than for serialize#1 + add some explanation of what is excepted for the option element.

review: Needs Fixing
Revision history for this message
Paul J. Lucas (paul-lucas) wrote : Posted in a previous version of this proposal

No, the statement "There are many ways to represent JSON data in XML" is correct as it is. There *are* *many* ways: Zorba only implements *two* of those *many* ways.

Adding *two* examples is too much. API documentation isn't supposed to be the primary documentation.

Revision history for this message
Matthias Brantner (matthias-brantner) wrote : Posted in a previous version of this proposal

I think William is right. We should have a couple of examples which help the user to get started with this module. Those could either be inline in the text or links generated using the @example xqdoc tag.

The serialize functions should be annotated %ann:streamable because they return a streamable string (see modules/com/zorba-xquery/www/modules/fetch.xq).

Some error codes lack a prefix (e.g. ZJPE0001). If I understood correctly, it should be zerr:ZJPE0001. Otherwise, the user doesn't know how to catch the error.

Under which circumstances does json:parse return the empty sequence? What does json:serialize return if the input is the empty sequence?

review: Needs Fixing
Revision history for this message
Sorin Marian Nasoi (sorin.marian.nasoi) wrote : Posted in a previous version of this proposal

1) Should be possible to call json:serialize(json:parse(VALID_JSON))
where VALID_JSON is any valid JSON string
see failing test test/rbkt/zorba/json/json-snelson-serialize-parse
added bug lp:920717

2) array and object closed prematurely in json:parse
see failing tests test/rbkt/zorba/json/json-snelson-parse-array-06 and test/rbkt/zorba/json/json-snelson-parse-array-07
added bug lp:920719

3) When trying to parsing a valid JSON string with invalid JSON option parameter the error raised is:
http://www.w3.org/2005/xqt-errors:XPST0003
Please add a more useful error message: see failing test test/rbkt/zorba/json/json-invalid-option-parameter
added bug lp:920720

4) Parsing an empty value has wrong behavior for both JSON mappings (Snelson and JSON-ML).
Please see failing tests:
- test/rbkt/zorba/json/json-snelson-empty-value
- test/rbkt/zorba/json/json-jsonml-empty-value
added bug lp:920721

5) Comment nodes should be ignored by json:serialize
Please see failing tests:
- test/rbkt/zorba/json/json-snelson-serialize-object-03
- test/rbkt/zorba/json/json-snelson-serialize-array-12
added bug lp:920722

6) XQDoc issues:
- there is no @project tag for the new json.xq module: as a result, in the XQDoc documentation is generated in the www.zorba-xquery.com/modules/converters instead of data processing/data converters
Please add a @project data processing/data converters in the module description in order to fix this.

- first parse function does not state
zerr:ZJPE0006 as a possible error condition if the passes JSON string is invalid
See added test json-snelson-invalid-json.xq
Added bug lp:920724

review: Needs Fixing
Revision history for this message
Sorin Marian Nasoi (sorin.marian.nasoi) wrote : Posted in a previous version of this proposal

r10618 contains all the tests mentioned above.

The tests are passing because they are marked as EXPECTED_FAILURES.

Revision history for this message
Paul J. Lucas (paul-lucas) wrote : Posted in a previous version of this proposal

Why did you mark them as EXPECTED_FAILURE if they're not expected to fail? Presumably, you *want* them fixed, right?

Revision history for this message
Chris Hillery (ceejatec) wrote : Posted in a previous version of this proposal

EXPECTED_FAILURE does *not* mean "negative test". It means "this is broken, we know it's broken, and we're working on it". That's why you have to supply a bug number to the macro. It probably should be renamed "KNOWN_BUG".

Revision history for this message
Paul J. Lucas (paul-lucas) wrote : Posted in a previous version of this proposal

It means "known bug" for things that are in the trunk. If it's on a branch (as this is), then either (1) it will be fixed before it's merged into the trunk (at which point the EXPECTED_FAILURE will have to be removed since it will no longer be failing -- which begs my question of, "Why put it in in the first place?") or (2) the test will be deemed invalid and removed.

Revision history for this message
Chris Hillery (ceejatec) wrote : Posted in a previous version of this proposal

Hmm... valid points. I think there's some value in using EXPECTED_FAILURE() anyway, since it documents the relationship to new bugs that are filed.

It does introduce the possibility of unintentionally merging a new bug onto the trunk, but the diff will clearly show a new EXPECTED_FAILURE() marker and I would hope that any reviewer would raise a serious question about that.

I guess I would say that it's probably unnecessary to add EXPECTED_FAILURE()s (and associated bugs) for small review comments. However, for anything which might reasonably take more than a few hours to fix, IMHO it's probably good practice just to help ensure that no issues get forgotten. In general I would leave that decision up to the team working on the branch in question, though.

Revision history for this message
Sorin Marian Nasoi (sorin.marian.nasoi) wrote : Posted in a previous version of this proposal

> It means "known bug" for things that are in the trunk. If it's on a branch
> (as this is), then either (1) it will be fixed before it's merged into the
> trunk (at which point the EXPECTED_FAILURE will have to be removed since it
> will no longer be failing -- which begs my question of, "Why put it in in the
> first place?") or (2) the test will be deemed invalid and removed.

Paul, IMO:
- adding some bugs on Launchpad
- adding tests that fail and marking them as KNOWN_ISSUE (a.k.a. EXPECTED_FAILURES)
was far better than adding a comment in your merge proposal.

Keep in mind that I have spent my time in order to give you a hand in pointing out the issues I found.

Adding separate bugs allows us to:
- discussed the raised issues separately
- make commits to fix them separately into the branch

And to prove my point: you already wrote 2 comments *without* even looking over *any* of the issues I have raised.

Anyway, I already committed a fix in the branch for bug lp:920724.

Revision history for this message
Paul J. Lucas (paul-lucas) wrote : Posted in a previous version of this proposal

Chris Hillery wrote: "I think there's some value in using EXPECTED_FAILURE() anyway, since it documents the relationship to new bugs that are filed."

The relationship to new bugs *from* _______?

Revision history for this message
Chris Hillery (ceejatec) wrote : Posted in a previous version of this proposal

Documents the relationship of the newly-added failing tests to the bugs tracking those issues.

Revision history for this message
Paul J. Lucas (paul-lucas) wrote : Posted in a previous version of this proposal

IMO, you didn't *need* to add any comment to the merge proposal other than "Bugs filed" -- I can read the bugs myself.

Sorin wrote: "Keep in mind that I have spent my time in order to give you a hand in pointing out the issues I found."

It's all of our job to review each others' code under the "New Order" so please don't act like it was a personal favor.

I never questioned your adding separate bugs. For the record, I *like* separate bugs. I *only* questioned why you added EXPECTED_FAILURE for those bugs that, as I've pointed out, is unnecessary and not only creates more work for you (because you put them in) but more work for me (because I have to take them out).

Sorin wrote: "And to prove my point: you already wrote 2 comments *without* even looking over *any* of the issues I have raised."

*My* point has *nothing* to do with any bugs in particular. Chris understands my point. Do you?

Revision history for this message
Paul J. Lucas (paul-lucas) wrote : Posted in a previous version of this proposal

@Chris: Hmmm... again, because this is a branch and no Zorba user will ever see this stuff, it's at best only marginally useful.

Revision history for this message
Sorin Marian Nasoi (sorin.marian.nasoi) wrote : Posted in a previous version of this proposal

Paul, let me ask you something: are you sure you are not missing the point?

IMHO the point is to fix the issues that were raised ASAP.

I have spent my time in order to give as many details as possible in order to fix them ASAP.
Also I have committed a fix in the branch for one of the opened bugs.

Please look over the bugs and let's try to fix them in order to commit the new improved JSON 2.0 module to the trunk.

If you think that the decision I took while reviewing your merge deserves further discussion let's put it on the next weekly conference agenda.

Revision history for this message
Sorin Marian Nasoi (sorin.marian.nasoi) wrote : Posted in a previous version of this proposal

> IMO, you didn't *need* to add any comment to the merge proposal other than
> "Bugs filed" -- I can read the bugs myself.
FYI: Matthias asked me (in a separate email discussion) to add a small review of the issues I fount in the merge proposal: please take this issue with him.

> Sorin wrote: "Keep in mind that I have spent my time in order to give you a
> hand in pointing out the issues I found."
>
> It's all of our job to review each others' code under the "New Order" so
> please don't act like it was a personal favor.
OK, next time I will review your code I will simply add a one sentence in the merge proposal and keep adding comments because you clearly think this is better.

> I never questioned your adding separate bugs. For the record, I *like*
> separate bugs. I *only* questioned why you added EXPECTED_FAILURE for those
> bugs that, as I've pointed out, is unnecessary and not only creates more work
> for you (because you put them in) but more work for me (because I have to take
> them out).
I will never do this again.

> Sorin wrote: "And to prove my point: you already wrote 2 comments *without*
> even looking over *any* of the issues I have raised."
>
> *My* point has *nothing* to do with any bugs in particular. Chris understands
> my point. Do you?
No, I do not. IMHO you are missing the point, that is: let's try to fix the *bugs* and discuss the procedures later.
Do you understand my point?

Revision history for this message
Paul J. Lucas (paul-lucas) wrote : Posted in a previous version of this proposal

No, the point is *not* to fix this issues ASAP. The feature is not a high-priority feature, so there's no reason to do this ASAP. My *only* point was why you added EXPECTED_FAILURE lines to the CMakeLists.txt file -- that's it.

But it's moot now since I've removed all the new EXPECTED_FAILURES that you've added. They're of no use to me. Now when I run the test suite and it reports 100% tests passed, I can be confident that I've fixed all the bugs and not have an errant EXPECTED_FAILURE in there.

In the future, please don't add EXPECTED_FAILURE lines to code on a *branch* -- thanks.

Revision history for this message
Sorin Marian Nasoi (sorin.marian.nasoi) wrote : Posted in a previous version of this proposal

> No, the point is *not* to fix this issues ASAP. The feature is not a high-
> priority feature, so there's no reason to do this ASAP. My *only* point was
> why you added EXPECTED_FAILURE lines to the CMakeLists.txt file -- that's it.
>
> But it's moot now since I've removed all the new EXPECTED_FAILURES that you've
> added. They're of no use to me. Now when I run the test suite and it reports
> 100% tests passed, I can be confident that I've fixed all the bugs and not
> have an errant EXPECTED_FAILURE in there.
>
> In the future, please don't add EXPECTED_FAILURE lines to code on a *branch*
> -- thanks.
My 2 cents: no matter what the brief description of the "ctest -R SOME_TEST" shows, one should *always* check out the details inside the ctest logs.

http://en.wikipedia.org/wiki/The_Devil_is_in_the_details

Revision history for this message
Paul J. Lucas (paul-lucas) : Posted in a previous version of this proposal
review: Approve
Revision history for this message
William Candillon (wcandillon) wrote : Posted in a previous version of this proposal

I believe that bug #920717 isn't fixed.

The intro has two examples of XML.
For each of the XML, you should add the associated JSON.

Would it be possible to get all the bug reports that Sorin created associated to this merge request?

review: Needs Fixing
Revision history for this message
Paul J. Lucas (paul-lucas) : Posted in a previous version of this proposal
review: Approve
Revision history for this message
Paul J. Lucas (paul-lucas) wrote : Posted in a previous version of this proposal

It was an unrelated bug -- fixed.

Revision history for this message
William Candillon (wcandillon) wrote : Posted in a previous version of this proposal

This merge request is pending on bug #920717

Also there are some documentation issues that have not been addressed yet.
How do you we do this?
Do you make another shot at it first or we should have call with Matthias to discuss how to review it?

review: Needs Fixing
Revision history for this message
William Candillon (wcandillon) wrote : Posted in a previous version of this proposal

Do you take another shot at it first or should we have a call with Matthias to discuss how to improve the module documentation?*

Revision history for this message
Paul J. Lucas (paul-lucas) wrote : Posted in a previous version of this proposal

If you want the documentation fixed, you need to specify exactly what needs fixing -- I'm not a mind-reader.

Revision history for this message
William Candillon (wcandillon) wrote : Posted in a previous version of this proposal

"Zorba implements that proposed by John Snelson." -> is that correct english? I'm not sure.
For John Snelson representation example, please add the corresponding JSON and XQuery function call above.
For the JSONML example, please add the corresponding JSON and XQuery function call above.

I think that this fix will dramatically improve the time needed for someone to get started with the module.

In parse#1, add a small example.
"Returns: said XDM instance." is that correct?

In parse#2, add a small example.
Add a description of how to build element(json-options:options)

In serialize#1, add a small example.

In serialize#2, add a small example.
Add a description of how to build element(json-options:options)

Revision history for this message
William Candillon (wcandillon) wrote : Posted in a previous version of this proposal

I have reopened bug #920717.
This merge is still pending on the resolution of this bug.

Revision history for this message
Paul J. Lucas (paul-lucas) wrote : Posted in a previous version of this proposal

> "Zorba implements that proposed by John Snelson." -> is that correct english?
> I'm not sure.

Yes.

> In parse#1, add a small example.
> "Returns: said XDM instance." is that correct?

Yes.

> In parse#2, add a small example.
> Add a description of how to build element(json-options:options)

I would except XQDoc is broken and renders it very badly.

> In serialize#1, add a small example.
> In serialize#2, add a small example.

It's just the reverse of what's above!

Revision history for this message
William Candillon (wcandillon) wrote : Posted in a previous version of this proposal

If the documentation is correct in the source, I will fix everything else.

Revision history for this message
Paul J. Lucas (paul-lucas) :
review: Approve
Revision history for this message
William Candillon (wcandillon) wrote :

Still pending on bug #930573

review: Needs Fixing
Revision history for this message
William Candillon (wcandillon) wrote :

I approve the fix for bug #930573 and opened #932186 which depends on this merge proposal.

Revision history for this message
William Candillon (wcandillon) wrote :

The intro is great!

There are examples missing for each function description.

Also I would like to understand the best practice for documenting XML parameters.
Currently it's pretty confusing.
Matthias what's your take on it?

Revision history for this message
Paul J. Lucas (paul-lucas) wrote :

As far as I can tell, I've already given examples. Since you're so picky and only you seem to know what you want, why don't you just add the documentation you want yourself?

Revision history for this message
William Candillon (wcandillon) wrote :

If you give/write a good overview of the possible options for parse/serialize I can definitely do that. Right know I have no clue of what's possible or not which is gonna the case of our users too.

Revision history for this message
Paul J. Lucas (paul-lucas) wrote :

Why can't you just look at the json-options schema? There are only two options.

Revision history for this message
Sorin Marian Nasoi (sorin.marian.nasoi) wrote :

The reported bugs were fixed, the documentation also looks good.

As far as William's last remark, IMO building the XQDoc documentation and looking at the 'json-options' schema solves the problem.

review: Approve
Revision history for this message
Zorba Build Bot (zorba-buildbot) wrote :
Revision history for this message
Zorba Build Bot (zorba-buildbot) wrote :

The attempt to merge lp:~zorba-coders/zorba/feature-json_parser into lp:zorba failed. Below is the output from the failed tests.

CMake Error at /home/ceej/zo/testing/zorbatest/tester/TarmacLander.cmake:274 (message):
  Validation queue job feature-json_parser-2012-02-15T17-27-26.321Z is
  finished. The final status was:

  41 tests did not succeed - changes not commited.

Error in read script: /home/ceej/zo/testing/zorbatest/tester/TarmacLander.cmake

10650. By Paul J. Lucas

Removed data-converters tag.

Revision history for this message
Zorba Build Bot (zorba-buildbot) wrote :
Revision history for this message
Zorba Build Bot (zorba-buildbot) wrote :

Validation queue job feature-json_parser-2012-02-16T00-25-35.097Z is finished. The final status was:

All tests succeeded!

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'ChangeLog'
2--- ChangeLog 2012-02-15 10:25:02 +0000
3+++ ChangeLog 2012-02-16 00:23:20 +0000
4@@ -41,6 +41,7 @@
5 * Fixed bug #918211 (xqueryx fulltext w3c conformance generation)
6 * Fixed bug #918157 (Add XQFTTS to validation queue)
7 * Fixed bug with unversioned modules with C++ external functions
8+ * Fixed bug #878508 (JSON Module not escaping escape characters)
9
10 version 2.1
11
12
13=== modified file 'include/zorba/diagnostic.h'
14--- include/zorba/diagnostic.h 2011-07-01 16:07:54 +0000
15+++ include/zorba/diagnostic.h 2012-02-16 00:23:20 +0000
16@@ -239,7 +239,10 @@
17 ZORBA_DEBUGGER, // Zorba Debugger
18 ZORBA_OS, // Operating System
19 ZORBA_SERIALIZATION,
20- ZORBA_STORE
21+ ZORBA_STORE,
22+
23+ JSON_PARSER,
24+ JSON_SERIALIZATION
25 };
26
27 /**
28
29=== modified file 'include/zorba/internal/ztd.h'
30--- include/zorba/internal/ztd.h 2011-08-23 13:32:16 +0000
31+++ include/zorba/internal/ztd.h 2012-02-16 00:23:20 +0000
32@@ -355,7 +355,8 @@
33 template<typename T> inline
34 typename std::enable_if<ZORBA_TR1_NS::is_pointer<T>::value,std::string>::type
35 to_string( T p ) {
36- return p ? to_string( *p ) : "<null>";
37+ typedef typename ZORBA_TR1_NS::remove_pointer<T>::type const* T_const_ptr;
38+ return p ? to_string( *static_cast<T_const_ptr>( p ) ) : "<null>";
39 }
40
41 /**
42
43=== modified file 'include/zorba/pregenerated/diagnostic_list.h'
44--- include/zorba/pregenerated/diagnostic_list.h 2011-12-21 14:40:33 +0000
45+++ include/zorba/pregenerated/diagnostic_list.h 2012-02-16 00:23:20 +0000
46@@ -746,6 +746,40 @@
47
48 extern ZORBA_DLL_PUBLIC ZorbaErrorCode XSST0010;
49
50+extern ZORBA_DLL_PUBLIC ZorbaErrorCode ZJPE0001_ILLEGAL_CHARACTER;
51+
52+extern ZORBA_DLL_PUBLIC ZorbaErrorCode ZJPE0002_ILLEGAL_CODEPOINT;
53+
54+extern ZORBA_DLL_PUBLIC ZorbaErrorCode ZJPE0003_ILLEGAL_ESCAPE;
55+
56+extern ZORBA_DLL_PUBLIC ZorbaErrorCode ZJPE0004_ILLEGAL_LITERAL;
57+
58+extern ZORBA_DLL_PUBLIC ZorbaErrorCode ZJPE0005_ILLEGAL_NUMBER;
59+
60+extern ZORBA_DLL_PUBLIC ZorbaErrorCode ZJPE0006_UNEXPECTED_TOKEN;
61+
62+extern ZORBA_DLL_PUBLIC ZorbaErrorCode ZJPE0007_UNTERMINATED_STRING;
63+
64+extern ZORBA_DLL_PUBLIC ZorbaErrorCode ZJPE0008_ILLEGAL_QNAME;
65+
66+extern ZORBA_DLL_PUBLIC ZorbaErrorCode ZJPE0009_ILLEGAL_EMPTY_STRING;
67+
68+extern ZORBA_DLL_PUBLIC ZorbaErrorCode ZJSE0001_NOT_DOCUMENT_OR_ELEMENT_NODE;
69+
70+extern ZORBA_DLL_PUBLIC ZorbaErrorCode ZJSE0002_ELEMENT_MISSING_ATTRIBUTE;
71+
72+extern ZORBA_DLL_PUBLIC ZorbaErrorCode ZJSE0003_BAD_ATTRIBUTE_VALUE;
73+
74+extern ZORBA_DLL_PUBLIC ZorbaErrorCode ZJSE0004_BAD_ELEMENT;
75+
76+extern ZORBA_DLL_PUBLIC ZorbaErrorCode ZJSE0005_BAD_CHILD_ELEMENT;
77+
78+extern ZORBA_DLL_PUBLIC ZorbaErrorCode ZJSE0006_NO_ELEMENT_CHILD;
79+
80+extern ZORBA_DLL_PUBLIC ZorbaErrorCode ZJSE0007_NO_TEXT_CHILD;
81+
82+extern ZORBA_DLL_PUBLIC ZorbaErrorCode ZJSE0008_BAD_VALUE;
83+
84 } // namespace zerr
85
86 namespace zwarn {
87
88=== modified file 'modules/ExternalModules.conf'
89--- modules/ExternalModules.conf 2012-02-15 10:25:02 +0000
90+++ modules/ExternalModules.conf 2012-02-16 00:23:20 +0000
91@@ -27,7 +27,7 @@
92 # currently only works for bzr, since svn tags are just different URLS)
93
94 data-cleaning bzr lp:zorba/data-cleaning-module zorba-2.1
95-data-converters bzr lp:zorba/data-converters-module zorba-2.1
96+data-converters bzr lp:zorba/data-converters-module
97 data-formatting bzr lp:zorba/data-formatting-module zorba-2.1
98 email bzr lp:zorba/email-module zorba-2.1
99 excel bzr lp:zorba/excel-module zorba-2.1
100
101=== modified file 'modules/com/zorba-xquery/www/modules/CMakeLists.txt'
102--- modules/com/zorba-xquery/www/modules/CMakeLists.txt 2012-02-15 10:25:02 +0000
103+++ modules/com/zorba-xquery/www/modules/CMakeLists.txt 2012-02-16 00:23:20 +0000
104@@ -71,6 +71,10 @@
105 # Subdirectories
106 DECLARE_ZORBA_MODULE(FILE converters/base64.xq VERSION 2.0
107 URI "http://www.zorba-xquery.com/modules/converters/base64")
108+DECLARE_ZORBA_MODULE(FILE converters/json.xq VERSION 2.0
109+ URI "http://www.zorba-xquery.com/modules/converters/json")
110+DECLARE_ZORBA_SCHEMA(FILE converters/json-options.xsd
111+ URI "http://www.zorba-xquery.com/modules/converters/json-options")
112 DECLARE_ZORBA_MODULE(FILE introspection/sctx.xq VERSION 2.0
113 URI "http://www.zorba-xquery.com/modules/introspection/sctx")
114 DECLARE_ZORBA_MODULE(FILE xqdoc2xhtml/error.xq VERSION 2.0
115
116=== added file 'modules/com/zorba-xquery/www/modules/converters/json-options.xsd'
117--- modules/com/zorba-xquery/www/modules/converters/json-options.xsd 1970-01-01 00:00:00 +0000
118+++ modules/com/zorba-xquery/www/modules/converters/json-options.xsd 2012-02-16 00:23:20 +0000
119@@ -0,0 +1,60 @@
120+<!--
121+ ! Copyright 2006-2008 The FLWOR Foundation.
122+ !
123+ ! Licensed under the Apache License, Version 2.0 (the "License");
124+ ! you may not use this file except in compliance with the License.
125+ ! You may obtain a copy of the License at
126+ !
127+ ! http://www.apache.org/licenses/LICENSE-2.0
128+ !
129+ ! Unless required by applicable law or agreed to in writing, software
130+ ! distributed under the License is distributed on an "AS IS" BASIS,
131+ ! WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
132+ ! See the License for the specific language governing permissions and
133+ ! limitations under the License.
134+-->
135+
136+<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
137+ xmlns:json="http://www.zorba-xquery.com/modules/converters/json-options"
138+ targetNamespace="http://www.zorba-xquery.com/modules/converters/json-options"
139+ elementFormDefault="qualified"
140+ attributeFormDefault="unqualified">
141+
142+ <xs:element name="options">
143+ <xs:complexType>
144+ <xs:all>
145+
146+ <xs:element name="json-format" minOccurs="1" maxOccurs="1">
147+ <xs:complexType>
148+ <xs:attribute name="value" use="required">
149+ <xs:simpleType>
150+ <xs:restriction base="xs:string">
151+ <xs:enumeration value="Snelson"/>
152+ <xs:enumeration value="JsonML-array"/>
153+ <xs:enumeration value="JsonML-object"/>
154+ </xs:restriction>
155+ </xs:simpleType>
156+ </xs:attribute>
157+ </xs:complexType>
158+ </xs:element>
159+
160+ <xs:element name="whitespace" minOccurs="0" maxOccurs="1">
161+ <xs:complexType>
162+ <xs:attribute name="value" use="required">
163+ <xs:simpleType>
164+ <xs:restriction base="xs:string">
165+ <xs:enumeration value="none"/>
166+ <xs:enumeration value="some"/>
167+ <xs:enumeration value="indent"/>
168+ </xs:restriction>
169+ </xs:simpleType>
170+ </xs:attribute>
171+ </xs:complexType>
172+ </xs:element>
173+
174+ </xs:all>
175+ </xs:complexType>
176+ </xs:element>
177+</xs:schema>
178+
179+<!-- vim:set et sw=2 ts=2: -->
180
181=== added file 'modules/com/zorba-xquery/www/modules/converters/json.xq'
182--- modules/com/zorba-xquery/www/modules/converters/json.xq 1970-01-01 00:00:00 +0000
183+++ modules/com/zorba-xquery/www/modules/converters/json.xq 2012-02-16 00:23:20 +0000
184@@ -0,0 +1,260 @@
185+(:
186+ : Copyright 2006-2009 The FLWOR Foundation.
187+ :
188+ : Licensed under the Apache License, Version 2.0 (the "License");
189+ : you may not use this file except in compliance with the License.
190+ : You may obtain a copy of the License at
191+ :
192+ : http://www.apache.org/licenses/LICENSE-2.0
193+ :
194+ : Unless required by applicable law or agreed to in writing, software
195+ : distributed under the License is distributed on an "AS IS" BASIS,
196+ : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
197+ : See the License for the specific language governing permissions and
198+ : limitations under the License.
199+ :)
200+
201+xquery version "3.0";
202+
203+ (:~
204+ : Using this module, you can parse JSON data into XML, manipulate it like any
205+ : other XML data using XQuery, and serialize the result back as JSON.
206+ :
207+ : There are many ways to represent JSON data in XML, some loss-less ("round
208+ : tripable") and some lossy ("one way"). Loss-less representations preserve
209+ : the JSON data types <i>boolean</i>, <i>number</i>, and <i>null</i>; lossy
210+ : representations convert all data to strings.
211+ : <p/>
212+ : For a loss-less representation, Zorba implements that proposed by
213+ : <a href="http://john.snelson.org.uk/parsing-json-into-xquery">John Snelson</a>.
214+ : For example:
215+ : <pre>
216+ : {
217+ : "firstName" : "John",
218+ : "lastName" : "Smith",
219+ : "address" : {
220+ : "streetAddress" : "21 2nd Street",
221+ : "city" : "New York",
222+ : "state" : "NY",
223+ : "postalCode" : 10021
224+ : },
225+ : "phoneNumbers" : [ "212 732-1234", "646 123-4567" ]
226+ : }
227+ : </pre>
228+ : would be represented as:
229+ : <pre>
230+ : &lt;json type="object"&gt;
231+ : &lt;pair name="firstName" type="string"&gt;John&lt;/pair&gt;
232+ : &lt;pair name="lastName" type="string"&gt;Smith&lt;/pair&gt;
233+ : &lt;pair name="address" type="object"&gt;
234+ : &lt;pair name="streetAddress" type="string"&gt;21 2nd Street&lt;/pair&gt;
235+ : &lt;pair name="city" type="string"&gt;New York&lt;/pair&gt;
236+ : &lt;pair name="state" type="string"&gt;NY&lt;/pair&gt;
237+ : &lt;pair name="postalCode" type="number"&gt;10021&lt;/pair&gt;
238+ : &lt;/pair&gt;
239+ : &lt;pair name="phoneNumbers" type="array"&gt;
240+ : &lt;item type="string"&gt;212 732-1234&lt;/item&gt;
241+ : &lt;item type="string"&gt;646 123-4567&lt;/item&gt;
242+ : &lt;/pair&gt;
243+ : &lt;/json&gt;
244+ : </pre>
245+ : For a lossy representation, Zorba implements
246+ : <a href="http://jsonml.org/">JsonML</a> (the array form).
247+ : For example:
248+ : <pre>
249+ : [ "person",
250+ : { "created" : "2006-11-11T19:23",
251+ : "modified" : "2006-12-31T23:59" },
252+ : [ "firstName", "Robert" ],
253+ : [ "lastName", "Smith" ],
254+ : [ "address",
255+ : { "type" : "home" },
256+ : [ "street", "12345 Sixth Ave" ],
257+ : [ "city", "Anytown" ],
258+ : [ "state", "CA" ],
259+ : [ "postalCode", "98765-4321" ]
260+ : ]
261+ : ]
262+ : </pre>
263+ : would be represented as:
264+ : <pre>
265+ : &lt;person created="2006-11-11T19:23" modified="2006-12-31T23:59"&gt;
266+ : &lt;firstName&gt;Robert&lt;/firstName&gt;
267+ : &lt;lastName&gt;Smith&lt;/lastName&gt;
268+ : &lt;address type="home"&gt;
269+ : &lt;street&gt;12345 Sixth Ave&lt;/street&gt;
270+ : &lt;city&gt;Anytown&lt;/city&gt;
271+ : &lt;state&gt;CA&lt;/state&gt;
272+ : &lt;postalCode&gt;98765-4321&lt;/postalCode&gt;
273+ : &lt;/address&gt;
274+ : &lt;/person&gt;
275+ : </pre>
276+ :
277+ : @author Paul J. Lucas
278+ : @project data processing/data converters
279+ :)
280+module namespace json = "http://www.zorba-xquery.com/modules/converters/json";
281+
282+import module namespace schema = "http://www.zorba-xquery.com/modules/schema";
283+
284+import schema namespace json-options =
285+ "http://www.zorba-xquery.com/modules/converters/json-options";
286+
287+declare namespace ann = "http://www.zorba-xquery.com/annotations";
288+declare namespace err = "http://www.w3.org/2005/xqt-errors";
289+declare namespace zerr = "http://www.zorba-xquery.com/errors";
290+
291+declare namespace ver = "http://www.zorba-xquery.com/options/versioning";
292+declare option ver:module-version "2.0";
293+
294+(:~
295+ : Parses JSON data from a string and returns an XDM instance using one of the
296+ : representations described above.
297+ :
298+ : @param $json The JSON data to parse.
299+ : @param $options The parsing options, for example:
300+ : <pre>
301+ : &lt;options xmlns="http://www.zorba-xquery.com/modules/converters/json-options"&gt;
302+ : &lt;json-format value="JsonML-array"/&gt;
303+ : &lt;/options&gt;
304+ : </pre>
305+ : @return said XDM instance.
306+ : @error err:XQDY0027 if $options can not be validated against the
307+ : json-options schema.
308+ : @error zerr:ZJPE0001 if $json contains an illegal JSON character.
309+ : @error zerr:ZJPE0002 if $json contains an illegal Unicode code-point.
310+ : @error zerr:ZJPE0003 if $json contains an illegal JSON character escape.
311+ : @error zerr:ZJPE0004 if $json contains an illegal JSON literal.
312+ : @error zerr:ZJPE0005 if $json contains an illegal JSON number.
313+ : @error zerr:ZJPE0006 if $json is not a valid JSON string.
314+ : @error zerr:ZJPE0007 if $json contains an unterminated string.
315+ : @error zerr:ZJPE0008 if $json contains an illegal QName.
316+ : @example test/rbkt/Queries/zorba/json/json-jsonml_array-parse-01.xq
317+ :)
318+declare function json:parse(
319+ $json as xs:string?,
320+ $options as element(json-options:options)
321+) as element(*,xs:untyped)*
322+{
323+ let $validated-options := if ( schema:is-validated( $options ) ) then
324+ $options
325+ else
326+ validate { $options }
327+ return json:parse-internal( $json, $validated-options )
328+};
329+
330+(:~
331+ : Parses JSON data from a string and returns an XDM instance using the Snelson
332+ : representation described above.
333+ :
334+ : @param $json The JSON data to parse.
335+ : @return said XDM instance.
336+ : @error zerr:ZJPE0001 if $json contains an illegal JSON character.
337+ : @error zerr:ZJPE0002 if $json contains an illegal Unicode code-point.
338+ : @error zerr:ZJPE0003 if $json contains an illegal JSON character escape.
339+ : @error zerr:ZJPE0004 if $json contains an illegal JSON literal.
340+ : @error zerr:ZJPE0005 if $json contains an illegal JSON number.
341+ : @error zerr:ZJPE0006 if $json is not a valid JSON string.
342+ : @error zerr:ZJPE0007 if $json contains an unterminated string.
343+ : @error zerr:ZJPE0008 if $json contains an illegal QName.
344+ : @example test/rbkt/Queries/zorba/json/json-snelson-parse-array-01.xq
345+ :)
346+declare function json:parse(
347+ $json as xs:string?
348+) as element(*,xs:untyped)*
349+{
350+ json:parse-internal(
351+ $json,
352+ validate {
353+ <options
354+ xmlns="http://www.zorba-xquery.com/modules/converters/json-options">
355+ <json-format value="Snelson"/>
356+ </options>
357+ }
358+ )
359+};
360+
361+(:~
362+ : Serializes an XDM into JSON using one of the representations described
363+ : above.
364+ :
365+ : @param $xml The XDM to serialize.
366+ : @param $options The serializing options, for example:
367+ : <pre>
368+ : &lt;options xmlns="http://www.zorba-xquery.com/modules/converters/json-options"&gt;
369+ : &lt;json-format value="JsonML-array"/&gt;
370+ : &lt;whitespace value="indent"/&gt;
371+ : &lt;/options&gt;
372+ : </pre>
373+ : @return a JSON string.
374+ : @error err:XQDY0027 if $options can not be validated against the
375+ : json-options schema.
376+ : @error zerr:ZJSE0001 if $xml is not a document or element node.
377+ : @error zerr:ZJSE0002 if $xml contains an element that is missing a required
378+ : attribute.
379+ : @error zerr:ZJSE0003 if $xml contains an attribute having an illegal value.
380+ : @error zerr:ZJSE0004 if $xml contains an illegal element.
381+ : @error zerr:ZJSE0005 if $xml contains an illegal child element for a JSON
382+ : type.
383+ : @error zerr:ZJSE0006 if $xml contains an illegal child element.
384+ : @error zerr:ZJSE0007 if $xml contains an illegal text node.
385+ : @error zerr:ZJSE0008 if $xml contains an illegal value for a JSON type.
386+ : @example test/rbkt/Queries/zorba/json/json-jsonml_array-serialize-01.xq
387+ :)
388+declare function json:serialize(
389+ $xml as item()*,
390+ $options as element(json-options:options)
391+) as xs:string
392+{
393+ let $validated-options := if ( schema:is-validated( $options ) ) then
394+ $options
395+ else
396+ validate { $options }
397+ return json:serialize-internal( $xml, $validated-options )
398+};
399+
400+(:~
401+ : Serializes an XDM into JSON using one of the representations described
402+ : above.
403+ :
404+ : @param $xml The XDM to serialize.
405+ : @return a JSON string.
406+ : @error zerr:ZJSE0001 if $xml is not a document or element node.
407+ : @error zerr:ZJSE0002 if $xml contains an element that is missing a required
408+ : attribute.
409+ : @error zerr:ZJSE0003 if $xml contains an attribute having an illegal value.
410+ : @error zerr:ZJSE0004 if $xml contains an illegal element.
411+ : @error zerr:ZJSE0005 if $xml contains an illegal child element for a JSON
412+ : type.
413+ : @error zerr:ZJSE0006 if $xml contains an illegal child element.
414+ : @error zerr:ZJSE0007 if $xml contains an illegal text node.
415+ : @error zerr:ZJSE0008 if $xml contains an illegal value for a JSON type.
416+ : @example test/rbkt/Queries/zorba/json/json-snelson-serialize-array-01.xq
417+ :)
418+declare function json:serialize(
419+ $xml as item()*
420+) as xs:string
421+{
422+ json:serialize-internal($xml,
423+ validate {
424+ <options
425+ xmlns="http://www.zorba-xquery.com/modules/converters/json-options">
426+ <json-format value="Snelson"/>
427+ </options>
428+ }
429+ )
430+};
431+
432+(:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::)
433+
434+declare %private function json:parse-internal(
435+ $json as xs:string?,
436+ $options as item()?
437+) as element()* external;
438+
439+declare %ann:streamable %private function json:serialize-internal(
440+ $xml as item()*,
441+ $options as item()?
442+) as xs:string external;
443+
444+(: vim:set et sw=2 ts=2: :)
445
446=== modified file 'modules/com/zorba-xquery/www/modules/pregenerated/errors.xq'
447--- modules/com/zorba-xquery/www/modules/pregenerated/errors.xq 2011-12-21 14:40:33 +0000
448+++ modules/com/zorba-xquery/www/modules/pregenerated/errors.xq 2012-02-16 00:23:20 +0000
449@@ -784,4 +784,72 @@
450
451 (:~
452 :)
453-declare variable $zerr:XSST0010 as xs:QName := fn:QName($zerr:NS, "zerr:XSST0010");
454\ No newline at end of file
455+declare variable $zerr:XSST0010 as xs:QName := fn:QName($zerr:NS, "zerr:XSST0010");
456+
457+(:~
458+:)
459+declare variable $zerr:ZJPE0001 as xs:QName := fn:QName($zerr:NS, "zerr:ZJPE0001");
460+
461+(:~
462+:)
463+declare variable $zerr:ZJPE0002 as xs:QName := fn:QName($zerr:NS, "zerr:ZJPE0002");
464+
465+(:~
466+:)
467+declare variable $zerr:ZJPE0003 as xs:QName := fn:QName($zerr:NS, "zerr:ZJPE0003");
468+
469+(:~
470+:)
471+declare variable $zerr:ZJPE0004 as xs:QName := fn:QName($zerr:NS, "zerr:ZJPE0004");
472+
473+(:~
474+:)
475+declare variable $zerr:ZJPE0005 as xs:QName := fn:QName($zerr:NS, "zerr:ZJPE0005");
476+
477+(:~
478+:)
479+declare variable $zerr:ZJPE0006 as xs:QName := fn:QName($zerr:NS, "zerr:ZJPE0006");
480+
481+(:~
482+:)
483+declare variable $zerr:ZJPE0007 as xs:QName := fn:QName($zerr:NS, "zerr:ZJPE0007");
484+
485+(:~
486+:)
487+declare variable $zerr:ZJPE0008 as xs:QName := fn:QName($zerr:NS, "zerr:ZJPE0008");
488+
489+(:~
490+:)
491+declare variable $zerr:ZJPE0009 as xs:QName := fn:QName($zerr:NS, "zerr:ZJPE0009");
492+
493+(:~
494+:)
495+declare variable $zerr:ZJSE0001 as xs:QName := fn:QName($zerr:NS, "zerr:ZJSE0001");
496+
497+(:~
498+:)
499+declare variable $zerr:ZJSE0002 as xs:QName := fn:QName($zerr:NS, "zerr:ZJSE0002");
500+
501+(:~
502+:)
503+declare variable $zerr:ZJSE0003 as xs:QName := fn:QName($zerr:NS, "zerr:ZJSE0003");
504+
505+(:~
506+:)
507+declare variable $zerr:ZJSE0004 as xs:QName := fn:QName($zerr:NS, "zerr:ZJSE0004");
508+
509+(:~
510+:)
511+declare variable $zerr:ZJSE0005 as xs:QName := fn:QName($zerr:NS, "zerr:ZJSE0005");
512+
513+(:~
514+:)
515+declare variable $zerr:ZJSE0006 as xs:QName := fn:QName($zerr:NS, "zerr:ZJSE0006");
516+
517+(:~
518+:)
519+declare variable $zerr:ZJSE0007 as xs:QName := fn:QName($zerr:NS, "zerr:ZJSE0007");
520+
521+(:~
522+:)
523+declare variable $zerr:ZJSE0008 as xs:QName := fn:QName($zerr:NS, "zerr:ZJSE0008");
524\ No newline at end of file
525
526=== modified file 'src/context/static_context.cpp'
527--- src/context/static_context.cpp 2012-02-15 10:25:02 +0000
528+++ src/context/static_context.cpp 2012-02-16 00:23:20 +0000
529@@ -280,6 +280,11 @@
530 static_context::ZORBA_BASE64_FN_NS =
531 "http://www.zorba-xquery.com/modules/converters/base64";
532
533+
534+const char*
535+static_context::ZORBA_JSON_FN_NS =
536+"http://www.zorba-xquery.com/modules/converters/json";
537+
538 const char*
539 static_context::ZORBA_NODEREF_FN_NS =
540 "http://www.zorba-xquery.com/modules/node-reference";
541@@ -436,6 +441,7 @@
542 ns == ZORBA_REFLECTION_FN_NS ||
543 ns == ZORBA_SCRIPTING_FN_NS ||
544 ns == ZORBA_STRING_FN_NS ||
545+ ns == ZORBA_JSON_FN_NS ||
546 ns == ZORBA_FETCH_FN_NS ||
547 ns == ZORBA_NODE_FN_NS ||
548 ns == ZORBA_XML_FN_NS);
549@@ -482,6 +488,7 @@
550 {
551 return (ns == ZORBA_MATH_FN_NS ||
552 ns == ZORBA_INTROSP_SCTX_FN_NS ||
553+ ns == ZORBA_JSON_FN_NS ||
554 ns == ZORBA_RANDOM_FN_NS);
555 }
556
557
558=== modified file 'src/context/static_context.h'
559--- src/context/static_context.h 2012-02-02 09:56:52 +0000
560+++ src/context/static_context.h 2012-02-16 00:23:20 +0000
561@@ -446,6 +446,7 @@
562 // Namespaces of external modules declaring zorba builtin functions
563 static const char* ZORBA_MATH_FN_NS;
564 static const char* ZORBA_BASE64_FN_NS;
565+ static const char* ZORBA_JSON_FN_NS;
566 static const char* ZORBA_NODEREF_FN_NS;
567 static const char* ZORBA_NODEPOS_FN_NS;
568 static const char* ZORBA_STORE_DYNAMIC_COLLECTIONS_DDL_FN_NS;
569
570=== modified file 'src/diagnostics/diagnostic.cpp'
571--- src/diagnostics/diagnostic.cpp 2011-07-11 21:01:20 +0000
572+++ src/diagnostics/diagnostic.cpp 2012-02-16 00:23:20 +0000
573@@ -134,6 +134,9 @@
574 case ZORBA_STORE : o << "Zorba store" ; break;
575 case ZORBA_XQP : o << "Zorba" ; break;
576
577+ case JSON_PARSER : o << "JSON parser" ; break;
578+ case JSON_SERIALIZATION : o << "JSON serialization" ; break;
579+
580 default : /* suppresses warning */ break;
581 }
582 return o;
583
584=== modified file 'src/diagnostics/diagnostic_en.xml'
585--- src/diagnostics/diagnostic_en.xml 2012-02-15 10:25:02 +0000
586+++ src/diagnostics/diagnostic_en.xml 2012-02-16 00:23:20 +0000
587@@ -2312,6 +2312,63 @@
588 <value>"continue loop" statement not inside while statement</value>
589 </diagnostic>
590
591+ <!--////////// JSON Parse Errors ////////////////////////////////////////-->
592+
593+ <diagnostic code="ZJPE0001" name="ILLEGAL_CHARACTER">
594+ <value>'$1': illegal JSON character</value>
595+ </diagnostic>
596+ <diagnostic code="ZJPE0002" name="ILLEGAL_CODEPOINT">
597+ <value>"$1": illegal Unicode code-point</value>
598+ </diagnostic>
599+ <diagnostic code="ZJPE0003" name="ILLEGAL_ESCAPE">
600+ <value>'\\$1': illegal JSON character escape</value>
601+ </diagnostic>
602+ <diagnostic code="ZJPE0004" name="ILLEGAL_LITERAL">
603+ <value>illegal JSON literal</value>
604+ </diagnostic>
605+ <diagnostic code="ZJPE0005" name="ILLEGAL_NUMBER">
606+ <value>illegal JSON number</value>
607+ </diagnostic>
608+ <diagnostic code="ZJPE0006" name="UNEXPECTED_TOKEN">
609+ <value>"$1": unexpected JSON token</value>
610+ </diagnostic>
611+ <diagnostic code="ZJPE0007" name="UNTERMINATED_STRING">
612+ <value>unterminated JSON string</value>
613+ </diagnostic>
614+ <diagnostic code="ZJPE0008" name="ILLEGAL_QNAME">
615+ <value>"$1": illegal QName</value>
616+ </diagnostic>
617+ <diagnostic code="ZJPE0009" name="ILLEGAL_EMPTY_STRING">
618+ <value>illegal empty string</value>
619+ </diagnostic>
620+
621+ <!--////////// JSON Serialization Errors ////////////////////////////////-->
622+
623+ <diagnostic code="ZJSE0001" name="NOT_DOCUMENT_OR_ELEMENT_NODE">
624+ <value>JSON serialization requires document or element node</value>
625+ </diagnostic>
626+ <diagnostic code="ZJSE0002" name="ELEMENT_MISSING_ATTRIBUTE">
627+ <value>"$1" element missing required "$2" attribute</value>
628+ </diagnostic>
629+ <diagnostic code="ZJSE0003" name="BAD_ATTRIBUTE_VALUE">
630+ <value>"$1": illegal value for attribute "$2"</value>
631+ </diagnostic>
632+ <diagnostic code="ZJSE0004" name="BAD_ELEMENT">
633+ <value>"$1": illegal element${; must be "2"}${ or "3"}</value>
634+ </diagnostic>
635+ <diagnostic code="ZJSE0005" name="BAD_CHILD_ELEMENT">
636+ <value>"$1": illegal child element of "$2" type; must be "$3"</value>
637+ </diagnostic>
638+ <diagnostic code="ZJSE0006" name="NO_ELEMENT_CHILD">
639+ <value>JSON type "$1" can not have a child element node</value>
640+ </diagnostic>
641+ <diagnostic code="ZJSE0007" name="NO_TEXT_CHILD">
642+ <value>JSON type "$1" can not have a child text node</value>
643+ </diagnostic>
644+ <diagnostic code="ZJSE0008" name="BAD_VALUE">
645+ <value>"$1": illegal value for JSON type "$2"</value>
646+ </diagnostic>
647+
648 </namespace>
649
650 <!--////////// Zorba Warnings ////////////////////////////////////////////-->
651@@ -3269,6 +3326,14 @@
652 <value>Zorba warning</value>
653 </entry>
654
655+ <entry key="JSON parser error">
656+ <value>JSON parser error</value>
657+ </entry>
658+
659+ <entry key="JSON serialization error">
660+ <value>JSON serialization error</value>
661+ </entry>
662+
663 <entry key="dynamic error">
664 <value>dynamic error</value>
665 </entry>
666
667=== modified file 'src/diagnostics/pregenerated/diagnostic_list.cpp'
668--- src/diagnostics/pregenerated/diagnostic_list.cpp 2011-12-21 14:40:33 +0000
669+++ src/diagnostics/pregenerated/diagnostic_list.cpp 2012-02-16 00:23:20 +0000
670@@ -1097,6 +1097,57 @@
671 ZorbaErrorCode XSST0010( "XSST0010" );
672
673
674+ZorbaErrorCode ZJPE0001_ILLEGAL_CHARACTER( "ZJPE0001" );
675+
676+
677+ZorbaErrorCode ZJPE0002_ILLEGAL_CODEPOINT( "ZJPE0002" );
678+
679+
680+ZorbaErrorCode ZJPE0003_ILLEGAL_ESCAPE( "ZJPE0003" );
681+
682+
683+ZorbaErrorCode ZJPE0004_ILLEGAL_LITERAL( "ZJPE0004" );
684+
685+
686+ZorbaErrorCode ZJPE0005_ILLEGAL_NUMBER( "ZJPE0005" );
687+
688+
689+ZorbaErrorCode ZJPE0006_UNEXPECTED_TOKEN( "ZJPE0006" );
690+
691+
692+ZorbaErrorCode ZJPE0007_UNTERMINATED_STRING( "ZJPE0007" );
693+
694+
695+ZorbaErrorCode ZJPE0008_ILLEGAL_QNAME( "ZJPE0008" );
696+
697+
698+ZorbaErrorCode ZJPE0009_ILLEGAL_EMPTY_STRING( "ZJPE0009" );
699+
700+
701+ZorbaErrorCode ZJSE0001_NOT_DOCUMENT_OR_ELEMENT_NODE( "ZJSE0001" );
702+
703+
704+ZorbaErrorCode ZJSE0002_ELEMENT_MISSING_ATTRIBUTE( "ZJSE0002" );
705+
706+
707+ZorbaErrorCode ZJSE0003_BAD_ATTRIBUTE_VALUE( "ZJSE0003" );
708+
709+
710+ZorbaErrorCode ZJSE0004_BAD_ELEMENT( "ZJSE0004" );
711+
712+
713+ZorbaErrorCode ZJSE0005_BAD_CHILD_ELEMENT( "ZJSE0005" );
714+
715+
716+ZorbaErrorCode ZJSE0006_NO_ELEMENT_CHILD( "ZJSE0006" );
717+
718+
719+ZorbaErrorCode ZJSE0007_NO_TEXT_CHILD( "ZJSE0007" );
720+
721+
722+ZorbaErrorCode ZJSE0008_BAD_VALUE( "ZJSE0008" );
723+
724+
725 } // namespace zerr
726
727 namespace zwarn {
728
729=== modified file 'src/diagnostics/pregenerated/dict_en.cpp'
730--- src/diagnostics/pregenerated/dict_en.cpp 2012-02-15 10:25:02 +0000
731+++ src/diagnostics/pregenerated/dict_en.cpp 2012-02-16 00:23:20 +0000
732@@ -332,6 +332,23 @@
733 #if defined(ZORBA_WITH_DEBUGGER)
734 { "ZGDB0001", "" },
735 #endif
736+ { "ZJPE0001", "'$1': illegal JSON character" },
737+ { "ZJPE0002", "\"$1\": illegal Unicode code-point" },
738+ { "ZJPE0003", "'\\$1': illegal JSON character escape" },
739+ { "ZJPE0004", "illegal JSON literal" },
740+ { "ZJPE0005", "illegal JSON number" },
741+ { "ZJPE0006", "\"$1\": unexpected JSON token" },
742+ { "ZJPE0007", "unterminated JSON string" },
743+ { "ZJPE0008", "\"$1\": illegal QName" },
744+ { "ZJPE0009", "illegal empty string" },
745+ { "ZJSE0001", "JSON serialization requires document or element node" },
746+ { "ZJSE0002", "\"$1\" element missing required \"$2\" attribute" },
747+ { "ZJSE0003", "\"$1\": illegal value for attribute \"$2\"" },
748+ { "ZJSE0004", "\"$1\": illegal element${; must be \"2\"}${ or \"3\"}" },
749+ { "ZJSE0005", "\"$1\": illegal child element of \"$2\" type; must be \"$3\"" },
750+ { "ZJSE0006", "JSON type \"$1\" can not have a child element node" },
751+ { "ZJSE0007", "JSON type \"$1\" can not have a child text node" },
752+ { "ZJSE0008", "\"$1\": illegal value for JSON type \"$2\"" },
753 { "ZOSE0001", "\"$1\": file not found" },
754 { "ZOSE0002", "\"$1\": not plain file" },
755 { "ZOSE0003", "stream read failure" },
756@@ -494,6 +511,8 @@
757 { "~HexBinaryMustBeEven", "HexBinary value must contain an even number of characters" },
758 { "~IncompleteKeyInIndexBuild", "incomplete key during index build" },
759 { "~IncompleteKeyInIndexRefresh", "incomplete key during index refresh" },
760+ { "~JSON parser error", "JSON parser error" },
761+ { "~JSON serialization error", "JSON serialization error" },
762 { "~LibModVersionMismatch_3", "XQuery library version can not be imported by a $3 version module" },
763 { "~ModuleDeclNotInMain", "module declaration must not be in main module" },
764 { "~ModuleNotFound", "module not found" },
765
766=== modified file 'src/diagnostics/qname.cpp'
767--- src/diagnostics/qname.cpp 2011-07-01 16:07:54 +0000
768+++ src/diagnostics/qname.cpp 2012-02-16 00:23:20 +0000
769@@ -79,9 +79,15 @@
770 case 'C': return ZORBA_SERIALIZATION;
771 case 'D': return ZORBA_DDF;
772 case 'G': return ZORBA_DEBUGGER;
773+ case 'J': switch ( name[2] ) {
774+ case 'P': return JSON_PARSER;
775+ case 'S': return JSON_SERIALIZATION;
776+ default : ZORBA_ASSERT( false );
777+ }
778 case 'O': return ZORBA_OS;
779 case 'S': return ZORBA_STORE;
780 case 'X': return ZORBA_XQP;
781+
782 default : ZORBA_ASSERT( false );
783 }
784 }
785
786=== modified file 'src/functions/library.cpp'
787--- src/functions/library.cpp 2011-10-14 07:35:51 +0000
788+++ src/functions/library.cpp 2012-02-16 00:23:20 +0000
789@@ -57,6 +57,7 @@
790 #include "functions/func_sequences.h"
791 #include "functions/func_sequences_impl.h"
792 #include "functions/func_strings.h"
793+#include "functions/func_json.h"
794 #include "functions/func_var_decl.h"
795 #include "functions/func_xqdoc.h"
796 #include "functions/func_documents.h"
797@@ -107,6 +108,7 @@
798 populate_context_fnput(sctx);
799 populate_context_index_ddl(sctx);
800 populate_context_ic_ddl(sctx);
801+ populate_context_json(sctx);
802 populate_context_maths(sctx);
803 populate_context_nodes(sctx);
804 populate_context_node_position(sctx);
805
806=== added file 'src/functions/pregenerated/func_json.cpp'
807--- src/functions/pregenerated/func_json.cpp 1970-01-01 00:00:00 +0000
808+++ src/functions/pregenerated/func_json.cpp 2012-02-16 00:23:20 +0000
809@@ -0,0 +1,87 @@
810+/*
811+ * Copyright 2006-2008 The FLWOR Foundation.
812+ *
813+ * Licensed under the Apache License, Version 2.0 (the "License");
814+ * you may not use this file except in compliance with the License.
815+ * You may obtain a copy of the License at
816+ *
817+ * http://www.apache.org/licenses/LICENSE-2.0
818+ *
819+ * Unless required by applicable law or agreed to in writing, software
820+ * distributed under the License is distributed on an "AS IS" BASIS,
821+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
822+ * See the License for the specific language governing permissions and
823+ * limitations under the License.
824+ */
825+
826+// ******************************************
827+// * *
828+// * THIS IS A GENERATED FILE. DO NOT EDIT! *
829+// * SEE .xml FILE WITH SAME NAME *
830+// * *
831+// ******************************************
832+
833+
834+#include "stdafx.h"
835+#include "runtime/json/json.h"
836+#include "functions/func_json.h"
837+
838+
839+namespace zorba{
840+
841+
842+
843+PlanIter_t fn_zorba_json_parse_internal::codegen(
844+ CompilerCB*,
845+ static_context* sctx,
846+ const QueryLoc& loc,
847+ std::vector<PlanIter_t>& argv,
848+ AnnotationHolder& ann) const
849+{
850+ return new JSONParseInternal(sctx, loc, argv);
851+}
852+
853+PlanIter_t fn_zorba_json_serialize_internal::codegen(
854+ CompilerCB*,
855+ static_context* sctx,
856+ const QueryLoc& loc,
857+ std::vector<PlanIter_t>& argv,
858+ AnnotationHolder& ann) const
859+{
860+ return new JSONSerializeInternal(sctx, loc, argv);
861+}
862+
863+void populate_context_json(static_context* sctx)
864+{
865+ {
866+
867+
868+ DECL_WITH_KIND(sctx, fn_zorba_json_parse_internal,
869+ (createQName("http://www.zorba-xquery.com/modules/converters/json","","parse-internal"),
870+ GENV_TYPESYSTEM.STRING_TYPE_ONE,
871+ GENV_TYPESYSTEM.ITEM_TYPE_QUESTION,
872+ GENV_TYPESYSTEM.ELEMENT_TYPE_STAR),
873+ FunctionConsts::FN_ZORBA_JSON_PARSE_INTERNAL_2);
874+
875+ }
876+
877+
878+ {
879+
880+
881+ DECL_WITH_KIND(sctx, fn_zorba_json_serialize_internal,
882+ (createQName("http://www.zorba-xquery.com/modules/converters/json","","serialize-internal"),
883+ GENV_TYPESYSTEM.ITEM_TYPE_STAR,
884+ GENV_TYPESYSTEM.ITEM_TYPE_QUESTION,
885+ GENV_TYPESYSTEM.STRING_TYPE_ONE),
886+ FunctionConsts::FN_ZORBA_JSON_SERIALIZE_INTERNAL_2);
887+
888+ }
889+
890+}
891+
892+
893+}
894+
895+
896+
897
898=== added file 'src/functions/pregenerated/func_json.h'
899--- src/functions/pregenerated/func_json.h 1970-01-01 00:00:00 +0000
900+++ src/functions/pregenerated/func_json.h 2012-02-16 00:23:20 +0000
901@@ -0,0 +1,79 @@
902+/*
903+ * Copyright 2006-2008 The FLWOR Foundation.
904+ *
905+ * Licensed under the Apache License, Version 2.0 (the "License");
906+ * you may not use this file except in compliance with the License.
907+ * You may obtain a copy of the License at
908+ *
909+ * http://www.apache.org/licenses/LICENSE-2.0
910+ *
911+ * Unless required by applicable law or agreed to in writing, software
912+ * distributed under the License is distributed on an "AS IS" BASIS,
913+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
914+ * See the License for the specific language governing permissions and
915+ * limitations under the License.
916+ */
917+
918+// ******************************************
919+// * *
920+// * THIS IS A GENERATED FILE. DO NOT EDIT! *
921+// * SEE .xml FILE WITH SAME NAME *
922+// * *
923+// ******************************************
924+
925+
926+#ifndef ZORBA_FUNCTIONS_JSON_H
927+#define ZORBA_FUNCTIONS_JSON_H
928+
929+
930+#include "common/shared_types.h"
931+#include "functions/function_impl.h"
932+
933+
934+namespace zorba {
935+
936+
937+void populate_context_json(static_context* sctx);
938+
939+
940+
941+
942+//fn-zorba-json:parse-internal
943+class fn_zorba_json_parse_internal : public function
944+{
945+public:
946+ fn_zorba_json_parse_internal(const signature& sig, FunctionConsts::FunctionKind kind)
947+ :
948+ function(sig, kind)
949+ {
950+
951+ }
952+
953+ CODEGEN_DECL();
954+};
955+
956+
957+//fn-zorba-json:serialize-internal
958+class fn_zorba_json_serialize_internal : public function
959+{
960+public:
961+ fn_zorba_json_serialize_internal(const signature& sig, FunctionConsts::FunctionKind kind)
962+ :
963+ function(sig, kind)
964+ {
965+
966+ }
967+
968+ CODEGEN_DECL();
969+};
970+
971+
972+} //namespace zorba
973+
974+
975+#endif
976+/*
977+ * Local variables:
978+ * mode: c++
979+ * End:
980+ */
981
982=== modified file 'src/functions/pregenerated/function_enum.h'
983--- src/functions/pregenerated/function_enum.h 2012-01-11 17:30:25 +0000
984+++ src/functions/pregenerated/function_enum.h 2012-02-16 00:23:20 +0000
985@@ -166,6 +166,8 @@
986 FN_ZORBA_INTROSPECT_SCTX_IN_SCOPE_ATTRIBUTE_GROUPS_0,
987 FN_ZORBA_INTROSPECT_SCTX_OPTION_1,
988 FN_ZORBA_INTROSPECT_SCTX_FUNCTION_ANNOTATIONS_2,
989+ FN_ZORBA_JSON_PARSE_INTERNAL_2,
990+ FN_ZORBA_JSON_SERIALIZE_INTERNAL_2,
991 MATH_SQRT_1,
992 MATH_EXP_1,
993 MATH_EXP10_1,
994
995=== modified file 'src/runtime/CMakeLists.txt'
996--- src/runtime/CMakeLists.txt 2011-06-01 13:16:28 +0000
997+++ src/runtime/CMakeLists.txt 2012-02-16 00:23:20 +0000
998@@ -115,6 +115,9 @@
999 durations_dates_times/DurationsDatesTimesImpl.cpp
1000 indexing/doc_indexer.cpp
1001 indexing/index_ddl.cpp
1002+ json/common.cpp
1003+ json/jsonml_array.cpp
1004+ json/snelson.cpp
1005 numerics/NumericsImpl.cpp
1006 numerics/format_integer_impl.cpp
1007 sequences/SequencesImpl.cpp
1008
1009=== modified file 'src/runtime/full_text/ft_match.cpp'
1010--- src/runtime/full_text/ft_match.cpp 2011-06-14 17:26:33 +0000
1011+++ src/runtime/full_text/ft_match.cpp 2012-02-16 00:23:20 +0000
1012@@ -31,7 +31,7 @@
1013 return o << "0x" << hex << reinterpret_cast<unsigned long>( obj ) << dec;
1014 }
1015
1016-DEF_OMANIP1( print_addr, void const*, obj )
1017+DEF_OMANIP1( print_addr, void const* )
1018
1019 ostream& operator<<( ostream &o, ft_string_match const &sm ) {
1020 return o << "{SM: "
1021@@ -52,8 +52,7 @@
1022 return o;
1023 }
1024
1025-DEF_OMANIP2( print_string_matches, char const*, label,
1026- ft_string_matches const&, sms )
1027+DEF_OMANIP2( print_string_matches, char const*, ft_string_matches const& )
1028
1029 ostream& operator<<( ostream &o, ft_match const &m ) {
1030 return o << indent << "ft_match @ " << print_addr( &m ) << '\n'
1031
1032=== added directory 'src/runtime/json'
1033=== added file 'src/runtime/json/common.cpp'
1034--- src/runtime/json/common.cpp 1970-01-01 00:00:00 +0000
1035+++ src/runtime/json/common.cpp 2012-02-16 00:23:20 +0000
1036@@ -0,0 +1,62 @@
1037+/*
1038+ * Copyright 2006-2011 The FLWOR Foundation.
1039+ *
1040+ * Licensed under the Apache License, Version 2.0 (the "License");
1041+ * you may not use this file except in compliance with the License.
1042+ * You may obtain a copy of the License at
1043+ *
1044+ * http://www.apache.org/licenses/LICENSE-2.0
1045+ *
1046+ * Unless required by applicable law or agreed to in writing, software
1047+ * distributed under the License is distributed on an "AS IS" BASIS,
1048+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1049+ * See the License for the specific language governing permissions and
1050+ * limitations under the License.
1051+ */
1052+#include "stdafx.h"
1053+
1054+#include "store/api/iterator.h"
1055+
1056+#include "common.h"
1057+
1058+using namespace std;
1059+
1060+namespace zorba {
1061+
1062+///////////////////////////////////////////////////////////////////////////////
1063+
1064+bool get_attribute_value( store::Item_t const &element, char const *att_name,
1065+ zstring *att_value ) {
1066+ store::Iterator_t i( element->getAttributes() );
1067+ bool found = false;
1068+ i->open();
1069+ store::Item_t att_item;
1070+ while ( i->next( att_item ) ) {
1071+ if ( att_item->getNodeName()->getStringValue() == att_name ) {
1072+ att_item->getStringValue2( *att_value );
1073+ found = true;
1074+ break;
1075+ }
1076+ }
1077+ i->close();
1078+ return found;
1079+}
1080+
1081+///////////////////////////////////////////////////////////////////////////////
1082+
1083+#if ZORBA_DEBUG_JSON
1084+
1085+ostream& operator<<( ostream &o, parse_state s ) {
1086+ static char const *const string_of[] = {
1087+ "in_array",
1088+ "in_object"
1089+ };
1090+ return o << string_of[ s ];
1091+}
1092+
1093+#endif /* ZORBA_DEBUG_JSON */
1094+
1095+///////////////////////////////////////////////////////////////////////////////
1096+
1097+} // namespace zorba
1098+/* vim:set et sw=2 ts=2: */
1099
1100=== added file 'src/runtime/json/common.h'
1101--- src/runtime/json/common.h 1970-01-01 00:00:00 +0000
1102+++ src/runtime/json/common.h 2012-02-16 00:23:20 +0000
1103@@ -0,0 +1,120 @@
1104+/*
1105+ * Copyright 2006-2011 The FLWOR Foundation.
1106+ *
1107+ * Licensed under the Apache License, Version 2.0 (the "License");
1108+ * you may not use this file except in compliance with the License.
1109+ * You may obtain a copy of the License at
1110+ *
1111+ * http://www.apache.org/licenses/LICENSE-2.0
1112+ *
1113+ * Unless required by applicable law or agreed to in writing, software
1114+ * distributed under the License is distributed on an "AS IS" BASIS,
1115+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1116+ * See the License for the specific language governing permissions and
1117+ * limitations under the License.
1118+ */
1119+
1120+#ifndef ZORBA_RUNTIME_JSON_COMMON_H
1121+#define ZORBA_RUNTIME_JSON_COMMON_H
1122+
1123+#include <iostream>
1124+#include <stack>
1125+
1126+#include "store/api/item.h"
1127+#include "store/api/item_factory.h"
1128+#include "util/indent.h"
1129+#include "util/omanip.h"
1130+#include "zorbatypes/zstring.h"
1131+
1132+#define ZORBA_DEBUG_JSON 0
1133+
1134+namespace zorba {
1135+
1136+///////////////////////////////////////////////////////////////////////////////
1137+
1138+typedef std::stack<store::Item*> item_stack_type;
1139+
1140+enum parse_state {
1141+ in_array,
1142+ in_object
1143+};
1144+
1145+typedef std::stack<int> state_stack_type;
1146+
1147+namespace whitespace {
1148+ enum type {
1149+ none,
1150+ some,
1151+ indent
1152+ };
1153+}
1154+
1155+///////////////////////////////////////////////////////////////////////////////
1156+
1157+bool get_attribute_value( store::Item_t const &element, char const *att_name,
1158+ zstring *att_value );
1159+
1160+typedef std::ostream& (*std_omanip_type)(std::ostream&);
1161+
1162+inline std::ostream& if_do( std::ostream &o, bool expr, std_omanip_type fn ) {
1163+ if ( expr )
1164+ o << fn;
1165+ return o;
1166+}
1167+DEF_OMANIP2( if_do, bool, std_omanip_type )
1168+
1169+#define if_indent(WS,FN) if_do( (WS) == whitespace::indent, FN )
1170+
1171+inline std::ostream& if_emit( std::ostream &o, bool expr, char c ) {
1172+ if ( expr )
1173+ o << c;
1174+ return o;
1175+}
1176+DEF_OMANIP2( if_emit, bool, char )
1177+
1178+///////////////////////////////////////////////////////////////////////////////
1179+
1180+#define IN_STATE(S) ztd::top_stack_equals( state_stack, (S) )
1181+
1182+#if ZORBA_DEBUG_JSON
1183+
1184+std::ostream& operator<<( std::ostream &o, parse_state s );
1185+
1186+# define PUSH_ITEM(I) \
1187+ do { \
1188+ cout << __LINE__ << ":PUSH_ITEM( " << (I)->show() << " )" << endl; \
1189+ item_stack.push( (I).getp() ); \
1190+ } while (0)
1191+
1192+# define POP_ITEM() \
1193+ do { \
1194+ cout << __LINE__ << ":POP_ITEM()" << endl; \
1195+ cur_item = ztd::pop_stack( item_stack ); \
1196+ } while (0)
1197+
1198+# define PUSH_STATE(S) \
1199+ do { \
1200+ cout << __LINE__ << ":PUSH_STATE( " << (S) << " )" << endl; \
1201+ state_stack.push( S ); \
1202+ } while (0)
1203+
1204+# define POP_STATE() \
1205+ do { \
1206+ cout << __LINE__ << ":POP_STATE()" << endl; \
1207+ state_stack.pop(); \
1208+ } while (0) \
1209+
1210+#else
1211+
1212+# define PUSH_ITEM(I) item_stack.push( (I).getp() )
1213+# define POP_ITEM() cur_item = ztd::pop_stack( item_stack )
1214+# define PUSH_STATE(S) state_stack.push( S )
1215+# define POP_STATE() state_stack.pop()
1216+
1217+#endif /* ZORBA_DEBUG_JSON */
1218+
1219+///////////////////////////////////////////////////////////////////////////////
1220+
1221+} // namespace zorba
1222+#endif /* ZORBA_RUNTIME_JSON_COMMON_H */
1223+/* vim:set et sw=2 ts=2: */
1224
1225=== added file 'src/runtime/json/json_impl.cpp'
1226--- src/runtime/json/json_impl.cpp 1970-01-01 00:00:00 +0000
1227+++ src/runtime/json/json_impl.cpp 2012-02-16 00:23:20 +0000
1228@@ -0,0 +1,217 @@
1229+/*
1230+ * Copyright 2006-2011 The FLWOR Foundation.
1231+ *
1232+ * Licensed under the Apache License, Version 2.0 (the "License");
1233+ * you may not use this file except in compliance with the License.
1234+ * You may obtain a copy of the License at
1235+ *
1236+ * http://www.apache.org/licenses/LICENSE-2.0
1237+ *
1238+ * Unless required by applicable law or agreed to in writing, software
1239+ * distributed under the License is distributed on an "AS IS" BASIS,
1240+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1241+ * See the License for the specific language governing permissions and
1242+ * limitations under the License.
1243+ */
1244+#include "stdafx.h"
1245+
1246+#include <map>
1247+#include <sstream>
1248+
1249+#include <zorba/diagnostic_list.h>
1250+
1251+#include "runtime/json/json.h"
1252+#include "store/api/item_factory.h"
1253+#include "system/globalenv.h"
1254+#include "util/mem_streambuf.h"
1255+
1256+#include "jsonml_array.h"
1257+#include "snelson.h"
1258+
1259+using namespace std;
1260+
1261+namespace zorba {
1262+
1263+///////////////////////////////////////////////////////////////////////////////
1264+
1265+typedef map<zstring,zstring> options_type;
1266+
1267+static void get_options( store::Item_t const &options_element,
1268+ options_type *options ) {
1269+ ZORBA_ASSERT( options_element->getNodeKind() ==
1270+ store::StoreConsts::elementNode );
1271+ store::Iterator_t i = options_element->getChildren();
1272+ i->open();
1273+ store::Item_t option_item;
1274+ while ( i->next( option_item ) ) {
1275+ if ( option_item->getNodeKind() == store::StoreConsts::elementNode ) {
1276+ zstring const name( option_item->getNodeName()->getStringValue() );
1277+ zstring value;
1278+ get_attribute_value( option_item, "value", &value );
1279+ (*options)[ name ] = value;
1280+ }
1281+ }
1282+ i->close();
1283+}
1284+
1285+///////////////////////////////////////////////////////////////////////////////
1286+
1287+bool JSONParseInternal::nextImpl( store::Item_t& result,
1288+ PlanState &planState ) const {
1289+ store::Item_t cur_item;
1290+ options_type options;
1291+ istringstream iss;
1292+ mem_streambuf buf;
1293+
1294+ PlanIteratorState *state;
1295+ DEFAULT_STACK_INIT( PlanIteratorState, state, planState );
1296+
1297+ ZORBA_ASSERT( theChildren.size() == 2 );
1298+ consumeNext( cur_item, theChildren[1], planState );
1299+ get_options( cur_item, &options );
1300+
1301+ consumeNext( cur_item, theChildren[0], planState );
1302+ result = nullptr;
1303+
1304+ istream *is;
1305+ if ( cur_item->isStreamable() ) {
1306+ is = &cur_item->getStream();
1307+ } else {
1308+ zstring s;
1309+ cur_item->getStringValue2( s );
1310+ // Doing it this way uses the string data in-place with no copy.
1311+ buf.set( s.data(), s.size() );
1312+ iss.ios::rdbuf( &buf );
1313+ is = &iss;
1314+ }
1315+
1316+ try {
1317+ json::parser p( *is );
1318+ p.set_loc(
1319+ loc.getFilename().c_str(), loc.getLineBegin(), loc.getColumnBegin()
1320+ );
1321+
1322+ options_type::mapped_type const &format = options[ "json-format" ];
1323+ ZORBA_ASSERT( !format.empty() );
1324+ if ( format == "Snelson" )
1325+ snelson::parse( p, &result );
1326+ else if ( format == "JsonML-array" )
1327+ jsonml_array::parse( p, &result );
1328+ else
1329+ ZORBA_ASSERT( false );
1330+ }
1331+ catch ( json::illegal_character const &e ) {
1332+ throw XQUERY_EXCEPTION(
1333+ zerr::ZJPE0001_ILLEGAL_CHARACTER,
1334+ ERROR_PARAMS( e.get_char() ),
1335+ ERROR_LOC( e.get_loc() )
1336+ );
1337+ }
1338+ catch ( json::illegal_codepoint const &e ) {
1339+ throw XQUERY_EXCEPTION(
1340+ zerr::ZJPE0002_ILLEGAL_CODEPOINT,
1341+ ERROR_PARAMS( e.get_codepoint() ),
1342+ ERROR_LOC( e.get_loc() )
1343+ );
1344+ }
1345+ catch ( json::illegal_escape const &e ) {
1346+ throw XQUERY_EXCEPTION(
1347+ zerr::ZJPE0003_ILLEGAL_ESCAPE,
1348+ ERROR_PARAMS( e.get_escape() ),
1349+ ERROR_LOC( e.get_loc() )
1350+ );
1351+ }
1352+ catch ( json::illegal_literal const &e ) {
1353+ throw XQUERY_EXCEPTION(
1354+ zerr::ZJPE0004_ILLEGAL_LITERAL,
1355+ ERROR_LOC( e.get_loc() )
1356+ );
1357+ }
1358+ catch ( json::illegal_number const &e ) {
1359+ throw XQUERY_EXCEPTION(
1360+ zerr::ZJPE0005_ILLEGAL_NUMBER,
1361+ ERROR_LOC( e.get_loc() )
1362+ );
1363+ }
1364+ catch ( json::unexpected_token const &e ) {
1365+ throw XQUERY_EXCEPTION(
1366+ zerr::ZJPE0006_UNEXPECTED_TOKEN,
1367+ ERROR_PARAMS( e.get_token() ),
1368+ ERROR_LOC( e.get_loc() )
1369+ );
1370+ }
1371+ catch ( json::unterminated_string const &e ) {
1372+ throw XQUERY_EXCEPTION(
1373+ zerr::ZJPE0007_UNTERMINATED_STRING,
1374+ ERROR_LOC( e.get_loc() )
1375+ );
1376+ }
1377+
1378+ STACK_PUSH( !!result, state );
1379+ STACK_END( state );
1380+}
1381+
1382+///////////////////////////////////////////////////////////////////////////////
1383+
1384+bool JSONSerializeInternal::nextImpl( store::Item_t& result,
1385+ PlanState &planState ) const {
1386+ store::Item_t cur_item;
1387+ options_type options;
1388+
1389+ PlanIteratorState *state;
1390+ DEFAULT_STACK_INIT( PlanIteratorState, state, planState );
1391+
1392+ ZORBA_ASSERT( theChildren.size() == 2 );
1393+ consumeNext( cur_item, theChildren[1], planState );
1394+ get_options( cur_item, &options );
1395+
1396+ consumeNext( cur_item, theChildren[0], planState );
1397+ try {
1398+ options_type::mapped_type const &format_opt = options[ "json-format" ];
1399+ ZORBA_ASSERT( !format_opt.empty() );
1400+
1401+ whitespace::type ws;
1402+ options_type::mapped_type const &whitespace_opt = options[ "whitespace" ];
1403+ if ( whitespace_opt.empty() || whitespace_opt == "none" )
1404+ ws = whitespace::none;
1405+ else if ( whitespace_opt == "some" )
1406+ ws = whitespace::some;
1407+ else if ( whitespace_opt == "indent" )
1408+ ws = whitespace::indent;
1409+ else
1410+ ZORBA_ASSERT( false );
1411+
1412+ ostringstream oss;
1413+ switch ( cur_item->getNodeKind() ) {
1414+ case store::StoreConsts::documentNode:
1415+ case store::StoreConsts::elementNode:
1416+ if ( format_opt == "Snelson" )
1417+ snelson::serialize( oss, cur_item, ws );
1418+ else if ( format_opt == "JsonML-array" )
1419+ jsonml_array::serialize( oss, cur_item, ws );
1420+ else
1421+ ZORBA_ASSERT( false );
1422+ break;
1423+ default:
1424+ throw XQUERY_EXCEPTION(
1425+ zerr::ZJSE0001_NOT_DOCUMENT_OR_ELEMENT_NODE,
1426+ ERROR_LOC( loc )
1427+ );
1428+ }
1429+ // This string copying is inefficient, but I can't see another way.
1430+ zstring temp( oss.str() );
1431+ GENV_ITEMFACTORY->createString( result, temp );
1432+ }
1433+ catch ( ZorbaException &e ) {
1434+ set_source( e, loc );
1435+ throw;
1436+ }
1437+
1438+ STACK_PUSH( !!result, state );
1439+ STACK_END( state );
1440+}
1441+
1442+///////////////////////////////////////////////////////////////////////////////
1443+
1444+} // namespace zorba
1445+/* vim:set et sw=2 ts=2: */
1446
1447=== added file 'src/runtime/json/jsonml_array.cpp'
1448--- src/runtime/json/jsonml_array.cpp 1970-01-01 00:00:00 +0000
1449+++ src/runtime/json/jsonml_array.cpp 2012-02-16 00:23:20 +0000
1450@@ -0,0 +1,285 @@
1451+/*
1452+ * Copyright 2006-2011 The FLWOR Foundation.
1453+ *
1454+ * Licensed under the Apache License, Version 2.0 (the "License");
1455+ * you may not use this file except in compliance with the License.
1456+ * You may obtain a copy of the License at
1457+ *
1458+ * http://www.apache.org/licenses/LICENSE-2.0
1459+ *
1460+ * Unless required by applicable law or agreed to in writing, software
1461+ * distributed under the License is distributed on an "AS IS" BASIS,
1462+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1463+ * See the License for the specific language governing permissions and
1464+ * limitations under the License.
1465+ */
1466+#include "stdafx.h"
1467+
1468+#include <sstream>
1469+
1470+#include <zorba/diagnostic_list.h>
1471+
1472+#include "runtime/json/json.h"
1473+#include "store/api/item_factory.h"
1474+#include "system/globalenv.h"
1475+#include "types/root_typemanager.h"
1476+#include "util/ascii_util.h"
1477+#include "util/cxx_util.h"
1478+#include "util/json_parser.h"
1479+#include "util/mem_streambuf.h"
1480+#include "util/omanip.h"
1481+#include "util/oseparator.h"
1482+#include "util/stl_util.h"
1483+
1484+#include "jsonml_array.h"
1485+
1486+using namespace std;
1487+
1488+namespace zorba {
1489+
1490+///////////////////////////////////////////////////////////////////////////////
1491+
1492+static void split_name( zstring const &name, zstring *prefix, zstring *local ) {
1493+ zstring::size_type const colon = name.find( ':' );
1494+ if ( colon != zstring::npos ) {
1495+ *prefix = name.substr( 0, colon );
1496+ *local = name.substr( colon + 1 );
1497+ if ( prefix->empty() || local->empty() )
1498+ throw XQUERY_EXCEPTION(
1499+ zerr::ZJPE0008_ILLEGAL_QNAME,
1500+ ERROR_PARAMS( name )
1501+ );
1502+ } else {
1503+ prefix->clear();
1504+ *local = name;
1505+ }
1506+}
1507+
1508+namespace expect {
1509+ enum type {
1510+ none,
1511+ element_name,
1512+ attribute_name,
1513+ attribute_value
1514+ };
1515+}
1516+
1517+///////////////////////////////////////////////////////////////////////////////
1518+
1519+namespace jsonml_array {
1520+
1521+void parse( json::parser &p, store::Item_t *result ) {
1522+ ZORBA_ASSERT( result );
1523+
1524+ state_stack_type state_stack;
1525+
1526+ store::Item_t cur_item, junk_item, value_item;
1527+ store::Item_t att_name, element_name, type_name;
1528+
1529+ zstring base_uri;
1530+ bool got_something = false;
1531+ item_stack_type item_stack;
1532+ expect::type expect_what = expect::none;
1533+ store::NsBindings ns_bindings;
1534+ zstring value;
1535+
1536+ json::token token;
1537+ while ( p.next( &token ) ) {
1538+ got_something = true;
1539+ switch ( token.get_type() ) {
1540+
1541+ case '[':
1542+ PUSH_STATE( in_array );
1543+ expect_what = expect::element_name;
1544+ break;
1545+
1546+ case '{':
1547+ PUSH_STATE( in_object );
1548+ expect_what = expect::attribute_name;
1549+ break;
1550+
1551+ case ']':
1552+ POP_ITEM();
1553+ // no break;
1554+ case '}':
1555+ POP_STATE();
1556+ expect_what = expect::none;
1557+ break;
1558+
1559+ case ',':
1560+ expect_what = IN_STATE( in_object ) ?
1561+ expect::attribute_name : expect::none;
1562+ break;
1563+
1564+ case ':':
1565+ expect_what = expect::attribute_value;
1566+ break;
1567+
1568+ case json::token::number:
1569+ case 'F':
1570+ case 'T':
1571+ case json::token::json_null:
1572+ case json::token::string: {
1573+ value = token.get_value();
1574+ zstring prefix, local;
1575+ switch ( expect_what ) {
1576+ case expect::element_name:
1577+ split_name( value, &prefix, &local );
1578+ GENV_ITEMFACTORY->createQName( element_name, "", prefix, local );
1579+ type_name = GENV_TYPESYSTEM.XS_UNTYPED_QNAME;
1580+ GENV_ITEMFACTORY->createElementNode(
1581+ cur_item,
1582+ item_stack.empty() ? nullptr : item_stack.top(),
1583+ element_name, type_name, false, false, ns_bindings, base_uri
1584+ );
1585+ PUSH_ITEM( cur_item );
1586+ if ( !*result )
1587+ *result = cur_item;
1588+ break;
1589+ case expect::attribute_name:
1590+ split_name( value, &prefix, &local );
1591+ GENV_ITEMFACTORY->createQName( att_name, "", prefix, local );
1592+ break;
1593+ case expect::attribute_value:
1594+ type_name = GENV_TYPESYSTEM.XS_UNTYPED_QNAME;
1595+ GENV_ITEMFACTORY->createString( value_item, value );
1596+ GENV_ITEMFACTORY->createAttributeNode(
1597+ junk_item, cur_item, att_name, type_name, value_item
1598+ );
1599+ break;
1600+ case expect::none:
1601+ GENV_ITEMFACTORY->createTextNode( junk_item, cur_item, value );
1602+ break;
1603+ }
1604+ break;
1605+ }
1606+
1607+ case json::token::none:
1608+ break;
1609+
1610+ default:
1611+ assert( false );
1612+ } // switch
1613+ } // while
1614+ if ( !got_something )
1615+ throw XQUERY_EXCEPTION( zerr::ZJPE0009_ILLEGAL_EMPTY_STRING );
1616+}
1617+
1618+} // namespace jsonml_array
1619+
1620+///////////////////////////////////////////////////////////////////////////////
1621+
1622+static ostream& serialize_attributes( ostream &o, store::Item_t const &element,
1623+ oseparator &sep, whitespace::type ws ) {
1624+ bool emitted_attributes = false;
1625+ oseparator att_sep;
1626+ switch ( ws ) {
1627+ case whitespace::none : att_sep.sep( "," ); break;
1628+ case whitespace::some : att_sep.sep( ", " ); break;
1629+ case whitespace::indent: att_sep.sep( ",\n" ); break;
1630+ }
1631+
1632+ store::Iterator_t i( element->getAttributes() );
1633+ i->open();
1634+ store::Item_t att_item;
1635+ while ( i->next( att_item ) ) {
1636+ zstring const att_name( att_item->getNodeName()->getStringValue() );
1637+ if ( att_name == "xmlns" )
1638+ continue;
1639+ if ( !emitted_attributes ) {
1640+ o << sep
1641+ << if_emit( ws == whitespace::indent, '\n' )
1642+ << if_indent( ws, indent ) << '{'
1643+ << if_indent( ws, inc_indent );
1644+ emitted_attributes = true;
1645+ }
1646+ bool const was_printing = att_sep.printing();
1647+ o << att_sep;
1648+ if ( was_printing )
1649+ o << if_indent( ws, indent );
1650+ else
1651+ o << if_emit( ws, ' ' );
1652+
1653+ o << '"' << att_name << '"'
1654+ << if_emit( ws, ' ' ) << ':' << if_emit( ws, ' ' )
1655+ << '"' << att_item->getStringValue() << '"';
1656+ }
1657+ i->close();
1658+ if ( emitted_attributes )
1659+ o << if_emit( ws, ' ' ) << '}' << if_indent( ws, dec_indent );
1660+ return o;
1661+}
1662+DEF_OMANIP3( serialize_attributes, store::Item_t const&, oseparator&,
1663+ whitespace::type )
1664+
1665+static ostream& serialize_children( ostream&, store::Item_t const &parent,
1666+ oseparator&, whitespace::type );
1667+DEF_OMANIP3( serialize_children, store::Item_t const&, oseparator&,
1668+ whitespace::type )
1669+
1670+static ostream& serialize_element( ostream &o, store::Item_t const &element,
1671+ oseparator &sep, whitespace::type ws ) {
1672+ if ( sep.printing() )
1673+ o << if_emit( ws == whitespace::indent, '\n' );
1674+ sep.printing( true );
1675+ o << if_indent( ws, indent ) << '[' << if_emit( ws, ' ' )
1676+ << '"' << element->getNodeName()->getStringValue() << '"'
1677+ << if_indent( ws, inc_indent )
1678+ << serialize_attributes( element, sep, ws )
1679+ << serialize_children( element, sep, ws )
1680+ << if_emit( ws, ' ' ) << ']'
1681+ << if_indent( ws, dec_indent );
1682+ return o;
1683+}
1684+DEF_OMANIP3( serialize_element, store::Item_t const&, oseparator&,
1685+ whitespace::type )
1686+
1687+static ostream& serialize_children( ostream &o, store::Item_t const &parent,
1688+ oseparator &sep, whitespace::type ws ) {
1689+ store::Iterator_t i( parent->getChildren() );
1690+ i->open();
1691+ store::Item_t child;
1692+ while ( i->next( child ) ) {
1693+ switch ( child->getNodeKind() ) {
1694+ case store::StoreConsts::elementNode:
1695+ o << sep << serialize_element( child, sep, ws );
1696+ break;
1697+ case store::StoreConsts::textNode:
1698+ o << sep << '"' << child->getStringValue() << '"';
1699+ break;
1700+ default:
1701+ break;
1702+ }
1703+ }
1704+ i->close();
1705+ return o;
1706+}
1707+
1708+///////////////////////////////////////////////////////////////////////////////
1709+
1710+namespace jsonml_array {
1711+
1712+void serialize( ostream &o, store::Item_t const &item, whitespace::type ws ) {
1713+ oseparator sep;
1714+ if ( ws )
1715+ sep.sep( ", " );
1716+ else
1717+ sep.sep( "," );
1718+ switch ( item->getNodeKind() ) {
1719+ case store::StoreConsts::documentNode:
1720+ o << serialize_children( item, sep, ws );
1721+ break;
1722+ case store::StoreConsts::elementNode:
1723+ o << serialize_element( item, sep, ws );
1724+ break;
1725+ default:
1726+ throw XQUERY_EXCEPTION( zerr::ZJSE0001_NOT_DOCUMENT_OR_ELEMENT_NODE );
1727+ }
1728+}
1729+
1730+} // namespace jsonml_array
1731+
1732+///////////////////////////////////////////////////////////////////////////////
1733+
1734+} // namespace zorba
1735+/* vim:set et sw=2 ts=2: */
1736
1737=== added file 'src/runtime/json/jsonml_array.h'
1738--- src/runtime/json/jsonml_array.h 1970-01-01 00:00:00 +0000
1739+++ src/runtime/json/jsonml_array.h 2012-02-16 00:23:20 +0000
1740@@ -0,0 +1,41 @@
1741+/*
1742+ * Copyright 2006-2011 The FLWOR Foundation.
1743+ *
1744+ * Licensed under the Apache License, Version 2.0 (the "License");
1745+ * you may not use this file except in compliance with the License.
1746+ * You may obtain a copy of the License at
1747+ *
1748+ * http://www.apache.org/licenses/LICENSE-2.0
1749+ *
1750+ * Unless required by applicable law or agreed to in writing, software
1751+ * distributed under the License is distributed on an "AS IS" BASIS,
1752+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1753+ * See the License for the specific language governing permissions and
1754+ * limitations under the License.
1755+ */
1756+#include "stdafx.h"
1757+
1758+#ifndef ZORBA_RUNTIME_JSON_JSONML_ARRAY_H
1759+#define ZORBA_RUNTIME_JSON_JSONML_ARRAY_H
1760+
1761+#include <iostream>
1762+
1763+#include "store/api/item.h"
1764+#include "util/json_parser.h"
1765+
1766+#include "common.h"
1767+
1768+namespace zorba {
1769+namespace jsonml_array {
1770+
1771+///////////////////////////////////////////////////////////////////////////////
1772+
1773+void parse( json::parser &p, store::Item_t *result );
1774+void serialize( std::ostream&, store::Item_t const &item, whitespace::type );
1775+
1776+///////////////////////////////////////////////////////////////////////////////
1777+
1778+} // namespace jsonml_array
1779+} // namespace zorba
1780+#endif /* ZORBA_RUNTIME_JSON_JSONML_ARRAY_H */
1781+/* vim:set et sw=2 ts=2: */
1782
1783=== added directory 'src/runtime/json/pregenerated'
1784=== added file 'src/runtime/json/pregenerated/json.cpp'
1785--- src/runtime/json/pregenerated/json.cpp 1970-01-01 00:00:00 +0000
1786+++ src/runtime/json/pregenerated/json.cpp 2012-02-16 00:23:20 +0000
1787@@ -0,0 +1,94 @@
1788+/*
1789+ * Copyright 2006-2008 The FLWOR Foundation.
1790+ *
1791+ * Licensed under the Apache License, Version 2.0 (the "License");
1792+ * you may not use this file except in compliance with the License.
1793+ * You may obtain a copy of the License at
1794+ *
1795+ * http://www.apache.org/licenses/LICENSE-2.0
1796+ *
1797+ * Unless required by applicable law or agreed to in writing, software
1798+ * distributed under the License is distributed on an "AS IS" BASIS,
1799+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1800+ * See the License for the specific language governing permissions and
1801+ * limitations under the License.
1802+ */
1803+
1804+// ******************************************
1805+// * *
1806+// * THIS IS A GENERATED FILE. DO NOT EDIT! *
1807+// * SEE .xml FILE WITH SAME NAME *
1808+// * *
1809+// ******************************************
1810+
1811+#include "stdafx.h"
1812+#include "zorbatypes/rchandle.h"
1813+#include "zorbatypes/zstring.h"
1814+#include "runtime/visitors/planiter_visitor.h"
1815+#include "runtime/json/json.h"
1816+#include "system/globalenv.h"
1817+
1818+
1819+
1820+namespace zorba {
1821+
1822+// <JSONParseInternal>
1823+const char* JSONParseInternal::class_name_str = "JSONParseInternal";
1824+JSONParseInternal::class_factory<JSONParseInternal>
1825+JSONParseInternal::g_class_factory;
1826+
1827+const serialization::ClassVersion
1828+JSONParseInternal::class_versions[] ={{ 1, 0x000905, false}};
1829+
1830+const int JSONParseInternal::class_versions_count =
1831+sizeof(JSONParseInternal::class_versions)/sizeof(struct serialization::ClassVersion);
1832+
1833+void JSONParseInternal::accept(PlanIterVisitor& v) const {
1834+ v.beginVisit(*this);
1835+
1836+ std::vector<PlanIter_t>::const_iterator lIter = theChildren.begin();
1837+ std::vector<PlanIter_t>::const_iterator lEnd = theChildren.end();
1838+ for ( ; lIter != lEnd; ++lIter ){
1839+ (*lIter)->accept(v);
1840+ }
1841+
1842+ v.endVisit(*this);
1843+}
1844+
1845+JSONParseInternal::~JSONParseInternal() {}
1846+
1847+// </JSONParseInternal>
1848+
1849+
1850+// <JSONSerializeInternal>
1851+const char* JSONSerializeInternal::class_name_str = "JSONSerializeInternal";
1852+JSONSerializeInternal::class_factory<JSONSerializeInternal>
1853+JSONSerializeInternal::g_class_factory;
1854+
1855+const serialization::ClassVersion
1856+JSONSerializeInternal::class_versions[] ={{ 1, 0x000905, false}};
1857+
1858+const int JSONSerializeInternal::class_versions_count =
1859+sizeof(JSONSerializeInternal::class_versions)/sizeof(struct serialization::ClassVersion);
1860+
1861+void JSONSerializeInternal::accept(PlanIterVisitor& v) const {
1862+ v.beginVisit(*this);
1863+
1864+ std::vector<PlanIter_t>::const_iterator lIter = theChildren.begin();
1865+ std::vector<PlanIter_t>::const_iterator lEnd = theChildren.end();
1866+ for ( ; lIter != lEnd; ++lIter ){
1867+ (*lIter)->accept(v);
1868+ }
1869+
1870+ v.endVisit(*this);
1871+}
1872+
1873+JSONSerializeInternal::~JSONSerializeInternal() {}
1874+
1875+// </JSONSerializeInternal>
1876+
1877+
1878+
1879+}
1880+
1881+
1882
1883=== added file 'src/runtime/json/pregenerated/json.h'
1884--- src/runtime/json/pregenerated/json.h 1970-01-01 00:00:00 +0000
1885+++ src/runtime/json/pregenerated/json.h 2012-02-16 00:23:20 +0000
1886@@ -0,0 +1,114 @@
1887+/*
1888+ * Copyright 2006-2008 The FLWOR Foundation.
1889+ *
1890+ * Licensed under the Apache License, Version 2.0 (the "License");
1891+ * you may not use this file except in compliance with the License.
1892+ * You may obtain a copy of the License at
1893+ *
1894+ * http://www.apache.org/licenses/LICENSE-2.0
1895+ *
1896+ * Unless required by applicable law or agreed to in writing, software
1897+ * distributed under the License is distributed on an "AS IS" BASIS,
1898+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1899+ * See the License for the specific language governing permissions and
1900+ * limitations under the License.
1901+ */
1902+
1903+// ******************************************
1904+// * *
1905+// * THIS IS A GENERATED FILE. DO NOT EDIT! *
1906+// * SEE .xml FILE WITH SAME NAME *
1907+// * *
1908+// ******************************************
1909+#ifndef ZORBA_RUNTIME_JSON_JSON_H
1910+#define ZORBA_RUNTIME_JSON_JSON_H
1911+
1912+
1913+#include "common/shared_types.h"
1914+
1915+
1916+
1917+#include "runtime/base/narybase.h"
1918+
1919+
1920+namespace zorba {
1921+
1922+/**
1923+ *
1924+ * function for parsing strings into json-xdm
1925+ *
1926+ * Author: Zorba Team
1927+ */
1928+class JSONParseInternal : public NaryBaseIterator<JSONParseInternal, PlanIteratorState>
1929+{
1930+public:
1931+ SERIALIZABLE_CLASS(JSONParseInternal);
1932+
1933+ SERIALIZABLE_CLASS_CONSTRUCTOR2T(JSONParseInternal,
1934+ NaryBaseIterator<JSONParseInternal, PlanIteratorState>);
1935+
1936+ void serialize( ::zorba::serialization::Archiver& ar)
1937+ {
1938+ serialize_baseclass(ar,
1939+ (NaryBaseIterator<JSONParseInternal, PlanIteratorState>*)this);
1940+ }
1941+
1942+ JSONParseInternal(
1943+ static_context* sctx,
1944+ const QueryLoc& loc,
1945+ std::vector<PlanIter_t>& children)
1946+ :
1947+ NaryBaseIterator<JSONParseInternal, PlanIteratorState>(sctx, loc, children)
1948+ {}
1949+
1950+ virtual ~JSONParseInternal();
1951+
1952+ void accept(PlanIterVisitor& v) const;
1953+
1954+ bool nextImpl(store::Item_t& result, PlanState& aPlanState) const;
1955+};
1956+
1957+
1958+/**
1959+ *
1960+ * Function to serialize json/jsonml xdm to string
1961+ *
1962+ * Author: Zorba Team
1963+ */
1964+class JSONSerializeInternal : public NaryBaseIterator<JSONSerializeInternal, PlanIteratorState>
1965+{
1966+public:
1967+ SERIALIZABLE_CLASS(JSONSerializeInternal);
1968+
1969+ SERIALIZABLE_CLASS_CONSTRUCTOR2T(JSONSerializeInternal,
1970+ NaryBaseIterator<JSONSerializeInternal, PlanIteratorState>);
1971+
1972+ void serialize( ::zorba::serialization::Archiver& ar)
1973+ {
1974+ serialize_baseclass(ar,
1975+ (NaryBaseIterator<JSONSerializeInternal, PlanIteratorState>*)this);
1976+ }
1977+
1978+ JSONSerializeInternal(
1979+ static_context* sctx,
1980+ const QueryLoc& loc,
1981+ std::vector<PlanIter_t>& children)
1982+ :
1983+ NaryBaseIterator<JSONSerializeInternal, PlanIteratorState>(sctx, loc, children)
1984+ {}
1985+
1986+ virtual ~JSONSerializeInternal();
1987+
1988+ void accept(PlanIterVisitor& v) const;
1989+
1990+ bool nextImpl(store::Item_t& result, PlanState& aPlanState) const;
1991+};
1992+
1993+
1994+}
1995+#endif
1996+/*
1997+ * Local variables:
1998+ * mode: c++
1999+ * End:
2000+ */
2001
2002=== added file 'src/runtime/json/snelson.cpp'
2003--- src/runtime/json/snelson.cpp 1970-01-01 00:00:00 +0000
2004+++ src/runtime/json/snelson.cpp 2012-02-16 00:23:20 +0000
2005@@ -0,0 +1,515 @@
2006+/*
2007+ * Copyright 2006-2011 The FLWOR Foundation.
2008+ *
2009+ * Licensed under the Apache License, Version 2.0 (the "License");
2010+ * you may not use this file except in compliance with the License.
2011+ * You may obtain a copy of the License at
2012+ *
2013+ * http://www.apache.org/licenses/LICENSE-2.0
2014+ *
2015+ * Unless required by applicable law or agreed to in writing, software
2016+ * distributed under the License is distributed on an "AS IS" BASIS,
2017+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
2018+ * See the License for the specific language governing permissions and
2019+ * limitations under the License.
2020+ */
2021+#include "stdafx.h"
2022+
2023+#include <sstream>
2024+
2025+#include <zorba/diagnostic_list.h>
2026+
2027+#include "runtime/json/json.h"
2028+#include "store/api/item_factory.h"
2029+#include "system/globalenv.h"
2030+#include "types/root_typemanager.h"
2031+#include "util/ascii_util.h"
2032+#include "util/cxx_util.h"
2033+#include "util/indent.h"
2034+#include "util/json_parser.h"
2035+#include "util/mem_streambuf.h"
2036+#include "util/omanip.h"
2037+#include "util/oseparator.h"
2038+#include "util/stl_util.h"
2039+
2040+#include "snelson.h"
2041+
2042+#define SNELSON_NS "http://john.snelson.org.uk/parsing-json-into-xquery"
2043+
2044+using namespace std;
2045+
2046+namespace zorba {
2047+
2048+///////////////////////////////////////////////////////////////////////////////
2049+
2050+static void add_type_attribute( store::Item *parent, char const *value ) {
2051+ store::Item_t junk_item, att_name, type_name, value_item;
2052+ GENV_ITEMFACTORY->createQName( att_name, "", "", "type" );
2053+ type_name = GENV_TYPESYSTEM.XS_UNTYPED_QNAME;
2054+ zstring value_string( value );
2055+ GENV_ITEMFACTORY->createString( value_item, value_string );
2056+ GENV_ITEMFACTORY->createAttributeNode(
2057+ junk_item, parent, att_name, type_name, value_item
2058+ );
2059+}
2060+
2061+#define ADD_TYPE_ATTRIBUTE(T) \
2062+ do { \
2063+ if ( needs_type_attribute ) { \
2064+ add_type_attribute( cur_item, T ); \
2065+ needs_type_attribute = false; \
2066+ } \
2067+ } while (0)
2068+
2069+static void add_item_element( item_stack_type &item_stack,
2070+ state_stack_type &state_stack,
2071+ store::Item_t &cur_item,
2072+ char const *type ) {
2073+ store::Item_t element_name, type_name;
2074+ zstring base_uri;
2075+ store::NsBindings ns_bindings;
2076+ GENV_ITEMFACTORY->createQName( element_name, SNELSON_NS, "", "item" );
2077+ type_name = GENV_TYPESYSTEM.XS_UNTYPED_QNAME;
2078+ GENV_ITEMFACTORY->createElementNode(
2079+ cur_item, item_stack.top(),
2080+ element_name, type_name, false, false, ns_bindings, base_uri
2081+ );
2082+ add_type_attribute( cur_item.getp(), type );
2083+ PUSH_ITEM( cur_item );
2084+}
2085+
2086+#define ADD_ITEM_ELEMENT(T) \
2087+ if ( !IN_STATE( in_array ) ) ; else \
2088+ add_item_element( item_stack, state_stack, cur_item, T )
2089+
2090+#define POP_ITEM_ELEMENT() \
2091+ if ( !IN_STATE( in_array ) ) ; else POP_ITEM()
2092+
2093+static void escape_json_chars( zstring *s ) {
2094+ ascii::replace_all( *s, "\"", 1, "\\\"", 2 );
2095+ ascii::replace_all( *s, "\\", 1, "\\\\", 2 );
2096+ ascii::replace_all( *s, "\b", 1, "\\b", 2 );
2097+ ascii::replace_all( *s, "\f", 1, "\\f", 2 );
2098+ ascii::replace_all( *s, "\n", 1, "\\n", 2 );
2099+ ascii::replace_all( *s, "\r", 1, "\\r", 2 );
2100+ ascii::replace_all( *s, "\t", 1, "\\t", 2 );
2101+}
2102+
2103+///////////////////////////////////////////////////////////////////////////////
2104+
2105+namespace snelson {
2106+
2107+void parse( json::parser &p, store::Item_t *result ) {
2108+ ZORBA_ASSERT( result );
2109+
2110+ store::Item_t cur_item, junk_item, value_item;
2111+ store::Item_t att_name, element_name, type_name;
2112+
2113+ zstring base_uri;
2114+ bool got_something = false;
2115+ item_stack_type item_stack;
2116+ bool needs_type_attribute = false;
2117+ bool next_string_is_key = false;
2118+ store::NsBindings ns_bindings;
2119+ state_stack_type state_stack;
2120+ zstring value;
2121+
2122+ json::token token;
2123+ while ( p.next( &token ) ) {
2124+ got_something = true;
2125+
2126+ if ( !*result ) {
2127+ GENV_ITEMFACTORY->createQName( element_name, SNELSON_NS, "", "json" );
2128+ type_name = GENV_TYPESYSTEM.XS_UNTYPED_QNAME;
2129+ GENV_ITEMFACTORY->createElementNode(
2130+ cur_item, nullptr,
2131+ element_name, type_name, false, false, ns_bindings, base_uri
2132+ );
2133+ *result = cur_item;
2134+ needs_type_attribute = true;
2135+ PUSH_ITEM( cur_item );
2136+ }
2137+
2138+ switch ( token.get_type() ) {
2139+
2140+ case '[':
2141+ if ( IN_STATE( in_object ) )
2142+ PUSH_ITEM( cur_item );
2143+ ADD_TYPE_ATTRIBUTE( "array" );
2144+ ADD_ITEM_ELEMENT( "array" );
2145+ PUSH_STATE( in_array );
2146+ break;
2147+
2148+ case '{':
2149+ if ( IN_STATE( in_object ) )
2150+ PUSH_ITEM( cur_item );
2151+ ADD_TYPE_ATTRIBUTE( "object" );
2152+ ADD_ITEM_ELEMENT( "object" );
2153+ PUSH_STATE( in_object );
2154+ next_string_is_key = true;
2155+ break;
2156+
2157+ case ']':
2158+ case '}':
2159+ POP_STATE();
2160+ POP_ITEM_ELEMENT();
2161+ if ( IN_STATE( in_object ) )
2162+ POP_ITEM();
2163+ break;
2164+
2165+ case ',':
2166+ next_string_is_key = IN_STATE( in_object );
2167+ break;
2168+
2169+ case json::token::number:
2170+ ADD_TYPE_ATTRIBUTE( "number" );
2171+ ADD_ITEM_ELEMENT( "number" );
2172+ value = token.get_value();
2173+ GENV_ITEMFACTORY->createTextNode( junk_item, cur_item, value );
2174+ POP_ITEM_ELEMENT();
2175+ break;
2176+
2177+ case json::token::string:
2178+ ADD_TYPE_ATTRIBUTE( "string" );
2179+ value = token.get_value();
2180+#if 0
2181+ escape_json_chars( &value );
2182+#endif
2183+
2184+ if ( next_string_is_key ) {
2185+ // <pair name="..." ...>
2186+ GENV_ITEMFACTORY->createQName( element_name, SNELSON_NS, "", "pair" );
2187+ type_name = GENV_TYPESYSTEM.XS_UNTYPED_QNAME;
2188+ GENV_ITEMFACTORY->createElementNode(
2189+ cur_item, item_stack.top(),
2190+ element_name, type_name, false, false, ns_bindings, base_uri
2191+ );
2192+
2193+ GENV_ITEMFACTORY->createQName( att_name, "", "", "name" );
2194+ type_name = GENV_TYPESYSTEM.XS_UNTYPED_QNAME;
2195+ GENV_ITEMFACTORY->createString( value_item, value );
2196+ GENV_ITEMFACTORY->createAttributeNode(
2197+ junk_item, cur_item, att_name, type_name, value_item
2198+ );
2199+
2200+ needs_type_attribute = true;
2201+ next_string_is_key = false;
2202+ } else {
2203+ ADD_ITEM_ELEMENT( "string" );
2204+ GENV_ITEMFACTORY->createTextNode( junk_item, cur_item, value );
2205+ POP_ITEM_ELEMENT();
2206+ }
2207+ break;
2208+
2209+ case 'F':
2210+ case 'T':
2211+ ADD_TYPE_ATTRIBUTE( "boolean" );
2212+ ADD_ITEM_ELEMENT( "boolean" );
2213+ value = token.get_type() == 'F' ? "false" : "true";
2214+ GENV_ITEMFACTORY->createTextNode( junk_item, cur_item, value );
2215+ POP_ITEM_ELEMENT();
2216+ break;
2217+
2218+ case json::token::json_null:
2219+ ADD_TYPE_ATTRIBUTE( "null" );
2220+ ADD_ITEM_ELEMENT( "null" );
2221+ POP_ITEM_ELEMENT();
2222+ break;
2223+
2224+ case ':':
2225+ case json::token::none:
2226+ break;
2227+
2228+ default:
2229+ assert( false );
2230+ } // switch
2231+ } // while
2232+ if ( !got_something )
2233+ throw XQUERY_EXCEPTION( zerr::ZJPE0009_ILLEGAL_EMPTY_STRING );
2234+}
2235+
2236+} // namespace snelson
2237+
2238+///////////////////////////////////////////////////////////////////////////////
2239+
2240+static void assert_json_type( json::type t, zstring const &s ) {
2241+ // Doing it this way uses the string data in-place with no copy.
2242+ mem_streambuf::char_type *const p =
2243+ const_cast<mem_streambuf::char_type*>( s.data() );
2244+ mem_streambuf buf( p, s.size() );
2245+ istringstream iss;
2246+ iss.ios::rdbuf( &buf );
2247+
2248+ json::lexer lex( iss );
2249+ json::token token;
2250+ try {
2251+ if ( lex.next( &token ) && json::map_type( token.get_type() ) == t )
2252+ return;
2253+ }
2254+ catch ( json::exception const& ) {
2255+ // do nothing
2256+ }
2257+ throw XQUERY_EXCEPTION(
2258+ zerr::ZJSE0008_BAD_VALUE,
2259+ ERROR_PARAMS( s, t )
2260+ );
2261+}
2262+
2263+static void require_attribute_value( store::Item_t const &element,
2264+ char const *att_name,
2265+ zstring *att_value ) {
2266+ if ( !get_attribute_value( element, att_name, att_value ) )
2267+ throw XQUERY_EXCEPTION(
2268+ zerr::ZJSE0002_ELEMENT_MISSING_ATTRIBUTE,
2269+ ERROR_PARAMS( element->getNodeName()->getStringValue(), att_name )
2270+ );
2271+}
2272+
2273+static json::type get_json_type( store::Item_t const &element,
2274+ bool allow_all_types = true ) {
2275+ zstring att_value;
2276+ require_attribute_value( element, "type", &att_value );
2277+ if ( att_value == "array" )
2278+ return json::array;
2279+ if ( att_value == "object" )
2280+ return json::object;
2281+ if ( allow_all_types ) {
2282+ if ( att_value == "boolean" )
2283+ return json::boolean;
2284+ if ( att_value == "null" )
2285+ return json::null;
2286+ if ( att_value == "number" )
2287+ return json::number;
2288+ if ( att_value == "string" )
2289+ return json::string;
2290+ }
2291+ throw XQUERY_EXCEPTION(
2292+ zerr::ZJSE0003_BAD_ATTRIBUTE_VALUE,
2293+ ERROR_PARAMS( att_value, "type" )
2294+ );
2295+}
2296+
2297+inline std::ostream& if_space_or_newline( std::ostream &o,
2298+ whitespace::type ws ) {
2299+ if ( ws == whitespace::some )
2300+ o << ' ';
2301+ else
2302+ o << if_emit( ws == whitespace::indent, '\n' );
2303+ return o;
2304+}
2305+DEF_OMANIP1( if_space_or_newline, whitespace::type )
2306+
2307+static ostream& serialize_begin( ostream &o, json::type t,
2308+ whitespace::type ws ) {
2309+ switch ( t ) {
2310+ case json::array :
2311+ o << '[' << if_emit( ws, ' ' );
2312+ break;
2313+ case json::object:
2314+ o << '{' << if_space_or_newline( ws ) << if_indent( ws, inc_indent );
2315+ break;
2316+ default:
2317+ /* suppress warning */;
2318+ }
2319+ return o;
2320+}
2321+DEF_OMANIP2( serialize_begin, json::type, whitespace::type )
2322+
2323+static ostream& serialize_end( ostream &o, json::type t, whitespace::type ws ) {
2324+ switch ( t ) {
2325+ case json::array:
2326+ o << if_emit( ws, ' ' ) << ']';
2327+ break;
2328+ case json::object:
2329+ o << if_space_or_newline( ws ) << if_indent( ws, dec_indent )
2330+ << if_indent( ws, indent ) << '}';
2331+ break;
2332+ default:
2333+ /* suppress warning */;
2334+ }
2335+ return o;
2336+}
2337+DEF_OMANIP2( serialize_end, json::type, whitespace::type )
2338+
2339+static ostream& serialize_boolean( ostream &o, zstring const &s ) {
2340+ assert_json_type( json::boolean, s );
2341+ return o << s;
2342+}
2343+DEF_OMANIP1( serialize_boolean, zstring const& )
2344+
2345+static ostream& serialize_number( ostream &o, zstring const &s ) {
2346+ assert_json_type( json::number, s );
2347+ return o << s;
2348+}
2349+DEF_OMANIP1( serialize_number, zstring const& )
2350+
2351+static ostream& serialize_string( ostream &o, zstring const &s ) {
2352+ zstring temp( s );
2353+ escape_json_chars( &temp );
2354+ temp.insert( (zstring::size_type)0, 1, '"' );
2355+ temp.append( 1, '"' );
2356+ assert_json_type( json::string, temp );
2357+ return o << temp;
2358+}
2359+DEF_OMANIP1( serialize_string, zstring const& )
2360+
2361+static ostream& serialize_children( ostream&, store::Item_t const&, json::type,
2362+ whitespace::type );
2363+DEF_OMANIP3( serialize_children, store::Item_t const&, json::type,
2364+ whitespace::type )
2365+
2366+static ostream& serialize_json_element( ostream &o,
2367+ store::Item_t const &element,
2368+ whitespace::type ws ) {
2369+ zstring const element_name( element->getNodeName()->getStringValue() );
2370+ if ( element_name != "json" )
2371+ throw XQUERY_EXCEPTION(
2372+ zerr::ZJSE0004_BAD_ELEMENT,
2373+ ERROR_PARAMS( element_name, "json" )
2374+ );
2375+
2376+ json::type const t = get_json_type( element, false );
2377+
2378+ return o
2379+ << serialize_begin( t, ws )
2380+ << serialize_children( element, t, ws )
2381+ << serialize_end( t, ws );
2382+}
2383+DEF_OMANIP2( serialize_json_element, store::Item_t const&, whitespace::type )
2384+
2385+static ostream& serialize_item_element( ostream &o,
2386+ store::Item_t const &element,
2387+ whitespace::type ws ) {
2388+ zstring const element_name( element->getNodeName()->getStringValue() );
2389+ if ( element_name != "item" )
2390+ throw XQUERY_EXCEPTION(
2391+ zerr::ZJSE0005_BAD_CHILD_ELEMENT,
2392+ ERROR_PARAMS( element_name, "array", "item" )
2393+ );
2394+
2395+ json::type const t = get_json_type( element );
2396+
2397+ return o
2398+ << serialize_begin( t, ws )
2399+ << serialize_children( element, t, ws )
2400+ << serialize_end( t, ws );
2401+}
2402+DEF_OMANIP2( serialize_item_element, store::Item_t const&, whitespace::type )
2403+
2404+static ostream& serialize_pair_element( ostream &o,
2405+ store::Item_t const &element,
2406+ whitespace::type ws ) {
2407+ zstring const element_name( element->getNodeName()->getStringValue() );
2408+ if ( element_name != "pair" )
2409+ throw XQUERY_EXCEPTION(
2410+ zerr::ZJSE0005_BAD_CHILD_ELEMENT,
2411+ ERROR_PARAMS( element_name, "object", "pair" )
2412+ );
2413+
2414+ zstring name_att_value;
2415+ require_attribute_value( element, "name", &name_att_value );
2416+ json::type const t = get_json_type( element );
2417+
2418+ return o
2419+ << if_indent( ws, indent ) << serialize_string( name_att_value )
2420+ << if_emit( ws, ' ' ) << ':' << if_emit( ws, ' ' )
2421+ << serialize_begin( t, ws )
2422+ << serialize_children( element, t, ws )
2423+ << serialize_end( t, ws );
2424+}
2425+DEF_OMANIP2( serialize_pair_element, store::Item_t const&, whitespace::type )
2426+
2427+static ostream& serialize_children( ostream &o, store::Item_t const &parent,
2428+ json::type parent_type,
2429+ whitespace::type ws ) {
2430+ if ( parent_type == json::null )
2431+ o << "null";
2432+ else {
2433+ oseparator sep;
2434+ if ( ws == whitespace::none )
2435+ sep.sep( "," );
2436+ else if ( ws == whitespace::some || parent_type == json::array )
2437+ sep.sep( ", " );
2438+ else
2439+ sep.sep( ",\n" );
2440+
2441+ store::Iterator_t i = parent->getChildren();
2442+ i->open();
2443+ store::Item_t child;
2444+ while ( i->next( child ) ) {
2445+
2446+ switch ( child->getNodeKind() ) {
2447+
2448+ case store::StoreConsts::elementNode:
2449+ o << sep;
2450+ switch ( parent_type ) {
2451+ case json::none:
2452+ o << serialize_json_element( child, ws );
2453+ break;
2454+ case json::array:
2455+ o << serialize_item_element( child, ws );
2456+ break;
2457+ case json::object:
2458+ o << serialize_pair_element( child, ws );
2459+ break;
2460+ default:
2461+ throw XQUERY_EXCEPTION(
2462+ zerr::ZJSE0006_NO_ELEMENT_CHILD,
2463+ ERROR_PARAMS( json::type_string_of[ parent_type ] )
2464+ );
2465+ }
2466+ break;
2467+
2468+ case store::StoreConsts::textNode:
2469+ o << sep;
2470+ switch ( parent_type ) {
2471+ case json::boolean:
2472+ o << serialize_boolean( child->getStringValue() );
2473+ break;
2474+ case json::number:
2475+ o << serialize_number( child->getStringValue() );
2476+ break;
2477+ case json::string:
2478+ o << serialize_string( child->getStringValue() );
2479+ break;
2480+ default:
2481+ throw XQUERY_EXCEPTION(
2482+ zerr::ZJSE0007_NO_TEXT_CHILD,
2483+ ERROR_PARAMS( json::type_string_of[ parent_type ] )
2484+ );
2485+ }
2486+ break;
2487+
2488+ default:
2489+ // do nothing
2490+ break;
2491+ } // switch
2492+ } // while
2493+ i->close();
2494+ }
2495+ return o;
2496+}
2497+
2498+///////////////////////////////////////////////////////////////////////////////
2499+
2500+namespace snelson {
2501+
2502+void serialize( ostream &o, store::Item_t const &item, whitespace::type ws ) {
2503+ switch ( item->getNodeKind() ) {
2504+ case store::StoreConsts::documentNode:
2505+ o << serialize_children( item, json::none, ws );
2506+ break;
2507+ case store::StoreConsts::elementNode:
2508+ o << serialize_json_element( item, ws );
2509+ break;
2510+ default:
2511+ throw XQUERY_EXCEPTION( zerr::ZJSE0001_NOT_DOCUMENT_OR_ELEMENT_NODE );
2512+ }
2513+}
2514+
2515+} // namespace snelson
2516+
2517+///////////////////////////////////////////////////////////////////////////////
2518+
2519+} // namespace zorba
2520+/* vim:set et sw=2 ts=2: */
2521
2522=== added file 'src/runtime/json/snelson.h'
2523--- src/runtime/json/snelson.h 1970-01-01 00:00:00 +0000
2524+++ src/runtime/json/snelson.h 2012-02-16 00:23:20 +0000
2525@@ -0,0 +1,41 @@
2526+/*
2527+ * Copyright 2006-2011 The FLWOR Foundation.
2528+ *
2529+ * Licensed under the Apache License, Version 2.0 (the "License");
2530+ * you may not use this file except in compliance with the License.
2531+ * You may obtain a copy of the License at
2532+ *
2533+ * http://www.apache.org/licenses/LICENSE-2.0
2534+ *
2535+ * Unless required by applicable law or agreed to in writing, software
2536+ * distributed under the License is distributed on an "AS IS" BASIS,
2537+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
2538+ * See the License for the specific language governing permissions and
2539+ * limitations under the License.
2540+ */
2541+#include "stdafx.h"
2542+
2543+#ifndef ZORBA_RUNTIME_JSON_SNELSON_H
2544+#define ZORBA_RUNTIME_JSON_SNELSON_H
2545+
2546+#include <iostream>
2547+
2548+#include "store/api/item.h"
2549+#include "util/json_parser.h"
2550+
2551+#include "common.h"
2552+
2553+namespace zorba {
2554+namespace snelson {
2555+
2556+///////////////////////////////////////////////////////////////////////////////
2557+
2558+void parse( json::parser &p, store::Item_t *result );
2559+void serialize( std::ostream&, store::Item_t const &item, whitespace::type );
2560+
2561+///////////////////////////////////////////////////////////////////////////////
2562+
2563+} // namespace snelson
2564+} // namespace zorba
2565+#endif /* ZORBA_RUNTIME_JSON_SNELSON_H */
2566+/* vim:set et sw=2 ts=2: */
2567
2568=== added directory 'src/runtime/spec/json'
2569=== added file 'src/runtime/spec/json/json.xml'
2570--- src/runtime/spec/json/json.xml 1970-01-01 00:00:00 +0000
2571+++ src/runtime/spec/json/json.xml 2012-02-16 00:23:20 +0000
2572@@ -0,0 +1,52 @@
2573+<?xml version="1.0" encoding="UTF-8"?>
2574+
2575+<!--
2576+////////////////////////////////////////////////////////////////////////////////
2577+////////////////////////////////////////////////////////////////////////////////
2578+-->
2579+<zorba:iterators
2580+ xmlns:zorba="http://www.zorba-xquery.com"
2581+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
2582+ xsi:schemaLocation="http://www.zorba-xquery.com ../runtime.xsd">
2583+
2584+<!--
2585+/*******************************************************************************
2586+*******************************************************************************/
2587+-->
2588+<zorba:iterator name="JSONParseInternal" arity="nary">
2589+
2590+ <zorba:description author="Zorba Team">
2591+ function for parsing strings into json-xdm
2592+ </zorba:description>
2593+
2594+ <zorba:function isDeterministic="true">
2595+ <zorba:signature localname="parse-internal" prefix="fn-zorba-json">
2596+ <zorba:param>xs:string</zorba:param>
2597+ <zorba:param>item()?</zorba:param>
2598+ <zorba:output>element()*</zorba:output>
2599+ </zorba:signature>
2600+ </zorba:function>
2601+
2602+</zorba:iterator>
2603+
2604+<!--
2605+/*******************************************************************************
2606+*******************************************************************************/
2607+-->
2608+<zorba:iterator name="JSONSerializeInternal" arity="nary">
2609+
2610+ <zorba:description author="Zorba Team">
2611+ Function to serialize json/jsonml xdm to string
2612+ </zorba:description>
2613+
2614+ <zorba:function isDeterministic="true">
2615+ <zorba:signature localname="serialize-internal" prefix="fn-zorba-json">
2616+ <zorba:param>item()*</zorba:param>
2617+ <zorba:param>item()?</zorba:param>
2618+ <zorba:output>xs:string</zorba:output>
2619+ </zorba:signature>
2620+ </zorba:function>
2621+
2622+</zorba:iterator>
2623+
2624+</zorba:iterators>
2625
2626=== modified file 'src/runtime/spec/mappings.xml'
2627--- src/runtime/spec/mappings.xml 2011-10-14 07:35:51 +0000
2628+++ src/runtime/spec/mappings.xml 2012-02-16 00:23:20 +0000
2629@@ -106,6 +106,10 @@
2630 define="ZORBA_STRING_FN_NS"
2631 prefix="fn-zorba-string"/>
2632
2633+ <zorba:namespace uri="http://www.zorba-xquery.com/modules/converters/json"
2634+ define="ZORBA_JSON_FN_NS"
2635+ prefix="fn-zorba-json"/>
2636+
2637 <zorba:namespace uri="http://www.zorba-xquery.com/modules/fetch"
2638 define="ZORBA_FETCH_FN_NS"
2639 prefix="fn-zorba-fetch"/>
2640
2641=== modified file 'src/runtime/visitors/pregenerated/planiter_visitor.h'
2642--- src/runtime/visitors/pregenerated/planiter_visitor.h 2012-01-11 17:30:25 +0000
2643+++ src/runtime/visitors/pregenerated/planiter_visitor.h 2012-02-16 00:23:20 +0000
2644@@ -251,6 +251,10 @@
2645
2646 class FunctionAnnotationsIterator;
2647
2648+ class JSONParseInternal;
2649+
2650+ class JSONSerializeInternal;
2651+
2652 class SqrtIterator;
2653
2654 class ExpIterator;
2655@@ -929,6 +933,12 @@
2656 virtual void beginVisit ( const FunctionAnnotationsIterator& ) = 0;
2657 virtual void endVisit ( const FunctionAnnotationsIterator& ) = 0;
2658
2659+ virtual void beginVisit ( const JSONParseInternal& ) = 0;
2660+ virtual void endVisit ( const JSONParseInternal& ) = 0;
2661+
2662+ virtual void beginVisit ( const JSONSerializeInternal& ) = 0;
2663+ virtual void endVisit ( const JSONSerializeInternal& ) = 0;
2664+
2665 virtual void beginVisit ( const SqrtIterator& ) = 0;
2666 virtual void endVisit ( const SqrtIterator& ) = 0;
2667
2668
2669=== modified file 'src/runtime/visitors/pregenerated/printer_visitor.cpp'
2670--- src/runtime/visitors/pregenerated/printer_visitor.cpp 2012-01-11 17:30:25 +0000
2671+++ src/runtime/visitors/pregenerated/printer_visitor.cpp 2012-02-16 00:23:20 +0000
2672@@ -50,6 +50,7 @@
2673 #include "runtime/function_item/function_item_iter.h"
2674 #include "runtime/indexing/ic_ddl.h"
2675 #include "runtime/introspection/sctx.h"
2676+#include "runtime/json/json.h"
2677 #include "runtime/maths/maths.h"
2678 #include "runtime/nodes/node_position.h"
2679 #include "runtime/nodes/nodes.h"
2680@@ -1650,6 +1651,34 @@
2681 // </FunctionAnnotationsIterator>
2682
2683
2684+// <JSONParseInternal>
2685+void PrinterVisitor::beginVisit ( const JSONParseInternal& a) {
2686+ thePrinter.startBeginVisit("JSONParseInternal", ++theId);
2687+ printCommons( &a, theId );
2688+ thePrinter.endBeginVisit( theId );
2689+}
2690+
2691+void PrinterVisitor::endVisit ( const JSONParseInternal& ) {
2692+ thePrinter.startEndVisit();
2693+ thePrinter.endEndVisit();
2694+}
2695+// </JSONParseInternal>
2696+
2697+
2698+// <JSONSerializeInternal>
2699+void PrinterVisitor::beginVisit ( const JSONSerializeInternal& a) {
2700+ thePrinter.startBeginVisit("JSONSerializeInternal", ++theId);
2701+ printCommons( &a, theId );
2702+ thePrinter.endBeginVisit( theId );
2703+}
2704+
2705+void PrinterVisitor::endVisit ( const JSONSerializeInternal& ) {
2706+ thePrinter.startEndVisit();
2707+ thePrinter.endEndVisit();
2708+}
2709+// </JSONSerializeInternal>
2710+
2711+
2712 // <SqrtIterator>
2713 void PrinterVisitor::beginVisit ( const SqrtIterator& a) {
2714 thePrinter.startBeginVisit("SqrtIterator", ++theId);
2715
2716=== modified file 'src/runtime/visitors/pregenerated/printer_visitor.h'
2717--- src/runtime/visitors/pregenerated/printer_visitor.h 2012-01-11 17:30:25 +0000
2718+++ src/runtime/visitors/pregenerated/printer_visitor.h 2012-02-16 00:23:20 +0000
2719@@ -379,6 +379,12 @@
2720 void beginVisit( const FunctionAnnotationsIterator& );
2721 void endVisit ( const FunctionAnnotationsIterator& );
2722
2723+ void beginVisit( const JSONParseInternal& );
2724+ void endVisit ( const JSONParseInternal& );
2725+
2726+ void beginVisit( const JSONSerializeInternal& );
2727+ void endVisit ( const JSONSerializeInternal& );
2728+
2729 void beginVisit( const SqrtIterator& );
2730 void endVisit ( const SqrtIterator& );
2731
2732
2733=== modified file 'src/unit_tests/CMakeLists.txt'
2734--- src/unit_tests/CMakeLists.txt 2012-02-02 09:56:52 +0000
2735+++ src/unit_tests/CMakeLists.txt 2012-02-16 00:23:20 +0000
2736@@ -19,6 +19,8 @@
2737 test_uri.cpp
2738 unique_ptr.cpp
2739 unit_tests.cpp
2740+ test_uri.cpp
2741+ json_parser.cpp
2742 )
2743
2744 IF (NOT ZORBA_NO_FULL_TEXT)
2745
2746=== added file 'src/unit_tests/json_parser.cpp'
2747--- src/unit_tests/json_parser.cpp 1970-01-01 00:00:00 +0000
2748+++ src/unit_tests/json_parser.cpp 2012-02-16 00:23:20 +0000
2749@@ -0,0 +1,636 @@
2750+/*
2751+ * Copyright 2006-2008 The FLWOR Foundation.
2752+ *
2753+ * Licensed under the Apache License, Version 2.0 (the "License");
2754+ * you may not use this file except in compliance with the License.
2755+ * You may obtain a copy of the License at
2756+ *
2757+ * http://www.apache.org/licenses/LICENSE-2.0
2758+ *
2759+ * Unless required by applicable law or agreed to in writing, software
2760+ * distributed under the License is distributed on an "AS IS" BASIS,
2761+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
2762+ * See the License for the specific language governing permissions and
2763+ * limitations under the License.
2764+ */
2765+
2766+#include <sstream>
2767+
2768+#include "util/json_parser.h"
2769+
2770+using namespace std;
2771+using namespace zorba;
2772+using namespace zorba::json;
2773+
2774+///////////////////////////////////////////////////////////////////////////////
2775+
2776+static int failures;
2777+
2778+static bool assert_true( char const *expr, int line, bool result ) {
2779+ if ( !result ) {
2780+ cout << "FAILED, line " << line << ": " << expr << endl;
2781+ ++failures;
2782+ }
2783+ return result;
2784+}
2785+
2786+static void print_exception( char const *expr, int line,
2787+ std::exception const &e ) {
2788+ assert_true( expr, line, false );
2789+ cout << "+ exception: ";
2790+ if ( json::exception const *j = dynamic_cast<json::exception const*>( &e ) ) {
2791+ json::location const &loc = j->get_loc();
2792+ if ( loc.file() && *loc.file() )
2793+ cout << '"' << loc.file() << "\": ";
2794+ cout << loc.line();
2795+ if ( loc.column() )
2796+ cout << ',' << loc.column();
2797+ cout << ": ";
2798+ }
2799+ cout << e.what() << endl;
2800+}
2801+
2802+#define ASSERT_TRUE( EXPR ) assert_true( #EXPR, __LINE__, !!(EXPR) )
2803+
2804+#define ASSERT_EXCEPTION( EXPR, EXCEPTION ) \
2805+ try { EXPR; assert_true( #EXPR, __LINE__, false ); } \
2806+ catch ( EXCEPTION const& ) { }
2807+
2808+#define ASSERT_NO_EXCEPTION( EXPR ) \
2809+ try { EXPR; } \
2810+ catch ( std::exception const &e ) { print_exception( #EXPR, __LINE__, e ); } \
2811+ catch ( ... ) { assert_true( #EXPR, __LINE__, false ); }
2812+
2813+#define ASSERT_TRUE_AND_NO_EXCEPTION( EXPR ) \
2814+ try { ASSERT_TRUE( EXPR ); } \
2815+ catch ( std::exception const &e ) { print_exception( #EXPR, __LINE__, e ); } \
2816+ catch ( ... ) { assert_true( #EXPR, __LINE__, false ); }
2817+
2818+///////////////////////////////////////////////////////////////////////////////
2819+
2820+static void test_empty_stream() {
2821+ char const source[] = "";
2822+ istringstream iss( source );
2823+ parser p( iss );
2824+ token t;
2825+ ASSERT_NO_EXCEPTION( p.next( &t ) );
2826+}
2827+
2828+static void test_illegal_character() {
2829+ char const source[] = " x ";
2830+ istringstream iss( source );
2831+ lexer lex( iss );
2832+ token t;
2833+ ASSERT_EXCEPTION( lex.next( &t ), illegal_character );
2834+}
2835+
2836+static void test_illegal_codepoint() {
2837+ static char const *const sources[] = {
2838+ " \" \\u \" ",
2839+ " \" \\u0 \" ",
2840+ " \" \\u00 \" ",
2841+ " \" \\u000 \" ",
2842+ " \" \\uG \" ",
2843+ " \" \\u\" ",
2844+ 0
2845+ };
2846+
2847+ for ( char const *const *s = sources; *s; ++s ) {
2848+ istringstream iss( *s );
2849+ lexer lex( iss );
2850+ token t;
2851+ ASSERT_EXCEPTION( lex.next( &t ), illegal_codepoint );
2852+ }
2853+}
2854+
2855+static void test_illegal_escape() {
2856+ char const source[] = " \" \\x \" ";
2857+ istringstream iss( source );
2858+ lexer lex( iss );
2859+ token t;
2860+ ASSERT_EXCEPTION( lex.next( &t ), illegal_escape );
2861+}
2862+
2863+static void test_illegal_literal() {
2864+ static char const *const sources[] = {
2865+ " f ",
2866+ " fa ",
2867+ " fal ",
2868+ " fals ",
2869+ " falsee ",
2870+ " t ",
2871+ " tr ",
2872+ " tru ",
2873+ " truee ",
2874+ " n ",
2875+ " nu ",
2876+ " nul ",
2877+ " nulll ",
2878+ 0
2879+ };
2880+
2881+ for ( char const *const *s = sources; *s; ++s ) {
2882+ istringstream iss( *s );
2883+ lexer lex( iss );
2884+ token t;
2885+ ASSERT_EXCEPTION( lex.next( &t ), illegal_literal );
2886+ }
2887+}
2888+
2889+static void test_illegal_number() {
2890+}
2891+
2892+static void test_json_org_example() {
2893+ char const source[] =
2894+/* 1 */ "{" "\n"
2895+/* 2 */ " \"glossary\": {" "\n"
2896+/* 3 */ " \"title\": \"example glossary\"," "\n"
2897+/* 4 */ " \"GlossDiv\": {" "\n"
2898+/* 5 */ " \"title\": \"S\"," "\n"
2899+/* 6 */ " \"GlossList\": {" "\n"
2900+/* 7 */ " \"GlossEntry\": {" "\n"
2901+/* 8 */ " \"ID\": \"SGML\"," "\n"
2902+/* 9 */ " \"SortAs\": \"SGML\"," "\n"
2903+/* 10 */ " \"GlossTerm\": \"Standard Generalized Markup Language\"," "\n"
2904+/* 11 */ " \"Acronym\": \"SGML\"," "\n"
2905+/* 12 */ " \"Abbrev\": \"ISO 8879:1986\"," "\n"
2906+/* 13 */ " \"GlossDef\": {" "\n"
2907+/* 14 */ " \"para\": \"A meta-markup language, used to create markup languages such as DocBook.\"," "\n"
2908+/* 15 */ " \"GlossSeeAlso\": [\"GML\", \"XML\"]" "\n"
2909+/* 16 */ " }," "\n"
2910+/* 17 */ " \"GlossSee\": \"markup\"" "\n"
2911+/* 18 */ " }" "\n"
2912+/* 19 */ " }" "\n"
2913+/* 20 */ " }" "\n"
2914+/* 21 */ " }" "\n"
2915+/* 22 */ "}" "\n" ;
2916+
2917+ istringstream iss( source );
2918+ parser p( iss );
2919+ token t;
2920+
2921+ ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) ); // 1: {
2922+ ASSERT_TRUE( t == token::begin_object );
2923+
2924+ ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) ); // 2: "glossary"
2925+ ASSERT_TRUE( t == token::string );
2926+
2927+ ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) ); // 2: :
2928+ ASSERT_TRUE( t == token::name_separator );
2929+
2930+ ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) ); // 2: {
2931+ ASSERT_TRUE( t == token::begin_object );
2932+
2933+ ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) ); // 3: "title"
2934+ ASSERT_TRUE( t == token::string );
2935+
2936+ ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) ); // 3: :
2937+ ASSERT_TRUE( t == token::name_separator );
2938+
2939+ ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) ); // 3: "example glossary"
2940+ ASSERT_TRUE( t == token::string );
2941+
2942+ ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) ); // 3: ,
2943+ ASSERT_TRUE( t == token::value_separator );
2944+
2945+ ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) ); // 4: "GlossDiv"
2946+ ASSERT_TRUE( t == token::string );
2947+
2948+ ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) ); // 4: :
2949+ ASSERT_TRUE( t == token::name_separator );
2950+
2951+ ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) ); // 4: {
2952+ ASSERT_TRUE( t == token::begin_object );
2953+
2954+ ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) ); // 5: "title"
2955+ ASSERT_TRUE( t == token::string );
2956+
2957+ ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) ); // 5: :
2958+ ASSERT_TRUE( t == token::name_separator );
2959+
2960+ ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) ); // 5: "S"
2961+ ASSERT_TRUE( t == token::string );
2962+
2963+ ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) ); // 5: ,
2964+ ASSERT_TRUE( t == token::value_separator );
2965+
2966+ ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) ); // 6: "GlossList"
2967+ ASSERT_TRUE( t == token::string );
2968+
2969+ ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) ); // 6: :
2970+ ASSERT_TRUE( t == token::name_separator );
2971+
2972+ ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) ); // 6: {
2973+ ASSERT_TRUE( t == token::begin_object );
2974+
2975+ ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) ); // 7: "GlossEntry"
2976+ ASSERT_TRUE( t == token::string );
2977+
2978+ ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) ); // 7: :
2979+ ASSERT_TRUE( t == token::name_separator );
2980+
2981+ ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) ); // 7: {
2982+ ASSERT_TRUE( t == token::begin_object );
2983+
2984+ ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) ); // 8: "ID"
2985+ ASSERT_TRUE( t == token::string );
2986+
2987+ ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) ); // 8: :
2988+ ASSERT_TRUE( t == token::name_separator );
2989+
2990+ ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) ); // 8: "SGML"
2991+ ASSERT_TRUE( t == token::string );
2992+
2993+ ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) ); // 8: ,
2994+ ASSERT_TRUE( t == token::value_separator );
2995+
2996+ ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) ); // 9: "SortAs"
2997+ ASSERT_TRUE( t == token::string );
2998+
2999+ ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) ); // 9: :
3000+ ASSERT_TRUE( t == token::name_separator );
3001+
3002+ ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) ); // 9: "SGML"
3003+ ASSERT_TRUE( t == token::string );
3004+
3005+ ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) ); // 9: ,
3006+ ASSERT_TRUE( t == token::value_separator );
3007+
3008+ ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) ); // 10: "GlossTerm"
3009+ ASSERT_TRUE( t == token::string );
3010+
3011+ ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) ); // 10: :
3012+ ASSERT_TRUE( t == token::name_separator );
3013+
3014+ ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) ); // 10: "Standard ..."
3015+ ASSERT_TRUE( t == token::string );
3016+
3017+ ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) ); // 10: ,
3018+ ASSERT_TRUE( t == token::value_separator );
3019+
3020+ ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) ); // 11: "Acronym"
3021+ ASSERT_TRUE( t == token::string );
3022+
3023+ ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) ); // 11: :
3024+ ASSERT_TRUE( t == token::name_separator );
3025+
3026+ ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) ); // 11: "SGML"
3027+ ASSERT_TRUE( t == token::string );
3028+
3029+ ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) ); // 11: ,
3030+ ASSERT_TRUE( t == token::value_separator );
3031+
3032+ ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) ); // 12: "Abbrev"
3033+ ASSERT_TRUE( t == token::string );
3034+
3035+ ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) ); // 12: :
3036+ ASSERT_TRUE( t == token::name_separator );
3037+
3038+ ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) ); // 12: "ISO 8879:1986"
3039+ ASSERT_TRUE( t == token::string );
3040+
3041+ ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) ); // 12: ,
3042+ ASSERT_TRUE( t == token::value_separator );
3043+
3044+ ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) ); // 13: "GlossDef"
3045+ ASSERT_TRUE( t == token::string );
3046+
3047+ ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) ); // 13: :
3048+ ASSERT_TRUE( t == token::name_separator );
3049+
3050+ ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) ); // 13: {
3051+ ASSERT_TRUE( t == token::begin_object );
3052+
3053+ ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) ); // 14: "para"
3054+ ASSERT_TRUE( t == token::string );
3055+
3056+ ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) ); // 14: :
3057+ ASSERT_TRUE( t == token::name_separator );
3058+
3059+ ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) ); // 14: "A meta-markup ..."
3060+ ASSERT_TRUE( t == token::string );
3061+
3062+ ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) ); // 14: ,
3063+ ASSERT_TRUE( t == token::value_separator );
3064+
3065+ ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) ); // 15: "GlossSeeAlso"
3066+ ASSERT_TRUE( t == token::string );
3067+
3068+ ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) ); // 15: :
3069+ ASSERT_TRUE( t == token::name_separator );
3070+
3071+ ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) ); // 15: [
3072+ ASSERT_TRUE( t == token::begin_array );
3073+
3074+ ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) ); // 15: "GML"
3075+ ASSERT_TRUE( t == token::string );
3076+
3077+ ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) ); // 15: ,
3078+ ASSERT_TRUE( t == token::value_separator );
3079+
3080+ ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) ); // 15: "XML"
3081+ ASSERT_TRUE( t == token::string );
3082+
3083+ ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) ); // 15: ]
3084+ ASSERT_TRUE( t == token::end_array );
3085+
3086+ ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) ); // 16: }
3087+ ASSERT_TRUE( t == token::end_object );
3088+
3089+ ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) ); // 16: ,
3090+ ASSERT_TRUE( t == token::value_separator );
3091+
3092+ ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) ); // 17: "GlossSee"
3093+ ASSERT_TRUE( t == token::string );
3094+
3095+ ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) ); // 17: :
3096+ ASSERT_TRUE( t == token::name_separator );
3097+
3098+ ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) ); // 17: "markup"
3099+ ASSERT_TRUE( t == token::string );
3100+
3101+ ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) ); // 18: }
3102+ ASSERT_TRUE( t == token::end_object );
3103+
3104+ ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) ); // 19: }
3105+ ASSERT_TRUE( t == token::end_object );
3106+
3107+ ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) ); // 20: }
3108+ ASSERT_TRUE( t == token::end_object );
3109+
3110+ ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) ); // 21: }
3111+ ASSERT_TRUE( t == token::end_object );
3112+
3113+ ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) ); // 22: }
3114+ ASSERT_TRUE( t == token::end_object );
3115+
3116+ ASSERT_TRUE( !p.next( &t ) );
3117+}
3118+
3119+static void test_lexer_array() {
3120+ char const source[] = "[ 1, \"2\", false, true, null ]";
3121+ istringstream iss( source );
3122+ lexer lex( iss );
3123+ token t;
3124+
3125+ ASSERT_TRUE( lex.next( &t ) );
3126+ ASSERT_TRUE( t == token::begin_array );
3127+
3128+ ASSERT_TRUE( lex.next( &t ) );
3129+ ASSERT_TRUE( t == token::number );
3130+ ASSERT_TRUE( t.get_value() == "1" );
3131+
3132+ ASSERT_TRUE( lex.next( &t ) );
3133+ ASSERT_TRUE( t == token::value_separator );
3134+
3135+ ASSERT_TRUE( lex.next( &t ) );
3136+ ASSERT_TRUE( t == token::string );
3137+ ASSERT_TRUE( t.get_value() == "2" );
3138+
3139+ ASSERT_TRUE( lex.next( &t ) );
3140+ ASSERT_TRUE( t == token::value_separator );
3141+
3142+ ASSERT_TRUE( lex.next( &t ) );
3143+ ASSERT_TRUE( t == token::json_false );
3144+
3145+ ASSERT_TRUE( lex.next( &t ) );
3146+ ASSERT_TRUE( t == token::value_separator );
3147+
3148+ ASSERT_TRUE( lex.next( &t ) );
3149+ ASSERT_TRUE( t == token::json_true );
3150+
3151+ ASSERT_TRUE( lex.next( &t ) );
3152+ ASSERT_TRUE( t == token::value_separator );
3153+
3154+ ASSERT_TRUE( lex.next( &t ) );
3155+ ASSERT_TRUE( t == token::json_null );
3156+
3157+ ASSERT_TRUE( lex.next( &t ) );
3158+ ASSERT_TRUE( t == token::end_array );
3159+
3160+ ASSERT_TRUE( !lex.next( &t ) );
3161+}
3162+
3163+static void test_lexer_object() {
3164+ char const source[] = "{ \"a\" : 1, \"b\" : \"2\" }";
3165+ istringstream iss( source );
3166+ lexer lex( iss );
3167+ token t;
3168+
3169+ ASSERT_TRUE( lex.next( &t ) );
3170+ ASSERT_TRUE( t == token::begin_object );
3171+
3172+ ASSERT_TRUE( lex.next( &t ) );
3173+ ASSERT_TRUE( t == token::string );
3174+
3175+ ASSERT_TRUE( lex.next( &t ) );
3176+ ASSERT_TRUE( t == token::name_separator );
3177+
3178+ ASSERT_TRUE( lex.next( &t ) );
3179+ ASSERT_TRUE( t == token::number );
3180+
3181+ ASSERT_TRUE( lex.next( &t ) );
3182+ ASSERT_TRUE( t == token::value_separator );
3183+
3184+ ASSERT_TRUE( lex.next( &t ) );
3185+ ASSERT_TRUE( t == token::string );
3186+
3187+ ASSERT_TRUE( lex.next( &t ) );
3188+ ASSERT_TRUE( t == token::name_separator );
3189+
3190+ ASSERT_TRUE( lex.next( &t ) );
3191+ ASSERT_TRUE( t == token::string );
3192+
3193+ ASSERT_TRUE( lex.next( &t ) );
3194+ ASSERT_TRUE( t == token::end_object );
3195+
3196+ ASSERT_TRUE( !lex.next( &t ) );
3197+}
3198+
3199+static void test_parser_array() {
3200+ char const source[] = "[ 1, \"2\", false, true, null ]";
3201+ istringstream iss( source );
3202+ parser p( iss );
3203+ token t;
3204+
3205+ ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );
3206+ ASSERT_TRUE( t == token::begin_array );
3207+
3208+ ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );
3209+ ASSERT_TRUE( t == token::number );
3210+ ASSERT_TRUE( t.get_value() == "1" );
3211+
3212+ ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );
3213+ ASSERT_TRUE( t == token::value_separator );
3214+
3215+ ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );
3216+ ASSERT_TRUE( t == token::string );
3217+ ASSERT_TRUE( t.get_value() == "2" );
3218+
3219+ ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );
3220+ ASSERT_TRUE( t == token::value_separator );
3221+
3222+ ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );
3223+ ASSERT_TRUE( t == token::json_false );
3224+
3225+ ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );
3226+ ASSERT_TRUE( t == token::value_separator );
3227+
3228+ ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );
3229+ ASSERT_TRUE( t == token::json_true );
3230+
3231+ ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );
3232+ ASSERT_TRUE( t == token::value_separator );
3233+
3234+ ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );
3235+ ASSERT_TRUE( t == token::json_null );
3236+
3237+ ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );
3238+ ASSERT_TRUE( t == token::end_array );
3239+
3240+ ASSERT_TRUE( !p.next( &t ) );
3241+}
3242+
3243+static void test_parser_object() {
3244+ char const source[] = "{ \"a\" : 1, \"b\" : \"2\" }";
3245+ istringstream iss( source );
3246+ parser p( iss );
3247+ token t;
3248+
3249+ ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );
3250+ ASSERT_TRUE( t == token::begin_object );
3251+
3252+ ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );
3253+ ASSERT_TRUE( t == token::string );
3254+
3255+ ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );
3256+ ASSERT_TRUE( t == token::name_separator );
3257+
3258+ ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );
3259+ ASSERT_TRUE( t == token::number );
3260+
3261+ ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );
3262+ ASSERT_TRUE( t == token::value_separator );
3263+
3264+ ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );
3265+ ASSERT_TRUE( t == token::string );
3266+
3267+ ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );
3268+ ASSERT_TRUE( t == token::name_separator );
3269+
3270+ ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );
3271+ ASSERT_TRUE( t == token::string );
3272+
3273+ ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );
3274+ ASSERT_TRUE( t == token::end_object );
3275+
3276+ ASSERT_TRUE( !p.next( &t ) );
3277+}
3278+
3279+static void test_unexpected_token() {
3280+ token t;
3281+ {
3282+ char const source[] = "{ 1 }";
3283+ istringstream iss( source );
3284+ parser p( iss );
3285+
3286+ ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );
3287+ ASSERT_TRUE( t == token::begin_object );
3288+ ASSERT_EXCEPTION( p.next( &t ), unexpected_token );
3289+ }
3290+ {
3291+ char const source[] = "{ \"a\" : 1, }";
3292+ istringstream iss( source );
3293+ parser p( iss );
3294+
3295+ ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );
3296+ ASSERT_TRUE( t == token::begin_object );
3297+
3298+ ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );
3299+ ASSERT_TRUE( t == token::string );
3300+
3301+ ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );
3302+ ASSERT_TRUE( t == token::name_separator );
3303+
3304+ ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );
3305+ ASSERT_TRUE( t == token::number );
3306+
3307+ ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );
3308+ ASSERT_TRUE( t == token::value_separator );
3309+
3310+ ASSERT_EXCEPTION( p.next( &t ), unexpected_token );
3311+ }
3312+ {
3313+ char const source[] = "{ \"t\" : true \"f\" : false }";
3314+ istringstream iss( source );
3315+ parser p( iss );
3316+
3317+ ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );
3318+ ASSERT_TRUE( t == token::begin_object );
3319+
3320+ ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );
3321+ ASSERT_TRUE( t == token::string );
3322+
3323+ ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );
3324+ ASSERT_TRUE( t == token::name_separator );
3325+
3326+ ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );
3327+ ASSERT_TRUE( t == token::json_true );
3328+
3329+ ASSERT_EXCEPTION( p.next( &t ), unexpected_token );
3330+ }
3331+ {
3332+ char const source[] = "[ 1";
3333+ istringstream iss( source );
3334+ parser p( iss );
3335+
3336+ ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );
3337+ ASSERT_TRUE( t == token::begin_array );
3338+
3339+ ASSERT_TRUE_AND_NO_EXCEPTION( p.next( &t ) );
3340+ ASSERT_TRUE( t == token::number );
3341+
3342+ ASSERT_EXCEPTION( p.next( &t ), unexpected_token );
3343+ }
3344+}
3345+
3346+static void test_unterminated_string() {
3347+ char const source[] = " \"hello ";
3348+ istringstream iss( source );
3349+ lexer lex( iss );
3350+ token t;
3351+
3352+ ASSERT_EXCEPTION( lex.next( &t ), unterminated_string );
3353+}
3354+
3355+///////////////////////////////////////////////////////////////////////////////
3356+
3357+namespace zorba {
3358+namespace UnitTests {
3359+
3360+int json_parser( int, char*[] ) {
3361+
3362+ // lexer-only tests
3363+ test_lexer_array();
3364+ test_lexer_object();
3365+ test_illegal_character();
3366+ test_illegal_codepoint();
3367+ test_illegal_escape();
3368+ test_illegal_literal();
3369+ test_illegal_number();
3370+ test_unterminated_string();
3371+
3372+ // parser tests
3373+ test_empty_stream();
3374+ test_parser_array();
3375+ test_parser_object();
3376+ test_unexpected_token();
3377+ test_json_org_example();
3378+
3379+ cout << failures << " test(s) failed\n";
3380+ return failures ? 1 : 0;
3381+}
3382+
3383+} // namespace UnitTests
3384+} // namespace zorba
3385+/* vim:set et sw=2 ts=2: */
3386
3387=== modified file 'src/unit_tests/unit_test_list.h'
3388--- src/unit_tests/unit_test_list.h 2012-02-02 09:56:52 +0000
3389+++ src/unit_tests/unit_test_list.h 2012-02-16 00:23:20 +0000
3390@@ -34,6 +34,7 @@
3391 /**
3392 * ADD NEW UNIT TESTS HERE
3393 */
3394+ int json_parser( int, char*[] );
3395
3396 void initializeTestList();
3397 };
3398
3399=== modified file 'src/unit_tests/unit_tests.cpp'
3400--- src/unit_tests/unit_tests.cpp 2012-02-02 09:56:52 +0000
3401+++ src/unit_tests/unit_tests.cpp 2012-02-16 00:23:20 +0000
3402@@ -39,6 +39,7 @@
3403 void initializeTestList() {
3404 libunittests["string"] = test_string;
3405 libunittests["uri"] = runUriTest;
3406+ libunittests["json_parser"] = json_parser;
3407 libunittests["unique_ptr"] = test_unique_ptr;
3408 #ifndef ZORBA_NO_FULL_TEXT
3409 libunittests["stemmer"] = test_stemmer;
3410
3411=== modified file 'src/util/CMakeLists.txt'
3412--- src/util/CMakeLists.txt 2011-07-18 14:25:21 +0000
3413+++ src/util/CMakeLists.txt 2012-02-16 00:23:20 +0000
3414@@ -20,6 +20,8 @@
3415 dir.cpp
3416 fs_util.cpp
3417 indent.cpp
3418+ json_parser.cpp
3419+ mem_streambuf.cpp
3420 regex.cpp
3421 string_util.cpp
3422 unicode_util.cpp
3423
3424=== added file 'src/util/json_parser.cpp'
3425--- src/util/json_parser.cpp 1970-01-01 00:00:00 +0000
3426+++ src/util/json_parser.cpp 2012-02-16 00:23:20 +0000
3427@@ -0,0 +1,662 @@
3428+/*
3429+ * Copyright 2006-2008 The FLWOR Foundation.
3430+ *
3431+ * Licensed under the Apache License, Version 2.0 (the "License");
3432+ * you may not use this file except in compliance with the License.
3433+ * You may obtain a copy of the License at
3434+ *
3435+ * http://www.apache.org/licenses/LICENSE-2.0
3436+ *
3437+ * Unless required by applicable law or agreed to in writing, software
3438+ * distributed under the License is distributed on an "AS IS" BASIS,
3439+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
3440+ * See the License for the specific language governing permissions and
3441+ * limitations under the License.
3442+ */
3443+
3444+#include "diagnostics/assert.h"
3445+
3446+#include "ascii_util.h"
3447+#include "stl_util.h"
3448+#include "string_util.h"
3449+#include "utf8_util.h"
3450+
3451+#define DEBUG_JSON_PARSER 0
3452+
3453+#if DEBUG_JSON_PARSER
3454+# include "indent.h"
3455+#endif /* DEBUG_JSON_PARSER */
3456+
3457+#include "json_parser.h"
3458+
3459+using namespace std;
3460+
3461+namespace zorba {
3462+namespace json {
3463+
3464+///////////////////////////////////////////////////////////////////////////////
3465+
3466+char const *const type_string_of[] = {
3467+ "none",
3468+ "array",
3469+ "boolean",
3470+ "null",
3471+ "number",
3472+ "object",
3473+ "string"
3474+};
3475+
3476+type map_type( token::type tt ) {
3477+ switch ( tt ) {
3478+ case token::string:
3479+ return string;
3480+ case token::number:
3481+ return number;
3482+ case token::json_false:
3483+ case token::json_true:
3484+ return boolean;
3485+ case token::json_null:
3486+ return null;
3487+ default:
3488+ return none;
3489+ }
3490+}
3491+
3492+///////////////////////////////////////////////////////////////////////////////
3493+
3494+exception::exception( location const &loc, std::string const &message ) :
3495+ loc_( loc ), message_( message )
3496+{
3497+}
3498+
3499+exception::~exception() throw() {
3500+ // out-of-line since it's virtual
3501+}
3502+
3503+char const* exception::what() const throw() {
3504+ return message_.c_str();
3505+}
3506+
3507+illegal_character::illegal_character( location const &loc, char c ) :
3508+ exception( loc, BUILD_STRING( '\'', c, "': illegal character" ) ),
3509+ c_( c )
3510+{
3511+}
3512+
3513+illegal_character::~illegal_character() throw() {
3514+ // out-of-line since it's virtual
3515+}
3516+
3517+illegal_codepoint::illegal_codepoint( location const &loc,
3518+ token::value_type const &cp ) :
3519+ exception( loc, BUILD_STRING( '"', cp, "\": illegal codepoint" ) ),
3520+ codepoint_( cp )
3521+{
3522+}
3523+
3524+illegal_codepoint::~illegal_codepoint() throw() {
3525+ // out-of-line since it's virtual
3526+}
3527+
3528+illegal_escape::illegal_escape( location const &loc, char c ) :
3529+ exception( loc, BUILD_STRING( "\"\\", c, "\": illegal character escape" ) ),
3530+ esc_( c )
3531+{
3532+}
3533+
3534+illegal_escape::~illegal_escape() throw() {
3535+ // out-of-line since it's virtual
3536+}
3537+
3538+illegal_literal::illegal_literal( location const &loc ) :
3539+ exception( loc, "illegal literal" )
3540+{
3541+}
3542+
3543+illegal_literal::~illegal_literal() throw() {
3544+ // out-of-line since it's virtual
3545+}
3546+
3547+illegal_number::illegal_number( location const &loc ) :
3548+ exception( loc, "illegal number" )
3549+{
3550+}
3551+
3552+illegal_number::~illegal_number() throw() {
3553+ // out-of-line since it's virtual
3554+}
3555+
3556+unexpected_token::unexpected_token( token const &t ) :
3557+ exception( t.get_loc(), BUILD_STRING( '"', t, "\": unexpected token" ) ),
3558+ token_( t )
3559+{
3560+}
3561+
3562+unexpected_token::~unexpected_token() throw() {
3563+ // out-of-line since it's virtual
3564+}
3565+
3566+unterminated_string::unterminated_string( location const &loc ) :
3567+ exception( loc, "unterminated string" )
3568+{
3569+}
3570+
3571+unterminated_string::~unterminated_string() throw() {
3572+ // out-of-line since it's virtual
3573+}
3574+
3575+///////////////////////////////////////////////////////////////////////////////
3576+
3577+token::token() :
3578+ type_( none )
3579+{
3580+}
3581+
3582+ostream& operator<<( ostream &o, token::type tt ) {
3583+ switch ( tt ) {
3584+ case token::string : o << "string"; break;
3585+ case token::number : o << "number"; break;
3586+ case token::json_false: o << "false" ; break;
3587+ case token::json_null : o << "null" ; break;
3588+ case token::json_true : o << "true" ; break;
3589+ case token::none : o << "<none>"; break;
3590+ default : o << static_cast<char>( tt );
3591+ }
3592+ return o;
3593+}
3594+
3595+ostream& operator<<( ostream &o, token const &t ) {
3596+ switch ( t.get_type() ) {
3597+ case token::string: o << '"' << t.get_value() << '"'; break;
3598+ case token::number: o << t.get_value() ; break;
3599+ default : o << t.get_type() ;
3600+ }
3601+ return o;
3602+}
3603+
3604+///////////////////////////////////////////////////////////////////////////////
3605+
3606+lexer::lexer( istream &in ) :
3607+ in_( &in ),
3608+ line_( 1 ),
3609+ col_( 1 )
3610+{
3611+}
3612+
3613+bool lexer::get_char( char *c ) {
3614+ char const temp = in_->get();
3615+ if ( in_->good() ) {
3616+ if ( temp == '\n' )
3617+ ++line_, col_ = 1;
3618+ else
3619+ ++col_;
3620+ if ( c )
3621+ *c = temp;
3622+ return true;
3623+ }
3624+ return false;
3625+}
3626+
3627+bool lexer::peek_char( char *c ) {
3628+ *c = in_->peek();
3629+ return in_->good();
3630+}
3631+
3632+bool lexer::next( token *t ) {
3633+ while ( true ) {
3634+ cur_loc_ = cur_loc();
3635+ char c;
3636+ if ( !get_char( &c ) )
3637+ return false;
3638+ switch ( c ) {
3639+ case ' ':
3640+ case '\n':
3641+ case '\r':
3642+ case '\t':
3643+ continue;
3644+ case '"':
3645+ t->type_ = token::string;
3646+ t->loc_ = cur_loc_;
3647+ parse_string( &t->value_ );
3648+ return true;
3649+ case '-':
3650+ case '0':
3651+ case '1':
3652+ case '2':
3653+ case '3':
3654+ case '4':
3655+ case '5':
3656+ case '6':
3657+ case '7':
3658+ case '8':
3659+ case '9':
3660+ t->type_ = token::number;
3661+ t->loc_ = cur_loc_;
3662+ parse_number( c, &t->value_ );
3663+ return true;
3664+ case 'f':
3665+ case 'n':
3666+ case 't':
3667+ t->type_ = parse_literal( c, &t->value_ );
3668+ t->loc_ = cur_loc_;
3669+ return true;
3670+ case '[':
3671+ case '{':
3672+ case ']':
3673+ case '}':
3674+ case ':':
3675+ case ',':
3676+ t->type_ = static_cast<token::type>( c );
3677+ t->loc_ = cur_loc_;
3678+ return true;
3679+ default:
3680+ throw illegal_character( cur_loc_, c );
3681+ }
3682+ } // while
3683+}
3684+
3685+unicode::code_point lexer::parse_codepoint() {
3686+ static char const hex_digits[] = "0123456789ABCDEF";
3687+
3688+ zstring cp_string( "\\u" ); // needed only for error message
3689+
3690+ unicode::code_point cp = 0;
3691+ for ( int i = 1; i <= 4; ++i ) {
3692+ char c;
3693+ if ( !get_char( &c ) || !ascii::is_xdigit( c ) )
3694+ throw illegal_codepoint( cur_loc_, cp_string );
3695+ cp_string += c;
3696+ c = ascii::to_upper( c );
3697+ char const *const p = std::strchr( hex_digits, c );
3698+ assert( p );
3699+ cp = (cp << 4) | (p - hex_digits);
3700+ }
3701+ return cp;
3702+}
3703+
3704+token::type lexer::parse_literal( char first_c, token::value_type *value ) {
3705+ static token::value_type const false_value( "false" );
3706+ static token::value_type const null_value ( "null" );
3707+ static token::value_type const true_value ( "true" );
3708+
3709+ token::type tt;
3710+ switch ( first_c ) {
3711+ case 'f': *value = false_value; tt = token::json_false; break;
3712+ case 'n': *value = null_value ; tt = token::json_null ; break;
3713+ case 't': *value = true_value ; tt = token::json_true ; break;
3714+ default : assert( false );
3715+ }
3716+
3717+ char c;
3718+ for ( char const *s = value->c_str(); *++s; ) {
3719+ if ( !get_char( &c ) || c != *s )
3720+ throw illegal_literal( cur_loc_ );
3721+ }
3722+ if ( peek_char( &c ) && ascii::is_alnum( c ) )
3723+ throw illegal_literal( cur_loc_ );
3724+
3725+ return tt;
3726+}
3727+
3728+void lexer::parse_number( char first_c, token::value_type *value ) {
3729+ value->clear();
3730+
3731+ // <number> ::= [-] <int> [<frac>] [<exp>]
3732+ char c = first_c;
3733+ if ( c == '-' ) {
3734+ *value += c;
3735+ if ( !get_char( &c ) )
3736+ throw illegal_number( cur_loc_ );
3737+ }
3738+
3739+ // <int> := '0' | <1-9> <digit>*
3740+ if ( !ascii::is_digit( c ) )
3741+ throw illegal_number( cur_loc_ );
3742+ *value += c;
3743+ if ( c == '0' ) {
3744+ if ( !get_char( &c ) )
3745+ return;
3746+ } else {
3747+ while ( true ) {
3748+ if ( !get_char( &c ) )
3749+ return;
3750+ if ( !ascii::is_digit( c ) )
3751+ break;
3752+ *value += c;
3753+ }
3754+ }
3755+
3756+ // <frac> ::= '.' <digit>+
3757+ if ( c == '.' ) {
3758+ *value += c;
3759+ if ( !get_char( &c ) || !ascii::is_digit( c ) )
3760+ throw illegal_number( cur_loc_ );
3761+ *value += c;
3762+ while ( true ) {
3763+ if ( !get_char( &c ) )
3764+ return;
3765+ if ( !ascii::is_digit( c ) )
3766+ break;
3767+ *value += c;
3768+ }
3769+ }
3770+
3771+ // <exp> ::= <e> [<sign>] <digit>+
3772+ // <e> ::= 'e' | 'E'
3773+ // <sign> ::= '-' | '+'
3774+ if ( c == 'e' || c == 'E' ) {
3775+ *value += c;
3776+ if ( !get_char( &c ) )
3777+ throw illegal_number( cur_loc_ );
3778+ if ( c == '+' || c == '-' ) {
3779+ *value += c;
3780+ if ( !get_char( &c ) )
3781+ throw illegal_number( cur_loc_ );
3782+ }
3783+ if ( !ascii::is_digit( c ) )
3784+ throw illegal_number( cur_loc_ );
3785+ *value += c;
3786+ while ( true ) {
3787+ if ( !get_char( &c ) )
3788+ return;
3789+ if ( !ascii::is_digit( c ) )
3790+ break;
3791+ *value += c;
3792+ }
3793+ }
3794+
3795+ in_->putback( c );
3796+}
3797+
3798+void lexer::parse_string( token::value_type *value ) {
3799+ value->clear();
3800+ bool got_backslash = false;
3801+ location const start_loc( cur_loc_ );
3802+
3803+ while ( true ) {
3804+ cur_loc_ = cur_loc();
3805+ char c;
3806+ if ( !get_char( &c ) )
3807+ throw unterminated_string( start_loc );
3808+ if ( got_backslash ) {
3809+ got_backslash = false;
3810+ switch ( c ) {
3811+ case '"':
3812+ case '/':
3813+ case '\\':
3814+ *value += c;
3815+ break;
3816+ case 'b':
3817+ *value += '\b';
3818+ break;
3819+ case 'f':
3820+ *value += '\f';
3821+ break;
3822+ case 'n':
3823+ *value += '\n';
3824+ break;
3825+ case 'r':
3826+ *value += '\r';
3827+ break;
3828+ case 't':
3829+ *value += '\t';
3830+ break;
3831+ case 'u':
3832+ utf8::encode( parse_codepoint(), value );
3833+ break;
3834+ default:
3835+ throw illegal_escape( cur_loc_, c );
3836+ }
3837+ continue;
3838+ }
3839+
3840+ switch ( c ) {
3841+ case '\\':
3842+ got_backslash = true;
3843+ break;
3844+ case '"':
3845+ return;
3846+ default:
3847+ *value += c;
3848+ }
3849+ } // while
3850+}
3851+
3852+void lexer::set_loc( char const *file, line_type line, column_type col ) {
3853+ if ( file )
3854+ file_ = file;
3855+ line_ = line;
3856+ col_ = col;
3857+}
3858+
3859+///////////////////////////////////////////////////////////////////////////////
3860+
3861+#if DEBUG_JSON_PARSER
3862+
3863+ostream& operator<<( ostream &o, parser::state s ) {
3864+ static char const *const string_of[] = {
3865+ "A0", "A1", "A2",
3866+ "E0", "E1",
3867+ "J0", "J1",
3868+ "M0", "M1",
3869+ "O0", "O1", "O2",
3870+ "P0", "P1",
3871+ "V0"
3872+ };
3873+ return o << string_of[ s ];
3874+}
3875+
3876+static void throw_unexpected_token( int line, token const &t ) {
3877+ try {
3878+ throw unexpected_token( t );
3879+ }
3880+ catch ( exception const &e ) {
3881+ cerr << line << ": " << e.what() << endl;
3882+ throw;
3883+ }
3884+}
3885+
3886+bool parser::get_token_debug( int line, token *t ) {
3887+ bool const got_token = get_token( t );
3888+ cout << line << ": get_token => " << *t << endl;
3889+ return got_token;
3890+}
3891+
3892+bool parser::matches_token_debug( int line, token::type tt, token *t ) {
3893+ bool const matched = matches_token( tt, t );
3894+ cout << line << ": token " << *t << " matches " << tt << " => " << (matched ? 'T' : 'F') << endl;
3895+ return matched;
3896+}
3897+
3898+token::type parser::peek_token_debug( int line ) {
3899+ token::type const tt = peek_token();
3900+ cout << line << ": peek_token => " << peeked_token_ << endl;
3901+ return tt;
3902+}
3903+
3904+void parser::require_token_debug( int line, token::type tt, token *t ) {
3905+ if ( !get_token_debug( line, t ) || t->get_type() != tt )
3906+ throw_unexpected_token( line, *t );
3907+}
3908+
3909+# define GET_TOKEN(T) get_token_debug( __LINE__, T )
3910+# define MATCHES_TOKEN(TT,T) matches_token_debug( __LINE__, TT, T )
3911+# define PEEK_TOKEN() peek_token_debug( __LINE__ )
3912+# define REQUIRE_TOKEN(TT,T) require_token_debug( __LINE__, TT, T )
3913+# define THROW_UNEXPECTED_TOKEN(T) throw_unexpected_token( __LINE__, T )
3914+
3915+# define GOTO_STATE(S) \
3916+ if (0) ; else { \
3917+ state_ = (S); \
3918+ cout << __LINE__ << ':' << indent << "GOTO_STATE( " << state_ << " )" << endl; \
3919+ continue; \
3920+ }
3921+
3922+# define PUSH_STATE(S) \
3923+ if (0) ; else { \
3924+ state_stack_.push(S); \
3925+ cout << __LINE__ << ':' << indent << "PUSH_STATE( " << (S) << " )" << endl << inc_indent; \
3926+ }
3927+
3928+# define POP_STATE() \
3929+ if (0) ; else { \
3930+ state_ = ztd::pop_stack( state_stack_ ); \
3931+ cout << __LINE__ << ':' << indent << "POP_STATE() => " << state_ << endl << dec_indent; \
3932+ }
3933+
3934+#else
3935+
3936+# define GET_TOKEN(T) get_token( T )
3937+# define MATCHES_TOKEN(TT,T) matches_token( TT, T )
3938+# define PEEK_TOKEN() peek_token()
3939+# define REQUIRE_TOKEN(TT,T) require_token( TT, T )
3940+# define THROW_UNEXPECTED_TOKEN(T) throw unexpected_token( T )
3941+
3942+# define GOTO_STATE(S) { state_ = (S); continue; }
3943+# define PUSH_STATE(S) state_stack_.push(S)
3944+# define POP_STATE() state_ = ztd::pop_stack( state_stack_ )
3945+
3946+#endif /* DEBUG_JSON_PARSER */
3947+
3948+///////////////////////////////////////////////////////////////////////////////
3949+
3950+parser::parser( istream &in ) : lexer_( in ) {
3951+#if DEBUG_JSON_PARSER
3952+ get_indent( cout ) = 0;
3953+#endif /* DEBUG_JSON_PARSER */
3954+ PUSH_STATE( J0 );
3955+}
3956+
3957+bool parser::get_token( token *t ) {
3958+ if ( peeked_token_ ) {
3959+ *t = peeked_token_;
3960+ peeked_token_.clear();
3961+ return true;
3962+ }
3963+ t->clear();
3964+ return lexer_.next( t );
3965+}
3966+
3967+bool parser::matches_token( token::type tt, token *t ) {
3968+ if ( peek_token() == tt )
3969+ return get_token( t );
3970+ *t = peeked_token_;
3971+ return false;
3972+}
3973+
3974+token::type parser::peek_token() {
3975+ if ( !peeked_token_ )
3976+ lexer_.next( &peeked_token_ );
3977+ return peeked_token_.get_type();
3978+}
3979+
3980+#if ! DEBUG_JSON_PARSER
3981+void parser::require_token( token::type tt, token *t ) {
3982+ if ( !get_token( t ) || t->get_type() != tt )
3983+ THROW_UNEXPECTED_TOKEN( *t );
3984+}
3985+#endif /* DEBUG_JSON_PARSER */
3986+
3987+bool parser::next( token *t ) {
3988+ if ( state_stack_.empty() )
3989+ return false;
3990+ POP_STATE();
3991+ while ( true ) {
3992+ switch ( state_ ) {
3993+
3994+ // <JSON> ::= <Array> | <Object>
3995+ case J0: PUSH_STATE( J1 );
3996+ switch ( PEEK_TOKEN() ) {
3997+ case token::begin_array : GOTO_STATE( A0 );
3998+ case token::begin_object: GOTO_STATE( O0 );
3999+ case token::none : break;
4000+ default: THROW_UNEXPECTED_TOKEN( peeked_token_ );
4001+ }
4002+ case J1: return false;
4003+
4004+ // <Array> ::= '[' <Element>* ']'
4005+ case A0: REQUIRE_TOKEN( token::begin_array, t );
4006+ PUSH_STATE( A1 );
4007+ return true;
4008+ case A1: if ( MATCHES_TOKEN( token::end_array, t ) )
4009+ return true;
4010+ PUSH_STATE( A2 );
4011+ GOTO_STATE( E0 );
4012+ case A2: REQUIRE_TOKEN( token::end_array, t );
4013+ return true;
4014+
4015+ // <Element> ::= <Value> [ ',' <Element> ]
4016+ case E0: PUSH_STATE( E1 );
4017+ GOTO_STATE( V0 );
4018+ case E1: if ( MATCHES_TOKEN( token::value_separator, t ) ) {
4019+ PUSH_STATE( E0 );
4020+ return true;
4021+ }
4022+ POP_STATE();
4023+ continue;
4024+
4025+ // <Object> ::= '{' <Member>* '}'
4026+ case O0: REQUIRE_TOKEN( token::begin_object, t );
4027+ PUSH_STATE( O1 );
4028+ return true;
4029+ case O1: if ( MATCHES_TOKEN( token::end_object, t ) )
4030+ return true;
4031+ PUSH_STATE( O2 );
4032+ GOTO_STATE( M0 );
4033+ case O2: REQUIRE_TOKEN( token::end_object, t );
4034+ return true;
4035+
4036+ // <Member> ::= <Pair> [ ',' <Member> ]
4037+ case M0: PUSH_STATE( M1 );
4038+ GOTO_STATE( P0 );
4039+ case M1: if ( MATCHES_TOKEN( token::value_separator, t ) ) {
4040+ PUSH_STATE( M0 );
4041+ return true;
4042+ }
4043+ POP_STATE();
4044+ continue;
4045+
4046+ // <Pair> ::= <String> ':' <Value>
4047+ case P0: REQUIRE_TOKEN( token::string, t );
4048+ PUSH_STATE( P1 );
4049+ return true;
4050+ case P1: REQUIRE_TOKEN( token::name_separator, t );
4051+ PUSH_STATE( V0 );
4052+ return true;
4053+
4054+ // <Value> ::= <Array> | <Object> | <String> | <Number>
4055+ // | false | null | true
4056+ case V0: switch ( PEEK_TOKEN() ) {
4057+ case token::begin_array:
4058+ GOTO_STATE( A0 );
4059+ case token::begin_object:
4060+ GOTO_STATE( O0 );
4061+ case token::string:
4062+ case token::number:
4063+ case token::json_false:
4064+ case token::json_null:
4065+ case token::json_true:
4066+ GET_TOKEN( t );
4067+ return true;
4068+ default:
4069+ THROW_UNEXPECTED_TOKEN( peeked_token_ );
4070+ }
4071+ } // switch ( state_ )
4072+ } // while
4073+}
4074+
4075+token::type parser::peek( token *t ) {
4076+ if ( token::type const tt = PEEK_TOKEN() ) {
4077+ if ( t )
4078+ *t = peeked_token_;
4079+ return tt;
4080+ }
4081+ return token::none;
4082+}
4083+
4084+///////////////////////////////////////////////////////////////////////////////
4085+
4086+} // namespace json
4087+} // namespace zorba
4088+
4089+/* vim:set et sw=2 ts=2: */
4090
4091=== added file 'src/util/json_parser.h'
4092--- src/util/json_parser.h 1970-01-01 00:00:00 +0000
4093+++ src/util/json_parser.h 2012-02-16 00:23:20 +0000
4094@@ -0,0 +1,570 @@
4095+/*
4096+ * Copyright 2006-2008 The FLWOR Foundation.
4097+ *
4098+ * Licensed under the Apache License, Version 2.0 (the "License");
4099+ * you may not use this file except in compliance with the License.
4100+ * You may obtain a copy of the License at
4101+ *
4102+ * http://www.apache.org/licenses/LICENSE-2.0
4103+ *
4104+ * Unless required by applicable law or agreed to in writing, software
4105+ * distributed under the License is distributed on an "AS IS" BASIS,
4106+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
4107+ * See the License for the specific language governing permissions and
4108+ * limitations under the License.
4109+ */
4110+
4111+#ifndef ZORBA_JSON_PARSER_H
4112+#define ZORBA_JSON_PARSER_H
4113+
4114+#include <zorba/config.h>
4115+
4116+#include <exception>
4117+#include <iostream>
4118+#include <stack>
4119+#include <string>
4120+
4121+#include <zorba/internal/diagnostic.h>
4122+
4123+#include "zorbatypes/zstring.h"
4124+
4125+#include "cxx_util.h"
4126+#include "unicode_util.h"
4127+
4128+namespace zorba {
4129+namespace json {
4130+
4131+///////////////////////////////////////////////////////////////////////////////
4132+
4133+typedef internal::diagnostic::location location;
4134+
4135+///////////////////////////////////////////////////////////////////////////////
4136+
4137+/**
4138+ * A JSON %type is the type of JSON data. This isn't used by the lexer or
4139+ * parser implementation at all, but it's handy.
4140+ */
4141+enum type {
4142+ none, // meaning "not set" as opposed to "null"
4143+ array,
4144+ boolean,
4145+ null,
4146+ number,
4147+ object,
4148+ string
4149+};
4150+extern char const *const type_string_of[];
4151+
4152+inline std::ostream& operator<<( std::ostream &o, type t ) {
4153+ return o << type_string_of[ t ];
4154+}
4155+
4156+/**
4157+ * A JSON %token. Tokens have a type, location at which they were found, and
4158+ * sometimes a value.
4159+ *
4160+ * See: "RFC 4627: The application/json Media Type for JavaScript Object
4161+ * Notation (JSON)."
4162+ */
4163+class token {
4164+ // see http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2333.html
4165+ struct pointer_conversion { int valid; };
4166+ typedef int pointer_conversion::*explicit_bool;
4167+public:
4168+ typedef zstring value_type;
4169+
4170+ /**
4171+ * The types of tokens in JSON. The first 6 constants have values that
4172+ * correspond to the actual structural characters used by JSON; the rest were
4173+ * assigned non-standard, mnemonic values for convenience.
4174+ */
4175+ enum type {
4176+ none,
4177+ begin_array = '[',
4178+ begin_object = '{',
4179+ end_array = ']',
4180+ end_object = '}',
4181+ name_separator = ':',
4182+ value_separator = ',',
4183+ string = 'S',
4184+ number = 'N',
4185+ json_false = 'F',
4186+ json_null = '0',
4187+ json_true = 'T',
4188+ };
4189+
4190+ /**
4191+ * Default constructor.
4192+ */
4193+ token();
4194+
4195+ /**
4196+ * Clears this %token.
4197+ */
4198+ void clear() {
4199+ type_ = none;
4200+ value_.clear();
4201+ }
4202+
4203+ /**
4204+ * Gets the location at which this %token was found.
4205+ *
4206+ * @return Returns said location.
4207+ */
4208+ location const& get_loc() const {
4209+ return loc_;
4210+ }
4211+
4212+ /**
4213+ * Gets the type of this %token.
4214+ *
4215+ * @return Returns said type.
4216+ */
4217+ type get_type() const {
4218+ return type_;
4219+ }
4220+
4221+ /**
4222+ * Gets the value of this %token, if any. Only %token types string, number,
4223+ * false, null, and true have a value.
4224+ *
4225+ * @return Returns said value or the empty string.
4226+ */
4227+ value_type const& get_value() const {
4228+ return value_;
4229+ }
4230+
4231+ /**
4232+ * Conversion to \c bool.
4233+ *
4234+ * @return Returns \c true only if this token's type is not \c none.
4235+ */
4236+ operator explicit_bool() const {
4237+ return type_ ? &pointer_conversion::valid : nullptr;
4238+ }
4239+
4240+private:
4241+ location loc_;
4242+ type type_;
4243+ value_type value_;
4244+
4245+ friend class lexer;
4246+};
4247+
4248+/**
4249+ * Map a token's type to a JSON type.
4250+ *
4251+ * @param tt The token::type to map.
4252+ * @return Returns the corresponding JSON type or \c none if \a tt doesn't map.
4253+ */
4254+type map_type( token::type tt );
4255+
4256+/**
4257+ * Emits the given token type to an ostream.
4258+ *
4259+ * @param o The ostream to emit to.
4260+ * @param tt The token type to emit.
4261+ * @return Returns \a o.
4262+ */
4263+std::ostream& operator<<( std::ostream &o, token::type tt );
4264+
4265+/**
4266+ * Emits the given token to an ostream.
4267+ *
4268+ * @param o The ostream to emit to.
4269+ * @param t The token to emit.
4270+ * @return Returns \a o.
4271+ */
4272+std::ostream& operator<<( std::ostream &o, token const &t );
4273+
4274+/**
4275+ * Compares two tokens for equality.
4276+ *
4277+ * @param t1 The first token.
4278+ * @param t2 The second token.
4279+ * @return Returns \c true only if the two tokens' types and values are equal.
4280+ */
4281+inline bool operator==( token const &t1, token const &t2 ) {
4282+ return t1.get_type() == t2.get_type() && t1.get_value() == t2.get_value();
4283+}
4284+
4285+/**
4286+ * Compares a token's type to another type for equality.
4287+ *
4288+ * @param t The token whose type to compare.
4289+ * @param tt The type to compare to.
4290+ * @return Returns \c true only if the token's type equals \a tt.
4291+ */
4292+inline bool operator==( token const &t, token::type tt ) {
4293+ return t.get_type() == tt;
4294+}
4295+
4296+/**
4297+ * Compares a token's type to another type for equality.
4298+ *
4299+ * @param tt The type to compare.
4300+ * @param t The token whose type to compare to.
4301+ * @return Returns \c true only if \a tt equals the token's type.
4302+ */
4303+inline bool operator==( token::type tt, token const &t ) {
4304+ return t == tt;
4305+}
4306+
4307+/**
4308+ * Compares a token's value to a C string for equality.
4309+ *
4310+ * @param t The token whose value to compare.
4311+ * @param value The value to compare to.
4312+ * @return Returns \c true only if the token's value equals \a value.
4313+ */
4314+inline bool operator==( token const &t, char const *value ) {
4315+ return t.get_value() == value;
4316+}
4317+
4318+/**
4319+ * Compares a C string to a token's value for equality.
4320+ *
4321+ * @param value The value to compare.
4322+ * @param t The token whose value to compare to.
4323+ * @return Returns \c true only if \a value equals the token's value.
4324+ */
4325+inline bool operator==( char const *value, token const &t ) {
4326+ return t == value;
4327+}
4328+
4329+/**
4330+ * Compares two tokens for inequality.
4331+ *
4332+ * @param t1 The first token.
4333+ * @param t2 The second token.
4334+ * @return Returns \c true if either the two tokens' types or values are not
4335+ * equal.
4336+ */
4337+inline bool operator!=( token const &t1, token const &t2 ) {
4338+ return !(t1 == t2);
4339+}
4340+
4341+/**
4342+ * Compares a token's type to another type for inequality.
4343+ *
4344+ * @param t The token whose type to compare.
4345+ * @param tt The type to compare to.
4346+ * @return Returns \c true only if the token's type is not equal to \a tt.
4347+ */
4348+inline bool operator!=( token const &t, token::type tt ) {
4349+ return !(t == tt);
4350+}
4351+
4352+/**
4353+ * Compares a token's type to another type for inequality.
4354+ *
4355+ * @param tt The type to compare.
4356+ * @param t The token whose type to compare to.
4357+ * @return Returns \c true only if \a tt is not equal to the token's type.
4358+ */
4359+inline bool operator!=( token::type tt, token const &t ) {
4360+ return !(tt == t);
4361+}
4362+
4363+/**
4364+ * Compares a token's value to a C string for inequality.
4365+ *
4366+ * @param t The token whose value to compare.
4367+ * @param value The value to compare to.
4368+ * @return Returns \c true only if the token's value is not equal to \a value.
4369+ */
4370+inline bool operator!=( token const &t, char const *value ) {
4371+ return !(t == value);
4372+}
4373+
4374+/**
4375+ * Compares a token's value to a C string for inequality.
4376+ *
4377+ * @param value The value to compare.
4378+ * @param t The token whose value to compare to.
4379+ * @return Returns \c true only if \a value is not equal to the token's value.
4380+ */
4381+inline bool operator!=( char const *value, token const &t ) {
4382+ return !(value == t);
4383+}
4384+
4385+///////////////////////////////////////////////////////////////////////////////
4386+
4387+/**
4388+ * An %exception is the root of the JSON %exception hierarchy.
4389+ */
4390+class exception : public std::exception {
4391+public:
4392+ ~exception() throw();
4393+
4394+ /**
4395+ * Gets the location in the JSON source whence this exception was thrown.
4396+ */
4397+ location const& get_loc() const {
4398+ return loc_;
4399+ }
4400+
4401+ // inherited
4402+ char const* what() const throw();
4403+
4404+protected:
4405+ exception( location const &loc, std::string const &message );
4406+
4407+private:
4408+ location loc_;
4409+ std::string message_;
4410+};
4411+
4412+/**
4413+ * This exception is thrown when an illegal character is encountered in a JSON
4414+ * data stream.
4415+ */
4416+class illegal_character : public exception {
4417+public:
4418+ illegal_character( location const &loc, char c );
4419+ ~illegal_character() throw();
4420+
4421+ /**
4422+ * Gets the illegal character.
4423+ *
4424+ * @return Returns said character.
4425+ */
4426+ char get_char() const {
4427+ return c_;
4428+ }
4429+
4430+private:
4431+ char c_;
4432+};
4433+
4434+/**
4435+ * This exception is thrown when an illegal Unicode code-point escape sequence
4436+ * (\uHHHH) is encountered.
4437+ */
4438+class illegal_codepoint : public exception {
4439+public:
4440+ illegal_codepoint( location const &loc, token::value_type const &cp );
4441+ ~illegal_codepoint() throw();
4442+
4443+ /**
4444+ * Gets the illegal code-point.
4445+ *
4446+ * @return Returns said code-point.
4447+ */
4448+ token::value_type get_codepoint() const {
4449+ return codepoint_;
4450+ }
4451+
4452+private:
4453+ token::value_type codepoint_;
4454+};
4455+
4456+/**
4457+ * This exception is thrown when an illegal character follows a backslash
4458+ * (escape) within a string literal. The legal escape characters are:
4459+ * ["/\bfnrtu].
4460+ */
4461+class illegal_escape : public exception {
4462+public:
4463+ illegal_escape( location const &loc, char escape );
4464+ ~illegal_escape() throw();
4465+
4466+ /**
4467+ * Gets the illegal escape character.
4468+ *
4469+ * @return Returns said character.
4470+ */
4471+ char get_escape() const {
4472+ return esc_;
4473+ }
4474+
4475+private:
4476+ char esc_;
4477+};
4478+
4479+/**
4480+ * This exception is thrown when a literal other than \c false, \c null, or
4481+ * \c true is encountered.
4482+ */
4483+class illegal_literal : public exception {
4484+public:
4485+ illegal_literal( location const &loc );
4486+ ~illegal_literal() throw();
4487+};
4488+
4489+/**
4490+ * This exception is thrown when an illegal number is encountered.
4491+ */
4492+class illegal_number : public exception {
4493+public:
4494+ illegal_number( location const &loc );
4495+ ~illegal_number() throw();
4496+};
4497+
4498+/**
4499+ * This exception is thrown when an unexpected token is encountered.
4500+ */
4501+class unexpected_token : public exception {
4502+public:
4503+ unexpected_token( token const &t );
4504+ ~unexpected_token() throw();
4505+
4506+ /**
4507+ * Gets the unexpected token
4508+ *
4509+ * @return Returns said token.
4510+ */
4511+ token const& get_token() const {
4512+ return token_;
4513+ }
4514+
4515+private:
4516+ token token_;
4517+};
4518+
4519+/**
4520+ * This exception is thrown when an EOF is encountered before a string's
4521+ * terminating quote.
4522+ */
4523+class unterminated_string : public exception {
4524+public:
4525+ unterminated_string( location const &loc );
4526+ ~unterminated_string() throw();
4527+};
4528+
4529+///////////////////////////////////////////////////////////////////////////////
4530+
4531+/**
4532+ * A %lexer extracts JSON tokens from an istream.
4533+ */
4534+class lexer {
4535+public:
4536+ typedef location::line_type line_type;
4537+ typedef location::column_type column_type;
4538+
4539+ /**
4540+ * Constructs a %lexer on the given istream.
4541+ *
4542+ * @param in The istream to read from.
4543+ */
4544+ lexer( std::istream &in );
4545+
4546+ /**
4547+ * Gets the next token, if any.
4548+ *
4549+ * @param result A pointer to the token to get into.
4550+ * @return Returns \c true only if there was a next token.
4551+ * @throws exception upon error.
4552+ */
4553+ bool next( token *result );
4554+
4555+ /**
4556+ * Sets the file location.
4557+ *
4558+ * @param file The source file name.
4559+ * @param line The source line number.
4560+ * @param col The source column number.
4561+ */
4562+ void set_loc( char const *file, line_type line, column_type col );
4563+
4564+private:
4565+ location cur_loc() const {
4566+ return location( file_, line_, col_ );
4567+ }
4568+
4569+ bool get_char( char* = nullptr );
4570+ bool peek_char( char* );
4571+ unicode::code_point parse_codepoint();
4572+ token::type parse_literal( char, token::value_type* );
4573+ void parse_number( char, token::value_type* );
4574+ void parse_string( token::value_type* );
4575+
4576+ std::istream *in_;
4577+ std::string file_;
4578+ line_type line_;
4579+ column_type col_;
4580+ location cur_loc_;
4581+};
4582+
4583+///////////////////////////////////////////////////////////////////////////////
4584+
4585+/**
4586+ * A %parser extracts JSON tokens from an istream while checking to ensure the
4587+ * token sequence is valid.
4588+ */
4589+class parser {
4590+public:
4591+ typedef lexer::line_type line_type;
4592+ typedef lexer::column_type column_type;
4593+
4594+ /**
4595+ * Constructs a %parser on the given istream.
4596+ *
4597+ * @param in The istream to read from.
4598+ */
4599+ parser( std::istream &in );
4600+
4601+ /**
4602+ * Gets the next token, if any.
4603+ *
4604+ * @param result A pointer to the token to receive the token.
4605+ * @return Returns \c true only if there was a next token.
4606+ * @throws exception upon error.
4607+ */
4608+ bool next( token *result );
4609+
4610+ /**
4611+ * Peeks at the next token, if any.
4612+ *
4613+ * @param result A pointer to the token to receive the token, if any.
4614+ * @return Returns the type of the peeked token.
4615+ * @throws exception upon error.
4616+ */
4617+ token::type peek( token *result = nullptr );
4618+
4619+ /**
4620+ * Sets the file location.
4621+ *
4622+ * @param file The source file name.
4623+ * @param line The source line number.
4624+ * @param col The source column number.
4625+ */
4626+ void set_loc( char const *file, line_type line, column_type col ) {
4627+ lexer_.set_loc( file, line, col );
4628+ }
4629+
4630+private:
4631+ enum state {
4632+ A0, A1, A2, // Array
4633+ E0, E1, // Element
4634+ J0, J1, // JSON
4635+ M0, M1, // Member
4636+ O0, O1, O2, // Object
4637+ P0, P1, // Pair
4638+ V0 // Value
4639+ };
4640+
4641+ friend std::ostream& operator<<( std::ostream&, state );
4642+
4643+ bool get_token( token* );
4644+ bool get_token_debug( int, token* );
4645+ bool matches_token( token::type, token* );
4646+ bool matches_token_debug( int, token::type, token* );
4647+ token::type peek_token();
4648+ token::type peek_token_debug( int );
4649+ void require_token( token::type, token* );
4650+ void require_token_debug( int, token::type, token* );
4651+
4652+ lexer lexer_;
4653+ token peeked_token_;
4654+ std::stack<state> state_stack_;
4655+ state state_;
4656+};
4657+
4658+///////////////////////////////////////////////////////////////////////////////
4659+
4660+} // namespace json
4661+} // namespace zorba
4662+
4663+#endif /* ZORBA_JSON_PARSER_H */
4664+/* vim:set et sw=2 ts=2: */
4665
4666=== added file 'src/util/mem_streambuf.cpp'
4667--- src/util/mem_streambuf.cpp 1970-01-01 00:00:00 +0000
4668+++ src/util/mem_streambuf.cpp 2012-02-16 00:23:20 +0000
4669@@ -0,0 +1,119 @@
4670+/*
4671+ * Copyright 2006-2008 The FLWOR Foundation.
4672+ *
4673+ * Licensed under the Apache License, Version 2.0 (the "License");
4674+ * you may not use this file except in compliance with the License.
4675+ * You may obtain a copy of the License at
4676+ *
4677+ * http://www.apache.org/licenses/LICENSE-2.0
4678+ *
4679+ * Unless required by applicable law or agreed to in writing, software
4680+ * distributed under the License is distributed on an "AS IS" BASIS,
4681+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
4682+ * See the License for the specific language governing permissions and
4683+ * limitations under the License.
4684+ */
4685+
4686+#include <cstring> /* for memcpy(3) */
4687+
4688+#include "diagnostics/assert.h"
4689+
4690+#include "cxx_util.h"
4691+#include "mem_streambuf.h"
4692+
4693+using namespace std;
4694+
4695+namespace zorba {
4696+
4697+///////////////////////////////////////////////////////////////////////////////
4698+
4699+mem_streambuf::mem_streambuf() {
4700+ set( nullptr, nullptr );
4701+}
4702+
4703+mem_streambuf::mem_streambuf( char_type *begin, char_type *end ) {
4704+ set( begin, end );
4705+}
4706+
4707+mem_streambuf::mem_streambuf( char_type *begin, off_type size ) {
4708+ set( begin, size );
4709+}
4710+
4711+mem_streambuf::int_type mem_streambuf::overflow( int_type c ) {
4712+ if ( traits_type::eq_int_type( c, traits_type::eof() ) )
4713+ return traits_type::not_eof( c );
4714+ if ( pptr() >= epptr() )
4715+ return traits_type::eof();
4716+ *pptr() = traits_type::to_char_type( c );
4717+ pbump( 1 );
4718+ return c;
4719+}
4720+
4721+mem_streambuf::int_type mem_streambuf::pbackfail( int_type c ) {
4722+ if ( !traits_type::eq_int_type( c, traits_type::eof() ) ) {
4723+ *pptr() = traits_type::to_int_type( c );
4724+ pbump( -1 );
4725+ }
4726+ return traits_type::to_int_type( *pptr() );
4727+}
4728+
4729+mem_streambuf::pos_type mem_streambuf::seekoff( off_type off,
4730+ ios_base::seekdir dir,
4731+ ios_base::openmode ) {
4732+ switch ( dir ) {
4733+ case ios_base::beg:
4734+ our_setg( begin_ + off );
4735+ break;
4736+ case ios_base::cur:
4737+ our_setg( gptr() + off );
4738+ break;
4739+ case ios_base::end:
4740+ our_setg( end_ + off );
4741+ break;
4742+ default:
4743+ ZORBA_ASSERT( false );
4744+ }
4745+ return off;
4746+}
4747+
4748+mem_streambuf::pos_type mem_streambuf::seekpos( pos_type pos,
4749+ ios_base::openmode mode ) {
4750+ return seekoff( pos, ios_base::beg, mode );
4751+}
4752+
4753+void mem_streambuf::set( char_type *begin, char_type *end ) {
4754+ begin_ = begin;
4755+ end_ = end;
4756+ our_setg( begin );
4757+ our_setp( end );
4758+}
4759+
4760+streamsize mem_streambuf::showmanyc() {
4761+ return egptr() - gptr();
4762+}
4763+
4764+mem_streambuf::int_type mem_streambuf::underflow() {
4765+ return gptr() < egptr() ?
4766+ traits_type::to_int_type( *gptr() ) : traits_type::eof();
4767+}
4768+
4769+streamsize mem_streambuf::xsgetn( char_type *buf, std::streamsize size ) {
4770+ streamsize const remaining = showmanyc();
4771+ if ( size > remaining )
4772+ size = remaining;
4773+ ::memcpy( buf, gptr(), size );
4774+ return size;
4775+}
4776+
4777+streamsize mem_streambuf::xsputn( char_type const *buf, streamsize size ) {
4778+ streamsize const remaining = epptr() - pptr();
4779+ if ( size > remaining )
4780+ size = remaining;
4781+ ::memcpy( pptr(), buf, size );
4782+ return size;
4783+}
4784+
4785+///////////////////////////////////////////////////////////////////////////////
4786+
4787+} // namespace zorba
4788+/* vim:set et sw=2 ts=2: */
4789
4790=== added file 'src/util/mem_streambuf.h'
4791--- src/util/mem_streambuf.h 1970-01-01 00:00:00 +0000
4792+++ src/util/mem_streambuf.h 2012-02-16 00:23:20 +0000
4793@@ -0,0 +1,108 @@
4794+/*
4795+ * Copyright 2006-2008 The FLWOR Foundation.
4796+ *
4797+ * Licensed under the Apache License, Version 2.0 (the "License");
4798+ * you may not use this file except in compliance with the License.
4799+ * You may obtain a copy of the License at
4800+ *
4801+ * http://www.apache.org/licenses/LICENSE-2.0
4802+ *
4803+ * Unless required by applicable law or agreed to in writing, software
4804+ * distributed under the License is distributed on an "AS IS" BASIS,
4805+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
4806+ * See the License for the specific language governing permissions and
4807+ * limitations under the License.
4808+ */
4809+
4810+#ifndef ZORBA_MMAP_STREAMBUF_H
4811+#define ZORBA_MMAP_STREAMBUF_H
4812+
4813+#include <streambuf>
4814+
4815+namespace zorba {
4816+
4817+///////////////////////////////////////////////////////////////////////////////
4818+
4819+/**
4820+ * A %mem_streambuf is-a std::streambuf for a fixed-size chunk of memory.
4821+ */
4822+class mem_streambuf : public std::streambuf {
4823+public:
4824+ typedef std::streambuf::char_type char_type;
4825+ typedef std::streambuf::int_type int_type;
4826+ typedef std::streambuf::off_type off_type;
4827+ typedef std::streambuf::pos_type pos_type;
4828+ typedef std::streambuf::traits_type traits_type;
4829+
4830+ /**
4831+ * Default constructor.
4832+ */
4833+ mem_streambuf();
4834+
4835+ /**
4836+ * Constructs a %mem_streambuf.
4837+ *
4838+ * @param begin A pointer to the beginning of the memory chunk.
4839+ * @param end A pointer to one past the end of the memory chunk.
4840+ */
4841+ mem_streambuf( char_type *begin, char_type *end );
4842+
4843+ /**
4844+ * Constructs a %mem_streambuf.
4845+ *
4846+ * @param begin A pointer to the beginning of the memory chunk.
4847+ * @param size The size of the memory chunk.
4848+ */
4849+ mem_streambuf( char_type *begin, off_type size );
4850+
4851+ /**
4852+ * Sets the memory chunk.
4853+ *
4854+ * @param begin A pointer to the beginning of the memory chunk.
4855+ * @param end A pointer to one past the end of the memory chunk.
4856+ */
4857+ void set( char_type *begin, char_type *end );
4858+
4859+ /**
4860+ * Sets the memory chunk.
4861+ *
4862+ * @param begin A pointer to the beginning of the memory chunk.
4863+ * @param size The size of the memory chunk.
4864+ */
4865+ void set( char_type *begin, off_type size );
4866+
4867+protected:
4868+ int_type overflow( int_type c );
4869+ int_type pbackfail( int_type c );
4870+ pos_type seekoff( off_type, std::ios_base::seekdir, std::ios_base::openmode );
4871+ pos_type seekpos( pos_type, std::ios_base::openmode );
4872+ std::streamsize showmanyc();
4873+ int_type underflow();
4874+ std::streamsize xsgetn( char_type*, std::streamsize );
4875+ std::streamsize xsputn( char_type const*, std::streamsize );
4876+
4877+private:
4878+ char_type *begin_, *end_;
4879+
4880+ void our_setg( char_type *ptr ) {
4881+ setg( begin_, ptr, end_ );
4882+ }
4883+
4884+ void our_setp( char_type *ptr ) {
4885+ setp( ptr, end_ );
4886+ }
4887+
4888+ // forbid
4889+ mem_streambuf( mem_streambuf const& );
4890+ mem_streambuf& operator=( mem_streambuf const& );
4891+};
4892+
4893+inline void mem_streambuf::set( char_type *begin, off_type size ) {
4894+ set( begin, begin + size );
4895+}
4896+
4897+///////////////////////////////////////////////////////////////////////////////
4898+
4899+} // namespace zorba
4900+#endif /* ZORBA_MMAP_STREAMBUF_H */
4901+/* vim:set et sw=2 ts=2: */
4902
4903=== modified file 'src/util/omanip.h'
4904--- src/util/omanip.h 2011-06-14 17:26:33 +0000
4905+++ src/util/omanip.h 2012-02-16 00:23:20 +0000
4906@@ -25,127 +25,275 @@
4907 ///////////////////////////////////////////////////////////////////////////////
4908
4909 /**
4910- * An omanip1 is a class for assisting in the creation of ostream manipulators
4911+ * An %omanip1 is a class for assisting in the creation of ostream manipulators
4912 * by storing a pointer to a function and its argument to be called later via
4913 * operator<<().
4914 *
4915 * See also: "Standard C++ IOStreams and Locales," Angelika Langer and Klaus
4916 * Kreft, Addison-Wesley, pp. 179-191.
4917 */
4918-template<typename Arg1Type> class omanip1 {
4919+template<typename Arg1Type>
4920+class omanip1 {
4921 public:
4922
4923 /**
4924- * The signature of functions this omanip1 can handle.
4925+ * The signature of functions this %omanip1 can handle.
4926 */
4927 typedef std::ostream& (*func_type)( std::ostream&, Arg1Type );
4928
4929 /**
4930- * Constructs an omanip1.
4931+ * Constructs an %omanip1.
4932 *
4933- * @param f The function to call when this omanip1 is inserted into an
4934- * ostream.
4935- * @param arg1 The argument to be passed to the function.
4936+ * @param f The function to call when this %omanip1 is inserted into an
4937+ * ostream.
4938+ * @param a1 The argument to be passed to the function.
4939 */
4940- omanip1( func_type f, Arg1Type arg1 ) :
4941- f_( f ), arg1_( arg1 )
4942+ omanip1( func_type f, Arg1Type a1 ) :
4943+ f_( f ), a1_( a1 )
4944 {
4945 }
4946
4947 /**
4948- * Inserts the given omanip1 into the given ostream. This has the effect of
4949- * calling the function and argument bound to the omanip1 at the time of its
4950+ * Inserts the given %omanip1 into the given ostream. This has the effect of
4951+ * calling the function and argument bound to the %omanip1 at the time of its
4952 * construction.
4953 *
4954 * @param o The ostream to insert into.
4955- * @param m The omanip1 to insert.
4956+ * @param m The %omanip1 to insert.
4957 */
4958 friend std::ostream& operator<<( std::ostream &o, omanip1 const &m ) {
4959- return (*m.f_)( o, m.arg1_ );
4960+ if ( o.good() )
4961+ (*m.f_)( o, m.a1_ );
4962+ return o;
4963 }
4964
4965 private:
4966 func_type const f_;
4967- Arg1Type const arg1_;
4968+ Arg1Type const a1_;
4969 };
4970
4971 /**
4972 * Defines an ostream manipulator "thunk" function that calls an existing
4973 * non-manipulator function having the same name.
4974 *
4975- * @param FN_NAME The name of the existing function.
4976- * @param ARG1_TYPE The type of the non-ostream argument.
4977- * @param ARG1_NAME The name of the non-ostream argument.
4978+ * @param FN_NAME The name of the existing function.
4979+ * @param ARG1_T The type of the non-ostream argument.
4980 */
4981-#define DEF_OMANIP1(FN_NAME,ARG1_TYPE,ARG1_NAME) \
4982- inline omanip1<ARG1_TYPE> \
4983- FN_NAME( ARG1_TYPE ARG1_NAME ) { \
4984- return omanip1<ARG1_TYPE>( FN_NAME, ARG1_NAME ); \
4985+#define DEF_OMANIP1(FN_NAME,ARG1_T) \
4986+ inline omanip1<ARG1_T> \
4987+ FN_NAME( ARG1_T a1 ) { \
4988+ return omanip1<ARG1_T>( FN_NAME, a1 ); \
4989 }
4990
4991 ///////////////////////////////////////////////////////////////////////////////
4992
4993 /**
4994- * An omanip2 is a class for assisting in the creation of ostream manipulators
4995+ * An %omanip2 is a class for assisting in the creation of ostream manipulators
4996 * by storing a pointer to a function and its arguments to be called later via
4997 * operator<<().
4998 *
4999 * See also: "Standard C++ IOStreams and Locales," Angelika Langer and Klaus
5000 * Kreft, Addison-Wesley, pp. 179-191.
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches