Compare commits

..

229 Commits

Author SHA1 Message Date
rtweeks21 7d1508e090 - Reintegrated the other-tags branch into my staging branch. Local edits were required to integrate with the changes from the event-api branch. 2010-10-16 09:08:03 +00:00
rtweeks21 3126507ab9 - Merged latest changes from the event-api branch. 2010-10-16 08:45:41 +00:00
rtweeks21 55c8486ee3 Reintegrated the event-api branch (second iteration) into the rtweeks21-staging branch. 2010-09-11 22:11:02 +00:00
rtweeks21 7220c6b783 Created staging branch for merging feature branches that may go into the trunk together. 2010-09-11 22:07:19 +00:00
jbeder 78db8b02c8 Fixed missing header 2010-05-01 20:05:15 +00:00
jbeder d99cb95d2d Tagged version 0.2.5 2010-03-15 19:25:02 +00:00
jbeder 11903da3fb Added overloads for parsing stl maps and vectors 2010-03-15 04:25:17 +00:00
jbeder e58f0f31b7 Set alias nodes to return the tag of their anchor 2010-03-15 04:10:36 +00:00
jbeder 8080400cb6 Disabled those warnings in the release version of the .svn too. 2010-03-03 05:33:07 +00:00
jbeder b869aab8e1 Updated to remove most of the warnings in Visual Studio. (There's still the one about all control paths returning a value left.) Fixed one warning (when an istream converts to void * to then convert to bool), and disabled three. 2010-03-03 05:30:06 +00:00
jbeder 3720ceb57b Added newline to install and license files 2009-12-21 20:35:27 +00:00
jbeder 6d37c370ba Added missing include 2009-12-02 05:59:18 +00:00
jbeder ac3d95f499 Added test for duplicate key 2009-12-02 01:29:16 +00:00
jbeder f4b81e7349 Fixed leak when adding duplicate keys (and actually changed the behavior - now we take the first instance, not the last) 2009-12-02 01:01:45 +00:00
jbeder 8f0f0d62a7 Refactored emitter operator << overloads to not template them, so it's easier to overload for pointer types 2009-11-17 20:21:22 +00:00
jbeder bbf510d6cc Refactored the traits a bit, and added displaying the key to string and numeric key not found errors 2009-11-12 17:00:12 +00:00
jbeder 7b33c7c4b4 Small bug from switching static initialized regexes to lazy ones 2009-11-12 05:45:47 +00:00
jbeder 63cc5adefd Replaced conversion macros with SFINAE 2009-11-10 21:23:52 +00:00
jbeder 71489e5abf Overloaded more integral types for emitting 2009-11-06 03:24:12 +00:00
jbeder 472bb80c9c Fixed the return value of the integral conversion functions, and also unset the dec flag so it reads other bases (just a temporary fix, since we're officially supposed to read binary too) 2009-11-06 03:13:54 +00:00
jbeder ca79c3da7f Switched the Exp:: regexes to functions that lazily evaluate their regexes 2009-11-04 22:56:59 +00:00
jbeder fea35e3e8f Fixed silly bug in node cloning 2009-10-30 20:29:14 +00:00
jbeder a55970c879 Added some block scalar tests (with errors) 2009-10-30 18:16:26 +00:00
jbeder 4dd1b19e51 Updated the Visual Studio solution for the new files/renaming. 2009-10-30 04:52:13 +00:00
jbeder b1f143cfaf Fixed bug with block maps with null value (the next key was being read as the value) 2009-10-30 01:06:19 +00:00
jbeder c3f222e4d9 Fixed the whitespace tracking when we escape a newline in a double-quoted string 2009-10-29 22:55:50 +00:00
jbeder e8beb6c98f Fixed mistake in test 2009-10-29 22:39:53 +00:00
jbeder 08ac48518f Refactored the compact map notation, which made it easy to implement explicit keys for compact maps 2009-10-29 22:09:50 +00:00
jbeder 7c4a8dad85 Added case for parsing a compact key: value pair in a flow sequence with a null key 2009-10-29 22:01:01 +00:00
jbeder 011a608b5a Implemented adjacent key:value pairs when the key is JSON-like 2009-10-29 21:05:48 +00:00
jbeder 72dceba671 Added test 2009-10-29 20:45:20 +00:00
jbeder 5618157a1e Added flow collection tests 2009-10-29 20:35:07 +00:00
jbeder 72413bafd4 Added ability to read compact maps in a flow sequence 2009-10-29 19:41:46 +00:00
jbeder cccbddb54c Merged r295:305 from the tags branch to the trunk 2009-10-29 15:48:06 +00:00
jbeder 4f74f805c2 Removed crt stuff (we can do memory leak checking in Linux easier) 2009-10-27 14:55:01 +00:00
jbeder 3d24383686 Removed unused test yaml file 2009-10-27 14:48:01 +00:00
jbeder 5986307b8e Now actually removed yaml-reader 2009-10-27 14:47:08 +00:00
jbeder d3b00fa6c5 Reverted yaml-reader name change 2009-10-27 14:45:14 +00:00
jbeder 50b026a3a9 Renamed yaml-reader test (try 2) 2009-10-27 14:39:48 +00:00
jbeder 7d5988401e Renamed yaml-reader test 2009-10-27 14:38:53 +00:00
jbeder 47628bf25e Tagged version 0.2.4 2009-10-25 20:27:31 +00:00
jbeder 52e3e0a4aa Updated the CMake globbing so it only compiles sources starting with a lowercase letter (apparently Mac OS auto-generates files looking like ._whatever and it was trying to compile those too) 2009-10-25 18:01:48 +00:00
jbeder 770466d5d4 Tagged version 0.2.3 2009-10-22 21:55:44 +00:00
jbeder 9ee348d62e Small refactoring 2009-10-22 21:51:32 +00:00
jbeder 2b2fca758c Switch to flow map when emitting an empty block map 2009-10-22 14:21:12 +00:00
jbeder 2022379cf4 Switch to flow sequence when emitting an empty sequence 2009-10-22 14:17:12 +00:00
jbeder 68df40c1dc Fixed bug in plain scalar folding 2009-10-20 14:47:16 +00:00
jbeder 0bf5b133e1 Added a bunch of tests, simplified the testing code 2009-10-20 14:43:24 +00:00
jbeder 9a28c9178e Merged r270:HEAD of the emitting-unicode branch 2009-10-19 23:31:11 +00:00
jbeder ae937a31d2 Fixed little bug in parser commit 2009-10-19 22:42:30 +00:00
jbeder afc7c1088d Added default constructor to Parser, and cleaned it up a bit 2009-10-19 22:40:46 +00:00
jbeder dd29c8181a Update CMakeLists.txt to append, not overwrite CMAKE_CXX_FLAGS 2009-10-19 22:32:26 +00:00
jbeder 06b8d4bacf Patched for optional building of tests and tools 2009-10-12 05:21:00 +00:00
jbeder 41a776b397 Refactored the UTF-8 emitting 2009-10-08 21:05:56 +00:00
jbeder 15d5b2b533 Fixed the emitter unicode output 2009-10-07 06:46:05 +00:00
jbeder fb443b3056 Updated signature of Parser::GetNextDocument (issue 45) 2009-09-29 18:25:11 +00:00
jbeder 60fce621e8 Modified old gcc version patch so it still uses the new Node::Read in Visual Studio. Also broke up the \uNNNN characters in the spec tests into \xNN-type strings. 2009-09-16 05:31:28 +00:00
jbeder a20141bca7 Patched for gcc version <= 3.3 (just fall back to original version of Node::Read) 2009-09-16 04:01:40 +00:00
jbeder d957634c25 Tagged version 0.2.2 2009-09-09 01:37:23 +00:00
jbeder 7b889b9f35 Cleaned up the read template overloads (per litb's update); it seems the old version didn't compile in VS2008. Also updated the VS project files. 2009-09-08 20:57:18 +00:00
jbeder 246d8993d2 More tests, found bug in implicit keys in flow sequence 2009-09-08 05:35:39 +00:00
jbeder e4540f2c2a Fixed flow folding, and made the separation slightly cleaner (but the whole scanscalar thing could use a major refactoring) 2009-09-08 05:24:06 +00:00
jbeder 1d52e03750 Tests through 6.29, skipping directives and tags 2009-09-08 04:16:45 +00:00
jbeder d38c4e6026 (Actually) fixed the folding newline bug, but it's a bit messy, and we don't accurately make the distinction between block folding and flow folding 2009-09-07 23:29:04 +00:00
jbeder afe01a86bd Fixed newlines in folded scalars bug 2009-09-07 22:48:32 +00:00
jbeder 994e6af8e0 Simplified testing output 2009-09-07 22:17:02 +00:00
jbeder d15ce26b58 Fixed bugs with tab as non-content whitespace 2009-09-07 17:12:45 +00:00
jbeder a725d4b190 Fixed bugs in escape characters (both parsing and emitting) 2009-09-07 16:31:23 +00:00
jbeder 315205298a Fixed error in test 2009-09-07 06:56:05 +00:00
jbeder e1a112a761 Fixed last newline of folded scalar bug 2009-09-07 06:54:38 +00:00
jbeder 21232e3bef Fixed bug in trailing newlines of plain scalars 2009-09-07 06:42:03 +00:00
jbeder 90be7e75c2 Added spec tests (minus tags, directives, and BOM) up through example 5.12 - this exposed an error in line folding 2009-09-07 06:35:37 +00:00
jbeder bdf6008dea Added spec tests through example 2.13 2009-09-06 22:17:53 +00:00
jbeder 21c87d4961 Tagged release 0.2.1 for patch with complex keys 2009-09-06 22:02:59 +00:00
jbeder e67e6e19f9 Fixed bug with complex keys (and simplified the parsing for flow maps) 2009-09-06 21:52:56 +00:00
jbeder fe47783b5f Refactored the operator >> and Node::Read default functions, as well as the conversion functions, to more easily read new types as keys (this uncovered an error, in example 2.11 of the spec) 2009-09-06 20:52:45 +00:00
jbeder dbcf401cbd Added spec tests through 2.10 2009-09-06 17:02:24 +00:00
jbeder 2fe7e8d525 Added templated casting to nodes, as well as operator == and != (for quick checks, especially to help in testing). Implemented size() on a map node to return the number of key/value pairs (as in std::map) 2009-09-06 15:54:11 +00:00
jbeder 44750974e7 Updated the CMake file for 0.2.0 release, and added install.txt 2009-09-05 23:05:39 +00:00
jbeder f21456972c Allowed solo entries in a flow map to be read as keys with null value 2009-09-05 22:42:01 +00:00
jbeder ba472cc9a3 Finished refactoring of simple keys so that they can refer to multiple tokens at a single level 2009-09-05 03:49:38 +00:00
jbeder a2f2ab8426 Refactored simple keys so that validating doesn't require popping indents, and so popping indents (and adding the end map) is independent of when we validate the simple key 2009-09-05 02:51:09 +00:00
jbeder 6594941d24 Moved token enums into Token scope 2009-09-05 02:28:11 +00:00
jbeder a926fefe0d Started implementing spec tests 2009-09-03 14:27:03 +00:00
jbeder f7a47e9f9f Fixed bug with omitted keys/values in a flow map 2009-09-02 21:39:57 +00:00
jbeder 2e859413e7 Added more explicit doc indicator tests 2009-08-26 16:23:58 +00:00
jbeder aadc5052bc Fixed bug with explicit doc start introduced in last commit 2009-08-26 16:15:27 +00:00
jbeder 3c35ab1e42 Added CMake option to build for the iphone 2009-08-24 23:43:53 +00:00
jbeder 4457b7dd5b Removed the implicit sequence code (since it's not used any more) 2009-08-24 22:58:47 +00:00
jbeder c7ed85a4ac Fixed bug in anchors with no content. This involved refactoring the 'implicit sequence' concept (where a map and a sequence start on the same indent, but we read the sequence as more indented since the '-' is visually an indent). 2009-08-24 22:56:54 +00:00
jbeder fc22d55b53 Added Node::Clone function 2009-08-24 20:10:42 +00:00
jbeder 8fcd09f30b Cleaned up 2009-08-24 18:23:20 +00:00
jbeder 2c4a7cf58c Removed the std::wstring conversion 2009-08-22 00:25:37 +00:00
jbeder 770d6de545 Converted indexing to std::size_t, and fixed the Node templated overloads to properly index any index type (determining what is an index type is a bit of a hack - it should be is_convertible<T, std::size_t> (I think), but I just explicitly wrote down a list) 2009-08-19 20:58:07 +00:00
jbeder c45372e2f3 Added 'yaml-cpp: ' to the exception messages 2009-08-19 05:09:12 +00:00
jbeder d1c888f57a Added templated Read() function that creates the output variable itself (so you don't need to have a temp variable) 2009-08-19 03:37:19 +00:00
jbeder c456eab7cd Fixed out-of-bounds memory access 2009-07-31 18:26:42 +00:00
jbeder 952f72233e Added IsNull function 2009-07-31 05:07:21 +00:00
jbeder cb2b5783fa Fixed null key/value bug, added tests 2009-07-30 06:49:09 +00:00
jbeder 49265fa12b Fixed empty scalar in sequence bug 2009-07-30 05:54:40 +00:00
jbeder c043b9c64b Added support for emitting and represeting null 2009-07-30 04:42:27 +00:00
jbeder a2bd317397 Added header file inclusion guards 2009-07-29 22:27:20 +00:00
jbeder 4725c4fabb Forgot to add mark.h 2009-07-27 04:14:19 +00:00
jbeder 7e26c711cf Collected pos, line, and column into a Mark struct 2009-07-27 02:56:18 +00:00
jbeder 25b5e9fec1 Fixed hex output in emitter (should be always two hex chars) 2009-07-26 07:57:22 +00:00
jbeder c4e1446dff Fixed bug in emitting null nodes 2009-07-26 07:42:50 +00:00
jbeder d0870b4112 Fixed the Exception::what() function 2009-07-26 01:37:21 +00:00
jbeder 27055f178f Fixed bug with simple keys that are quoted scalars 2009-07-25 18:58:41 +00:00
jbeder ab7c8b0df0 Fixed yaml-cpp.pc file (with prefix) 2009-07-25 18:03:58 +00:00
jbeder 94cb26ae59 Fixed location of yaml-cpp.pc file 2009-07-24 06:18:46 +00:00
jbeder e6a26ef104 Updated visual studio project, and fixed a VS warning 2009-07-20 20:18:59 +00:00
jbeder f8440aa0e5 Patched to read into std::wstring 2009-07-15 20:47:51 +00:00
jbeder fd5bf7c29a Cosmetic change to .pc.cmake file 2009-07-15 20:38:25 +00:00
jbeder 64a5687656 Added support for pkgconfig 2009-07-15 20:37:11 +00:00
jbeder ba787edee4 Added FindValue to more easily read optional keys in a map 2009-07-12 02:59:23 +00:00
jbeder a48191c970 Added emitting for a YAML::Node (instead of the ad-hoc std::ostream overload) so it'll actually emit valid YAML always 2009-07-10 23:39:14 +00:00
jbeder 689c5fa7b7 Added check for extra compiler flags if using gcc 2009-07-10 17:26:39 +00:00
jbeder 10b5961f3c Set up the parse utility program to read from standard input if no file is specified 2009-07-10 04:25:11 +00:00
jbeder 6752e25bcd (Finally) overrode Exception::what()\n 2009-07-10 04:17:30 +00:00
jbeder ae89793c28 Applied patch to build and version a shared library 2009-07-10 03:52:05 +00:00
jbeder 616eafc3c1 Fixed warnings to compile on gcc with -Wall -pedantic -Wextra 2009-07-10 03:30:04 +00:00
jbeder 907960850b Clarified some copy/assignment issues with the stream/streamcharsource. 2009-07-10 03:20:16 +00:00
jbeder 4ba713bf43 Updated the visual studio project with some of the utf changes 2009-07-10 03:15:08 +00:00
jbeder e7f1ca7fb1 Merged utf branch changes r178:187 into the trunk 2009-07-10 03:10:03 +00:00
jbeder aa959e6705 Fixed bug that didn't allow multiple docs in a stream (using only "---") 2009-06-25 03:05:09 +00:00
jbeder 8aefb675a2 Patched CMake file to allow flexibility in build (in particular to allow shared lib build) 2009-06-12 04:28:36 +00:00
jbeder ed8f016c1f Updated the nested RegEx classes so they don't need to also take an std::string 2009-06-01 03:42:16 +00:00
jbeder 6e1fc798e1 Updated yaml-reader CMake file 2009-05-31 06:39:08 +00:00
jbeder ec578d45f1 Switched from loading test files to testing specific parsing constructs. The tests don't fully cover the span (eventually I'll add more, maybe), but there's a bunch there.
More to the point, the yaml-reader program doesn't do any file IO, so it doesn't require a specific working directory.
2009-05-31 06:36:01 +00:00
jbeder f2ed49f720 Patch - added testing 2009-05-30 02:41:27 +00:00
jbeder f09e4497b6 Set eol-style to native on all of the new files 2009-05-30 02:29:47 +00:00
jbeder 2fdf2475bb Patched - removed unnecessary CMake statements 2009-05-29 22:58:14 +00:00
jbeder ade7e7cd18 Patched - install target 2009-05-29 22:55:59 +00:00
jbeder b444913576 Patch to simplify CMakeLists.txt files 2009-05-29 22:48:25 +00:00
jbeder c150e9945c Patch for gcc -Wall (order of initialization) 2009-05-29 22:36:52 +00:00
jbeder 51457eece9 Changed the way we read different types of scalars.
It's better organized now, I think - nodes only offer a single main way of getting the fundamental scalar (as a string), and now we can specialize a single template to read specific types.
2009-05-23 23:51:01 +00:00
jbeder 0c34137d84 Updated Visual Studio project for the emitter. 2009-05-23 22:58:05 +00:00
jbeder 947356a64a Changed output library directory to /lib (in the source directory) - this makes more sense 2009-05-23 17:11:19 +00:00
jbeder fcab73a9b6 Added emitter headers to yaml.h 2009-05-22 22:23:57 +00:00
jbeder 7dd29ee5db Replaced direct emitter writing with an accessor to a C-string 2009-05-22 22:21:01 +00:00
jbeder 3e41edd30e Restructured CMake file to include headers, and to be better organized 2009-05-22 22:11:21 +00:00
jbeder e6617e3273 Removed excessive stderr logging 2009-05-22 21:56:45 +00:00
jbeder cba20711b0 Merged emitter branch into trunk, changes r105:r151 2009-05-22 21:52:31 +00:00
jbeder 5abf31b991 Merged aliases branch into trunk, changes r100:150 2009-05-22 21:48:05 +00:00
jbeder 7297387015 Fixed several bugs from the new file i/o setup.
In particular:
1. Windows CR/LF weren't read properly (issue #11)
2. Scanning wasn't reading EOF properly
3. Documents may be empty (this was old, I think)
Also fixed some VS2008 warnings on /W4.
2009-02-07 07:57:13 +00:00
jbeder 855d0d60df Switched to reading the entire file into a buffer at the start.\nThis speeds it up a TON (like 100x). 2009-02-01 20:48:43 +00:00
jbeder e9512a5ac8 Included <cstdio> for gcc-4.4 (issue 9) 2009-01-27 21:08:40 +00:00
jbeder 4e2e644c35 Included <cstring> for strcmp 2009-01-27 20:16:30 +00:00
jbeder d44502c979 Applied patch for gcc -Wall 2009-01-15 17:12:13 +00:00
jbeder 6434b4f0c8 Re-added the throw() specification to ~Exception(), and also to ~TypedKeyNotFound(); I suppose this'll fix the gcc compiler error. 2009-01-01 23:59:37 +00:00
jbeder 4cebe50a9f Removed throw() specifier in Exception (I don't remember putting it in). This may solve a gcc error (I haven't tested it yet) or it may break it further. 2009-01-01 20:14:32 +00:00
jbeder 51ea36e444 Added a templated derived exception to KeyNotFound so that you can figure out *which* key wasn't found. 2009-01-01 02:40:18 +00:00
jbeder ad2b9fbaaf Fixed tag output bug 2008-11-20 04:12:31 +00:00
jbeder 4b45a7185a Replaced a pointer-centered try/catch block with std::auto_ptr 2008-11-20 03:41:40 +00:00
jbeder 27da48bac2 Added line/column data for nodes so they can give better invalid scalar exceptions. 2008-11-18 04:20:07 +00:00
jbeder 09d2858dc0 Added line/column data for nodes so they can give better invalid scalar exceptions. 2008-11-18 04:19:50 +00:00
jbeder d1ef1e8ef1 Added more natural ways to parse boolean values (based on the YAML spec).
(Thanks to Vadim Zeitlin)
2008-09-25 00:15:40 +00:00
jbeder bf01059c38 Added Read() functions for Node that return true/false, so we can easily check if a read is successful without throwing.
But we still have operator >> that throws on failure.
2008-09-24 23:29:00 +00:00
jbeder ecba08e240 Fixed infinite loop bug having to do with simple keys when we hit an unexpected EOF. 2008-09-24 22:45:04 +00:00
jbeder d51888bc7e Fixed a problem where you lose the exception type on rethrow. 2008-09-23 21:13:23 +00:00
jbeder 0b6edc6cfe Made Node non-copyable. 2008-09-19 02:44:49 +00:00
jbeder 1d92deff31 2008-09-11 03:49:52 +00:00
jbeder c44b8e601e 2008-09-11 03:48:04 +00:00
jbeder b43f827188 Set the eol style to native for all files. 2008-09-03 22:20:39 +00:00
jbeder 859ac5e520 Fixed some gcc warnings. 2008-09-03 22:19:27 +00:00
jbeder 7f2c3591e3 Unified line endings. 2008-09-03 22:17:17 +00:00
jbeder a57a5748f8 Added the license.txt file describing the MIT license. 2008-09-03 04:37:06 +00:00
jbeder aa25fadf94 Fixed struct vs. class disparity. 2008-08-07 03:37:16 +00:00
jbeder 2d93b6ce58 Added CMake scripts for other platforms\nFixed some bugs that gcc complained about\nFixed CR/LF vs LF bug 2008-08-07 03:30:56 +00:00
beder 2601f5fd49 2008-07-31 19:41:11 +00:00
beder 89ed418b83 Small changes in the iterator code.
Changed the public interface of Scanner to resemble an STL container.
2008-07-23 04:38:18 +00:00
beder 57255a9898 Switched the Iterator implementation to a dedicated helper class (to hide the specific implementation, since it's pretty messy and may change). 2008-07-21 02:54:39 +00:00
beder 557f81e622 Replaced the queue of Token pointers with values.
We were getting memory leaks (as told by the CRT detectors, which I also added), and there's really no reason (as long as we're careful) to use pointers there.
2008-07-20 05:02:01 +00:00
beder f4e522490f Moved the testing source to the yaml-reader folder. 2008-07-14 05:18:25 +00:00
beder 2ffc7dc6ac Set the yaml-reader project to link to the yamlcpp library. 2008-07-14 05:08:46 +00:00
beder 11eb40e636 Added a static library project 'yamlcpp' to the solution. 2008-07-14 05:03:38 +00:00
beder ef8e9415f8 Renamed the solution yamlcpp. 2008-07-14 04:51:47 +00:00
beder 4c1c0977ab 2008-07-14 04:37:58 +00:00
beder 516637fcdc Moved all code to src/ and include/ directories. 2008-07-14 04:33:30 +00:00
beder e6aeb45d09 Switched from moving the cursor forward (in Regex) to ignoring (this handles newlines properly).
Updated some of the character-in-scalar rules.
2008-07-10 00:23:25 +00:00
beder 0b2e0dd32b Centralized the error messages to one location. 2008-07-08 20:31:48 +00:00
beder 84bcdda342 Removed the (unused) 'required' flag from simple keys (the parser should take care of this, not the scanner). 2008-07-08 18:34:26 +00:00
beder 5d5651861d Added some exceptions for directives. 2008-07-08 06:06:24 +00:00
beder 2f5c19fa00 Combined the myriad ScannerExceptions and ParserExceptions to a single ParserException class that has a message and a line/column position in the file where the error occurred. 2008-07-08 05:48:38 +00:00
beder 1acc0e4982 Added a (recursive) ordering, so we have a canonical output that we can compare. 2008-07-06 00:06:36 +00:00
beder 3cad5a2ed0 Wrote some tests, but they don't work because it doesn't output maps in a canonical form. 2008-07-05 19:00:58 +00:00
beder ba97c9f719 Rewrote the output so that it emits correct YAML.
Fixed a bug in the last newline of a block folded scalar.
2008-07-05 05:28:23 +00:00
beder 5feaef3748 2008-07-04 22:57:52 +00:00
beder c4c873733b Removed the document class (since it's really just a root node, and that's it). 2008-07-04 22:56:43 +00:00
beder 99a9aaa591 Specialized the overloaded [] operator for int/unsigned, and added a size() function, so that you can iterate through a sequence node like a vector. 2008-07-02 21:41:54 +00:00
beder 620c322df5 Added some parser exceptions. 2008-07-02 05:00:32 +00:00
beder 807045bc14 Overloaded the iterator's -> operator. 2008-07-02 01:32:19 +00:00
beder b4b287c4e9 Added an iterator class that can iterate through both sequence and map nodes. 2008-07-02 01:22:39 +00:00
beder 81ff4946ae Fixed opening newline bug for block scalars. 2008-07-01 06:34:55 +00:00
beder 8eb50fe9d0 Tags, anchors, and aliases are all parsed now. 2008-07-01 06:28:10 +00:00
beder 104da5c244 Added parsing of anchors, aliases, and tags (still no semantics yet).
Fixed a silly bug in the simple key pushing (queues are FIFO!).
2008-07-01 01:17:10 +00:00
beder d41503da5a Finished parsing of basic data types (scalar, sequence, map). 2008-06-30 23:57:58 +00:00
beder 146122f455 Renamed the stream member functions get() and eat(). 2008-06-30 22:34:10 +00:00
beder 17533e22da Instead of deriving different tokens from a base Token class, we now use an enumerated TOKEN_TYPE to distinguish types. This is so we don't have to cast all the time when parsing the resulting token stream.
Also, removed start/end stream tokens.
2008-06-30 21:47:21 +00:00
beder 2a7e20a315 Started the parser. 2008-06-30 06:51:22 +00:00
beder 795df7224b Added a peek token command (for the parser to use). 2008-06-30 06:21:12 +00:00
beder a93584b065 Added directives and tags. 2008-06-30 04:22:41 +00:00
beder b58c0c94e4 Moved the three scalar token scanning functions back to scantoken.cpp, so scanscalar.cpp now only has the main scalar scanning function.
Renamed ScanScalarInfo to ScanScalarParams.
2008-06-30 01:38:32 +00:00
beder 67250833b8 Mostly finished refactoring the scalar scanning. 2008-06-30 01:31:23 +00:00
beder 4de9cb48a5 Moved scalar scanning-related parameters to a struct.
Renamed the valid/possible tokens to a single variable status with enums valid, invalid, and unverified.
2008-06-29 17:39:33 +00:00
beder 6efc5614ec Moved the input stream, together with line/column info, into its own class, which allowed some other stuff just to pass the stream, and not have to be a member of Scanner. 2008-06-29 06:32:13 +00:00
beder 8dfb5c0ea8 Refactored common scalar scanning code (from plain, quoted, and block) to one function. 2008-06-29 05:45:41 +00:00
beder 3c56fd49eb Moved the scalar-related functions to their own file. 2008-06-29 03:11:25 +00:00
beder 45dfc719e1 2008-06-29 00:33:34 +00:00
beder ab27b9781e Small refactoring. 2008-06-28 22:05:51 +00:00
beder 34cd7177cd 2008-06-28 20:09:49 +00:00
beder 566916ba19 Added folded and literal scalars. 2008-06-28 20:08:21 +00:00
beder 1a96548fa5 Fixed complex keys. 2008-06-28 17:32:10 +00:00
beder b1c60706d7 Moved the simple key validation to before each token scan (plus at newlines of scalars). 2008-06-28 16:46:37 +00:00
beder 70afd130ad Added simple keys.
There's a bug (and question): should we test simple keys' validity BEFORE stuff or AFTER stuff?
2008-06-28 06:36:59 +00:00
beder fb9176a054 Added quoted scalars (with escaping).
Refactored some common whitespace-parsing code in scanning both scalars.
Implemented the flow collection tokens.
2008-06-27 23:11:46 +00:00
beder ba132b01bc Small plain scalar scanning fixes. 2008-06-27 20:54:43 +00:00
beder 10c4a2687f Split off the specific regular expressions, and the specialized token-scanning functions, into their own files. 2008-06-27 19:13:03 +00:00
beder aad36b8c47 Added stream input to the regular expressions, greatly simplifying the usage (in particular, we no longer have to specify the number of characters to be checked). 2008-06-27 19:07:30 +00:00
beder bb4bc8c4ae Wrote a simplified regular expression parser to make life easier (it only does single matches; i.e., no one-or-more matches, etc.).
Fixed some of the whitespace/line break matching.
2008-06-27 08:20:41 +00:00
beder 20dba9cd75 The plain scalar scanner is almost done (and it scans a simple list correctly).
Also messed around with multiple character peeking on the input, and got something working.
2008-06-27 00:18:52 +00:00
beder c7274ff2e8 More simple scalar scanning. 2008-06-26 22:00:39 +00:00
beder 2040e4de8b Continued working on scanner.
We're now using exceptions for errors, and scanning/pushing tokens is exception-safe (using a set of "limbo tokens").
2008-06-26 19:30:11 +00:00
beder 4b33531240 Started the scanner. 2008-06-26 09:05:28 +00:00
beder e6977cbe4e Beginning of first attempt to parse.
Will be completely wiped, I think, in favor of a Scanner (to tokens), then Parser mechanism.
2008-06-26 06:49:50 +00:00
beder 2d0f324529 Preliminary setup - basic data structures are there. 2008-06-25 23:00:18 +00:00
beder ffaf6a19ca 2008-06-25 22:46:18 +00:00
beder 0134c553a5 2008-06-25 22:45:08 +00:00
beder f959a475b7 2008-06-25 22:44:44 +00:00
90 changed files with 4651 additions and 1278 deletions
+16 -7
View File
@@ -10,16 +10,23 @@ if(IPHONE)
endif(IPHONE)
if(CMAKE_COMPILER_IS_GNUCC)
set(CMAKE_CXX_FLAGS "-O2 -Wall -pedantic -Wextra")
set(CMAKE_CXX_FLAGS "-O2 -Wall -Wextra -pedantic -Wno-long-long ${CMAKE_CXX_FLAGS}")
endif(CMAKE_COMPILER_IS_GNUCC)
if(MSVC)
set(LIB_TYPE) # I can't figure out how CMake handles Windows shared libraries
set(CMAKE_CXX_FLAGS "/W3 /wd4127 /wd4355 /D_SCL_SECURE_NO_WARNINGS ${CMAKE_CXX_FLAGS}")
endif(MSVC)
set(YAML_CPP_VERSION_MAJOR "0")
set(YAML_CPP_VERSION_MINOR "2")
set(YAML_CPP_VERSION_PATCH "1")
set(YAML_CPP_VERSION_PATCH "5")
set(YAML_CPP_VERSION "${YAML_CPP_VERSION_MAJOR}.${YAML_CPP_VERSION_MINOR}.${YAML_CPP_VERSION_PATCH}")
enable_testing()
option(YAML_CPP_BUILD_TOOLS "Enables or disables testing and parse tools" true)
if(WIN32)
set(_library_dir bin) # .dll are in PATH, like executables
else(WIN32)
@@ -36,9 +43,9 @@ set(_INSTALL_DESTINATIONS
ARCHIVE DESTINATION lib${LIB_SUFFIX}
)
#
file(GLOB public_headers include/*.h)
file(GLOB private_headers src/*.h)
file(GLOB sources src/*.cpp)
file(GLOB public_headers include/[a-z]*.h)
file(GLOB private_headers src/[a-z]*.h)
file(GLOB sources src/[a-z]*.cpp)
include_directories(${YAML_CPP_SOURCE_DIR}/include)
add_library(yaml-cpp
@@ -64,5 +71,7 @@ if(UNIX)
install(FILES ${PC_FILE} DESTINATION ${LIB_INSTALL_DIR}/pkgconfig)
endif(UNIX)
add_subdirectory (yaml-reader)
add_subdirectory (util)
if(YAML_CPP_BUILD_TOOLS)
add_subdirectory (test)
add_subdirectory (util)
endif(YAML_CPP_BUILD_TOOLS)
+38
View File
@@ -0,0 +1,38 @@
#pragma once
#ifndef ALIASMANAGER_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#define ALIASMANAGER_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#include "anchor.h"
#include <map>
namespace YAML
{
class Node;
class AliasManager
{
public:
AliasManager();
void RegisterReference(const Node& node);
const Node *LookupReference(const Node& node) const;
anchor_t LookupAnchor(const Node& node) const;
private:
const Node *_LookupReference(const Node& oldIdentity) const;
anchor_t _CreateNewAnchor();
private:
typedef std::map<const Node*, const Node*> NodeByNode;
NodeByNode m_newIdentityByOldIdentity;
typedef std::map<const Node*, anchor_t> AnchorByIdentity;
AnchorByIdentity m_anchorByIdentity;
anchor_t m_curAnchor;
};
}
#endif // ALIASMANAGER_H_62B23520_7C8E_11DE_8A39_0800200C9A66
+14
View File
@@ -0,0 +1,14 @@
#pragma once
#ifndef ANCHOR_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#define ANCHOR_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#include <cstddef>
namespace YAML
{
typedef std::size_t anchor_t;
const anchor_t NullAnchor = 0;
}
#endif // ANCHOR_H_62B23520_7C8E_11DE_8A39_0800200C9A66
+40
View File
@@ -0,0 +1,40 @@
#pragma once
#ifndef ANCHORDICT_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#define ANCHORDICT_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#include <vector>
#include "anchor.h"
namespace YAML
{
/// AnchorDict
/// . An object that stores and retrieves values correlating to anchor_t
/// values.
/// . Efficient implementation that can make assumptions about how anchor_t
/// values are assigned by the Parser class.
template <class T>
class AnchorDict
{
public:
void Register(anchor_t anchor, T value)
{
if (anchor > m_data.size())
{
m_data.resize(anchor);
}
m_data[anchor - 1] = value;
}
T Get(anchor_t anchor) const
{
return m_data[anchor - 1];
}
private:
std::vector<T> m_data;
};
}
#endif // ANCHORDICT_H_62B23520_7C8E_11DE_8A39_0800200C9A66
+7 -19
View File
@@ -5,6 +5,7 @@
#include "null.h"
#include "traits.h"
#include <string>
#include <sstream>
@@ -18,26 +19,13 @@ namespace YAML
bool Convert(const std::string& input, bool& output);
bool Convert(const std::string& input, _Null& output);
#define YAML_MAKE_STREAM_CONVERT(type) \
inline bool Convert(const std::string& input, type& output) { \
std::stringstream stream(input); \
stream >> output; \
return !stream.fail(); \
template <typename T>
inline bool Convert(const std::string& input, T& output, typename enable_if<is_numeric<T> >::type * = 0) {
std::stringstream stream(input);
stream.unsetf(std::ios::dec);
stream >> output;
return !!stream;
}
YAML_MAKE_STREAM_CONVERT(char)
YAML_MAKE_STREAM_CONVERT(unsigned char)
YAML_MAKE_STREAM_CONVERT(int)
YAML_MAKE_STREAM_CONVERT(unsigned int)
YAML_MAKE_STREAM_CONVERT(short)
YAML_MAKE_STREAM_CONVERT(unsigned short)
YAML_MAKE_STREAM_CONVERT(long)
YAML_MAKE_STREAM_CONVERT(unsigned long)
YAML_MAKE_STREAM_CONVERT(float)
YAML_MAKE_STREAM_CONVERT(double)
YAML_MAKE_STREAM_CONVERT(long double)
#undef YAML_MAKE_STREAM_CONVERT
}
#endif // CONVERSION_H_62B23520_7C8E_11DE_8A39_0800200C9A66
-17
View File
@@ -1,17 +0,0 @@
#pragma once
#ifndef CRT_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#define CRT_H_62B23520_7C8E_11DE_8A39_0800200C9A66
// for detecting memory leaks
#ifdef _DEBUG
#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
#endif // _DEBUG
#endif // CRT_H_62B23520_7C8E_11DE_8A39_0800200C9A66
+43
View File
@@ -0,0 +1,43 @@
#pragma once
#ifndef EMITFROMEVENTS_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#define EMITFROMEVENTS_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#include "eventhandler.h"
#include <stack>
namespace YAML
{
class Emitter;
class EmitFromEvents: public EventHandler
{
public:
EmitFromEvents(Emitter& emitter);
virtual void OnDocumentStart(const Mark& mark);
virtual void OnDocumentEnd();
virtual void OnNull(const std::string& tag, anchor_t anchor);
virtual void OnAlias(const Mark& mark, anchor_t anchor);
virtual void OnScalar(const Mark& mark, const std::string& tag, anchor_t anchor, const std::string& value);
virtual void OnSequenceStart(const Mark& mark, const std::string& tag, anchor_t anchor);
virtual void OnSequenceEnd();
virtual void OnMapStart(const Mark& mark, const std::string& tag, anchor_t anchor);
virtual void OnMapEnd();
private:
void BeginNode();
void EmitProps(const std::string& tag, anchor_t anchor);
private:
Emitter& m_emitter;
struct State { enum value { WaitingForSequenceEntry, WaitingForKey, WaitingForValue }; };
std::stack<State::value> m_stateStack;
};
}
#endif // EMITFROMEVENTS_H_62B23520_7C8E_11DE_8A39_0800200C9A66
+63 -9
View File
@@ -9,6 +9,7 @@
#include "null.h"
#include <memory>
#include <string>
#include <sstream>
namespace YAML
{
@@ -29,6 +30,7 @@ namespace YAML
const std::string GetLastError() const;
// global setters
bool SetOutputCharset(EMITTER_MANIP value);
bool SetStringFormat(EMITTER_MANIP value);
bool SetBoolFormat(EMITTER_MANIP value);
bool SetIntBase(EMITTER_MANIP value);
@@ -44,16 +46,23 @@ namespace YAML
// overloads of write
Emitter& Write(const std::string& str);
Emitter& Write(const char *str);
Emitter& Write(int i);
Emitter& Write(bool b);
Emitter& Write(float f);
Emitter& Write(double d);
Emitter& Write(const _Alias& alias);
Emitter& Write(const _Anchor& anchor);
Emitter& Write(const _Tag& tag);
Emitter& Write(const _Comment& comment);
Emitter& Write(const _Null& null);
template <typename T>
Emitter& WriteIntegralType(T value);
template <typename T>
Emitter& WriteStreamable(T value);
private:
void PreWriteIntegralType(std::stringstream& str);
void PostWriteIntegralType(const std::stringstream& str);
private:
enum ATOMIC_TYPE { AT_SCALAR, AT_SEQ, AT_BLOCK_SEQ, AT_FLOW_SEQ, AT_MAP, AT_BLOCK_MAP, AT_FLOW_MAP };
@@ -68,24 +77,69 @@ namespace YAML
void EmitEndMap();
void EmitKey();
void EmitValue();
void EmitKindTag();
void EmitTag(bool verbatim, const _Tag& tag);
private:
ostream m_stream;
std::auto_ptr <EmitterState> m_pState;
};
// overloads of insertion
template <typename T>
inline Emitter& operator << (Emitter& emitter, T v) {
return emitter.Write(v);
inline Emitter& Emitter::WriteIntegralType(T value)
{
if(!good())
return *this;
std::stringstream str;
PreWriteIntegralType(str);
str << value;
PostWriteIntegralType(str);
return *this;
}
template <>
template <typename T>
inline Emitter& Emitter::WriteStreamable(T value)
{
if(!good())
return *this;
PreAtomicWrite();
EmitSeparationIfNecessary();
std::stringstream str;
str << value;
m_stream << str.str();
PostAtomicWrite();
return *this;
}
// overloads of insertion
inline Emitter& operator << (Emitter& emitter, const std::string& v) { return emitter.Write(v); }
inline Emitter& operator << (Emitter& emitter, bool v) { return emitter.Write(v); }
inline Emitter& operator << (Emitter& emitter, const _Alias& v) { return emitter.Write(v); }
inline Emitter& operator << (Emitter& emitter, const _Anchor& v) { return emitter.Write(v); }
inline Emitter& operator << (Emitter& emitter, const _Tag& v) { return emitter.Write(v); }
inline Emitter& operator << (Emitter& emitter, const _Comment& v) { return emitter.Write(v); }
inline Emitter& operator << (Emitter& emitter, const _Null& v) { return emitter.Write(v); }
inline Emitter& operator << (Emitter& emitter, const char *v) { return emitter.Write(std::string(v)); }
inline Emitter& operator << (Emitter& emitter, int v) { return emitter.WriteIntegralType(v); }
inline Emitter& operator << (Emitter& emitter, unsigned int v) { return emitter.WriteIntegralType(v); }
inline Emitter& operator << (Emitter& emitter, short v) { return emitter.WriteIntegralType(v); }
inline Emitter& operator << (Emitter& emitter, unsigned short v) { return emitter.WriteIntegralType(v); }
inline Emitter& operator << (Emitter& emitter, long v) { return emitter.WriteIntegralType(v); }
inline Emitter& operator << (Emitter& emitter, unsigned long v) { return emitter.WriteIntegralType(v); }
inline Emitter& operator << (Emitter& emitter, float v) { return emitter.WriteStreamable(v); }
inline Emitter& operator << (Emitter& emitter, double v) { return emitter.WriteStreamable(v); }
inline Emitter& operator << (Emitter& emitter, EMITTER_MANIP value) {
return emitter.SetLocalValue(value);
}
template <>
inline Emitter& operator << (Emitter& emitter, _Indent indent) {
return emitter.SetLocalIndent(indent);
}
+25
View File
@@ -11,6 +11,11 @@ namespace YAML
enum EMITTER_MANIP {
// general manipulators
Auto,
TagByKind,
// output character set
EmitNonAscii,
EscapeNonAscii,
// string manipulators
// Auto, // duplicate
@@ -76,6 +81,26 @@ namespace YAML
inline _Anchor Anchor(const std::string content) {
return _Anchor(content);
}
struct _Tag {
explicit _Tag(const std::string& content_)
: content(content_), verbatim(true)
{
}
std::string content;
bool verbatim;
};
typedef _Tag VerbatimTag;
struct LocalTag : public _Tag
{
explicit LocalTag(const std::string& content_)
: _Tag(content_)
{
verbatim = false;
}
};
struct _Comment {
_Comment(const std::string& content_): content(content_) {}
+34
View File
@@ -0,0 +1,34 @@
#pragma once
#ifndef EVENTHANDLER_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#define EVENTHANDLER_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#include "anchor.h"
#include <string>
namespace YAML
{
struct Mark;
class EventHandler
{
public:
virtual ~EventHandler() {}
virtual void OnDocumentStart(const Mark& mark) = 0;
virtual void OnDocumentEnd() = 0;
virtual void OnNull(const std::string& tag, anchor_t anchor) = 0;
virtual void OnAlias(const Mark& mark, anchor_t anchor) = 0;
virtual void OnScalar(const Mark& mark, const std::string& tag, anchor_t anchor, const std::string& value) = 0;
virtual void OnSequenceStart(const Mark& mark, const std::string& tag, anchor_t anchor) = 0;
virtual void OnSequenceEnd() = 0;
virtual void OnMapStart(const Mark& mark, const std::string& tag, anchor_t anchor) = 0;
virtual void OnMapEnd() = 0;
};
}
#endif // EVENTHANDLER_H_62B23520_7C8E_11DE_8A39_0800200C9A66
+30 -6
View File
@@ -5,6 +5,7 @@
#include "mark.h"
#include "traits.h"
#include <exception>
#include <string>
#include <sstream>
@@ -17,7 +18,12 @@ namespace YAML
const std::string YAML_DIRECTIVE_ARGS = "YAML directives must have exactly one argument";
const std::string YAML_VERSION = "bad YAML version: ";
const std::string YAML_MAJOR_VERSION = "YAML major version too large";
const std::string REPEATED_YAML_DIRECTIVE= "repeated YAML directive";
const std::string TAG_DIRECTIVE_ARGS = "TAG directives must have exactly two arguments";
const std::string REPEATED_TAG_DIRECTIVE = "repeated TAG directive";
const std::string CHAR_IN_TAG_HANDLE = "illegal character found while scanning tag handle";
const std::string TAG_WITH_NO_SUFFIX = "tag handle with no suffix";
const std::string END_OF_VERBATIM_TAG = "end of verbatim tag not found";
const std::string END_OF_MAP = "end of map not found";
const std::string END_OF_MAP_FLOW = "end of map flow not found";
const std::string END_OF_SEQ = "end of sequence not found";
@@ -57,10 +63,27 @@ namespace YAML
const std::string SINGLE_QUOTED_CHAR = "invalid character in single-quoted string";
const std::string INVALID_ANCHOR = "invalid anchor";
const std::string INVALID_ALIAS = "invalid alias";
const std::string INVALID_TAG = "invalid tag";
const std::string EXPECTED_KEY_TOKEN = "expected key token";
const std::string EXPECTED_VALUE_TOKEN = "expected value token";
const std::string UNEXPECTED_KEY_TOKEN = "unexpected key token";
const std::string UNEXPECTED_VALUE_TOKEN = "unexpected value token";
template <typename T>
inline const std::string KEY_NOT_FOUND_WITH_KEY(const T&, typename disable_if<is_numeric<T> >::type * = 0) {
return KEY_NOT_FOUND;
}
inline const std::string KEY_NOT_FOUND_WITH_KEY(const std::string& key) {
return KEY_NOT_FOUND + ": " + key;
}
template <typename T>
inline const std::string KEY_NOT_FOUND_WITH_KEY(const T& key, typename enable_if<is_numeric<T> >::type * = 0) {
std::stringstream stream;
stream << KEY_NOT_FOUND << ": " << key;
return stream.str();
}
}
class Exception: public std::exception {
@@ -102,22 +125,23 @@ namespace YAML
class KeyNotFound: public RepresentationException {
public:
KeyNotFound(const Mark& mark_)
: RepresentationException(mark_, ErrorMsg::KEY_NOT_FOUND) {}
template <typename T>
KeyNotFound(const Mark& mark_, const T& key_)
: RepresentationException(mark_, ErrorMsg::KEY_NOT_FOUND_WITH_KEY(key_)) {}
};
template <typename T>
class TypedKeyNotFound: public KeyNotFound {
public:
TypedKeyNotFound(const Mark& mark_, const T& key_)
: KeyNotFound(mark_), key(key_) {}
~TypedKeyNotFound() throw() {}
: KeyNotFound(mark_, key_), key(key_) {}
virtual ~TypedKeyNotFound() throw() {}
T key;
};
template <typename T>
TypedKeyNotFound <T> MakeTypedKeyNotFound(const Mark& mark, const T& key) {
inline TypedKeyNotFound <T> MakeTypedKeyNotFound(const Mark& mark, const T& key) {
return TypedKeyNotFound <T> (mark, key);
}
+117
View File
@@ -0,0 +1,117 @@
#ifndef GRAPHBUILDER_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#define GRAPHBUILDER_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#include <string>
namespace YAML
{
struct Mark;
// GraphBuilderInterface
// . Abstraction of node creation
// . pParentNode is always NULL or the return value of one of the NewXXX()
// functions.
class GraphBuilderInterface
{
public:
// Create and return a new node with a null value.
virtual void *NewNull(const std::string& tag, void *pParentNode) = 0;
// Create and return a new node with the given tag and value.
virtual void *NewScalar(const Mark& mark, const std::string& tag, void *pParentNode, const std::string& value) = 0;
// Create and return a new sequence node
virtual void *NewSequence(const Mark& mark, const std::string& tag, void *pParentNode) = 0;
// Add pNode to pSequence. pNode was created with one of the NewXxx()
// functions and pSequence with NewSequence().
virtual void AppendToSequence(void *pSequence, void *pNode) = 0;
// Note that no moew entries will be added to pSequence
virtual void SequenceComplete(void *pSequence) {(void)pSequence;}
// Create and return a new map node
virtual void *NewMap(const Mark& mark, const std::string& tag, void *pParentNode) = 0;
// Add the pKeyNode => pValueNode mapping to pMap. pKeyNode and pValueNode
// were created with one of the NewXxx() methods and pMap with NewMap().
virtual void AssignInMap(void *pMap, void *pKeyNode, void *pValueNode) = 0;
// Note that no more assignments will be made in pMap
virtual void MapComplete(void *pMap) {(void)pMap;}
// Return the node that should be used in place of an alias referencing
// pNode (pNode by default)
virtual void *AnchorReference(const Mark& mark, void *pNode) {(void)mark; return pNode;}
};
// Typesafe wrapper for GraphBuilderInterface. Assumes that Impl defines
// Node, Sequence, and Map types. Sequence and Map must derive from Node
// (unless Node is defined as void). Impl must also implement function with
// all of the same names as the virtual functions in GraphBuilderInterface
// -- including the ones with default implementations -- but with the
// prototypes changed to accept an explicit Node*, Sequence*, or Map* where
// appropriate.
template <class Impl>
class GraphBuilder : public GraphBuilderInterface
{
public:
typedef typename Impl::Node Node;
typedef typename Impl::Sequence Sequence;
typedef typename Impl::Map Map;
GraphBuilder(Impl& impl) : m_impl(impl)
{
Map* pMap = NULL;
Sequence* pSeq = NULL;
Node* pNode = NULL;
// Type consistency checks
pNode = pMap;
pNode = pSeq;
}
GraphBuilderInterface& AsBuilderInterface() {return *this;}
virtual void *NewNull(const std::string& tag, void* pParentNode) {
return CheckType<Node>(m_impl.NewNull(tag, AsNode(pParentNode)));
}
virtual void *NewScalar(const Mark& mark, const std::string& tag, void *pParentNode, const std::string& value) {
return CheckType<Node>(m_impl.NewScalar(mark, tag, AsNode(pParentNode), value));
}
virtual void *NewSequence(const Mark& mark, const std::string& tag, void *pParentNode) {
return CheckType<Sequence>(m_impl.NewSequence(mark, tag, AsNode(pParentNode)));
}
virtual void AppendToSequence(void *pSequence, void *pNode) {
m_impl.AppendToSequence(AsSequence(pSequence), AsNode(pNode));
}
virtual void SequenceComplete(void *pSequence) {
m_impl.SequenceComplete(AsSequence(pSequence));
}
virtual void *NewMap(const Mark& mark, const std::string& tag, void *pParentNode) {
return CheckType<Map>(m_impl.NewMap(mark, tag, AsNode(pParentNode)));
}
virtual void AssignInMap(void *pMap, void *pKeyNode, void *pValueNode) {
m_impl.AssignInMap(AsMap(pMap), AsNode(pKeyNode), AsNode(pValueNode));
}
virtual void MapComplete(void *pMap) {
m_impl.MapComplete(AsMap(pMap));
}
virtual void *AnchorReference(const Mark& mark, void *pNode) {
return CheckType<Node>(m_impl.AnchorReference(mark, AsNode(pNode)));
}
private:
Impl& m_impl;
// Static check for pointer to T
template <class T, class U>
static T* CheckType(U* p) {return p;}
static Node *AsNode(void *pNode) {return static_cast<Node*>(pNode);}
static Sequence *AsSequence(void *pSeq) {return static_cast<Sequence*>(pSeq);}
static Map *AsMap(void *pMap) {return static_cast<Map*>(pMap);}
};
}
#endif // GRAPHBUILDER_H_62B23520_7C8E_11DE_8A39_0800200C9A66
+17 -12
View File
@@ -9,7 +9,6 @@
#include "iterator.h"
#include "mark.h"
#include "noncopyable.h"
#include "parserstate.h"
#include <iostream>
#include <string>
#include <vector>
@@ -18,9 +17,12 @@
namespace YAML
{
class AliasManager;
class Content;
class Scanner;
class Emitter;
class EventHandler;
struct NodeProperties;
enum CONTENT_TYPE { CT_NONE, CT_SCALAR, CT_SEQUENCE, CT_MAP };
@@ -32,7 +34,16 @@ namespace YAML
void Clear();
std::auto_ptr<Node> Clone() const;
void Parse(Scanner *pScanner, const ParserState& state);
void EmitEvents(EventHandler& eventHandler) const;
void EmitEvents(AliasManager& am, EventHandler& eventHandler) const;
void Init(CONTENT_TYPE type, const Mark& mark, const std::string& tag);
void InitNull(const std::string& tag);
void InitAlias(const Mark& mark, const Node& identity);
void SetData(const std::string& data);
void Append(std::auto_ptr<Node> pNode);
void Insert(std::auto_ptr<Node> pKey, std::auto_ptr<Node> pValue);
CONTENT_TYPE GetType() const;
@@ -75,6 +86,9 @@ namespace YAML
const Node *Identity() const { return m_pIdentity; }
bool IsAlias() const { return m_alias; }
bool IsReferenced() const { return m_referenced; }
// for tags
const std::string GetTag() const { return IsAlias() ? m_pIdentity->GetTag() : m_tag; }
// emitting
friend Emitter& operator << (Emitter& out, const Node& node);
@@ -94,19 +108,10 @@ namespace YAML
template <typename T>
const Node *FindValueForKey(const T& key) const;
// helper for cloning
Node(const Mark& mark, const std::string& anchor, const std::string& tag, const Content *pContent);
// helpers for parsing
void ParseHeader(Scanner *pScanner, const ParserState& state);
void ParseTag(Scanner *pScanner, const ParserState& state);
void ParseAnchor(Scanner *pScanner, const ParserState& state);
void ParseAlias(Scanner *pScanner, const ParserState& state);
private:
Mark m_mark;
std::string m_anchor, m_tag;
std::string m_tag;
Content *m_pContent;
bool m_alias;
const Node *m_pIdentity;
+4 -4
View File
@@ -79,22 +79,22 @@ namespace YAML
template <typename T>
inline bool operator == (const T& value, const Node& node) {
return value == node.Read<T>();
return value == node.operator T();
}
template <typename T>
inline bool operator == (const Node& node, const T& value) {
return value == node.Read<T>();
return value == node.operator T();
}
template <typename T>
inline bool operator != (const T& value, const Node& node) {
return value != node.Read<T>();
return value != node.operator T();
}
template <typename T>
inline bool operator != (const Node& node, const T& value) {
return value != node.Read<T>();
return value != node.operator T();
}
inline bool operator == (const char *value, const Node& node) {
+14
View File
@@ -0,0 +1,14 @@
#pragma once
#ifndef NODEPROPERTIES_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#define NODEPROPERTIES_H_62B23520_7C8E_11DE_8A39_0800200C9A66
namespace YAML
{
struct NodeProperties {
std::string tag;
std::string anchor;
};
}
#endif // NODEPROPERTIES_H_62B23520_7C8E_11DE_8A39_0800200C9A66
+14 -1
View File
@@ -6,7 +6,18 @@ namespace YAML
// (the goal is to call ConvertScalar if we can, and fall back to operator >> if not)
// thanks to litb from stackoverflow.com
// http://stackoverflow.com/questions/1386183/how-to-call-a-templated-function-if-it-exists-and-something-else-otherwise/1386390#1386390
// Note: this doesn't work on gcc 3.2, but does on gcc 3.4 and above. I'm not sure about 3.3.
#if __GNUC__ && (__GNUC__ < 3 || (__GNUC__ == 3 && __GNUC_MINOR__ <= 3))
// trick doesn't work? Just fall back to ConvertScalar.
// This means that we can't use any user-defined types as keys in a map
template <typename T>
inline bool Node::Read(T& value) const {
return ConvertScalar(*this, value);
}
#else
// usual case: the trick!
template<bool>
struct read_impl;
@@ -41,9 +52,10 @@ namespace YAML
int operator,(flag, flag);
template<typename T>
void operator,(flag, T const&);
char operator,(flag, T const&);
char operator,(int, flag);
int operator,(char, flag);
}
template <typename T>
@@ -52,6 +64,7 @@ namespace YAML
return read_impl<sizeof (fallback::flag(), Convert(std::string(), value), fallback::flag()) != 1>::read(*this, value);
}
#endif // done with trick
// the main conversion function
template <typename T>
+30 -19
View File
@@ -4,44 +4,55 @@
#define PARSER_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#include "graphbuilder.h"
#include "noncopyable.h"
#include <ios>
#include <string>
#include <vector>
#include <map>
#include "node.h"
#include "parserstate.h"
#include <memory>
namespace YAML
{
class Scanner;
struct Directives;
struct Mark;
struct Token;
class EventHandler;
class GraphBuilderInterface;
class Node;
class Scanner;
class Parser
class Parser: private noncopyable
{
public:
Parser();
Parser(std::istream& in);
~Parser();
operator bool() const;
void Load(std::istream& in);
void GetNextDocument(Node& document);
bool HandleNextDocument(EventHandler& eventHandler);
void *BuildNextDocumentGraph(GraphBuilderInterface& graphBuilder);
template <class Builder>
typename Builder::Node *BuildNextDocumentGraph(Builder& graphBuilder)
{
GraphBuilder<Builder> wrapper(graphBuilder); // Must be lvalue to make C++ happy
return static_cast<typename Builder::Node *>(
BuildNextDocumentGraph(wrapper.AsBuilderInterface())
);
}
bool GetNextDocument(Node& document);
void PrintTokens(std::ostream& out);
private:
void ParseDirectives();
void HandleDirective(Token *pToken);
void HandleYamlDirective(Token *pToken);
void HandleTagDirective(Token *pToken);
void HandleDirective(const Token& token);
void HandleYamlDirective(const Token& token);
void HandleTagDirective(const Token& token);
private:
// can't copy this
Parser(const Parser&) {}
Parser& operator = (const Parser&) { return *this; }
private:
Scanner *m_pScanner;
ParserState m_state;
std::auto_ptr<Scanner> m_pScanner;
std::auto_ptr<Directives> m_pDirectives;
};
}
-26
View File
@@ -1,26 +0,0 @@
#pragma once
#ifndef PARSERSTATE_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#define PARSERSTATE_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#include <string>
#include <map>
namespace YAML
{
struct Version {
int major, minor;
};
struct ParserState
{
Version version;
std::map <std::string, std::string> tags;
void Reset();
std::string TranslateTag(const std::string& handle) const;
};
}
#endif // PARSERSTATE_H_62B23520_7C8E_11DE_8A39_0800200C9A66
+36
View File
@@ -0,0 +1,36 @@
#pragma once
#ifndef STLNODE_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#define STLNODE_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#include <vector>
#include <map>
namespace YAML
{
template <typename T>
void operator >> (const Node& node, std::vector<T>& v)
{
v.clear();
v.resize(node.size());
for(unsigned i=0;i<node.size();++i)
node[i] >> v[i];
}
template <typename K, typename V>
void operator >> (const Node& node, std::map<K, V>& m)
{
m.clear();
for(Iterator it=node.begin();it!=node.end();++it) {
K k;
V v;
it.first() >> k;
it.second() >> v;
m[k] = v;
}
}
}
#endif // STLNODE_H_62B23520_7C8E_11DE_8A39_0800200C9A66
+50
View File
@@ -0,0 +1,50 @@
#pragma once
#ifndef TRAITS_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#define TRAITS_H_62B23520_7C8E_11DE_8A39_0800200C9A66
namespace YAML
{
template <typename>
struct is_numeric { enum { value = false }; };
template <> struct is_numeric <char> { enum { value = true }; };
template <> struct is_numeric <unsigned char> { enum { value = true }; };
template <> struct is_numeric <int> { enum { value = true }; };
template <> struct is_numeric <unsigned int> { enum { value = true }; };
template <> struct is_numeric <long int> { enum { value = true }; };
template <> struct is_numeric <unsigned long int> { enum { value = true }; };
template <> struct is_numeric <short int> { enum { value = true }; };
template <> struct is_numeric <unsigned short int> { enum { value = true }; };
template <> struct is_numeric <long long> { enum { value = true }; };
template <> struct is_numeric <unsigned long long> { enum { value = true }; };
template <> struct is_numeric <float> { enum { value = true }; };
template <> struct is_numeric <double> { enum { value = true }; };
template <> struct is_numeric <long double> { enum { value = true }; };
template <bool, class T = void>
struct enable_if_c {
typedef T type;
};
template <class T>
struct enable_if_c<false, T> {};
template <class Cond, class T = void>
struct enable_if : public enable_if_c<Cond::value, T> {};
template <bool, class T = void>
struct disable_if_c {
typedef T type;
};
template <class T>
struct disable_if_c<true, T> {};
template <class Cond, class T = void>
struct disable_if : public disable_if_c<Cond::value, T> {};
}
#endif // TRAITS_H_62B23520_7C8E_11DE_8A39_0800200C9A66
+1 -1
View File
@@ -4,9 +4,9 @@
#define YAML_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#include "crt.h"
#include "parser.h"
#include "node.h"
#include "stlnode.h"
#include "iterator.h"
#include "emitter.h"
#include "stlemitter.h"
+1 -1
View File
@@ -21,4 +21,4 @@ make install
If you don't want to use CMake, just add all .cpp files to a makefile. yaml-cpp does not need any special build settings, so no 'configure' file is necessary.
(Note: this is pretty tedious. It's sooo much easier to use CMake.)
(Note: this is pretty tedious. It's sooo much easier to use CMake.)
+1 -1
View File
@@ -16,4 +16,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
THE SOFTWARE.
+16 -38
View File
@@ -2,9 +2,9 @@
<VisualStudioProject
ProjectType="Visual C++"
Version="9.00"
Name="yaml-reader"
ProjectGUID="{E8CC0D8A-D784-4A6B-B78B-ACEA13F9FB0B}"
RootNamespace="yamlreader"
Name="parse"
ProjectGUID="{CD007B57-7812-4930-A5E2-6E5E56338814}"
RootNamespace="parse"
TargetFrameworkVersion="196613"
>
<Platforms>
@@ -39,13 +39,15 @@
/>
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/D_SCL_SECURE_NO_WARNINGS"
Optimization="0"
AdditionalIncludeDirectories="include"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
WarningLevel="3"
DebugInformationFormat="3"
DebugInformationFormat="4"
DisableSpecificWarnings="4127;4355"
/>
<Tool
Name="VCManagedResourceCompilerTool"
@@ -110,13 +112,15 @@
/>
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/D_SCL_SECURE_NO_WARNINGS"
Optimization="2"
EnableIntrinsicFunctions="true"
AdditionalIncludeDirectories="include"
RuntimeLibrary="2"
EnableFunctionLevelLinking="true"
WarningLevel="4"
WarningLevel="3"
DebugInformationFormat="3"
DisableSpecificWarnings="4127;4355"
/>
<Tool
Name="VCManagedResourceCompilerTool"
@@ -168,23 +172,7 @@
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
>
<File
RelativePath=".\yaml-reader\emittertests.cpp"
>
</File>
<File
RelativePath=".\yaml-reader\main.cpp"
>
</File>
<File
RelativePath=".\yaml-reader\parsertests.cpp"
>
</File>
<File
RelativePath=".\yaml-reader\spectests.cpp"
>
</File>
<File
RelativePath=".\yaml-reader\tests.cpp"
RelativePath=".\util\parse.cpp"
>
</File>
</Filter>
@@ -193,22 +181,12 @@
Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
>
<File
RelativePath=".\yaml-reader\emittertests.h"
>
</File>
<File
RelativePath=".\yaml-reader\parsertests.h"
>
</File>
<File
RelativePath=".\yaml-reader\spectests.h"
>
</File>
<File
RelativePath=".\yaml-reader\tests.h"
>
</File>
</Filter>
<Filter
Name="Resource Files"
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
>
</Filter>
</Files>
<Globals>
+6 -17
View File
@@ -1,27 +1,11 @@
#include "crt.h"
#include "aliascontent.h"
namespace YAML
{
AliasContent::AliasContent(Content* pNodeContent)
: m_pRef(pNodeContent)
AliasContent::AliasContent(Content* pNodeContent): m_pRef(pNodeContent)
{
}
Content *AliasContent::Clone() const
{
return 0; // TODO: how to clone an alias?
}
void AliasContent::Parse(Scanner * /*pScanner*/, const ParserState& /*state*/)
{
}
void AliasContent::Write(Emitter&) const
{
// no content (just an alias)
}
bool AliasContent::GetBegin(std::vector <Node *>::const_iterator& i) const
{
return m_pRef->GetBegin(i);
@@ -72,6 +56,11 @@ namespace YAML
return m_pRef->GetScalar(scalar);
}
void AliasContent::EmitEvents(AliasManager& am, EventHandler& eventHandler, const Mark& mark, const std::string& tag, anchor_t anchor) const
{
m_pRef->EmitEvents(am, eventHandler, mark, tag, anchor);
}
int AliasContent::Compare(Content *pContent)
{
return m_pRef->Compare(pContent);
+1 -5
View File
@@ -12,11 +12,6 @@ namespace YAML
{
public:
AliasContent(Content *pNodeContent);
virtual Content *Clone() const;
virtual void Parse(Scanner* pScanner, const ParserState& state);
virtual void Write(Emitter&) const;
virtual bool GetBegin(std::vector <Node *>::const_iterator&) const;
virtual bool GetBegin(std::map <Node *, Node *, ltnode>::const_iterator&) const;
@@ -29,6 +24,7 @@ namespace YAML
virtual bool IsSequence() const;
virtual bool GetScalar(std::string& s) const;
virtual void EmitEvents(AliasManager& am, EventHandler& eventHandler, const Mark& mark, const std::string& tag, anchor_t anchor) const;
virtual int Compare(Content *);
virtual int Compare(Scalar *);
+45
View File
@@ -0,0 +1,45 @@
#include "aliasmanager.h"
#include "node.h"
#include <cassert>
#include <sstream>
namespace YAML
{
AliasManager::AliasManager(): m_curAnchor(0)
{
}
void AliasManager::RegisterReference(const Node& node)
{
const Node *pIdentity = node.Identity();
m_newIdentityByOldIdentity.insert(std::make_pair(pIdentity, &node));
m_anchorByIdentity.insert(std::make_pair(&node, _CreateNewAnchor()));
}
const Node *AliasManager::LookupReference(const Node& node) const
{
const Node *pIdentity = node.Identity();
return _LookupReference(*pIdentity);
}
anchor_t AliasManager::LookupAnchor(const Node& node) const
{
AnchorByIdentity::const_iterator it = m_anchorByIdentity.find(&node);
if(it == m_anchorByIdentity.end())
assert(false); // TODO: throw
return it->second;
}
const Node *AliasManager::_LookupReference(const Node& oldIdentity) const
{
NodeByNode::const_iterator it = m_newIdentityByOldIdentity.find(&oldIdentity);
if(it == m_newIdentityByOldIdentity.end())
return 0;
return it->second;
}
anchor_t AliasManager::_CreateNewAnchor()
{
return ++m_curAnchor;
}
}
+33
View File
@@ -0,0 +1,33 @@
#pragma once
#ifndef COLLECTIONSTACK_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#define COLLECTIONSTACK_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#include <stack>
#include <cassert>
namespace YAML
{
struct CollectionType {
enum value { None, BlockMap, BlockSeq, FlowMap, FlowSeq, CompactMap };
};
class CollectionStack
{
public:
CollectionType::value GetCurCollectionType() const {
if(collectionStack.empty())
return CollectionType::None;
return collectionStack.top();
}
void PushCollectionType(CollectionType::value type) { collectionStack.push(type); }
void PopCollectionType(CollectionType::value type) { assert(type == GetCurCollectionType()); collectionStack.pop(); }
private:
std::stack<CollectionType::value> collectionStack;
};
}
#endif // COLLECTIONSTACK_H_62B23520_7C8E_11DE_8A39_0800200C9A66
+11 -3
View File
@@ -1,13 +1,21 @@
#include "crt.h"
#include "content.h"
#include "node.h"
#include <cassert>
namespace YAML
{
Content::Content()
void Content::SetData(const std::string&)
{
assert(false); // TODO: throw
}
Content::~Content()
void Content::Append(std::auto_ptr<Node>)
{
assert(false); // TODO: throw
}
void Content::Insert(std::auto_ptr<Node>, std::auto_ptr<Node>)
{
assert(false); // TODO: throw
}
}
+17 -14
View File
@@ -4,32 +4,30 @@
#define CONTENT_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#include <vector>
#include <map>
#include "parserstate.h"
#include "anchor.h"
#include "exceptions.h"
#include "ltnode.h"
#include <map>
#include <memory>
#include <vector>
namespace YAML
{
class Scanner;
class Parser;
struct Mark;
struct NodeProperties;
class AliasManager;
class EventHandler;
class Map;
class Node;
class Scalar;
class Scanner;
class Sequence;
class Map;
class Emitter;
class Content
{
public:
Content();
virtual ~Content();
virtual Content *Clone() const = 0;
virtual void Parse(Scanner *pScanner, const ParserState& state) = 0;
virtual void Write(Emitter& out) const = 0;
Content() {}
virtual ~Content() {}
virtual bool GetBegin(std::vector <Node *>::const_iterator&) const { return false; }
virtual bool GetBegin(std::map <Node *, Node *, ltnode>::const_iterator&) const { return false; }
@@ -40,6 +38,11 @@ namespace YAML
virtual bool IsScalar() const { return false; }
virtual bool IsMap() const { return false; }
virtual bool IsSequence() const { return false; }
virtual void SetData(const std::string& data);
virtual void Append(std::auto_ptr<Node> pNode);
virtual void Insert(std::auto_ptr<Node> pKey, std::auto_ptr<Node> pValue);
virtual void EmitEvents(AliasManager& am, EventHandler& eventHandler, const Mark& mark, const std::string& tag, anchor_t anchor) const = 0;
// extraction
virtual bool GetScalar(std::string&) const { return false; }
+24
View File
@@ -0,0 +1,24 @@
#include "directives.h"
namespace YAML
{
Directives::Directives()
{
// version
version.isDefault = true;
version.major = 1;
version.minor = 2;
}
const std::string Directives::TranslateTagHandle(const std::string& handle) const
{
std::map <std::string, std::string>::const_iterator it = tags.find(handle);
if(it == tags.end()) {
if(handle == "!!")
return "tag:yaml.org,2002:";
return handle;
}
return it->second;
}
}
+27
View File
@@ -0,0 +1,27 @@
#pragma once
#ifndef DIRECTIVES_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#define DIRECTIVES_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#include <string>
#include <map>
namespace YAML
{
struct Version {
bool isDefault;
int major, minor;
};
struct Directives {
Directives();
const std::string TranslateTagHandle(const std::string& handle) const;
Version version;
std::map<std::string, std::string> tags;
};
}
#endif // DIRECTIVES_H_62B23520_7C8E_11DE_8A39_0800200C9A66
+106
View File
@@ -0,0 +1,106 @@
#include "emitfromevents.h"
#include "emitter.h"
#include "null.h"
#include <cassert>
#include <sstream>
namespace {
std::string ToString(YAML::anchor_t anchor) {
std::stringstream stream;
stream << anchor;
return stream.str();
}
}
namespace YAML
{
EmitFromEvents::EmitFromEvents(Emitter& emitter): m_emitter(emitter)
{
}
void EmitFromEvents::OnDocumentStart(const Mark&)
{
}
void EmitFromEvents::OnDocumentEnd()
{
}
void EmitFromEvents::OnNull(const std::string& tag, anchor_t anchor)
{
BeginNode();
EmitProps(tag, anchor);
if(tag.empty())
m_emitter << Null;
}
void EmitFromEvents::OnAlias(const Mark&, anchor_t anchor)
{
BeginNode();
m_emitter << Alias(ToString(anchor));
}
void EmitFromEvents::OnScalar(const Mark&, const std::string& tag, anchor_t anchor, const std::string& value)
{
BeginNode();
EmitProps(tag, anchor);
m_emitter << value;
}
void EmitFromEvents::OnSequenceStart(const Mark&, const std::string& tag, anchor_t anchor)
{
BeginNode();
EmitProps(tag, anchor);
m_emitter << BeginSeq;
m_stateStack.push(State::WaitingForSequenceEntry);
}
void EmitFromEvents::OnSequenceEnd()
{
m_emitter << EndSeq;
assert(m_stateStack.top() == State::WaitingForSequenceEntry);
m_stateStack.pop();
}
void EmitFromEvents::OnMapStart(const Mark&, const std::string& tag, anchor_t anchor)
{
BeginNode();
EmitProps(tag, anchor);
m_emitter << BeginMap;
m_stateStack.push(State::WaitingForKey);
}
void EmitFromEvents::OnMapEnd()
{
m_emitter << EndMap;
assert(m_stateStack.top() == State::WaitingForKey);
m_stateStack.pop();
}
void EmitFromEvents::BeginNode()
{
if(m_stateStack.empty())
return;
switch(m_stateStack.top()) {
case State::WaitingForKey:
m_emitter << Key;
m_stateStack.top() = State::WaitingForValue;
break;
case State::WaitingForValue:
m_emitter << Value;
m_stateStack.top() = State::WaitingForKey;
break;
default:
break;
}
}
void EmitFromEvents::EmitProps(const std::string& tag, anchor_t anchor)
{
if(!tag.empty())
m_emitter << VerbatimTag(tag);
if(anchor)
m_emitter << Anchor(ToString(anchor));
}
}
+83 -63
View File
@@ -37,6 +37,11 @@ namespace YAML
}
// global setters
bool Emitter::SetOutputCharset(EMITTER_MANIP value)
{
return m_pState->SetOutputCharset(value, GLOBAL);
}
bool Emitter::SetStringFormat(EMITTER_MANIP value)
{
return m_pState->SetStringFormat(value, GLOBAL);
@@ -115,6 +120,9 @@ namespace YAML
case Value:
EmitValue();
break;
case TagByKind:
EmitKindTag();
break;
default:
m_pState->SetLocalValue(value);
break;
@@ -141,6 +149,8 @@ namespace YAML
switch(curState) {
// document-level
case ES_WAITING_FOR_DOC:
m_stream << "---";
m_pState->RequireSeparation();
m_pState->SwitchState(ES_WRITING_DOC);
return true;
case ES_WRITING_DOC:
@@ -318,7 +328,10 @@ namespace YAML
EMITTER_STATE curState = m_pState->GetCurState();
EMITTER_MANIP flowType = m_pState->GetFlowType(GT_SEQ);
if(flowType == Block) {
if(curState == ES_WRITING_BLOCK_SEQ_ENTRY || curState == ES_WRITING_BLOCK_MAP_KEY || curState == ES_WRITING_BLOCK_MAP_VALUE) {
if(curState == ES_WRITING_BLOCK_SEQ_ENTRY ||
curState == ES_WRITING_BLOCK_MAP_KEY || curState == ES_WRITING_BLOCK_MAP_VALUE ||
curState == ES_WRITING_DOC
) {
m_stream << "\n";
m_pState->UnsetSeparation();
}
@@ -344,12 +357,22 @@ namespace YAML
EMITTER_STATE curState = m_pState->GetCurState();
FLOW_TYPE flowType = m_pState->GetCurGroupFlowType();
if(flowType == FT_BLOCK)
assert(curState == ES_DONE_WITH_BLOCK_SEQ_ENTRY);
else if(flowType == FT_FLOW) {
m_stream << "]";
if(flowType == FT_BLOCK) {
// Note: block sequences are *not* allowed to be empty, but we convert it
// to a flow sequence if it is
assert(curState == ES_DONE_WITH_BLOCK_SEQ_ENTRY || curState == ES_WAITING_FOR_BLOCK_SEQ_ENTRY);
if(curState == ES_WAITING_FOR_BLOCK_SEQ_ENTRY) {
// Note: only one of these will actually output anything for a given situation
EmitSeparationIfNecessary();
unsigned curIndent = m_pState->GetCurIndent();
m_stream << IndentTo(curIndent);
m_stream << "[]";
}
} else if(flowType == FT_FLOW) {
// Note: flow sequences are allowed to be empty
assert(curState == ES_DONE_WITH_FLOW_SEQ_ENTRY || curState == ES_WAITING_FOR_FLOW_SEQ_ENTRY);
m_stream << "]";
} else
assert(false);
@@ -373,7 +396,10 @@ namespace YAML
EMITTER_STATE curState = m_pState->GetCurState();
EMITTER_MANIP flowType = m_pState->GetFlowType(GT_MAP);
if(flowType == Block) {
if(curState == ES_WRITING_BLOCK_SEQ_ENTRY || curState == ES_WRITING_BLOCK_MAP_KEY || curState == ES_WRITING_BLOCK_MAP_VALUE) {
if(curState == ES_WRITING_BLOCK_SEQ_ENTRY ||
curState == ES_WRITING_BLOCK_MAP_KEY || curState == ES_WRITING_BLOCK_MAP_VALUE ||
curState == ES_WRITING_DOC
) {
m_stream << "\n";
m_pState->UnsetSeparation();
}
@@ -399,12 +425,21 @@ namespace YAML
EMITTER_STATE curState = m_pState->GetCurState();
FLOW_TYPE flowType = m_pState->GetCurGroupFlowType();
if(flowType == FT_BLOCK)
assert(curState == ES_DONE_WITH_BLOCK_MAP_VALUE);
else if(flowType == FT_FLOW) {
m_stream << "}";
if(flowType == FT_BLOCK) {
// Note: block sequences are *not* allowed to be empty, but we convert it
// to a flow sequence if it is
assert(curState == ES_DONE_WITH_BLOCK_MAP_VALUE || curState == ES_WAITING_FOR_BLOCK_MAP_ENTRY);
if(curState == ES_WAITING_FOR_BLOCK_MAP_ENTRY) {
// Note: only one of these will actually output anything for a given situation
EmitSeparationIfNecessary();
unsigned curIndent = m_pState->GetCurIndent();
m_stream << IndentTo(curIndent);
m_stream << "{}";
}
} else if(flowType == FT_FLOW) {
// Note: flow maps are allowed to be empty
assert(curState == ES_DONE_WITH_FLOW_MAP_VALUE || curState == ES_WAITING_FOR_FLOW_MAP_ENTRY);
m_stream << "}";
} else
assert(false);
@@ -485,13 +520,14 @@ namespace YAML
PreAtomicWrite();
EmitSeparationIfNecessary();
bool escapeNonAscii = m_pState->GetOutputCharset() == EscapeNonAscii;
EMITTER_MANIP strFmt = m_pState->GetStringFormat();
FLOW_TYPE flowType = m_pState->GetCurGroupFlowType();
unsigned curIndent = m_pState->GetCurIndent();
switch(strFmt) {
case Auto:
Utils::WriteString(m_stream, str, flowType == FT_FLOW);
Utils::WriteString(m_stream, str, flowType == FT_FLOW, escapeNonAscii);
break;
case SingleQuoted:
if(!Utils::WriteSingleQuotedString(m_stream, str)) {
@@ -500,11 +536,11 @@ namespace YAML
}
break;
case DoubleQuoted:
Utils::WriteDoubleQuotedString(m_stream, str);
Utils::WriteDoubleQuotedString(m_stream, str, escapeNonAscii);
break;
case Literal:
if(flowType == FT_FLOW)
Utils::WriteString(m_stream, str, flowType == FT_FLOW);
Utils::WriteString(m_stream, str, flowType == FT_FLOW, escapeNonAscii);
else
Utils::WriteLiteralString(m_stream, str, curIndent + m_pState->GetIndent());
break;
@@ -516,24 +552,12 @@ namespace YAML
return *this;
}
Emitter& Emitter::Write(const char *str)
void Emitter::PreWriteIntegralType(std::stringstream& str)
{
if(!good())
return *this;
return Write(std::string(str));
}
Emitter& Emitter::Write(int i)
{
if(!good())
return *this;
PreAtomicWrite();
EmitSeparationIfNecessary();
EMITTER_MANIP intFmt = m_pState->GetIntFormat();
std::stringstream str;
switch(intFmt) {
case Dec:
str << std::dec;
@@ -541,18 +565,18 @@ namespace YAML
case Hex:
str << std::hex;
break;
case Oct:
case Oct:
str << std::oct;
break;
default:
assert(false);
}
str << i;
}
void Emitter::PostWriteIntegralType(const std::stringstream& str)
{
m_stream << str.str();
PostAtomicWrite();
return *this;
}
Emitter& Emitter::Write(bool b)
@@ -594,38 +618,6 @@ namespace YAML
return *this;
}
Emitter& Emitter::Write(float f)
{
if(!good())
return *this;
PreAtomicWrite();
EmitSeparationIfNecessary();
std::stringstream str;
str << f;
m_stream << str.str();
PostAtomicWrite();
return *this;
}
Emitter& Emitter::Write(double d)
{
if(!good())
return *this;
PreAtomicWrite();
EmitSeparationIfNecessary();
std::stringstream str;
str << d;
m_stream << str.str();
PostAtomicWrite();
return *this;
}
Emitter& Emitter::Write(const _Alias& alias)
{
if(!good())
@@ -657,6 +649,33 @@ namespace YAML
return *this;
}
Emitter& Emitter::Write(const _Tag& tag)
{
if(!good())
return *this;
EmitTag(tag.verbatim, tag);
return *this;
}
void Emitter::EmitTag(bool verbatim, const _Tag& tag)
{
PreAtomicWrite();
EmitSeparationIfNecessary();
if(!Utils::WriteTag(m_stream, tag.content, verbatim)) {
m_pState->SetError(ErrorMsg::INVALID_TAG);
return;
}
m_pState->RequireSeparation();
// Note: no PostAtomicWrite() because we need another value for this node
}
void Emitter::EmitKindTag()
{
_Tag tag("");
EmitTag(false, tag);
}
Emitter& Emitter::Write(const _Comment& comment)
{
if(!good())
@@ -679,3 +698,4 @@ namespace YAML
return *this;
}
}
+14
View File
@@ -9,6 +9,7 @@ namespace YAML
m_stateStack.push(ES_WAITING_FOR_DOC);
// set default global manipulators
m_charset.set(EmitNonAscii);
m_strFmt.set(Auto);
m_boolFmt.set(TrueFalseBool);
m_boolLengthFmt.set(LongBool);
@@ -43,6 +44,7 @@ namespace YAML
// . Only the ones that make sense will be accepted
void EmitterState::SetLocalValue(EMITTER_MANIP value)
{
SetOutputCharset(value, LOCAL);
SetStringFormat(value, LOCAL);
SetBoolFormat(value, LOCAL);
SetBoolCaseFormat(value, LOCAL);
@@ -132,6 +134,18 @@ namespace YAML
{
m_modifiedSettings.clear();
}
bool EmitterState::SetOutputCharset(EMITTER_MANIP value, FMT_SCOPE scope)
{
switch(value) {
case EmitNonAscii:
case EscapeNonAscii:
_Set(m_charset, value, scope);
return true;
default:
return false;
}
}
bool EmitterState::SetStringFormat(EMITTER_MANIP value, FMT_SCOPE scope)
{
+4
View File
@@ -108,6 +108,9 @@ namespace YAML
void ClearModifiedSettings();
// formatters
bool SetOutputCharset(EMITTER_MANIP value, FMT_SCOPE scope);
EMITTER_MANIP GetOutputCharset() const { return m_charset.get(); }
bool SetStringFormat(EMITTER_MANIP value, FMT_SCOPE scope);
EMITTER_MANIP GetStringFormat() const { return m_strFmt.get(); }
@@ -149,6 +152,7 @@ namespace YAML
// other state
std::stack <EMITTER_STATE> m_stateStack;
Setting <EMITTER_MANIP> m_charset;
Setting <EMITTER_MANIP> m_strFmt;
Setting <EMITTER_MANIP> m_boolFmt;
Setting <EMITTER_MANIP> m_boolLengthFmt;
+226 -53
View File
@@ -11,13 +11,125 @@ namespace YAML
namespace Utils
{
namespace {
bool IsPrintable(char ch) {
return (0x20 <= ch && ch <= 0x7E);
enum {REPLACEMENT_CHARACTER = 0xFFFD};
bool IsAnchorChar(int ch) { // test for ns-anchor-char
switch (ch) {
case ',': case '[': case ']': case '{': case '}': // c-flow-indicator
case ' ': case '\t': // s-white
case 0xFEFF: // c-byte-order-mark
case 0xA: case 0xD: // b-char
return false;
case 0x85:
return true;
}
if (ch < 0x20)
return false;
if (ch < 0x7E)
return true;
if (ch < 0xA0)
return false;
if (ch >= 0xD800 && ch <= 0xDFFF)
return false;
if ((ch & 0xFFFE) == 0xFFFE)
return false;
if ((ch >= 0xFDD0) && (ch <= 0xFDEF))
return false;
if (ch > 0x10FFFF)
return false;
return true;
}
bool IsValidPlainScalar(const std::string& str, bool inFlow) {
int Utf8BytesIndicated(char ch) {
int byteVal = static_cast<unsigned char>(ch);
switch (byteVal >> 4) {
case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
return 1;
case 12: case 13:
return 2;
case 14:
return 3;
case 15:
return 4;
default:
return -1;
}
}
bool IsTrailingByte(char ch) {
return (ch & 0xC0) == 0x80;
}
bool GetNextCodePointAndAdvance(int& codePoint, std::string::const_iterator& first, std::string::const_iterator last) {
if (first == last)
return false;
int nBytes = Utf8BytesIndicated(*first);
if (nBytes < 1) {
// Bad lead byte
++first;
codePoint = REPLACEMENT_CHARACTER;
return true;
}
if (nBytes == 1) {
codePoint = *first++;
return true;
}
// Gather bits from trailing bytes
codePoint = static_cast<unsigned char>(*first) & ~(0xFF << (7 - nBytes));
++first;
--nBytes;
for (; nBytes > 0; ++first, --nBytes) {
if ((first == last) || !IsTrailingByte(*first)) {
codePoint = REPLACEMENT_CHARACTER;
break;
}
codePoint <<= 6;
codePoint |= *first & 0x3F;
}
// Check for illegal code points
if (codePoint > 0x10FFFF)
codePoint = REPLACEMENT_CHARACTER;
else if (codePoint >= 0xD800 && codePoint <= 0xDFFF)
codePoint = REPLACEMENT_CHARACTER;
else if ((codePoint & 0xFFFE) == 0xFFFE)
codePoint = REPLACEMENT_CHARACTER;
else if (codePoint >= 0xFDD0 && codePoint <= 0xFDEF)
codePoint = REPLACEMENT_CHARACTER;
return true;
}
void WriteCodePoint(ostream& out, int codePoint) {
if (codePoint < 0 || codePoint > 0x10FFFF) {
codePoint = REPLACEMENT_CHARACTER;
}
if (codePoint < 0x7F) {
out << static_cast<char>(codePoint);
} else if (codePoint < 0x7FF) {
out << static_cast<char>(0xC0 | (codePoint >> 6))
<< static_cast<char>(0x80 | (codePoint & 0x3F));
} else if (codePoint < 0xFFFF) {
out << static_cast<char>(0xE0 | (codePoint >> 12))
<< static_cast<char>(0x80 | ((codePoint >> 6) & 0x3F))
<< static_cast<char>(0x80 | (codePoint & 0x3F));
} else {
out << static_cast<char>(0xF0 | (codePoint >> 18))
<< static_cast<char>(0x80 | ((codePoint >> 12) & 0x3F))
<< static_cast<char>(0x80 | ((codePoint >> 6) & 0x3F))
<< static_cast<char>(0x80 | (codePoint & 0x3F));
}
}
bool IsValidPlainScalar(const std::string& str, bool inFlow, bool allowOnlyAscii) {
// first check the start
const RegEx& start = (inFlow ? Exp::PlainScalarInFlow : Exp::PlainScalar);
const RegEx& start = (inFlow ? Exp::PlainScalarInFlow() : Exp::PlainScalar());
if(!start.Matches(str))
return false;
@@ -26,66 +138,111 @@ namespace YAML
return false;
// then check until something is disallowed
const RegEx& disallowed = (inFlow ? Exp::EndScalarInFlow : Exp::EndScalar)
|| (Exp::BlankOrBreak + Exp::Comment)
|| (!Exp::Printable)
|| Exp::Break
|| Exp::Tab;
const RegEx& disallowed = (inFlow ? Exp::EndScalarInFlow() : Exp::EndScalar())
|| (Exp::BlankOrBreak() + Exp::Comment())
|| Exp::NotPrintable()
|| Exp::Utf8_ByteOrderMark()
|| Exp::Break()
|| Exp::Tab();
StringCharSource buffer(str.c_str(), str.size());
while(buffer) {
if(disallowed.Matches(buffer))
return false;
if(allowOnlyAscii && (0x7F < static_cast<unsigned char>(buffer[0])))
return false;
++buffer;
}
return true;
}
void WriteDoubleQuoteEscapeSequence(ostream& out, int codePoint) {
static const char hexDigits[] = "0123456789abcdef";
char escSeq[] = "\\U00000000";
int digits = 8;
if (codePoint < 0xFF) {
escSeq[1] = 'x';
digits = 2;
} else if (codePoint < 0xFFFF) {
escSeq[1] = 'u';
digits = 4;
}
// Write digits into the escape sequence
int i = 2;
for (; digits > 0; --digits, ++i) {
escSeq[i] = hexDigits[(codePoint >> (4 * (digits - 1))) & 0xF];
}
escSeq[i] = 0; // terminate with NUL character
out << escSeq;
}
bool WriteAliasName(ostream& out, const std::string& str) {
int codePoint;
for(std::string::const_iterator i = str.begin();
GetNextCodePointAndAdvance(codePoint, i, str.end());
)
{
if (!IsAnchorChar(codePoint))
return false;
WriteCodePoint(out, codePoint);
}
return true;
}
}
bool WriteString(ostream& out, const std::string& str, bool inFlow)
bool WriteString(ostream& out, const std::string& str, bool inFlow, bool escapeNonAscii)
{
if(IsValidPlainScalar(str, inFlow)) {
if(IsValidPlainScalar(str, inFlow, escapeNonAscii)) {
out << str;
return true;
} else
return WriteDoubleQuotedString(out, str);
return WriteDoubleQuotedString(out, str, escapeNonAscii);
}
bool WriteSingleQuotedString(ostream& out, const std::string& str)
{
out << "'";
for(std::size_t i=0;i<str.size();i++) {
char ch = str[i];
if(!IsPrintable(ch))
return false;
if(ch == '\'')
int codePoint;
for(std::string::const_iterator i = str.begin();
GetNextCodePointAndAdvance(codePoint, i, str.end());
)
{
if (codePoint == '\n')
return false; // We can't handle a new line and the attendant indentation yet
if (codePoint == '\'')
out << "''";
else
out << ch;
WriteCodePoint(out, codePoint);
}
out << "'";
return true;
}
bool WriteDoubleQuotedString(ostream& out, const std::string& str)
bool WriteDoubleQuotedString(ostream& out, const std::string& str, bool escapeNonAscii)
{
out << "\"";
for(std::size_t i=0;i<str.size();i++) {
char ch = str[i];
if(IsPrintable(ch)) {
if(ch == '\"')
out << "\\\"";
else if(ch == '\\')
out << "\\\\";
else
out << ch;
} else {
// TODO: for the common escaped characters, give their usual symbol
std::stringstream str;
str << "\\x" << std::hex << std::setfill('0') << std::setw(2) << static_cast<unsigned int>(static_cast<unsigned char>(ch));
out << str.str();
}
int codePoint;
for(std::string::const_iterator i = str.begin();
GetNextCodePointAndAdvance(codePoint, i, str.end());
)
{
if (codePoint == '\"')
out << "\\\"";
else if (codePoint == '\\')
out << "\\\\";
else if (codePoint < 0x20 || (codePoint >= 0x80 && codePoint <= 0xA0)) // Control characters and non-breaking space
WriteDoubleQuoteEscapeSequence(out, codePoint);
else if (codePoint == 0xFEFF) // Byte order marks (ZWNS) should be escaped (YAML 1.2, sec. 5.2)
WriteDoubleQuoteEscapeSequence(out, codePoint);
else if (escapeNonAscii && codePoint > 0x7E)
WriteDoubleQuoteEscapeSequence(out, codePoint);
else
WriteCodePoint(out, codePoint);
}
out << "\"";
return true;
@@ -95,11 +252,15 @@ namespace YAML
{
out << "|\n";
out << IndentTo(indent);
for(std::size_t i=0;i<str.size();i++) {
if(str[i] == '\n')
out << "\n" << IndentTo(indent);
int codePoint;
for(std::string::const_iterator i = str.begin();
GetNextCodePointAndAdvance(codePoint, i, str.end());
)
{
if (codePoint == '\n')
out << "\n" << IndentTo(indent);
else
out << str[i];
WriteCodePoint(out, codePoint);
}
return true;
}
@@ -108,11 +269,15 @@ namespace YAML
{
unsigned curIndent = out.col();
out << "#" << Indentation(postCommentIndent);
for(std::size_t i=0;i<str.size();i++) {
if(str[i] == '\n')
int codePoint;
for(std::string::const_iterator i = str.begin();
GetNextCodePointAndAdvance(codePoint, i, str.end());
)
{
if(codePoint == '\n')
out << "\n" << IndentTo(curIndent) << "#" << Indentation(postCommentIndent);
else
out << str[i];
WriteCodePoint(out, codePoint);
}
return true;
}
@@ -120,24 +285,32 @@ namespace YAML
bool WriteAlias(ostream& out, const std::string& str)
{
out << "*";
for(std::size_t i=0;i<str.size();i++) {
if(!IsPrintable(str[i]) || str[i] == ' ' || str[i] == '\t' || str[i] == '\n' || str[i] == '\r')
return false;
out << str[i];
}
return true;
return WriteAliasName(out, str);
}
bool WriteAnchor(ostream& out, const std::string& str)
{
out << "&";
for(std::size_t i=0;i<str.size();i++) {
if(!IsPrintable(str[i]) || str[i] == ' ' || str[i] == '\t' || str[i] == '\n' || str[i] == '\r')
return WriteAliasName(out, str);
}
bool WriteTag(ostream& out, const std::string& str, bool verbatim)
{
out << (verbatim ? "!<" : "!");
StringCharSource buffer(str.c_str(), str.size());
const RegEx& reValid = verbatim ? Exp::URI() : Exp::Tag();
while(buffer) {
int n = reValid.Match(buffer);
if(n <= 0)
return false;
out << str[i];
while(--n >= 0) {
out << buffer[0];
++buffer;
}
}
if (verbatim)
out << ">";
return true;
}
}
+3 -2
View File
@@ -11,13 +11,14 @@ namespace YAML
{
namespace Utils
{
bool WriteString(ostream& out, const std::string& str, bool inFlow);
bool WriteString(ostream& out, const std::string& str, bool inFlow, bool escapeNonAscii);
bool WriteSingleQuotedString(ostream& out, const std::string& str);
bool WriteDoubleQuotedString(ostream& out, const std::string& str);
bool WriteDoubleQuotedString(ostream& out, const std::string& str, bool escapeNonAscii);
bool WriteLiteralString(ostream& out, const std::string& str, int indent);
bool WriteComment(ostream& out, const std::string& str, int postCommentIndent);
bool WriteAlias(ostream& out, const std::string& str);
bool WriteAnchor(ostream& out, const std::string& str);
bool WriteTag(ostream& out, const std::string& str, bool verbatim);
}
}
+2 -3
View File
@@ -1,4 +1,3 @@
#include "crt.h"
#include "exp.h"
#include "exceptions.h"
#include <sstream>
@@ -28,9 +27,9 @@ namespace YAML
return value;
}
std::string Str(char ch)
std::string Str(unsigned ch)
{
return std::string("") + ch;
return std::string(1, static_cast<char>(ch));
}
// Escape
+138 -28
View File
@@ -17,45 +17,153 @@ namespace YAML
namespace Exp
{
// misc
const RegEx Space = RegEx(' ');
const RegEx Tab = RegEx('\t');
const RegEx Blank = Space || Tab;
const RegEx Break = RegEx('\n') || RegEx("\r\n");
const RegEx BlankOrBreak = Blank || Break;
const RegEx Digit = RegEx('0', '9');
const RegEx Alpha = RegEx('a', 'z') || RegEx('A', 'Z');
const RegEx AlphaNumeric = Alpha || Digit;
const RegEx Hex = Digit || RegEx('A', 'F') || RegEx('a', 'f');
const RegEx Printable = RegEx(0x20, 0x7E);
inline const RegEx& Space() {
static const RegEx e = RegEx(' ');
return e;
}
inline const RegEx& Tab() {
static const RegEx e = RegEx('\t');
return e;
}
inline const RegEx& Blank() {
static const RegEx e = Space() || Tab();
return e;
}
inline const RegEx& Break() {
static const RegEx e = RegEx('\n') || RegEx("\r\n");
return e;
}
inline const RegEx& BlankOrBreak() {
static const RegEx e = Blank() || Break();
return e;
}
inline const RegEx& Digit() {
static const RegEx e = RegEx('0', '9');
return e;
}
inline const RegEx& Alpha() {
static const RegEx e = RegEx('a', 'z') || RegEx('A', 'Z');
return e;
}
inline const RegEx& AlphaNumeric() {
static const RegEx e = Alpha() || Digit();
return e;
}
inline const RegEx& Word() {
static const RegEx e = AlphaNumeric() || RegEx('-');
return e;
}
inline const RegEx& Hex() {
static const RegEx e = Digit() || RegEx('A', 'F') || RegEx('a', 'f');
return e;
}
// Valid Unicode code points that are not part of c-printable (YAML 1.2, sec. 5.1)
inline const RegEx& NotPrintable() {
static const RegEx e = RegEx(0) ||
RegEx("\x01\x02\x03\x04\x05\x06\x07\x08\x0B\x0C\x7F", REGEX_OR) ||
RegEx(0x0E, 0x1F) ||
(RegEx('\xC2') + (RegEx('\x80', '\x84') || RegEx('\x86', '\x9F')));
return e;
}
inline const RegEx& Utf8_ByteOrderMark() {
static const RegEx e = RegEx("\xEF\xBB\xBF");
return e;
}
// actual tags
const RegEx DocStart = RegEx("---") + (BlankOrBreak || RegEx());
const RegEx DocEnd = RegEx("...") + (BlankOrBreak || RegEx());
const RegEx DocIndicator = DocStart || DocEnd;
const RegEx BlockEntry = RegEx('-') + (BlankOrBreak || RegEx());
const RegEx Key = RegEx('?'),
KeyInFlow = RegEx('?') + BlankOrBreak;
const RegEx Value = RegEx(':') + (BlankOrBreak || RegEx()),
ValueInFlow = RegEx(':') + (BlankOrBreak || RegEx(",}", REGEX_OR));
const RegEx Comment = RegEx('#');
const RegEx AnchorEnd = RegEx("?:,]}%@`", REGEX_OR) || BlankOrBreak;
inline const RegEx& DocStart() {
static const RegEx e = RegEx("---") + (BlankOrBreak() || RegEx());
return e;
}
inline const RegEx& DocEnd() {
static const RegEx e = RegEx("...") + (BlankOrBreak() || RegEx());
return e;
}
inline const RegEx& DocIndicator() {
static const RegEx e = DocStart() || DocEnd();
return e;
}
inline const RegEx& BlockEntry() {
static const RegEx e = RegEx('-') + (BlankOrBreak() || RegEx());
return e;
}
inline const RegEx& Key() {
static const RegEx e = RegEx('?');
return e;
}
inline const RegEx& KeyInFlow() {
static const RegEx e = RegEx('?') + BlankOrBreak();
return e;
}
inline const RegEx& Value() {
static const RegEx e = RegEx(':') + (BlankOrBreak() || RegEx());
return e;
}
inline const RegEx& ValueInFlow() {
static const RegEx e = RegEx(':') + (BlankOrBreak() || RegEx(",}", REGEX_OR));
return e;
}
inline const RegEx& ValueInJSONFlow() {
static const RegEx e = RegEx(':');
return e;
}
inline const RegEx Comment() {
static const RegEx e = RegEx('#');
return e;
}
inline const RegEx& AnchorEnd() {
static const RegEx e = RegEx("?:,]}%@`", REGEX_OR) || BlankOrBreak();
return e;
}
inline const RegEx& URI() {
static const RegEx e = Word() || RegEx("#;/?:@&=+$,_.!~*'()[]", REGEX_OR) || (RegEx('%') + Hex() + Hex());
return e;
}
inline const RegEx& Tag() {
static const RegEx e = Word() || RegEx("#;/?:@&=+$_.~*'", REGEX_OR) || (RegEx('%') + Hex() + Hex());
return e;
}
// Plain scalar rules:
// . Cannot start with a blank.
// . Can never start with any of , [ ] { } # & * ! | > \' \" % @ `
// . In the block context - ? : must be not be followed with a space.
// . In the flow context ? is illegal and : and - must not be followed with a space.
const RegEx PlainScalar = !(BlankOrBreak || RegEx(",[]{}#&*!|>\'\"%@`", REGEX_OR) || (RegEx("-?:", REGEX_OR) + Blank)),
PlainScalarInFlow = !(BlankOrBreak || RegEx("?,[]{}#&*!|>\'\"%@`", REGEX_OR) || (RegEx("-:", REGEX_OR) + Blank));
const RegEx EndScalar = RegEx(':') + (BlankOrBreak || RegEx()),
EndScalarInFlow = (RegEx(':') + (BlankOrBreak || RegEx(",]}", REGEX_OR))) || RegEx(",?[]{}", REGEX_OR);
inline const RegEx& PlainScalar() {
static const RegEx e = !(BlankOrBreak() || RegEx(",[]{}#&*!|>\'\"%@`", REGEX_OR) || (RegEx("-?:", REGEX_OR) + Blank()));
return e;
}
inline const RegEx& PlainScalarInFlow() {
static const RegEx e = !(BlankOrBreak() || RegEx("?,[]{}#&*!|>\'\"%@`", REGEX_OR) || (RegEx("-:", REGEX_OR) + Blank()));
return e;
}
inline const RegEx& EndScalar() {
static const RegEx e = RegEx(':') + (BlankOrBreak() || RegEx());
return e;
}
inline const RegEx& EndScalarInFlow() {
static const RegEx e = (RegEx(':') + (BlankOrBreak() || RegEx(",]}", REGEX_OR))) || RegEx(",?[]{}", REGEX_OR);
return e;
}
const RegEx EscSingleQuote = RegEx("\'\'");
const RegEx EscBreak = RegEx('\\') + Break;
inline const RegEx& EscSingleQuote() {
static const RegEx e = RegEx("\'\'");
return e;
}
inline const RegEx& EscBreak() {
static const RegEx e = RegEx('\\') + Break();
return e;
}
const RegEx ChompIndicator = RegEx("+-", REGEX_OR);
const RegEx Chomp = (ChompIndicator + Digit) || (Digit + ChompIndicator) || ChompIndicator || Digit;
inline const RegEx& ChompIndicator() {
static const RegEx e = RegEx("+-", REGEX_OR);
return e;
}
inline const RegEx& Chomp() {
static const RegEx e = (ChompIndicator() + Digit()) || (Digit() + ChompIndicator()) || ChompIndicator() || Digit();
return e;
}
// and some functions
std::string Escape(Stream& in);
@@ -74,6 +182,8 @@ namespace YAML
const char Tag = '!';
const char LiteralScalar = '|';
const char FoldedScalar = '>';
const char VerbatimTagStart = '<';
const char VerbatimTagEnd = '>';
}
}
+96
View File
@@ -0,0 +1,96 @@
#include "graphbuilderadapter.h"
namespace YAML
{
int GraphBuilderAdapter::ContainerFrame::sequenceMarker;
void GraphBuilderAdapter::OnNull(const std::string& tag, anchor_t anchor)
{
void *pParent = GetCurrentParent();
void *pNode = m_builder.NewNull(tag, pParent);
RegisterAnchor(anchor, pNode);
DispositionNode(pNode);
}
void GraphBuilderAdapter::OnAlias(const Mark& mark, anchor_t anchor)
{
void *pReffedNode = m_anchors.Get(anchor);
DispositionNode(m_builder.AnchorReference(mark, pReffedNode));
}
void GraphBuilderAdapter::OnScalar(const Mark& mark, const std::string& tag, anchor_t anchor, const std::string& value)
{
void *pParent = GetCurrentParent();
void *pNode = m_builder.NewScalar(mark, tag, pParent, value);
RegisterAnchor(anchor, pNode);
DispositionNode(pNode);
}
void GraphBuilderAdapter::OnSequenceStart(const Mark& mark, const std::string& tag, anchor_t anchor)
{
void *pNode = m_builder.NewSequence(mark, tag, GetCurrentParent());
m_containers.push(ContainerFrame(pNode));
RegisterAnchor(anchor, pNode);
}
void GraphBuilderAdapter::OnSequenceEnd()
{
void *pSequence = m_containers.top().pContainer;
m_containers.pop();
DispositionNode(pSequence);
}
void GraphBuilderAdapter::OnMapStart(const Mark& mark, const std::string& tag, anchor_t anchor)
{
void *pNode = m_builder.NewMap(mark, tag, GetCurrentParent());
m_containers.push(ContainerFrame(pNode, m_pKeyNode));
m_pKeyNode = NULL;
RegisterAnchor(anchor, pNode);
}
void GraphBuilderAdapter::OnMapEnd()
{
void *pMap = m_containers.top().pContainer;
m_pKeyNode = m_containers.top().pPrevKeyNode;
m_containers.pop();
DispositionNode(pMap);
}
void *GraphBuilderAdapter::GetCurrentParent() const
{
if (m_containers.empty()) {
return NULL;
}
return m_containers.top().pContainer;
}
void GraphBuilderAdapter::RegisterAnchor(anchor_t anchor, void *pNode)
{
if (anchor) {
m_anchors.Register(anchor, pNode);
}
}
void GraphBuilderAdapter::DispositionNode(void *pNode)
{
if (m_containers.empty()) {
m_pRootNode = pNode;
return;
}
void *pContainer = m_containers.top().pContainer;
if (m_containers.top().isMap()) {
if (m_pKeyNode) {
m_builder.AssignInMap(pContainer, m_pKeyNode, pNode);
m_pKeyNode = NULL;
} else {
m_pKeyNode = pNode;
}
} else {
m_builder.AppendToSequence(pContainer, pNode);
}
}
}
+68
View File
@@ -0,0 +1,68 @@
#ifndef GRAPHBUILDERADAPTER_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#define GRAPHBUILDERADAPTER_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#include <map>
#include <stack>
#include "anchordict.h"
#include "eventhandler.h"
#include "graphbuilder.h"
namespace YAML
{
class GraphBuilderAdapter : public EventHandler
{
public:
GraphBuilderAdapter(GraphBuilderInterface& builder)
: m_builder(builder), m_pRootNode(NULL), m_pKeyNode(NULL)
{
}
virtual void OnDocumentStart(const Mark& mark) {(void)mark;}
virtual void OnDocumentEnd() {}
virtual void OnNull(const std::string& tag, anchor_t anchor);
virtual void OnAlias(const Mark& mark, anchor_t anchor);
virtual void OnScalar(const Mark& mark, const std::string& tag, anchor_t anchor, const std::string& value);
virtual void OnSequenceStart(const Mark& mark, const std::string& tag, anchor_t anchor);
virtual void OnSequenceEnd();
virtual void OnMapStart(const Mark& mark, const std::string& tag, anchor_t anchor);
virtual void OnMapEnd();
void *RootNode() const {return m_pRootNode;}
private:
struct ContainerFrame
{
ContainerFrame(void *pSequence)
: pContainer(pSequence), pPrevKeyNode(&sequenceMarker)
{}
ContainerFrame(void *pMap, void* pPrevKeyNode)
: pContainer(pMap), pPrevKeyNode(pPrevKeyNode)
{}
void *pContainer;
void *pPrevKeyNode;
bool isMap() const {return pPrevKeyNode != &sequenceMarker;}
private:
static int sequenceMarker;
};
typedef std::stack<ContainerFrame> ContainerStack;
typedef AnchorDict<void*> AnchorMap;
GraphBuilderInterface& m_builder;
ContainerStack m_containers;
AnchorMap m_anchors;
void *m_pRootNode;
void *m_pKeyNode;
void *GetCurrentParent() const;
void RegisterAnchor(anchor_t anchor, void *pNode);
void DispositionNode(void *pNode);
};
}
#endif // GRAPHBUILDERADAPTER_H_62B23520_7C8E_11DE_8A39_0800200C9A66
-1
View File
@@ -1,4 +1,3 @@
#include "crt.h"
#include "node.h"
#include "exceptions.h"
#include "iterpriv.h"
+13 -111
View File
@@ -1,26 +1,13 @@
#include "crt.h"
#include "map.h"
#include "node.h"
#include "scanner.h"
#include "token.h"
#include "eventhandler.h"
#include "exceptions.h"
#include "emitter.h"
#include <memory>
namespace YAML
{
Map::Map()
{
}
Map::Map(const node_map& data)
{
for(node_map::const_iterator it=data.begin();it!=data.end();++it) {
std::auto_ptr<Node> pKey = it->first->Clone();
std::auto_ptr<Node> pValue = it->second->Clone();
m_data[pKey.release()] = pValue.release();
}
}
Map::~Map()
{
@@ -36,11 +23,6 @@ namespace YAML
m_data.clear();
}
Content *Map::Clone() const
{
return new Map(m_data);
}
bool Map::GetBegin(std::map <Node *, Node *, ltnode>::const_iterator& it) const
{
it = m_data.begin();
@@ -58,103 +40,23 @@ namespace YAML
return m_data.size();
}
void Map::Parse(Scanner *pScanner, const ParserState& state)
void Map::Insert(std::auto_ptr<Node> pKey, std::auto_ptr<Node> pValue)
{
Clear();
// split based on start token
switch(pScanner->peek().type) {
case Token::BLOCK_MAP_START: ParseBlock(pScanner, state); break;
case Token::FLOW_MAP_START: ParseFlow(pScanner, state); break;
default: break;
}
node_map::const_iterator it = m_data.find(pKey.get());
if(it != m_data.end())
return;
m_data[pKey.release()] = pValue.release();
}
void Map::ParseBlock(Scanner *pScanner, const ParserState& state)
void Map::EmitEvents(AliasManager& am, EventHandler& eventHandler, const Mark& mark, const std::string& tag, anchor_t anchor) const
{
// eat start token
pScanner->pop();
while(1) {
if(pScanner->empty())
throw ParserException(Mark::null(), ErrorMsg::END_OF_MAP);
Token token = pScanner->peek();
if(token.type != Token::KEY && token.type != Token::VALUE && token.type != Token::BLOCK_MAP_END)
throw ParserException(token.mark, ErrorMsg::END_OF_MAP);
if(token.type == Token::BLOCK_MAP_END) {
pScanner->pop();
break;
}
std::auto_ptr <Node> pKey(new Node), pValue(new Node);
// grab key (if non-null)
if(token.type == Token::KEY) {
pScanner->pop();
pKey->Parse(pScanner, state);
}
// now grab value (optional)
if(!pScanner->empty() && pScanner->peek().type == Token::VALUE) {
pScanner->pop();
pValue->Parse(pScanner, state);
}
// assign the map with the actual pointers
m_data[pKey.release()] = pValue.release();
eventHandler.OnMapStart(mark, tag, anchor);
for(node_map::const_iterator it=m_data.begin();it!=m_data.end();++it) {
it->first->EmitEvents(am, eventHandler);
it->second->EmitEvents(am, eventHandler);
}
}
void Map::ParseFlow(Scanner *pScanner, const ParserState& state)
{
// eat start token
pScanner->pop();
while(1) {
if(pScanner->empty())
throw ParserException(Mark::null(), ErrorMsg::END_OF_MAP_FLOW);
Token& token = pScanner->peek();
// first check for end
if(token.type == Token::FLOW_MAP_END) {
pScanner->pop();
break;
}
std::auto_ptr <Node> pKey(new Node), pValue(new Node);
// grab key (if non-null)
if(token.type == Token::KEY) {
pScanner->pop();
pKey->Parse(pScanner, state);
}
// now grab value (optional)
if(!pScanner->empty() && pScanner->peek().type == Token::VALUE) {
pScanner->pop();
pValue->Parse(pScanner, state);
}
// now eat the separator (or could be a map end, which we ignore - but if it's neither, then it's a bad node)
Token& nextToken = pScanner->peek();
if(nextToken.type == Token::FLOW_ENTRY)
pScanner->pop();
else if(nextToken.type != Token::FLOW_MAP_END)
throw ParserException(nextToken.mark, ErrorMsg::END_OF_MAP_FLOW);
// assign the map with the actual pointers
m_data[pKey.release()] = pValue.release();
}
}
void Map::Write(Emitter& out) const
{
out << BeginMap;
for(node_map::const_iterator it=m_data.begin();it!=m_data.end();++it)
out << Key << *it->first << Value << *it->second;
out << EndMap;
eventHandler.OnMapEnd();
}
int Map::Compare(Content *pContent)
+4 -8
View File
@@ -6,6 +6,7 @@
#include "content.h"
#include <map>
#include <memory>
namespace YAML
{
@@ -18,17 +19,16 @@ namespace YAML
public:
Map();
Map(const node_map& data);
virtual ~Map();
void Clear();
virtual Content *Clone() const;
virtual bool GetBegin(std::map <Node *, Node *, ltnode>::const_iterator& it) const;
virtual bool GetEnd(std::map <Node *, Node *, ltnode>::const_iterator& it) const;
virtual std::size_t GetSize() const;
virtual void Parse(Scanner *pScanner, const ParserState& state);
virtual void Write(Emitter& out) const;
virtual void Insert(std::auto_ptr<Node> pKey, std::auto_ptr<Node> pValue);
virtual void EmitEvents(AliasManager& am, EventHandler& eventHandler, const Mark& mark, const std::string& tag, anchor_t anchor) const;
virtual bool IsMap() const { return true; }
@@ -38,10 +38,6 @@ namespace YAML
virtual int Compare(Sequence *) { return 1; }
virtual int Compare(Map *pMap);
private:
void ParseBlock(Scanner *pScanner, const ParserState& state);
void ParseFlow(Scanner *pScanner, const ParserState& state);
private:
node_map m_data;
};
+93 -129
View File
@@ -1,15 +1,21 @@
#include "crt.h"
#include "node.h"
#include "token.h"
#include "scanner.h"
#include "content.h"
#include "parser.h"
#include "scalar.h"
#include "sequence.h"
#include "map.h"
#include "aliascontent.h"
#include "iterpriv.h"
#include "aliasmanager.h"
#include "content.h"
#include "emitfromevents.h"
#include "emitter.h"
#include "eventhandler.h"
#include "graphbuilderadapter.h"
#include "iterpriv.h"
#include "map.h"
#include "nodebuilder.h"
#include "nodeproperties.h"
#include "scalar.h"
#include "scanner.h"
#include "sequence.h"
#include "tag.h"
#include "token.h"
#include <cassert>
#include <stdexcept>
namespace YAML
@@ -20,17 +26,10 @@ namespace YAML
return *pNode1 < *pNode2;
}
Node::Node(): m_pContent(0), m_alias(false), m_pIdentity(this), m_referenced(true)
Node::Node(): m_pContent(0), m_alias(false), m_pIdentity(this), m_referenced(false)
{
}
Node::Node(const Mark& mark, const std::string& anchor, const std::string& tag, const Content *pContent)
: m_mark(mark), m_anchor(anchor), m_tag(tag), m_pContent(0), m_alias(false), m_pIdentity(this), m_referenced(false)
{
if(m_pContent)
m_pContent = pContent->Clone();
}
Node::~Node()
{
Clear();
@@ -42,131 +41,107 @@ namespace YAML
m_pContent = 0;
m_alias = false;
m_referenced = false;
m_anchor.clear();
m_tag.clear();
}
std::auto_ptr<Node> Node::Clone() const
{
if(m_alias)
throw std::runtime_error("yaml-cpp: Can't clone alias"); // TODO: what to do about aliases?
return std::auto_ptr<Node> (new Node(m_mark, m_anchor, m_tag, m_pContent));
std::auto_ptr<Node> pNode(new Node);
NodeBuilder nodeBuilder(*pNode);
GraphBuilder<NodeBuilder> graphBuilder(nodeBuilder);
GraphBuilderAdapter eventHandler(graphBuilder);
EmitEvents(eventHandler);
return pNode;
}
void Node::Parse(Scanner *pScanner, const ParserState& state)
void Node::EmitEvents(EventHandler& eventHandler) const
{
eventHandler.OnDocumentStart(m_mark);
AliasManager am;
EmitEvents(am, eventHandler);
eventHandler.OnDocumentEnd();
}
void Node::EmitEvents(AliasManager& am, EventHandler& eventHandler) const
{
anchor_t anchor = NullAnchor;
if(m_referenced || m_alias) {
if(const Node *pOther = am.LookupReference(*this)) {
eventHandler.OnAlias(m_mark, am.LookupAnchor(*pOther));
return;
}
am.RegisterReference(*this);
anchor = am.LookupAnchor(*this);
}
if(m_pContent)
m_pContent->EmitEvents(am, eventHandler, m_mark, GetTag(), anchor);
else
eventHandler.OnNull(GetTag(), anchor);
}
void Node::Init(CONTENT_TYPE type, const Mark& mark, const std::string& tag)
{
Clear();
m_mark = mark;
m_tag = tag;
m_alias = false;
m_pIdentity = this;
m_referenced = false;
// an empty node *is* a possibility
if(pScanner->empty())
return;
// save location
m_mark = pScanner->peek().mark;
ParseHeader(pScanner, state);
// is this an alias? if so, its contents are an alias to
// a previously defined anchor
if(m_alias) {
// the scanner throws an exception if it doesn't know this anchor name
const Node *pReferencedNode = pScanner->Retrieve(m_anchor);
m_pIdentity = pReferencedNode;
// mark the referenced node for the sake of the client code
pReferencedNode->m_referenced = true;
// use of an Alias object keeps the referenced content from
// being deleted twice
Content *pAliasedContent = pReferencedNode->m_pContent;
if(pAliasedContent)
m_pContent = new AliasContent(pAliasedContent);
return;
}
// now split based on what kind of node we should be
switch(pScanner->peek().type) {
case Token::SCALAR:
switch(type) {
case CT_SCALAR:
m_pContent = new Scalar;
break;
case Token::FLOW_SEQ_START:
case Token::BLOCK_SEQ_START:
case CT_SEQUENCE:
m_pContent = new Sequence;
break;
case Token::FLOW_MAP_START:
case Token::BLOCK_MAP_START:
case CT_MAP:
m_pContent = new Map;
break;
default:
// std::stringstream str;
// str << TokenNames[pScanner->peek().type];
// throw std::runtime_error(str.str());
m_pContent = 0;
break;
}
// Have to save anchor before parsing to allow for aliases as
// contained node (recursive structure)
if(!m_anchor.empty())
pScanner->Save(m_anchor, this);
if(m_pContent)
m_pContent->Parse(pScanner, state);
}
// ParseHeader
// . Grabs any tag, alias, or anchor tokens and deals with them.
void Node::ParseHeader(Scanner *pScanner, const ParserState& state)
void Node::InitNull(const std::string& tag)
{
while(1) {
if(pScanner->empty())
return;
switch(pScanner->peek().type) {
case Token::TAG: ParseTag(pScanner, state); break;
case Token::ANCHOR: ParseAnchor(pScanner, state); break;
case Token::ALIAS: ParseAlias(pScanner, state); break;
default: return;
}
}
Clear();
m_tag = tag;
m_alias = false;
m_pIdentity = this;
m_referenced = false;
}
void Node::ParseTag(Scanner *pScanner, const ParserState& state)
void Node::InitAlias(const Mark& mark, const Node& identity)
{
Token& token = pScanner->peek();
if(m_tag != "")
throw ParserException(token.mark, ErrorMsg::MULTIPLE_TAGS);
Clear();
m_mark = mark;
m_alias = true;
m_pIdentity = &identity;
if(identity.m_pContent)
m_pContent = new AliasContent(identity.m_pContent);
identity.m_referenced = true;
}
m_tag = state.TranslateTag(token.value);
void Node::SetData(const std::string& data)
{
assert(m_pContent); // TODO: throw
m_pContent->SetData(data);
}
for(std::size_t i=0;i<token.params.size();i++)
m_tag += token.params[i];
pScanner->pop();
void Node::Append(std::auto_ptr<Node> pNode)
{
assert(m_pContent); // TODO: throw
m_pContent->Append(pNode);
}
void Node::ParseAnchor(Scanner *pScanner, const ParserState& /*state*/)
void Node::Insert(std::auto_ptr<Node> pKey, std::auto_ptr<Node> pValue)
{
Token& token = pScanner->peek();
if(m_anchor != "")
throw ParserException(token.mark, ErrorMsg::MULTIPLE_ANCHORS);
m_anchor = token.value;
m_alias = false;
pScanner->pop();
}
void Node::ParseAlias(Scanner *pScanner, const ParserState& /*state*/)
{
Token& token = pScanner->peek();
if(m_anchor != "")
throw ParserException(token.mark, ErrorMsg::MULTIPLE_ALIASES);
if(m_tag != "")
throw ParserException(token.mark, ErrorMsg::ALIAS_CONTENT);
m_anchor = token.value;
m_alias = true;
pScanner->pop();
assert(m_pContent); // TODO: throw
m_pContent->Insert(pKey, pValue);
}
CONTENT_TYPE Node::GetType() const
@@ -242,7 +217,10 @@ namespace YAML
bool Node::GetScalar(std::string& s) const
{
if(!m_pContent) {
s = "~";
if(m_tag.empty())
s = "~";
else
s = "";
return true;
}
@@ -251,22 +229,8 @@ namespace YAML
Emitter& operator << (Emitter& out, const Node& node)
{
// write anchor/alias
if(node.m_anchor != "") {
if(node.m_alias)
out << Alias(node.m_anchor);
else
out << Anchor(node.m_anchor);
}
// TODO: write tag
// write content
if(node.m_pContent)
node.m_pContent->Write(out);
else if(!node.m_alias)
out << Null;
EmitFromEvents emitFromEvents(out);
node.EmitEvents(emitFromEvents);
return out;
}
+90
View File
@@ -0,0 +1,90 @@
#include "nodebuilder.h"
#include "mark.h"
#include "node.h"
#include "nodeproperties.h"
#include <cassert>
namespace YAML
{
NodeBuilder::NodeBuilder(Node& root): m_root(root), m_initializedRoot(false)
{
m_root.Clear();
}
NodeBuilder::NodeBuilder(const NodeBuilder& o): m_root(o.m_root), m_initializedRoot(o.m_initializedRoot)
{
}
NodeBuilder::~NodeBuilder()
{
}
Node *NodeBuilder::NewNull(const std::string& tag, Node *pParent)
{
(void)pParent;
Node *pNode = NewNode();
pNode->InitNull(tag);
return pNode;
}
Node *NodeBuilder::AnchorReference(const Mark& mark, Node *pNode)
{
Node *pAlias = NewNode();
pAlias->InitAlias(mark, *pNode);
return pAlias;
}
Node *NodeBuilder::NewScalar(const Mark& mark, const std::string& tag, Node *pParent, const std::string& value)
{
(void)pParent;
Node *pNode = NewNode();
pNode->Init(CT_SCALAR, mark, tag);
pNode->SetData(value);
return pNode;
}
NodeBuilder::Sequence *NodeBuilder::NewSequence(const Mark& mark, const std::string& tag, Node *pParent)
{
(void)pParent;
Node *pNode = NewNode();
pNode->Init(CT_SEQUENCE, mark, tag);
return pNode;
}
void NodeBuilder::AppendToSequence(Sequence *pSequence, Node *pNode)
{
std::auto_ptr<Node> apNode(m_unlinked.pop(pNode));
assert(apNode.get());
pSequence->Append(apNode);
}
NodeBuilder::Map *NodeBuilder::NewMap(const Mark& mark, const std::string& tag, Node* pParent)
{
(void)pParent;
Node *pNode = NewNode();
pNode->Init(CT_MAP, mark, tag);
return pNode;
}
void NodeBuilder::AssignInMap(Map *pMap, Node *pKeyNode, Node *pValueNode)
{
std::auto_ptr<Node> apKeyNode(m_unlinked.pop(pKeyNode));
std::auto_ptr<Node> apValueNode(m_unlinked.pop(pValueNode));
assert(apKeyNode.get() && apValueNode.get());
pMap->Insert(apKeyNode, apValueNode);
}
Node* NodeBuilder::NewNode()
{
if(!m_initializedRoot) {
m_initializedRoot = true;
return &m_root;
}
std::auto_ptr<Node> pNode(new Node);
Node* pResult = pNode.get();
// Save the pointer in a collection that will free it on exception
m_unlinked.push(pNode);
return pResult;
}
}
+53
View File
@@ -0,0 +1,53 @@
#pragma once
#ifndef NODEBUILDER_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#define NODEBUILDER_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#include <map>
#include <memory>
#include <stack>
#include <string>
#include "ptr_stack.h"
namespace YAML
{
class Node;
class Mark;
class NodeBuilder
{
public:
typedef YAML::Node Node;
typedef YAML::Node Map;
typedef YAML::Node Sequence;
explicit NodeBuilder(Node& root);
NodeBuilder(const NodeBuilder& o);
virtual ~NodeBuilder();
Node *NewNull(const std::string& tag, Node *pParent);
Node *AnchorReference(const Mark& mark, Node *pNode);
Node *NewScalar(const Mark& mark, const std::string& tag, Node *pParent, const std::string& value);
Sequence *NewSequence(const Mark& mark, const std::string& tag, Node *pParent);
void AppendToSequence(Sequence *pSequence, Node *pNode);
void SequenceComplete(Sequence *pSequence) {(void)pSequence;}
Map *NewMap(const Mark& mark, const std::string& tag, Node *pParent);
void AssignInMap(Map *pMap, Node *pKeyNode, Node *pValueNode);
void MapComplete(Map *pMap) {(void)pMap;}
private:
Node* NewNode();
private:
Node& m_root;
bool m_initializedRoot;
ptr_stack<Node> m_unlinked;
};
}
#endif // NODEBUILDER_H_62B23520_7C8E_11DE_8A39_0800200C9A66
+83 -54
View File
@@ -1,63 +1,81 @@
#include "crt.h"
#include "parser.h"
#include "scanner.h"
#include "token.h"
#include "directives.h"
#include "eventhandler.h"
#include "exceptions.h"
#include "graphbuilderadapter.h"
#include "node.h"
#include "nodebuilder.h"
#include "scanner.h"
#include "singledocparser.h"
#include "tag.h"
#include "token.h"
#include <sstream>
#include <cstdio>
namespace YAML
{
Parser::Parser(std::istream& in): m_pScanner(0)
Parser::Parser()
{
}
Parser::Parser(std::istream& in)
{
Load(in);
}
Parser::~Parser()
{
delete m_pScanner;
}
Parser::operator bool() const
{
return !m_pScanner->empty();
return m_pScanner.get() && !m_pScanner->empty();
}
void Parser::Load(std::istream& in)
{
delete m_pScanner;
m_pScanner = new Scanner(in);
m_state.Reset();
m_pScanner.reset(new Scanner(in));
m_pDirectives.reset(new Directives);
}
// HandleNextDocument
// . Handles the next document
// . Throws a ParserException on error.
// . Returns false if there are no more documents
bool Parser::HandleNextDocument(EventHandler& eventHandler)
{
if(!m_pScanner.get())
return false;
ParseDirectives();
if(m_pScanner->empty())
return false;
SingleDocParser sdp(*m_pScanner, *m_pDirectives);
sdp.HandleDocument(eventHandler);
return true;
}
// BuildNextDocumentGraph
// . Builds a graph of the next document
// . Returns NULL if there are no more documents
void *Parser::BuildNextDocumentGraph(GraphBuilderInterface& graphBuilder)
{
GraphBuilderAdapter eventHandler(graphBuilder);
if (HandleNextDocument(eventHandler)) {
return eventHandler.RootNode();
} else {
return NULL;
}
}
// GetNextDocument
// . Reads the next document in the queue (of tokens).
// . Throws a ParserException on error.
void Parser::GetNextDocument(Node& document)
bool Parser::GetNextDocument(Node& document)
{
// clear node
document.Clear();
// first read directives
ParseDirectives();
// we better have some tokens in the queue
if(m_pScanner->empty())
return;
// first eat doc start (optional)
if(m_pScanner->peek().type == Token::DOC_START)
m_pScanner->pop();
// now parse our root node
document.Parse(m_pScanner, m_state);
// and finally eat any doc ends we see
while(!m_pScanner->empty() && m_pScanner->peek().type == Token::DOC_END)
m_pScanner->pop();
// clear anchors from the scanner, which are no longer relevant
m_pScanner->ClearAnchors();
NodeBuilder builder(document);
return BuildNextDocumentGraph(builder);
}
// ParseDirectives
@@ -77,55 +95,66 @@ namespace YAML
// we keep the directives from the last document if none are specified;
// but if any directives are specific, then we reset them
if(!readDirective)
m_state.Reset();
m_pDirectives.reset(new Directives);
readDirective = true;
HandleDirective(&token);
HandleDirective(token);
m_pScanner->pop();
}
}
void Parser::HandleDirective(Token *pToken)
void Parser::HandleDirective(const Token& token)
{
if(pToken->value == "YAML")
HandleYamlDirective(pToken);
else if(pToken->value == "TAG")
HandleTagDirective(pToken);
if(token.value == "YAML")
HandleYamlDirective(token);
else if(token.value == "TAG")
HandleTagDirective(token);
}
// HandleYamlDirective
// . Should be of the form 'major.minor' (like a version number)
void Parser::HandleYamlDirective(Token *pToken)
void Parser::HandleYamlDirective(const Token& token)
{
if(pToken->params.size() != 1)
throw ParserException(pToken->mark, ErrorMsg::YAML_DIRECTIVE_ARGS);
if(token.params.size() != 1)
throw ParserException(token.mark, ErrorMsg::YAML_DIRECTIVE_ARGS);
if(!m_pDirectives->version.isDefault)
throw ParserException(token.mark, ErrorMsg::REPEATED_YAML_DIRECTIVE);
std::stringstream str(pToken->params[0]);
str >> m_state.version.major;
std::stringstream str(token.params[0]);
str >> m_pDirectives->version.major;
str.get();
str >> m_state.version.minor;
str >> m_pDirectives->version.minor;
if(!str || str.peek() != EOF)
throw ParserException(pToken->mark, ErrorMsg::YAML_VERSION + pToken->params[0]);
throw ParserException(token.mark, ErrorMsg::YAML_VERSION + token.params[0]);
if(m_state.version.major > 1)
throw ParserException(pToken->mark, ErrorMsg::YAML_MAJOR_VERSION);
if(m_pDirectives->version.major > 1)
throw ParserException(token.mark, ErrorMsg::YAML_MAJOR_VERSION);
m_pDirectives->version.isDefault = false;
// TODO: warning on major == 1, minor > 2?
}
// HandleTagDirective
// . Should be of the form 'handle prefix', where 'handle' is converted to 'prefix' in the file.
void Parser::HandleTagDirective(Token *pToken)
void Parser::HandleTagDirective(const Token& token)
{
if(pToken->params.size() != 2)
throw ParserException(pToken->mark, ErrorMsg::TAG_DIRECTIVE_ARGS);
if(token.params.size() != 2)
throw ParserException(token.mark, ErrorMsg::TAG_DIRECTIVE_ARGS);
std::string handle = pToken->params[0], prefix = pToken->params[1];
m_state.tags[handle] = prefix;
const std::string& handle = token.params[0];
const std::string& prefix = token.params[1];
if(m_pDirectives->tags.find(handle) != m_pDirectives->tags.end())
throw ParserException(token.mark, ErrorMsg::REPEATED_TAG_DIRECTIVE);
m_pDirectives->tags[handle] = prefix;
}
void Parser::PrintTokens(std::ostream& out)
{
if(!m_pScanner.get())
return;
while(1) {
if(m_pScanner->empty())
break;
-26
View File
@@ -1,26 +0,0 @@
#include "crt.h"
#include "parserstate.h"
namespace YAML
{
void ParserState::Reset()
{
// version
version.major = 1;
version.minor = 2;
// and tags
tags.clear();
tags["!"] = "!";
tags["!!"] = "tag:yaml.org,2002:";
}
std::string ParserState::TranslateTag(const std::string& handle) const
{
std::map <std::string, std::string>::const_iterator it = tags.find(handle);
if(it == tags.end())
return handle;
return it->second;
}
}
+55
View File
@@ -0,0 +1,55 @@
#pragma once
#ifndef PTR_STACK_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#define PTR_STACK_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#include <algorithm>
#include <memory>
#include <vector>
#include "noncopyable.h"
template <typename T>
class ptr_stack : private YAML::noncopyable
{
public:
ptr_stack() {}
~ptr_stack() { clear(); }
void clear() {
for(unsigned i=0;i<m_data.size();i++)
delete m_data[i];
m_data.clear();
}
std::size_t size() const { return m_data.size(); }
bool empty() const { return m_data.empty(); }
void push(std::auto_ptr<T> t) {
// Make sure that the space is available before releasing the
// auto_ptr to it. NULL can be deleted safely.
m_data.push_back(NULL);
m_data.back() = t.release();
}
std::auto_ptr<T> pop() {
std::auto_ptr<T> t(m_data.back());
m_data.pop_back();
return t;
}
std::auto_ptr<T> pop(T* val) {
typename std::vector<T*>::reverse_iterator itVal =
std::find(m_data.rbegin(), m_data.rend(), val);
std::auto_ptr<T> t;
if (itVal != m_data.rend()) {
t.reset(*itVal);
m_data.erase((itVal + 1).base());
}
return t;
}
T& top() const { return *m_data.back(); }
private:
std::vector<T*> m_data;
};
#endif // PTR_STACK_H_62B23520_7C8E_11DE_8A39_0800200C9A66
-1
View File
@@ -1,4 +1,3 @@
#include "crt.h"
#include "regex.h"
namespace YAML
+1 -1
View File
@@ -37,12 +37,12 @@ namespace YAML
int Match(const std::string& str) const;
int Match(const Stream& in) const;
template <typename Source> int Match(const Source& source) const;
private:
RegEx(REGEX_OP op);
template <typename Source> bool IsValidSource(const Source& source) const;
template <typename Source> int Match(const Source& source) const;
template <typename Source> int MatchUnchecked(const Source& source) const;
template <typename Source> int MatchOpEmpty(const Source& source) const;
+3 -24
View File
@@ -1,10 +1,5 @@
#include "crt.h"
#include "scalar.h"
#include "scanner.h"
#include "token.h"
#include "exceptions.h"
#include "node.h"
#include "emitter.h"
#include "eventhandler.h"
namespace YAML
{
@@ -12,29 +7,13 @@ namespace YAML
{
}
Scalar::Scalar(const std::string& data): m_data(data)
{
}
Scalar::~Scalar()
{
}
Content *Scalar::Clone() const
void Scalar::EmitEvents(AliasManager&, EventHandler& eventHandler, const Mark& mark, const std::string& tag, anchor_t anchor) const
{
return new Scalar(m_data);
}
void Scalar::Parse(Scanner *pScanner, const ParserState& /*state*/)
{
Token& token = pScanner->peek();
m_data = token.value;
pScanner->pop();
}
void Scalar::Write(Emitter& out) const
{
out << m_data;
eventHandler.OnScalar(mark, tag, anchor, m_data);
}
int Scalar::Compare(Content *pContent)
+2 -5
View File
@@ -13,15 +13,12 @@ namespace YAML
{
public:
Scalar();
Scalar(const std::string& data);
virtual ~Scalar();
virtual Content *Clone() const;
virtual void Parse(Scanner *pScanner, const ParserState& state);
virtual void Write(Emitter& out) const;
virtual void SetData(const std::string& data) { m_data = data; }
virtual bool IsScalar() const { return true; }
virtual void EmitEvents(AliasManager& am, EventHandler& eventHandler, const Mark& mark, const std::string& tag, anchor_t anchor) const;
// extraction
virtual bool GetScalar(std::string& scalar) const {
+67 -69
View File
@@ -1,19 +1,22 @@
#include "crt.h"
#include "scanner.h"
#include "token.h"
#include "exceptions.h"
#include "exp.h"
#include <cassert>
#include <memory>
namespace YAML
{
Scanner::Scanner(std::istream& in)
: INPUT(in), m_startedStream(false), m_endedStream(false), m_simpleKeyAllowed(false)
: INPUT(in), m_startedStream(false), m_endedStream(false), m_simpleKeyAllowed(false), m_canBeJSONFlow(false)
{
}
Scanner::~Scanner()
{
for(unsigned i=0;i<m_indentRefs.size();i++)
delete m_indentRefs[i];
m_indentRefs.clear();
}
// empty
@@ -29,13 +32,8 @@ namespace YAML
void Scanner::pop()
{
EnsureTokensInQueue();
if(!m_tokens.empty()) {
// Saved anchors shouldn't survive popping the document end marker
if (m_tokens.front().type == Token::DOC_END) {
ClearAnchors();
}
if(!m_tokens.empty())
m_tokens.pop();
}
}
// peek
@@ -116,10 +114,10 @@ namespace YAML
return ScanDirective();
// document token
if(INPUT.column() == 0 && Exp::DocStart.Matches(INPUT))
if(INPUT.column() == 0 && Exp::DocStart().Matches(INPUT))
return ScanDocStart();
if(INPUT.column() == 0 && Exp::DocEnd.Matches(INPUT))
if(INPUT.column() == 0 && Exp::DocEnd().Matches(INPUT))
return ScanDocEnd();
// flow start/end/entry
@@ -133,13 +131,13 @@ namespace YAML
return ScanFlowEntry();
// block/map stuff
if(Exp::BlockEntry.Matches(INPUT))
if(Exp::BlockEntry().Matches(INPUT))
return ScanBlockEntry();
if((InBlockContext() ? Exp::Key : Exp::KeyInFlow).Matches(INPUT))
if((InBlockContext() ? Exp::Key() : Exp::KeyInFlow()).Matches(INPUT))
return ScanKey();
if((InBlockContext() ? Exp::Value : Exp::ValueInFlow).Matches(INPUT))
if(GetValueRegex().Matches(INPUT))
return ScanValue();
// alias/anchor
@@ -158,7 +156,7 @@ namespace YAML
return ScanQuotedScalar();
// plain scalars
if((InBlockContext() ? Exp::PlainScalar : Exp::PlainScalarInFlow).Matches(INPUT))
if((InBlockContext() ? Exp::PlainScalar() : Exp::PlainScalarInFlow()).Matches(INPUT))
return ScanPlainScalar();
// don't know what it is!
@@ -172,24 +170,24 @@ namespace YAML
while(1) {
// first eat whitespace
while(INPUT && IsWhitespaceToBeEaten(INPUT.peek())) {
if(InBlockContext() && Exp::Tab.Matches(INPUT))
if(InBlockContext() && Exp::Tab().Matches(INPUT))
m_simpleKeyAllowed = false;
INPUT.eat(1);
}
// then eat a comment
if(Exp::Comment.Matches(INPUT)) {
if(Exp::Comment().Matches(INPUT)) {
// eat until line break
while(INPUT && !Exp::Break.Matches(INPUT))
while(INPUT && !Exp::Break().Matches(INPUT))
INPUT.eat(1);
}
// if it's NOT a line break, then we're done!
if(!Exp::Break.Matches(INPUT))
if(!Exp::Break().Matches(INPUT))
break;
// otherwise, let's eat the line break and keep going
int n = Exp::Break.Match(INPUT);
int n = Exp::Break().Match(INPUT);
INPUT.eat(n);
// oh yeah, and let's get rid of that simple key
@@ -223,14 +221,25 @@ namespace YAML
return false;
}
// GetValueRegex
// . Get the appropriate regex to check if it's a value token
const RegEx& Scanner::GetValueRegex() const
{
if(InBlockContext())
return Exp::Value();
return m_canBeJSONFlow ? Exp::ValueInJSONFlow() : Exp::ValueInFlow();
}
// StartStream
// . Set the initial conditions for starting a stream.
void Scanner::StartStream()
{
m_startedStream = true;
m_simpleKeyAllowed = true;
m_indents.push(IndentMarker(-1, IndentMarker::NONE));
m_anchors.clear();
IndentMarker *pIndent = new IndentMarker(-1, IndentMarker::NONE);
m_indentRefs.push_back(pIndent);
m_indents.push(pIndent);
}
// EndStream
@@ -248,6 +257,22 @@ namespace YAML
m_endedStream = true;
}
Token *Scanner::PushToken(Token::TYPE type)
{
m_tokens.push(Token(type, INPUT.mark()));
return &m_tokens.back();
}
Token::TYPE Scanner::GetStartTokenFor(IndentMarker::INDENT_TYPE type) const
{
switch(type) {
case IndentMarker::SEQ: return Token::BLOCK_SEQ_START;
case IndentMarker::MAP: return Token::BLOCK_MAP_START;
case IndentMarker::NONE: assert(false); break;
}
assert(false);
}
// PushIndentTo
// . Pushes an indentation onto the stack, and enqueues the
// proper token (sequence start or mapping start).
@@ -258,8 +283,9 @@ namespace YAML
if(InFlowContext())
return 0;
IndentMarker indent(column, type);
const IndentMarker& lastIndent = m_indents.top();
std::auto_ptr<IndentMarker> pIndent(new IndentMarker(column, type));
IndentMarker& indent = *pIndent;
const IndentMarker& lastIndent = *m_indents.top();
// is this actually an indentation?
if(indent.column < lastIndent.column)
@@ -268,22 +294,18 @@ namespace YAML
return 0;
// push a start token
if(type == IndentMarker::SEQ)
m_tokens.push(Token(Token::BLOCK_SEQ_START, INPUT.mark()));
else if(type == IndentMarker::MAP)
m_tokens.push(Token(Token::BLOCK_MAP_START, INPUT.mark()));
else
assert(false);
indent.pStartToken = &m_tokens.back();
indent.pStartToken = PushToken(GetStartTokenFor(type));
// and then the indent
m_indents.push(indent);
return &m_indents.top();
m_indents.push(&indent);
m_indentRefs.push_back(pIndent.release());
return m_indentRefs.back();
}
// PopIndentToHere
// . Pops indentations off the stack until we reach the current indentation level,
// and enqueues the proper token each time.
// . Then pops all invalid indentations off.
void Scanner::PopIndentToHere()
{
// are we in flow?
@@ -292,14 +314,17 @@ namespace YAML
// now pop away
while(!m_indents.empty()) {
const IndentMarker& indent = m_indents.top();
const IndentMarker& indent = *m_indents.top();
if(indent.column < INPUT.column())
break;
if(indent.column == INPUT.column() && !(indent.type == IndentMarker::SEQ && !Exp::BlockEntry.Matches(INPUT)))
if(indent.column == INPUT.column() && !(indent.type == IndentMarker::SEQ && !Exp::BlockEntry().Matches(INPUT)))
break;
PopIndent();
}
while(!m_indents.empty() && m_indents.top()->status == IndentMarker::INVALID)
PopIndent();
}
// PopAllIndents
@@ -313,7 +338,7 @@ namespace YAML
// now pop away
while(!m_indents.empty()) {
const IndentMarker& indent = m_indents.top();
const IndentMarker& indent = *m_indents.top();
if(indent.type == IndentMarker::NONE)
break;
@@ -325,17 +350,17 @@ namespace YAML
// . Pops a single indent, pushing the proper token
void Scanner::PopIndent()
{
IndentMarker indent = m_indents.top();
IndentMarker::INDENT_TYPE type = indent.type;
const IndentMarker& indent = *m_indents.top();
m_indents.pop();
if(!indent.isValid) {
if(indent.status != IndentMarker::VALID) {
InvalidateSimpleKey();
return;
}
if(type == IndentMarker::SEQ)
if(indent.type == IndentMarker::SEQ)
m_tokens.push(Token(Token::BLOCK_SEQ_END, INPUT.mark()));
else if(type == IndentMarker::MAP)
else if(indent.type == IndentMarker::MAP)
m_tokens.push(Token(Token::BLOCK_MAP_END, INPUT.mark()));
}
@@ -344,30 +369,7 @@ namespace YAML
{
if(m_indents.empty())
return 0;
return m_indents.top().column;
}
// Save
// . Saves a pointer to the Node object referenced by a particular anchor
// name.
void Scanner::Save(const std::string& anchor, Node* value)
{
m_anchors[anchor] = value;
}
// Retrieve
// . Retrieves a pointer previously saved for an anchor name.
// . Throws an exception if the anchor has not been defined.
const Node *Scanner::Retrieve(const std::string& anchor) const
{
typedef std::map<std::string, const Node *> map;
map::const_iterator itNode = m_anchors.find(anchor);
if(m_anchors.end() == itNode)
ThrowParserException(ErrorMsg::UNKNOWN_ANCHOR);
return itNode->second;
return m_indents.top()->column;
}
// ThrowParserException
@@ -383,9 +385,5 @@ namespace YAML
}
throw ParserException(mark, msg);
}
void Scanner::ClearAnchors()
{
m_anchors.clear();
}
}
+11 -9
View File
@@ -16,6 +16,7 @@
namespace YAML
{
class Node;
class RegEx;
class Scanner
{
@@ -28,19 +29,15 @@ namespace YAML
void pop();
Token& peek();
// anchor management
void Save(const std::string& anchor, Node* value);
const Node *Retrieve(const std::string& anchor) const;
void ClearAnchors();
private:
struct IndentMarker {
enum INDENT_TYPE { MAP, SEQ, NONE };
IndentMarker(int column_, INDENT_TYPE type_): column(column_), type(type_), isValid(true), pStartToken(0) {}
enum STATUS { VALID, INVALID, UNKNOWN };
IndentMarker(int column_, INDENT_TYPE type_): column(column_), type(type_), status(VALID), pStartToken(0) {}
int column;
INDENT_TYPE type;
bool isValid;
STATUS status;
Token *pStartToken;
};
@@ -53,11 +50,13 @@ namespace YAML
void ScanToNextToken();
void StartStream();
void EndStream();
Token *PushToken(Token::TYPE type);
bool InFlowContext() const { return !m_flows.empty(); }
bool InBlockContext() const { return m_flows.empty(); }
int GetFlowLevel() const { return m_flows.size(); }
Token::TYPE GetStartTokenFor(IndentMarker::INDENT_TYPE type) const;
IndentMarker *PushIndentTo(int column, IndentMarker::INDENT_TYPE type);
void PopIndentToHere();
void PopAllIndents();
@@ -75,6 +74,7 @@ namespace YAML
void ThrowParserException(const std::string& msg) const;
bool IsWhitespaceToBeEaten(char ch);
const RegEx& GetValueRegex() const;
struct SimpleKey {
SimpleKey(const Mark& mark_, int flowLevel_);
@@ -117,11 +117,13 @@ namespace YAML
// state info
bool m_startedStream, m_endedStream;
bool m_simpleKeyAllowed;
bool m_canBeJSONFlow;
std::stack <SimpleKey> m_simpleKeys;
std::stack <IndentMarker> m_indents;
std::stack <IndentMarker *> m_indents;
std::vector <IndentMarker *> m_indentRefs; // for "garbage collection"
std::stack <FLOW_MARKER> m_flows;
std::map <std::string, const Node *> m_anchors;
};
}
#endif // SCANNER_H_62B23520_7C8E_11DE_8A39_0800200C9A66
+14 -13
View File
@@ -1,4 +1,3 @@
#include "crt.h"
#include "scanscalar.h"
#include "scanner.h"
#include "exp.h"
@@ -32,12 +31,13 @@ namespace YAML
// Phase #1: scan until line ending
std::size_t lastNonWhitespaceChar = scalar.size();
while(!params.end.Matches(INPUT) && !Exp::Break.Matches(INPUT)) {
bool escapedNewline = false;
while(!params.end.Matches(INPUT) && !Exp::Break().Matches(INPUT)) {
if(!INPUT)
break;
// document indicator?
if(INPUT.column() == 0 && Exp::DocIndicator.Matches(INPUT)) {
if(INPUT.column() == 0 && Exp::DocIndicator().Matches(INPUT)) {
if(params.onDocIndicator == BREAK)
break;
else if(params.onDocIndicator == THROW)
@@ -48,11 +48,12 @@ namespace YAML
pastOpeningBreak = true;
// escaped newline? (only if we're escaping on slash)
if(params.escape == '\\' && Exp::EscBreak.Matches(INPUT)) {
int n = Exp::EscBreak.Match(INPUT);
INPUT.eat(n);
if(params.escape == '\\' && Exp::EscBreak().Matches(INPUT)) {
// eat escape character and get out (but preserve trailing whitespace!)
INPUT.get();
lastNonWhitespaceChar = scalar.size();
continue;
escapedNewline = true;
break;
}
// escape this?
@@ -77,7 +78,7 @@ namespace YAML
}
// doc indicator?
if(params.onDocIndicator == BREAK && INPUT.column() == 0 && Exp::DocIndicator.Matches(INPUT))
if(params.onDocIndicator == BREAK && INPUT.column() == 0 && Exp::DocIndicator().Matches(INPUT))
break;
// are we done via character match?
@@ -94,7 +95,7 @@ namespace YAML
// ********************************
// Phase #2: eat line ending
n = Exp::Break.Match(INPUT);
n = Exp::Break().Match(INPUT);
INPUT.eat(n);
// ********************************
@@ -109,7 +110,7 @@ namespace YAML
params.indent = std::max(params.indent, INPUT.column());
// and then the rest of the whitespace
while(Exp::Blank.Matches(INPUT)) {
while(Exp::Blank().Matches(INPUT)) {
// we check for tabs that masquerade as indentation
if(INPUT.peek() == '\t'&& INPUT.column() < params.indent && params.onTabInIndentation == THROW)
throw ParserException(INPUT.mark(), ErrorMsg::TAB_IN_INDENTATION);
@@ -121,8 +122,8 @@ namespace YAML
}
// was this an empty line?
bool nextEmptyLine = Exp::Break.Matches(INPUT);
bool nextMoreIndented = Exp::Blank.Matches(INPUT);
bool nextEmptyLine = Exp::Break().Matches(INPUT);
bool nextMoreIndented = Exp::Blank().Matches(INPUT);
if(params.fold == FOLD_BLOCK && foldedNewlineCount == 0 && nextEmptyLine)
foldedNewlineStartedMoreIndented = moreIndented;
@@ -150,7 +151,7 @@ namespace YAML
case FOLD_FLOW:
if(nextEmptyLine)
scalar += "\n";
else if(!emptyLine && !nextEmptyLine)
else if(!emptyLine && !nextEmptyLine && !escapedNewline)
scalar += " ";
break;
}
+1
View File
@@ -40,3 +40,4 @@ namespace YAML
}
#endif // SCANSCALAR_H_62B23520_7C8E_11DE_8A39_0800200C9A66
+84
View File
@@ -0,0 +1,84 @@
#include "scanner.h"
#include "regex.h"
#include "exp.h"
#include "exceptions.h"
namespace YAML
{
const std::string ScanVerbatimTag(Stream& INPUT)
{
std::string tag;
// eat the start character
INPUT.get();
while(INPUT) {
if(INPUT.peek() == Keys::VerbatimTagEnd) {
// eat the end character
INPUT.get();
return tag;
}
int n = Exp::URI().Match(INPUT);
if(n <= 0)
break;
tag += INPUT.get(n);
}
throw ParserException(INPUT.mark(), ErrorMsg::END_OF_VERBATIM_TAG);
}
const std::string ScanTagHandle(Stream& INPUT, bool& canBeHandle)
{
std::string tag;
canBeHandle = true;
Mark firstNonWordChar;
while(INPUT) {
if(INPUT.peek() == Keys::Tag) {
if(!canBeHandle)
throw ParserException(firstNonWordChar, ErrorMsg::CHAR_IN_TAG_HANDLE);
break;
}
int n = 0;
if(canBeHandle) {
n = Exp::Word().Match(INPUT);
if(n <= 0) {
canBeHandle = false;
firstNonWordChar = INPUT.mark();
}
}
if(!canBeHandle)
n = Exp::Tag().Match(INPUT);
if(n <= 0)
break;
tag += INPUT.get(n);
}
return tag;
}
const std::string ScanTagSuffix(Stream& INPUT)
{
std::string tag;
while(INPUT) {
int n = Exp::Tag().Match(INPUT);
if(n <= 0)
break;
tag += INPUT.get(n);
}
if(tag.empty())
throw ParserException(INPUT.mark(), ErrorMsg::TAG_WITH_NO_SUFFIX);
return tag;
}
}
+18
View File
@@ -0,0 +1,18 @@
#pragma once
#ifndef SCANTAG_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#define SCANTAG_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#include <string>
#include "stream.h"
namespace YAML
{
const std::string ScanVerbatimTag(Stream& INPUT);
const std::string ScanTagHandle(Stream& INPUT, bool& canBeHandle);
const std::string ScanTagSuffix(Stream& INPUT);
}
#endif // SCANTAG_H_62B23520_7C8E_11DE_8A39_0800200C9A66
+71 -49
View File
@@ -1,9 +1,10 @@
#include "crt.h"
#include "scanner.h"
#include "token.h"
#include "exceptions.h"
#include "exp.h"
#include "scanscalar.h"
#include "scantag.h"
#include "tag.h"
#include <sstream>
namespace YAML
@@ -23,36 +24,34 @@ namespace YAML
PopAllSimpleKeys();
m_simpleKeyAllowed = false;
m_canBeJSONFlow = false;
// store pos and eat indicator
Mark mark = INPUT.mark();
Token token(Token::DIRECTIVE, INPUT.mark());
INPUT.eat(1);
// read name
while(INPUT && !Exp::BlankOrBreak.Matches(INPUT))
name += INPUT.get();
while(INPUT && !Exp::BlankOrBreak().Matches(INPUT))
token.value += INPUT.get();
// read parameters
while(1) {
// first get rid of whitespace
while(Exp::Blank.Matches(INPUT))
while(Exp::Blank().Matches(INPUT))
INPUT.eat(1);
// break on newline or comment
if(!INPUT || Exp::Break.Matches(INPUT) || Exp::Comment.Matches(INPUT))
if(!INPUT || Exp::Break().Matches(INPUT) || Exp::Comment().Matches(INPUT))
break;
// now read parameter
std::string param;
while(INPUT && !Exp::BlankOrBreak.Matches(INPUT))
while(INPUT && !Exp::BlankOrBreak().Matches(INPUT))
param += INPUT.get();
params.push_back(param);
token.params.push_back(param);
}
Token token(Token::DIRECTIVE, mark);
token.value = name;
token.params = params;
m_tokens.push(token);
}
@@ -62,6 +61,7 @@ namespace YAML
PopAllIndents();
PopAllSimpleKeys();
m_simpleKeyAllowed = false;
m_canBeJSONFlow = false;
// eat
Mark mark = INPUT.mark();
@@ -75,6 +75,7 @@ namespace YAML
PopAllIndents();
PopAllSimpleKeys();
m_simpleKeyAllowed = false;
m_canBeJSONFlow = false;
// eat
Mark mark = INPUT.mark();
@@ -88,6 +89,7 @@ namespace YAML
// flows can be simple keys
InsertPotentialSimpleKey();
m_simpleKeyAllowed = true;
m_canBeJSONFlow = false;
// eat
Mark mark = INPUT.mark();
@@ -105,10 +107,15 @@ namespace YAML
throw ParserException(INPUT.mark(), ErrorMsg::FLOW_END);
// we might have a solo entry in the flow context
if(VerifySimpleKey())
m_tokens.push(Token(Token::VALUE, INPUT.mark()));
if(InFlowContext()) {
if(m_flows.top() == FLOW_MAP && VerifySimpleKey())
m_tokens.push(Token(Token::VALUE, INPUT.mark()));
else if(m_flows.top() == FLOW_SEQ)
InvalidateSimpleKey();
}
m_simpleKeyAllowed = false;
m_canBeJSONFlow = true;
// eat
Mark mark = INPUT.mark();
@@ -127,11 +134,16 @@ namespace YAML
// FlowEntry
void Scanner::ScanFlowEntry()
{
// we might have a solo entry in the flow context
if(VerifySimpleKey())
m_tokens.push(Token(Token::VALUE, INPUT.mark()));
// we might have a solo entry in the flow context
if(InFlowContext()) {
if(m_flows.top() == FLOW_MAP && VerifySimpleKey())
m_tokens.push(Token(Token::VALUE, INPUT.mark()));
else if(m_flows.top() == FLOW_SEQ)
InvalidateSimpleKey();
}
m_simpleKeyAllowed = true;
m_canBeJSONFlow = false;
// eat
Mark mark = INPUT.mark();
@@ -152,6 +164,7 @@ namespace YAML
PushIndentTo(INPUT.column(), IndentMarker::SEQ);
m_simpleKeyAllowed = true;
m_canBeJSONFlow = false;
// eat
Mark mark = INPUT.mark();
@@ -184,6 +197,7 @@ namespace YAML
{
// and check that simple key
bool isSimpleKey = VerifySimpleKey();
m_canBeJSONFlow = false;
if(isSimpleKey) {
// can't follow a simple key with another simple key (dunno why, though - it seems fine)
@@ -216,6 +230,7 @@ namespace YAML
// insert a potential simple key
InsertPotentialSimpleKey();
m_simpleKeyAllowed = false;
m_canBeJSONFlow = false;
// eat the indicator
Mark mark = INPUT.mark();
@@ -223,7 +238,7 @@ namespace YAML
alias = (indicator == Keys::Alias);
// now eat the content
while(Exp::AlphaNumeric.Matches(INPUT))
while(Exp::AlphaNumeric().Matches(INPUT))
name += INPUT.get();
// we need to have read SOMETHING!
@@ -231,7 +246,7 @@ namespace YAML
throw ParserException(INPUT.mark(), alias ? ErrorMsg::ALIAS_NOT_FOUND : ErrorMsg::ANCHOR_NOT_FOUND);
// and needs to end correctly
if(INPUT && !Exp::AnchorEnd.Matches(INPUT))
if(INPUT && !Exp::AnchorEnd().Matches(INPUT))
throw ParserException(INPUT.mark(), alias ? ErrorMsg::CHAR_IN_ALIAS : ErrorMsg::CHAR_IN_ANCHOR);
// and we're done
@@ -243,37 +258,40 @@ namespace YAML
// Tag
void Scanner::ScanTag()
{
std::string handle, suffix;
// insert a potential simple key
InsertPotentialSimpleKey();
m_simpleKeyAllowed = false;
m_canBeJSONFlow = false;
Token token(Token::TAG, INPUT.mark());
// eat the indicator
Mark mark = INPUT.mark();
handle += INPUT.get();
INPUT.get();
if(INPUT && INPUT.peek() == Keys::VerbatimTagStart){
std::string tag = ScanVerbatimTag(INPUT);
// read the handle
while(INPUT && INPUT.peek() != Keys::Tag && !Exp::BlankOrBreak.Matches(INPUT))
handle += INPUT.get();
// is there a suffix?
if(INPUT.peek() == Keys::Tag) {
// eat the indicator
handle += INPUT.get();
// then read it
while(INPUT && !Exp::BlankOrBreak.Matches(INPUT))
suffix += INPUT.get();
token.value = tag;
token.data = Tag::VERBATIM;
} else {
// this is a bit weird: we keep just the '!' as the handle and move the rest to the suffix
suffix = handle.substr(1);
handle = "!";
bool canBeHandle;
token.value = ScanTagHandle(INPUT, canBeHandle);
if(!canBeHandle && token.value.empty())
token.data = Tag::NON_SPECIFIC;
else if(token.value.empty())
token.data = Tag::SECONDARY_HANDLE;
else
token.data = Tag::PRIMARY_HANDLE;
// is there a suffix?
if(canBeHandle && INPUT.peek() == Keys::Tag) {
// eat the indicator
INPUT.get();
token.params.push_back(ScanTagSuffix(INPUT));
token.data = Tag::NAMED_HANDLE;
}
}
Token token(Token::TAG, mark);
token.value = handle;
token.params.push_back(suffix);
m_tokens.push(token);
}
@@ -284,10 +302,10 @@ namespace YAML
// set up the scanning parameters
ScanScalarParams params;
params.end = (InFlowContext() ? Exp::EndScalarInFlow : Exp::EndScalar) || (Exp::BlankOrBreak + Exp::Comment);
params.end = (InFlowContext() ? Exp::EndScalarInFlow() : Exp::EndScalar()) || (Exp::BlankOrBreak() + Exp::Comment());
params.eatEnd = false;
params.indent = (InFlowContext() ? 0 : GetTopIndent() + 1);
params.fold = FOLD_BLOCK;
params.fold = FOLD_FLOW;
params.eatLeadingWhitespace = true;
params.trimTrailingSpaces = true;
params.chomp = STRIP;
@@ -302,6 +320,7 @@ namespace YAML
// can have a simple key only if we ended the scalar by starting a new line
m_simpleKeyAllowed = params.leadingSpaces;
m_canBeJSONFlow = false;
// finally, check and see if we ended on an illegal character
//if(Exp::IllegalCharInScalar.Matches(INPUT))
@@ -309,6 +328,7 @@ namespace YAML
Token token(Token::SCALAR, mark);
token.value = scalar;
token.params.push_back(Token::PLAIN_SCALAR);
m_tokens.push(token);
}
@@ -323,7 +343,7 @@ namespace YAML
// setup the scanning parameters
ScanScalarParams params;
params.end = (single ? RegEx(quote) && !Exp::EscSingleQuote : RegEx(quote));
params.end = (single ? RegEx(quote) && !Exp::EscSingleQuote() : RegEx(quote));
params.eatEnd = true;
params.escape = (single ? '\'' : '\\');
params.indent = 0;
@@ -344,6 +364,7 @@ namespace YAML
// and scan
scalar = ScanScalar(INPUT, params);
m_simpleKeyAllowed = false;
m_canBeJSONFlow = true;
Token token(Token::SCALAR, mark);
token.value = scalar;
@@ -369,14 +390,14 @@ namespace YAML
// eat chomping/indentation indicators
params.chomp = CLIP;
int n = Exp::Chomp.Match(INPUT);
int n = Exp::Chomp().Match(INPUT);
for(int i=0;i<n;i++) {
char ch = INPUT.get();
if(ch == '+')
params.chomp = KEEP;
else if(ch == '-')
params.chomp = STRIP;
else if(Exp::Digit.Matches(ch)) {
else if(Exp::Digit().Matches(ch)) {
if(ch == '0')
throw ParserException(INPUT.mark(), ErrorMsg::ZERO_INDENT_IN_BLOCK);
@@ -386,16 +407,16 @@ namespace YAML
}
// now eat whitespace
while(Exp::Blank.Matches(INPUT))
while(Exp::Blank().Matches(INPUT))
INPUT.eat(1);
// and comments to the end of the line
if(Exp::Comment.Matches(INPUT))
while(INPUT && !Exp::Break.Matches(INPUT))
if(Exp::Comment().Matches(INPUT))
while(INPUT && !Exp::Break().Matches(INPUT))
INPUT.eat(1);
// if it's not a line break, then we ran into a bad character inline
if(INPUT && !Exp::Break.Matches(INPUT))
if(INPUT && !Exp::Break().Matches(INPUT))
throw ParserException(INPUT.mark(), ErrorMsg::CHAR_IN_BLOCK);
// set the initial indentation
@@ -410,6 +431,7 @@ namespace YAML
// simple keys always ok after block scalars (since we're gonna start a new line anyways)
m_simpleKeyAllowed = true;
m_canBeJSONFlow = false;
Token token(Token::SCALAR, mark);
token.value = scalar;
+8 -89
View File
@@ -1,9 +1,6 @@
#include "crt.h"
#include "sequence.h"
#include "eventhandler.h"
#include "node.h"
#include "scanner.h"
#include "token.h"
#include "emitter.h"
#include <stdexcept>
namespace YAML
@@ -13,12 +10,6 @@ namespace YAML
}
Sequence::Sequence(const std::vector<Node *>& data)
{
for(std::size_t i=0;i<data.size();i++)
m_data.push_back(data[i]->Clone().release());
}
Sequence::~Sequence()
{
Clear();
@@ -31,11 +22,6 @@ namespace YAML
m_data.clear();
}
Content *Sequence::Clone() const
{
return new Sequence(m_data);
}
bool Sequence::GetBegin(std::vector <Node *>::const_iterator& it) const
{
it = m_data.begin();
@@ -60,84 +46,17 @@ namespace YAML
return m_data.size();
}
void Sequence::Parse(Scanner *pScanner, const ParserState& state)
void Sequence::Append(std::auto_ptr<Node> pNode)
{
Clear();
// split based on start token
switch(pScanner->peek().type) {
case Token::BLOCK_SEQ_START: ParseBlock(pScanner, state); break;
case Token::FLOW_SEQ_START: ParseFlow(pScanner, state); break;
default: break;
}
m_data.push_back(pNode.release());
}
void Sequence::ParseBlock(Scanner *pScanner, const ParserState& state)
void Sequence::EmitEvents(AliasManager& am, EventHandler& eventHandler, const Mark& mark, const std::string& tag, anchor_t anchor) const
{
// eat start token
pScanner->pop();
while(1) {
if(pScanner->empty())
throw ParserException(Mark::null(), ErrorMsg::END_OF_SEQ);
Token token = pScanner->peek();
if(token.type != Token::BLOCK_ENTRY && token.type != Token::BLOCK_SEQ_END)
throw ParserException(token.mark, ErrorMsg::END_OF_SEQ);
pScanner->pop();
if(token.type == Token::BLOCK_SEQ_END)
break;
Node *pNode = new Node;
m_data.push_back(pNode);
// check for null
if(!pScanner->empty()) {
const Token& token = pScanner->peek();
if(token.type == Token::BLOCK_ENTRY || token.type == Token::BLOCK_SEQ_END)
continue;
}
pNode->Parse(pScanner, state);
}
}
void Sequence::ParseFlow(Scanner *pScanner, const ParserState& state)
{
// eat start token
pScanner->pop();
while(1) {
if(pScanner->empty())
throw ParserException(Mark::null(), ErrorMsg::END_OF_SEQ_FLOW);
// first check for end
if(pScanner->peek().type == Token::FLOW_SEQ_END) {
pScanner->pop();
break;
}
// then read the node
Node *pNode = new Node;
m_data.push_back(pNode);
pNode->Parse(pScanner, state);
// now eat the separator (or could be a sequence end, which we ignore - but if it's neither, then it's a bad node)
Token& token = pScanner->peek();
if(token.type == Token::FLOW_ENTRY)
pScanner->pop();
else if(token.type != Token::FLOW_SEQ_END)
throw ParserException(token.mark, ErrorMsg::END_OF_SEQ_FLOW);
}
}
void Sequence::Write(Emitter& out) const
{
out << BeginSeq;
eventHandler.OnSequenceStart(mark, tag, anchor);
for(std::size_t i=0;i<m_data.size();i++)
out << *m_data[i];
out << EndSeq;
m_data[i]->EmitEvents(am, eventHandler);
eventHandler.OnSequenceEnd();
}
int Sequence::Compare(Content *pContent)
+2 -8
View File
@@ -15,19 +15,17 @@ namespace YAML
{
public:
Sequence();
Sequence(const std::vector<Node *>& data);
virtual ~Sequence();
void Clear();
virtual Content *Clone() const;
virtual bool GetBegin(std::vector <Node *>::const_iterator& it) const;
virtual bool GetEnd(std::vector <Node *>::const_iterator& it) const;
virtual Node *GetNode(std::size_t i) const;
virtual std::size_t GetSize() const;
virtual void Parse(Scanner *pScanner, const ParserState& state);
virtual void Write(Emitter& out) const;
virtual void Append(std::auto_ptr<Node> pNode);
virtual void EmitEvents(AliasManager& am, EventHandler& eventHandler, const Mark& mark, const std::string& tag, anchor_t anchor) const;
virtual bool IsSequence() const { return true; }
@@ -37,10 +35,6 @@ namespace YAML
virtual int Compare(Sequence *pSeq);
virtual int Compare(Map *) { return -1; }
private:
void ParseBlock(Scanner *pScanner, const ParserState& state);
void ParseFlow(Scanner *pScanner, const ParserState& state);
protected:
std::vector <Node *> m_data;
};
+14 -13
View File
@@ -1,4 +1,3 @@
#include "crt.h"
#include "scanner.h"
#include "token.h"
#include "exceptions.h"
@@ -13,9 +12,11 @@ namespace YAML
void Scanner::SimpleKey::Validate()
{
// Note: pIndent will *not* be garbage here; see below
// Note: pIndent will *not* be garbage here;
// we "garbage collect" them so we can
// always refer to them
if(pIndent)
pIndent->isValid = true;
pIndent->status = IndentMarker::VALID;
if(pMapStart)
pMapStart->status = Token::VALID;
if(pKey)
@@ -24,8 +25,8 @@ namespace YAML
void Scanner::SimpleKey::Invalidate()
{
// Note: pIndent might be a garbage pointer here, but that's ok
// An indent will only be popped if the simple key is invalid
if(pIndent)
pIndent->status = IndentMarker::INVALID;
if(pMapStart)
pMapStart->status = Token::INVALID;
if(pKey)
@@ -37,9 +38,6 @@ namespace YAML
{
if(!m_simpleKeyAllowed)
return false;
if(InFlowContext() && m_flows.top() != FLOW_MAP)
return false;
return !ExistsActiveSimpleKey();
}
@@ -67,11 +65,13 @@ namespace YAML
SimpleKey key(INPUT.mark(), GetFlowLevel());
// first add a map start, if necessary
key.pIndent = PushIndentTo(INPUT.column(), IndentMarker::MAP);
if(key.pIndent) {
key.pIndent->isValid = false;
key.pMapStart = key.pIndent->pStartToken;
key.pMapStart->status = Token::UNVERIFIED;
if(InBlockContext()) {
key.pIndent = PushIndentTo(INPUT.column(), IndentMarker::MAP);
if(key.pIndent) {
key.pIndent->status = IndentMarker::UNKNOWN;
key.pMapStart = key.pIndent->pStartToken;
key.pMapStart->status = Token::UNVERIFIED;
}
}
// then add the (now unverified) key
@@ -136,3 +136,4 @@ namespace YAML
m_simpleKeys.pop();
}
}
+381
View File
@@ -0,0 +1,381 @@
#include "singledocparser.h"
#include "collectionstack.h"
#include "directives.h"
#include "eventhandler.h"
#include "exceptions.h"
#include "scanner.h"
#include "tag.h"
#include "token.h"
#include <sstream>
#include <cstdio>
#include <algorithm>
namespace YAML
{
SingleDocParser::SingleDocParser(Scanner& scanner, const Directives& directives): m_scanner(scanner), m_directives(directives), m_pCollectionStack(new CollectionStack), m_curAnchor(0)
{
}
SingleDocParser::~SingleDocParser()
{
}
// HandleDocument
// . Handles the next document
// . Throws a ParserException on error.
void SingleDocParser::HandleDocument(EventHandler& eventHandler)
{
assert(!m_scanner.empty()); // guaranteed that there are tokens
assert(!m_curAnchor);
eventHandler.OnDocumentStart(m_scanner.peek().mark);
// eat doc start
if(m_scanner.peek().type == Token::DOC_START)
m_scanner.pop();
// recurse!
HandleNode(eventHandler);
eventHandler.OnDocumentEnd();
// and finally eat any doc ends we see
while(!m_scanner.empty() && m_scanner.peek().type == Token::DOC_END)
m_scanner.pop();
}
void SingleDocParser::HandleNode(EventHandler& eventHandler)
{
// an empty node *is* a possibility
if(m_scanner.empty()) {
eventHandler.OnNull("", NullAnchor);
return;
}
// save location
Mark mark = m_scanner.peek().mark;
// special case: a value node by itself must be a map, with no header
if(m_scanner.peek().type == Token::VALUE) {
eventHandler.OnMapStart(mark, "", NullAnchor);
HandleMap(eventHandler);
eventHandler.OnMapEnd();
return;
}
// special case: an alias node
if(m_scanner.peek().type == Token::ALIAS) {
eventHandler.OnAlias(mark, LookupAnchor(mark, m_scanner.peek().value));
m_scanner.pop();
return;
}
std::string tag;
anchor_t anchor;
ParseProperties(tag, anchor);
if (tag.empty()) {
const Token& token = m_scanner.peek();
const std::vector<std::string>& tparams = token.params;
if (token.type != Token::SCALAR ||
std::find(tparams.begin(), tparams.end(), Token::PLAIN_SCALAR) != tparams.end()) {
tag = "?";
} else {
tag = "!";
}
}
// now split based on what kind of node we should be
switch(m_scanner.peek().type) {
case Token::SCALAR:
eventHandler.OnScalar(mark, tag, anchor, m_scanner.peek().value);
m_scanner.pop();
return;
case Token::FLOW_SEQ_START:
case Token::BLOCK_SEQ_START:
eventHandler.OnSequenceStart(mark, tag, anchor);
HandleSequence(eventHandler);
eventHandler.OnSequenceEnd();
return;
case Token::FLOW_MAP_START:
case Token::BLOCK_MAP_START:
eventHandler.OnMapStart(mark, tag, anchor);
HandleMap(eventHandler);
eventHandler.OnMapEnd();
return;
case Token::KEY:
// compact maps can only go in a flow sequence
if(m_pCollectionStack->GetCurCollectionType() == CollectionType::FlowSeq) {
eventHandler.OnMapStart(mark, tag, anchor);
HandleMap(eventHandler);
eventHandler.OnMapEnd();
return;
}
break;
default:
break;
}
eventHandler.OnNull(tag, anchor);
}
void SingleDocParser::HandleSequence(EventHandler& eventHandler)
{
// split based on start token
switch(m_scanner.peek().type) {
case Token::BLOCK_SEQ_START: HandleBlockSequence(eventHandler); break;
case Token::FLOW_SEQ_START: HandleFlowSequence(eventHandler); break;
default: break;
}
}
void SingleDocParser::HandleBlockSequence(EventHandler& eventHandler)
{
// eat start token
m_scanner.pop();
m_pCollectionStack->PushCollectionType(CollectionType::BlockSeq);
while(1) {
if(m_scanner.empty())
throw ParserException(Mark::null(), ErrorMsg::END_OF_SEQ);
Token token = m_scanner.peek();
if(token.type != Token::BLOCK_ENTRY && token.type != Token::BLOCK_SEQ_END)
throw ParserException(token.mark, ErrorMsg::END_OF_SEQ);
m_scanner.pop();
if(token.type == Token::BLOCK_SEQ_END)
break;
// check for null
if(!m_scanner.empty()) {
const Token& token = m_scanner.peek();
if(token.type == Token::BLOCK_ENTRY || token.type == Token::BLOCK_SEQ_END) {
eventHandler.OnNull("", NullAnchor);
continue;
}
}
HandleNode(eventHandler);
}
m_pCollectionStack->PopCollectionType(CollectionType::BlockSeq);
}
void SingleDocParser::HandleFlowSequence(EventHandler& eventHandler)
{
// eat start token
m_scanner.pop();
m_pCollectionStack->PushCollectionType(CollectionType::FlowSeq);
while(1) {
if(m_scanner.empty())
throw ParserException(Mark::null(), ErrorMsg::END_OF_SEQ_FLOW);
// first check for end
if(m_scanner.peek().type == Token::FLOW_SEQ_END) {
m_scanner.pop();
break;
}
// then read the node
HandleNode(eventHandler);
// now eat the separator (or could be a sequence end, which we ignore - but if it's neither, then it's a bad node)
Token& token = m_scanner.peek();
if(token.type == Token::FLOW_ENTRY)
m_scanner.pop();
else if(token.type != Token::FLOW_SEQ_END)
throw ParserException(token.mark, ErrorMsg::END_OF_SEQ_FLOW);
}
m_pCollectionStack->PopCollectionType(CollectionType::FlowSeq);
}
void SingleDocParser::HandleMap(EventHandler& eventHandler)
{
// split based on start token
switch(m_scanner.peek().type) {
case Token::BLOCK_MAP_START: HandleBlockMap(eventHandler); break;
case Token::FLOW_MAP_START: HandleFlowMap(eventHandler); break;
case Token::KEY: HandleCompactMap(eventHandler); break;
case Token::VALUE: HandleCompactMapWithNoKey(eventHandler); break;
default: break;
}
}
void SingleDocParser::HandleBlockMap(EventHandler& eventHandler)
{
// eat start token
m_scanner.pop();
m_pCollectionStack->PushCollectionType(CollectionType::BlockMap);
while(1) {
if(m_scanner.empty())
throw ParserException(Mark::null(), ErrorMsg::END_OF_MAP);
Token token = m_scanner.peek();
if(token.type != Token::KEY && token.type != Token::VALUE && token.type != Token::BLOCK_MAP_END)
throw ParserException(token.mark, ErrorMsg::END_OF_MAP);
if(token.type == Token::BLOCK_MAP_END) {
m_scanner.pop();
break;
}
// grab key (if non-null)
if(token.type == Token::KEY) {
m_scanner.pop();
HandleNode(eventHandler);
} else {
eventHandler.OnNull("", NullAnchor);
}
// now grab value (optional)
if(!m_scanner.empty() && m_scanner.peek().type == Token::VALUE) {
m_scanner.pop();
HandleNode(eventHandler);
} else {
eventHandler.OnNull("", NullAnchor);
}
}
m_pCollectionStack->PopCollectionType(CollectionType::BlockMap);
}
void SingleDocParser::HandleFlowMap(EventHandler& eventHandler)
{
// eat start token
m_scanner.pop();
m_pCollectionStack->PushCollectionType(CollectionType::FlowMap);
while(1) {
if(m_scanner.empty())
throw ParserException(Mark::null(), ErrorMsg::END_OF_MAP_FLOW);
Token& token = m_scanner.peek();
// first check for end
if(token.type == Token::FLOW_MAP_END) {
m_scanner.pop();
break;
}
// grab key (if non-null)
if(token.type == Token::KEY) {
m_scanner.pop();
HandleNode(eventHandler);
} else {
eventHandler.OnNull("", NullAnchor);
}
// now grab value (optional)
if(!m_scanner.empty() && m_scanner.peek().type == Token::VALUE) {
m_scanner.pop();
HandleNode(eventHandler);
} else {
eventHandler.OnNull("", NullAnchor);
}
// now eat the separator (or could be a map end, which we ignore - but if it's neither, then it's a bad node)
Token& nextToken = m_scanner.peek();
if(nextToken.type == Token::FLOW_ENTRY)
m_scanner.pop();
else if(nextToken.type != Token::FLOW_MAP_END)
throw ParserException(nextToken.mark, ErrorMsg::END_OF_MAP_FLOW);
}
m_pCollectionStack->PopCollectionType(CollectionType::FlowMap);
}
// . Single "key: value" pair in a flow sequence
void SingleDocParser::HandleCompactMap(EventHandler& eventHandler)
{
m_pCollectionStack->PushCollectionType(CollectionType::CompactMap);
// grab key
m_scanner.pop();
HandleNode(eventHandler);
// now grab value (optional)
if(!m_scanner.empty() && m_scanner.peek().type == Token::VALUE) {
m_scanner.pop();
HandleNode(eventHandler);
} else {
eventHandler.OnNull("", NullAnchor);
}
m_pCollectionStack->PopCollectionType(CollectionType::CompactMap);
}
// . Single ": value" pair in a flow sequence
void SingleDocParser::HandleCompactMapWithNoKey(EventHandler& eventHandler)
{
m_pCollectionStack->PushCollectionType(CollectionType::CompactMap);
// null key
eventHandler.OnNull("", NullAnchor);
// grab value
m_scanner.pop();
HandleNode(eventHandler);
m_pCollectionStack->PopCollectionType(CollectionType::CompactMap);
}
// ParseProperties
// . Grabs any tag or anchor tokens and deals with them.
void SingleDocParser::ParseProperties(std::string& tag, anchor_t& anchor)
{
tag.clear();
anchor = NullAnchor;
while(1) {
if(m_scanner.empty())
return;
switch(m_scanner.peek().type) {
case Token::TAG: ParseTag(tag); break;
case Token::ANCHOR: ParseAnchor(anchor); break;
default: return;
}
}
}
void SingleDocParser::ParseTag(std::string& tag)
{
Token& token = m_scanner.peek();
if(!tag.empty())
throw ParserException(token.mark, ErrorMsg::MULTIPLE_TAGS);
Tag tagInfo(token);
tag = tagInfo.Translate(m_directives);
m_scanner.pop();
}
void SingleDocParser::ParseAnchor(anchor_t& anchor)
{
Token& token = m_scanner.peek();
if(anchor)
throw ParserException(token.mark, ErrorMsg::MULTIPLE_ANCHORS);
anchor = RegisterAnchor(token.value);
m_scanner.pop();
}
anchor_t SingleDocParser::RegisterAnchor(const std::string& name)
{
if(name.empty())
return NullAnchor;
return m_anchors[name] = ++m_curAnchor;
}
anchor_t SingleDocParser::LookupAnchor(const Mark& mark, const std::string& name) const
{
Anchors::const_iterator it = m_anchors.find(name);
if(it == m_anchors.end())
throw ParserException(mark, ErrorMsg::UNKNOWN_ANCHOR);
return it->second;
}
}
+63
View File
@@ -0,0 +1,63 @@
#pragma once
#ifndef SINGLEDOCPARSER_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#define SINGLEDOCPARSER_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#include "anchor.h"
#include "noncopyable.h"
#include <string>
#include <map>
#include <memory>
namespace YAML
{
struct Directives;
struct Mark;
struct Token;
class CollectionStack;
class EventHandler;
class Node;
class Scanner;
class SingleDocParser: private noncopyable
{
public:
SingleDocParser(Scanner& scanner, const Directives& directives);
~SingleDocParser();
void HandleDocument(EventHandler& eventHandler);
private:
void HandleNode(EventHandler& eventHandler);
void HandleSequence(EventHandler& eventHandler);
void HandleBlockSequence(EventHandler& eventHandler);
void HandleFlowSequence(EventHandler& eventHandler);
void HandleMap(EventHandler& eventHandler);
void HandleBlockMap(EventHandler& eventHandler);
void HandleFlowMap(EventHandler& eventHandler);
void HandleCompactMap(EventHandler& eventHandler);
void HandleCompactMapWithNoKey(EventHandler& eventHandler);
void ParseProperties(std::string& tag, anchor_t& anchor);
void ParseTag(std::string& tag);
void ParseAnchor(anchor_t& anchor);
anchor_t RegisterAnchor(const std::string& name);
anchor_t LookupAnchor(const Mark& mark, const std::string& name) const;
private:
Scanner& m_scanner;
const Directives& m_directives;
std::auto_ptr<CollectionStack> m_pCollectionStack;
typedef std::map<std::string, anchor_t> Anchors;
Anchors m_anchors;
anchor_t m_curAnchor;
};
}
#endif // SINGLEDOCPARSER_H_62B23520_7C8E_11DE_8A39_0800200C9A66
-1
View File
@@ -1,4 +1,3 @@
#include "crt.h"
#include "stream.h"
#include <iostream>
#include "exp.h"
+5
View File
@@ -30,6 +30,11 @@ namespace YAML
++m_offset;
return *this;
}
StringCharSource& operator += (std::size_t offset) {
m_offset += offset;
return *this;
}
private:
const char *m_str;
std::size_t m_size;
+50
View File
@@ -0,0 +1,50 @@
#include "tag.h"
#include "directives.h"
#include "token.h"
#include <cassert>
namespace YAML
{
Tag::Tag(const Token& token): type(static_cast<TYPE>(token.data))
{
switch(type) {
case VERBATIM:
value = token.value;
break;
case PRIMARY_HANDLE:
value = token.value;
break;
case SECONDARY_HANDLE:
value = token.value;
break;
case NAMED_HANDLE:
handle = token.value;
value = token.params[0];
break;
case NON_SPECIFIC:
break;
default:
assert(false);
}
}
const std::string Tag::Translate(const Directives& directives)
{
switch(type) {
case VERBATIM:
return value;
case PRIMARY_HANDLE:
return directives.TranslateTagHandle("!") + value;
case SECONDARY_HANDLE:
return directives.TranslateTagHandle("!!") + value;
case NAMED_HANDLE:
return directives.TranslateTagHandle("!" + handle + "!") + value;
case NON_SPECIFIC:
// TODO:
return "!";
default:
assert(false);
}
}
}
+26
View File
@@ -0,0 +1,26 @@
#pragma once
#ifndef TAG_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#define TAG_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#include <string>
namespace YAML
{
struct Token;
struct Directives;
struct Tag {
enum TYPE {
VERBATIM, PRIMARY_HANDLE, SECONDARY_HANDLE, NAMED_HANDLE, NON_SPECIFIC
};
Tag(const Token& token);
const std::string Translate(const Directives& directives);
TYPE type;
std::string handle, value;
};
}
#endif // TAG_H_62B23520_7C8E_11DE_8A39_0800200C9A66
+6
View File
@@ -0,0 +1,6 @@
#include "token.h"
namespace YAML
{
const std::string Token::PLAIN_SCALAR("pln");
}
+7 -2
View File
@@ -5,7 +5,7 @@
#include "mark.h"
#include <ios>
#include <iostream>
#include <string>
#include <vector>
@@ -24,6 +24,7 @@ namespace YAML
"FLOW_MAP_START",
"FLOW_SEQ_END",
"FLOW_MAP_END",
"FLOW_MAP_COMPACT",
"FLOW_ENTRY",
"KEY",
"VALUE",
@@ -49,6 +50,7 @@ namespace YAML
FLOW_MAP_START,
FLOW_SEQ_END,
FLOW_MAP_END,
FLOW_MAP_COMPACT,
FLOW_ENTRY,
KEY,
VALUE,
@@ -57,9 +59,11 @@ namespace YAML
TAG,
SCALAR
};
static const std::string PLAIN_SCALAR;
// data
Token(TYPE type_, const Mark& mark_): status(VALID), type(type_), mark(mark_) {}
Token(TYPE type_, const Mark& mark_): status(VALID), type(type_), mark(mark_), data(0) {}
friend std::ostream& operator << (std::ostream& out, const Token& token) {
out << TokenNames[token.type] << std::string(": ") << token.value;
@@ -73,6 +77,7 @@ namespace YAML
Mark mark;
std::string value;
std::vector <std::string> params;
int data;
};
}
+226
View File
@@ -0,0 +1,226 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="9.00"
Name="test"
ProjectGUID="{D1108F40-6ADF-467E-A95A-236C39A515C5}"
RootNamespace="test"
TargetFrameworkVersion="196613"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/D_SCL_SECURE_NO_WARNINGS"
Optimization="0"
AdditionalIncludeDirectories="include"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
WarningLevel="3"
DebugInformationFormat="4"
DisableSpecificWarnings="4127;4355"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="yamlcppd.lib"
AdditionalLibraryDirectories="lib"
GenerateDebugInformation="true"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="2"
WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/D_SCL_SECURE_NO_WARNINGS"
Optimization="2"
EnableIntrinsicFunctions="true"
AdditionalIncludeDirectories="include"
RuntimeLibrary="2"
EnableFunctionLevelLinking="true"
WarningLevel="3"
DebugInformationFormat="3"
DisableSpecificWarnings="4127;4355"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="yamlcpp.lib"
AdditionalLibraryDirectories="lib"
GenerateDebugInformation="true"
OptimizeReferences="2"
EnableCOMDATFolding="2"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
>
<File
RelativePath=".\test\emittertests.cpp"
>
</File>
<File
RelativePath=".\test\main.cpp"
>
</File>
<File
RelativePath=".\test\parsertests.cpp"
>
</File>
<File
RelativePath=".\test\spectests.cpp"
>
</File>
<File
RelativePath=".\test\tests.cpp"
>
</File>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
>
<File
RelativePath=".\test\emittertests.h"
>
</File>
<File
RelativePath=".\test\parsertests.h"
>
</File>
<File
RelativePath=".\test\spectests.h"
>
</File>
<File
RelativePath=".\test\tests.h"
>
</File>
</Filter>
<Filter
Name="Resource Files"
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
>
</Filter>
</Files>
<Globals>
</Globals>
</VisualStudioProject>
+10
View File
@@ -0,0 +1,10 @@
file(GLOB test_headers [a-z]*.h)
file(GLOB test_sources [a-z]*.cpp)
add_executable(run-tests
${test_sources}
${test_headers}
)
target_link_libraries(run-tests yaml-cpp)
add_test(yaml-reader-test run-tests)
@@ -9,7 +9,7 @@ namespace Test
void SimpleScalar(YAML::Emitter& out, std::string& desiredOutput) {
out << "Hello, World!";
desiredOutput = "Hello, World!";
desiredOutput = "--- Hello, World!";
}
void SimpleSeq(YAML::Emitter& out, std::string& desiredOutput) {
@@ -19,7 +19,7 @@ namespace Test
out << "milk";
out << YAML::EndSeq;
desiredOutput = "- eggs\n- bread\n- milk";
desiredOutput = "---\n- eggs\n- bread\n- milk";
}
void SimpleFlowSeq(YAML::Emitter& out, std::string& desiredOutput) {
@@ -30,7 +30,7 @@ namespace Test
out << "Moe";
out << YAML::EndSeq;
desiredOutput = "[Larry, Curly, Moe]";
desiredOutput = "--- [Larry, Curly, Moe]";
}
void EmptyFlowSeq(YAML::Emitter& out, std::string& desiredOutput) {
@@ -38,7 +38,7 @@ namespace Test
out << YAML::BeginSeq;
out << YAML::EndSeq;
desiredOutput = "[]";
desiredOutput = "--- []";
}
void NestedBlockSeq(YAML::Emitter& out, std::string& desiredOutput) {
@@ -47,7 +47,7 @@ namespace Test
out << YAML::BeginSeq << "subitem 1" << "subitem 2" << YAML::EndSeq;
out << YAML::EndSeq;
desiredOutput = "- item 1\n-\n - subitem 1\n - subitem 2";
desiredOutput = "---\n- item 1\n-\n - subitem 1\n - subitem 2";
}
void NestedFlowSeq(YAML::Emitter& out, std::string& desiredOutput) {
@@ -56,7 +56,7 @@ namespace Test
out << YAML::Flow << YAML::BeginSeq << "two" << "three" << YAML::EndSeq;
out << YAML::EndSeq;
desiredOutput = "- one\n- [two, three]";
desiredOutput = "---\n- one\n- [two, three]";
}
void SimpleMap(YAML::Emitter& out, std::string& desiredOutput) {
@@ -67,7 +67,7 @@ namespace Test
out << YAML::Value << "3B";
out << YAML::EndMap;
desiredOutput = "name: Ryan Braun\nposition: 3B";
desiredOutput = "---\nname: Ryan Braun\nposition: 3B";
}
void SimpleFlowMap(YAML::Emitter& out, std::string& desiredOutput) {
@@ -79,7 +79,7 @@ namespace Test
out << YAML::Value << "blue";
out << YAML::EndMap;
desiredOutput = "{shape: square, color: blue}";
desiredOutput = "--- {shape: square, color: blue}";
}
void MapAndList(YAML::Emitter& out, std::string& desiredOutput) {
@@ -90,7 +90,7 @@ namespace Test
out << YAML::Value << YAML::BeginSeq << "Sasha" << "Malia" << YAML::EndSeq;
out << YAML::EndMap;
desiredOutput = "name: Barack Obama\nchildren:\n - Sasha\n - Malia";
desiredOutput = "---\nname: Barack Obama\nchildren:\n - Sasha\n - Malia";
}
void ListAndMap(YAML::Emitter& out, std::string& desiredOutput) {
@@ -103,7 +103,7 @@ namespace Test
out << "item 2";
out << YAML::EndSeq;
desiredOutput = "- item 1\n-\n pens: 8\n pencils: 14\n- item 2";
desiredOutput = "---\n- item 1\n-\n pens: 8\n pencils: 14\n- item 2";
}
void NestedBlockMap(YAML::Emitter& out, std::string& desiredOutput) {
@@ -119,7 +119,7 @@ namespace Test
out << YAML::EndMap;
out << YAML::EndMap;
desiredOutput = "name: Fred\ngrades:\n algebra: A\n physics: C+\n literature: B";
desiredOutput = "---\nname: Fred\ngrades:\n algebra: A\n physics: C+\n literature: B";
}
void NestedFlowMap(YAML::Emitter& out, std::string& desiredOutput) {
@@ -136,7 +136,7 @@ namespace Test
out << YAML::EndMap;
out << YAML::EndMap;
desiredOutput = "{name: Fred, grades: {algebra: A, physics: C+, literature: B}}";
desiredOutput = "--- {name: Fred, grades: {algebra: A, physics: C+, literature: B}}";
}
void MapListMix(YAML::Emitter& out, std::string& desiredOutput) {
@@ -149,7 +149,7 @@ namespace Test
out << YAML::Key << "invincible" << YAML::Value << YAML::OnOffBool << false;
out << YAML::EndMap;
desiredOutput = "name: Bob\nposition: [2, 4]\ninvincible: off";
desiredOutput = "---\nname: Bob\nposition: [2, 4]\ninvincible: off";
}
void SimpleLongKey(YAML::Emitter& out, std::string& desiredOutput)
@@ -162,7 +162,7 @@ namespace Test
out << YAML::Value << 145;
out << YAML::EndMap;
desiredOutput = "? height\n: 5'9\"\n? weight\n: 145";
desiredOutput = "---\n? height\n: 5'9\"\n? weight\n: 145";
}
void SingleLongKey(YAML::Emitter& out, std::string& desiredOutput)
@@ -176,7 +176,7 @@ namespace Test
out << YAML::Value << 145;
out << YAML::EndMap;
desiredOutput = "age: 24\n? height\n: 5'9\"\nweight: 145";
desiredOutput = "---\nage: 24\n? height\n: 5'9\"\nweight: 145";
}
void ComplexLongKey(YAML::Emitter& out, std::string& desiredOutput)
@@ -189,7 +189,7 @@ namespace Test
out << YAML::Value << "demon";
out << YAML::EndMap;
desiredOutput = "?\n - 1\n - 3\n: monster\n? [2, 0]\n: demon";
desiredOutput = "---\n?\n - 1\n - 3\n: monster\n? [2, 0]\n: demon";
}
void AutoLongKey(YAML::Emitter& out, std::string& desiredOutput)
@@ -203,7 +203,7 @@ namespace Test
out << YAML::Value << "angel";
out << YAML::EndMap;
desiredOutput = "?\n - 1\n - 3\n: monster\n? [2, 0]\n: demon\nthe origin: angel";
desiredOutput = "---\n?\n - 1\n - 3\n: monster\n? [2, 0]\n: demon\nthe origin: angel";
}
void ScalarFormat(YAML::Emitter& out, std::string& desiredOutput)
@@ -217,7 +217,7 @@ namespace Test
out << YAML::Literal << "literal scalar\nthat may span\nmany, many\nlines and have \"whatever\" crazy\tsymbols that we like";
out << YAML::EndSeq;
desiredOutput = "- simple scalar\n- 'explicit single-quoted scalar'\n- \"explicit double-quoted scalar\"\n- \"auto-detected\\x0adouble-quoted scalar\"\n- a non-\"auto-detected\" double-quoted scalar\n- |\n literal scalar\n that may span\n many, many\n lines and have \"whatever\" crazy\tsymbols that we like";
desiredOutput = "---\n- simple scalar\n- 'explicit single-quoted scalar'\n- \"explicit double-quoted scalar\"\n- \"auto-detected\\x0adouble-quoted scalar\"\n- a non-\"auto-detected\" double-quoted scalar\n- |\n literal scalar\n that may span\n many, many\n lines and have \"whatever\" crazy\tsymbols that we like";
}
void AutoLongKeyScalar(YAML::Emitter& out, std::string& desiredOutput)
@@ -227,7 +227,7 @@ namespace Test
out << YAML::Value << "and its value";
out << YAML::EndMap;
desiredOutput = "? |\n multi-line\n scalar\n: and its value";
desiredOutput = "---\n? |\n multi-line\n scalar\n: and its value";
}
void LongKeyFlowMap(YAML::Emitter& out, std::string& desiredOutput)
@@ -240,7 +240,7 @@ namespace Test
out << YAML::Value << "and its value";
out << YAML::EndMap;
desiredOutput = "{simple key: and value, ? long key: and its value}";
desiredOutput = "--- {simple key: and value, ? long key: and its value}";
}
void BlockMapAsKey(YAML::Emitter& out, std::string& desiredOutput)
@@ -255,7 +255,7 @@ namespace Test
out << "total value";
out << YAML::EndMap;
desiredOutput = "?\n key: value\n next key: next value\n: total value";
desiredOutput = "---\n?\n key: value\n next key: next value\n: total value";
}
void AliasAndAnchor(YAML::Emitter& out, std::string& desiredOutput)
@@ -269,7 +269,7 @@ namespace Test
out << YAML::Alias("fred");
out << YAML::EndSeq;
desiredOutput = "- &fred\n name: Fred\n age: 42\n- *fred";
desiredOutput = "---\n- &fred\n name: Fred\n age: 42\n- *fred";
}
void AliasAndAnchorWithNull(YAML::Emitter& out, std::string& desiredOutput)
@@ -279,7 +279,123 @@ namespace Test
out << YAML::Alias("fred");
out << YAML::EndSeq;
desiredOutput = "- &fred ~\n- *fred";
desiredOutput = "---\n- &fred ~\n- *fred";
}
void SimpleVerbatimTag(YAML::Emitter& out, std::string& desiredOutput)
{
out << YAML::VerbatimTag("!foo") << "bar";
desiredOutput = "--- !<!foo> bar";
}
void VerbatimTagInBlockSeq(YAML::Emitter& out, std::string& desiredOutput)
{
out << YAML::BeginSeq;
out << YAML::VerbatimTag("!foo") << "bar";
out << "baz";
out << YAML::EndSeq;
desiredOutput = "---\n- !<!foo> bar\n- baz";
}
void VerbatimTagInFlowSeq(YAML::Emitter& out, std::string& desiredOutput)
{
out << YAML::Flow << YAML::BeginSeq;
out << YAML::VerbatimTag("!foo") << "bar";
out << "baz";
out << YAML::EndSeq;
desiredOutput = "--- [!<!foo> bar, baz]";
}
void VerbatimTagInFlowSeqWithNull(YAML::Emitter& out, std::string& desiredOutput)
{
out << YAML::Flow << YAML::BeginSeq;
out << YAML::VerbatimTag("!foo") << YAML::Null;
out << "baz";
out << YAML::EndSeq;
desiredOutput = "--- [!<!foo> ~, baz]";
}
void VerbatimTagInBlockMap(YAML::Emitter& out, std::string& desiredOutput)
{
out << YAML::BeginMap;
out << YAML::Key << YAML::VerbatimTag("!foo") << "bar";
out << YAML::Value << YAML::VerbatimTag("!waz") << "baz";
out << YAML::EndMap;
desiredOutput = "---\n!<!foo> bar: !<!waz> baz";
}
void VerbatimTagInFlowMap(YAML::Emitter& out, std::string& desiredOutput)
{
out << YAML::Flow << YAML::BeginMap;
out << YAML::Key << YAML::VerbatimTag("!foo") << "bar";
out << YAML::Value << "baz";
out << YAML::EndMap;
desiredOutput = "--- {!<!foo> bar: baz}";
}
void VerbatimTagInFlowMapWithNull(YAML::Emitter& out, std::string& desiredOutput)
{
out << YAML::Flow << YAML::BeginMap;
out << YAML::Key << YAML::VerbatimTag("!foo") << YAML::Null;
out << YAML::Value << "baz";
out << YAML::EndMap;
desiredOutput = "--- {!<!foo> ~: baz}";
}
void VerbatimTagWithEmptySeq(YAML::Emitter& out, std::string& desiredOutput)
{
out << YAML::VerbatimTag("!foo") << YAML::BeginSeq << YAML::EndSeq;
desiredOutput = "--- !<!foo>\n[]";
}
void VerbatimTagWithEmptyMap(YAML::Emitter& out, std::string& desiredOutput)
{
out << YAML::VerbatimTag("!bar") << YAML::BeginMap << YAML::EndMap;
desiredOutput = "--- !<!bar>\n{}";
}
void VerbatimTagWithEmptySeqAndMap(YAML::Emitter& out, std::string& desiredOutput)
{
out << YAML::BeginSeq;
out << YAML::VerbatimTag("!foo") << YAML::BeginSeq << YAML::EndSeq;
out << YAML::VerbatimTag("!bar") << YAML::BeginMap << YAML::EndMap;
out << YAML::EndSeq;
desiredOutput = "---\n- !<!foo>\n []\n- !<!bar>\n {}";
}
void ByKindTagWithScalar(YAML::Emitter& out, std::string& desiredOutput)
{
out << YAML::BeginSeq;
out << YAML::DoubleQuoted << "12";
out << "12";
out << YAML::TagByKind << "12";
out << YAML::EndSeq;
desiredOutput = "---\n- \"12\"\n- 12\n- ! 12";
}
void LocalTagWithScalar(YAML::Emitter& out, std::string& desiredOutput)
{
out << YAML::LocalTag("foo") << "bar";
desiredOutput = "--- !foo bar";
}
void BadLocalTag(YAML::Emitter& out, std::string& desiredError)
{
out << YAML::LocalTag("e!far") << "bar";
desiredError = "invalid tag";
}
void ComplexDoc(YAML::Emitter& out, std::string& desiredOutput)
@@ -335,7 +451,7 @@ namespace Test
out << YAML::Value << YAML::Alias("id001");
out << YAML::EndMap;
desiredOutput = "receipt: Oz-Ware Purchase Invoice\ndate: 2007-08-06\ncustomer:\n given: Dorothy\n family: Gale\nitems:\n -\n part_no: A4786\n descrip: Water Bucket (Filled)\n price: 1.47\n quantity: 4\n -\n part_no: E1628\n descrip: High Heeled \"Ruby\" Slippers\n price: 100.27\n quantity: 1\nbill-to: &id001\n street: |\n 123 Tornado Alley\n Suite 16\n city: East Westville\n state: KS\nship-to: *id001";
desiredOutput = "---\nreceipt: Oz-Ware Purchase Invoice\ndate: 2007-08-06\ncustomer:\n given: Dorothy\n family: Gale\nitems:\n -\n part_no: A4786\n descrip: Water Bucket (Filled)\n price: 1.47\n quantity: 4\n -\n part_no: E1628\n descrip: High Heeled \"Ruby\" Slippers\n price: 100.27\n quantity: 1\nbill-to: &id001\n street: |\n 123 Tornado Alley\n Suite 16\n city: East Westville\n state: KS\nship-to: *id001";
}
void STLContainers(YAML::Emitter& out, std::string& desiredOutput)
@@ -355,7 +471,7 @@ namespace Test
out << ages;
out << YAML::EndSeq;
desiredOutput = "- [2, 3, 5, 7, 11, 13]\n-\n Daniel: 26\n Jesse: 24";
desiredOutput = "---\n- [2, 3, 5, 7, 11, 13]\n-\n Daniel: 26\n Jesse: 24";
}
void SimpleComment(YAML::Emitter& out, std::string& desiredOutput)
@@ -365,7 +481,7 @@ namespace Test
out << YAML::Value << "least squares" << YAML::Comment("should we change this method?");
out << YAML::EndMap;
desiredOutput = "method: least squares # should we change this method?";
desiredOutput = "---\nmethod: least squares # should we change this method?";
}
void MultiLineComment(YAML::Emitter& out, std::string& desiredOutput)
@@ -375,7 +491,7 @@ namespace Test
out << "item 2";
out << YAML::EndSeq;
desiredOutput = "- item 1 # really really long\n # comment that couldn't possibly\n # fit on one line\n- item 2";
desiredOutput = "---\n- item 1 # really really long\n # comment that couldn't possibly\n # fit on one line\n- item 2";
}
void ComplexComments(YAML::Emitter& out, std::string& desiredOutput)
@@ -385,7 +501,7 @@ namespace Test
out << YAML::Value << "value";
out << YAML::EndMap;
desiredOutput = "? long key # long key\n: value";
desiredOutput = "---\n? long key # long key\n: value";
}
void Indentation(YAML::Emitter& out, std::string& desiredOutput)
@@ -398,7 +514,7 @@ namespace Test
out << YAML::EndMap;
out << YAML::EndSeq;
desiredOutput = "-\n key 1: value 1\n key 2:\n - a\n - b\n - c";
desiredOutput = "---\n-\n key 1: value 1\n key 2:\n - a\n - b\n - c";
}
void SimpleGlobalSettings(YAML::Emitter& out, std::string& desiredOutput)
@@ -413,7 +529,7 @@ namespace Test
out << YAML::EndMap;
out << YAML::EndSeq;
desiredOutput = "-\n ? key 1\n : value 1\n ? key 2\n : [a, b, c]";
desiredOutput = "---\n-\n ? key 1\n : value 1\n ? key 2\n : [a, b, c]";
}
void ComplexGlobalSettings(YAML::Emitter& out, std::string& desiredOutput)
@@ -432,7 +548,7 @@ namespace Test
out << YAML::EndMap;
out << YAML::EndSeq;
desiredOutput = "-\n key 1: value 1\n key 2: [a, b, c]\n-\n ? [1, 2]\n :\n a: b";
desiredOutput = "---\n-\n key 1: value 1\n key 2: [a, b, c]\n-\n ? [1, 2]\n :\n a: b";
}
void Null(YAML::Emitter& out, std::string& desiredOutput)
@@ -445,7 +561,95 @@ namespace Test
out << YAML::EndMap;
out << YAML::EndSeq;
desiredOutput = "- ~\n-\n null value: ~\n ~: null key";
desiredOutput = "---\n- ~\n-\n null value: ~\n ~: null key";
}
void EscapedUnicode(YAML::Emitter& out, std::string& desiredOutput)
{
out << YAML::EscapeNonAscii << "\x24 \xC2\xA2 \xE2\x82\xAC \xF0\xA4\xAD\xA2";
desiredOutput = "--- \"$ \\xa2 \\u20ac \\U00024b62\"";
}
void Unicode(YAML::Emitter& out, std::string& desiredOutput)
{
out << "\x24 \xC2\xA2 \xE2\x82\xAC \xF0\xA4\xAD\xA2";
desiredOutput = "--- \x24 \xC2\xA2 \xE2\x82\xAC \xF0\xA4\xAD\xA2";
}
void DoubleQuotedUnicode(YAML::Emitter& out, std::string& desiredOutput)
{
out << YAML::DoubleQuoted << "\x24 \xC2\xA2 \xE2\x82\xAC \xF0\xA4\xAD\xA2";
desiredOutput = "--- \"\x24 \xC2\xA2 \xE2\x82\xAC \xF0\xA4\xAD\xA2\"";
}
struct Foo {
Foo(): x(0) {}
Foo(int x_, const std::string& bar_): x(x_), bar(bar_) {}
int x;
std::string bar;
};
YAML::Emitter& operator << (YAML::Emitter& out, const Foo& foo) {
out << YAML::BeginMap;
out << YAML::Key << "x" << YAML::Value << foo.x;
out << YAML::Key << "bar" << YAML::Value << foo.bar;
out << YAML::EndMap;
return out;
}
void UserType(YAML::Emitter& out, std::string& desiredOutput)
{
out << YAML::BeginSeq;
out << Foo(5, "hello");
out << Foo(3, "goodbye");
out << YAML::EndSeq;
desiredOutput = "---\n-\n x: 5\n bar: hello\n-\n x: 3\n bar: goodbye";
}
void UserTypeInContainer(YAML::Emitter& out, std::string& desiredOutput)
{
std::vector<Foo> fv;
fv.push_back(Foo(5, "hello"));
fv.push_back(Foo(3, "goodbye"));
out << fv;
desiredOutput = "---\n-\n x: 5\n bar: hello\n-\n x: 3\n bar: goodbye";
}
template <typename T>
YAML::Emitter& operator << (YAML::Emitter& out, const T *v) {
if(v)
out << *v;
else
out << YAML::Null;
return out;
}
void PointerToInt(YAML::Emitter& out, std::string& desiredOutput)
{
int foo = 5;
int *bar = &foo;
int *baz = 0;
out << YAML::BeginSeq;
out << bar << baz;
out << YAML::EndSeq;
desiredOutput = "---\n- 5\n- ~";
}
void PointerToUserType(YAML::Emitter& out, std::string& desiredOutput)
{
Foo foo(5, "hello");
Foo *bar = &foo;
Foo *baz = 0;
out << YAML::BeginSeq;
out << bar << baz;
out << YAML::EndSeq;
desiredOutput = "---\n-\n x: 5\n bar: hello\n- ~";
}
////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -600,6 +804,18 @@ namespace Test
RunEmitterTest(&Emitter::BlockMapAsKey, "block map as key", passed, total);
RunEmitterTest(&Emitter::AliasAndAnchor, "alias and anchor", passed, total);
RunEmitterTest(&Emitter::AliasAndAnchorWithNull, "alias and anchor with null", passed, total);
RunEmitterTest(&Emitter::SimpleVerbatimTag, "simple verbatim tag", passed, total);
RunEmitterTest(&Emitter::VerbatimTagInBlockSeq, "verbatim tag in block seq", passed, total);
RunEmitterTest(&Emitter::VerbatimTagInFlowSeq, "verbatim tag in flow seq", passed, total);
RunEmitterTest(&Emitter::VerbatimTagInFlowSeqWithNull, "verbatim tag in flow seq with null", passed, total);
RunEmitterTest(&Emitter::VerbatimTagInBlockMap, "verbatim tag in block map", passed, total);
RunEmitterTest(&Emitter::VerbatimTagInFlowMap, "verbatim tag in flow map", passed, total);
RunEmitterTest(&Emitter::VerbatimTagInFlowMapWithNull, "verbatim tag in flow map with null", passed, total);
RunEmitterTest(&Emitter::VerbatimTagWithEmptySeq, "verbatim tag with empty seq", passed, total);
RunEmitterTest(&Emitter::VerbatimTagWithEmptyMap, "verbatim tag with empty map", passed, total);
RunEmitterTest(&Emitter::VerbatimTagWithEmptySeqAndMap, "verbatim tag with empty seq and map", passed, total);
RunEmitterTest(&Emitter::ByKindTagWithScalar, "by-kind tag with scalar", passed, total);
RunEmitterTest(&Emitter::LocalTagWithScalar, "local tag with scalar", passed, total);
RunEmitterTest(&Emitter::ComplexDoc, "complex doc", passed, total);
RunEmitterTest(&Emitter::STLContainers, "STL containers", passed, total);
RunEmitterTest(&Emitter::SimpleComment, "simple comment", passed, total);
@@ -609,6 +825,13 @@ namespace Test
RunEmitterTest(&Emitter::SimpleGlobalSettings, "simple global settings", passed, total);
RunEmitterTest(&Emitter::ComplexGlobalSettings, "complex global settings", passed, total);
RunEmitterTest(&Emitter::Null, "null", passed, total);
RunEmitterTest(&Emitter::EscapedUnicode, "escaped unicode", passed, total);
RunEmitterTest(&Emitter::Unicode, "unicode", passed, total);
RunEmitterTest(&Emitter::DoubleQuotedUnicode, "double quoted unicode", passed, total);
RunEmitterTest(&Emitter::UserType, "user type", passed, total);
RunEmitterTest(&Emitter::UserTypeInContainer, "user type in container", passed, total);
RunEmitterTest(&Emitter::PointerToInt, "pointer to int", passed, total);
RunEmitterTest(&Emitter::PointerToUserType, "pointer to user type", passed, total);
RunEmitterErrorTest(&Emitter::ExtraEndSeq, "extra EndSeq", passed, total);
RunEmitterErrorTest(&Emitter::ExtraEndMap, "extra EndMap", passed, total);
@@ -619,6 +842,7 @@ namespace Test
RunEmitterErrorTest(&Emitter::MissingValue, "missing value", passed, total);
RunEmitterErrorTest(&Emitter::UnexpectedKey, "unexpected key", passed, total);
RunEmitterErrorTest(&Emitter::UnexpectedValue, "unexpected value", passed, total);
RunEmitterErrorTest(&Emitter::BadLocalTag, "bad local tag", passed, total);
std::cout << "Emitter tests: " << passed << "/" << total << " passed\n";
return passed == total;
+7
View File
@@ -0,0 +1,7 @@
#include "tests.h"
int main()
{
Test::RunAll();
return 0;
}
@@ -118,7 +118,7 @@ namespace Test
inputScalar = "http://example.com/foo#bar";
desiredOutput = "http://example.com/foo#bar";
}
bool SimpleSeq()
{
std::string input =
@@ -610,6 +610,202 @@ namespace Test
return true;
}
bool BlockKeyWithNullValue()
{
std::string input =
"key:\n"
"just a key: value";
std::stringstream stream(input);
YAML::Parser parser(stream);
YAML::Node doc;
parser.GetNextDocument(doc);
if(doc.size() != 2)
return false;
if(!IsNull(doc["key"]))
return false;
if(doc["just a key"] != "value")
return false;
return true;
}
bool Bases()
{
std::string input =
"- 15\n"
"- 0x10\n"
"- 030\n"
"- 0xffffffff\n";
std::stringstream stream(input);
YAML::Parser parser(stream);
YAML::Node doc;
parser.GetNextDocument(doc);
if(doc.size() != 4)
return false;
if(doc[0] != 15)
return false;
if(doc[1] != 0x10)
return false;
if(doc[2] != 030)
return false;
if(doc[3] != 0xffffffff)
return false;
return true;
}
bool KeyNotFound()
{
std::string input = "key: value";
std::stringstream stream(input);
YAML::Parser parser(stream);
YAML::Node doc;
parser.GetNextDocument(doc);
try {
doc["bad key"];
} catch(const YAML::Exception& e) {
if(e.msg != YAML::ErrorMsg::KEY_NOT_FOUND + ": bad key")
throw;
}
try {
doc[5];
} catch(const YAML::Exception& e) {
if(e.msg != YAML::ErrorMsg::KEY_NOT_FOUND + ": 5")
throw;
}
try {
doc[2.5];
} catch(const YAML::Exception& e) {
if(e.msg != YAML::ErrorMsg::KEY_NOT_FOUND + ": 2.5")
throw;
}
return true;
}
bool DuplicateKey()
{
std::string input = "{a: 1, b: 2, c: 3, a: 4}";
std::stringstream stream(input);
YAML::Parser parser(stream);
YAML::Node doc;
parser.GetNextDocument(doc);
if(doc["a"] != 1)
return false;
if(doc["b"] != 2)
return false;
if(doc["c"] != 3)
return false;
return true;
}
void PrepareNodeForTagExam(YAML::Node& doc, const std::string& input)
{
std::stringstream stream(input);
YAML::Parser parser(stream);
parser.GetNextDocument(doc);
}
struct TagMismatch: public std::exception {
TagMismatch(const std::string& actualTag, const std::string& expectedTag) {
std::stringstream output;
output << "Tag has value \"" << actualTag << "\" but \"" << expectedTag << "\" was expected";
what_ = output.str();
}
virtual ~TagMismatch() throw() {}
virtual const char *what() const throw() { return what_.c_str(); }
private:
std::string what_;
};
bool ExpectedTagValue(YAML::Node& node, const char* tag)
{
if(node.GetTag() == tag)
return true;
throw TagMismatch(node.GetTag(), tag);
}
bool DefaultPlainScalarTag()
{
YAML::Node node;
PrepareNodeForTagExam(node, "--- 12");
return ExpectedTagValue(node, "?");
}
bool DefaultSingleQuotedScalarTag()
{
YAML::Node node;
PrepareNodeForTagExam(node, "--- '12'");
return ExpectedTagValue(node, "!");
}
bool ExplicitNonSpecificPlainScalarTag()
{
YAML::Node node;
PrepareNodeForTagExam(node, "--- ! 12");
return ExpectedTagValue(node, "!");
}
bool BasicLocalTag()
{
YAML::Node node;
PrepareNodeForTagExam(node, "--- !foo 12");
return ExpectedTagValue(node, "!foo");
}
bool VerbatimLocalTag()
{
YAML::Node node;
PrepareNodeForTagExam(node, "--- !<!foo> 12");
return ExpectedTagValue(node, "!foo");
}
bool StandardShortcutTag()
{
YAML::Node node;
PrepareNodeForTagExam(node, "--- !!int 12");
return ExpectedTagValue(node, "tag:yaml.org,2002:int");
}
bool VerbatimURITag()
{
YAML::Node node;
PrepareNodeForTagExam(node, "--- !<tag:yaml.org,2002:int> 12");
return ExpectedTagValue(node, "tag:yaml.org,2002:int");
}
bool DefaultSequenceTag()
{
YAML::Node node;
PrepareNodeForTagExam(node, "--- [12]");
return ExpectedTagValue(node, "?");
}
bool ExplicitNonSpecificSequenceTag()
{
YAML::Node node;
PrepareNodeForTagExam(node, "--- ! [12]");
return ExpectedTagValue(node, "!");
}
}
namespace {
@@ -627,7 +823,7 @@ namespace Test
doc >> output;
} catch(const YAML::Exception& e) {
ok = false;
error = e.msg;
error = e.what();
}
if(ok && output == desiredOutput) {
passed++;
@@ -650,7 +846,10 @@ namespace Test
ok = test();
} catch(const YAML::Exception& e) {
ok = false;
error = e.msg;
error = e.what();
} catch(const Parser::TagMismatch& e) {
ok = false;
error = e.what();
}
if(ok) {
passed++;
@@ -869,6 +1068,20 @@ namespace Test
RunParserTest(&Parser::MultipleDocs, "multiple docs", passed, total);
RunParserTest(&Parser::ExplicitEndDoc, "explicit end doc", passed, total);
RunParserTest(&Parser::MultipleDocsWithSomeExplicitIndicators, "multiple docs with some explicit indicators", passed, total);
RunParserTest(&Parser::BlockKeyWithNullValue, "block key with null value", passed, total);
RunParserTest(&Parser::Bases, "bases", passed, total);
RunParserTest(&Parser::KeyNotFound, "key not found", passed, total);
RunParserTest(&Parser::DuplicateKey, "duplicate key", passed, total);
RunParserTest(&Parser::DefaultPlainScalarTag, "default plain scalar tag", passed, total);
RunParserTest(&Parser::DefaultSingleQuotedScalarTag, "default single-quoted scalar tag", passed, total);
RunParserTest(&Parser::ExplicitNonSpecificPlainScalarTag, "explicit, non-specific plain scalar tag", passed, total);
RunParserTest(&Parser::BasicLocalTag, "basic local tag", passed, total);
RunParserTest(&Parser::VerbatimLocalTag, "verbatim local tag", passed, total);
RunParserTest(&Parser::StandardShortcutTag, "standard shortcut tag", passed, total);
RunParserTest(&Parser::VerbatimURITag, "verbatim URI tag", passed, total);
RunParserTest(&Parser::DefaultPlainScalarTag, "default plain scalar tag", passed, total);
RunParserTest(&Parser::DefaultSequenceTag, "default sequence tag", passed, total);
RunParserTest(&Parser::ExplicitNonSpecificSequenceTag, "explicit, non-specific sequence tag", passed, total);
RunEncodingTest(&EncodeToUtf8, false, "UTF-8, no BOM", passed, total);
RunEncodingTest(&EncodeToUtf8, true, "UTF-8 with BOM", passed, total);
File diff suppressed because it is too large Load Diff
+18 -3
View File
@@ -1,9 +1,25 @@
#include "yaml.h"
#include <fstream>
#include <iostream>
#include <vector>
struct Params {
bool hasFile;
std::string fileName;
};
Params ParseArgs(int argc, char **argv) {
Params p;
std::vector<char*> args(argv + 1, argv + argc);
return p;
}
int main(int argc, char **argv)
{
Params p = ParseArgs(argc, argv);
std::ifstream fin;
if(argc > 1)
fin.open(argv[1]);
@@ -11,9 +27,8 @@ int main(int argc, char **argv)
std::istream& input = (argc > 1 ? fin : std::cin);
try {
YAML::Parser parser(input);
while(parser) {
YAML::Node doc;
parser.GetNextDocument(doc);
YAML::Node doc;
while(parser.GetNextDocument(doc)) {
YAML::Emitter emitter;
emitter << doc;
std::cout << emitter.c_str() << "\n";
-10
View File
@@ -1,10 +0,0 @@
file(GLOB yaml-reader_headers *.h)
file(GLOB yaml-reader_sources *.cpp)
add_executable(yaml-reader
${yaml-reader_sources}
${yaml-reader_headers}
)
target_link_libraries(yaml-reader yaml-cpp)
add_test(yaml-reader-test yaml-reader)
-11
View File
@@ -1,11 +0,0 @@
#include "tests.h"
int main()
{
#ifdef WINDOWS
_CrtSetDbgFlag(_CRTDBG_LEAK_CHECK_DF|_CRTDBG_ALLOC_MEM_DF);
#endif // WINDOWS
Test::RunAll();
return 0;
}
-4
View File
@@ -1,4 +0,0 @@
--- &list
- This document contains a recursive list.
- *list
...
+15 -6
View File
@@ -1,12 +1,17 @@
Microsoft Visual Studio Solution File, Format Version 10.00
# Visual Studio 2008
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "yaml-reader", "yaml-reader.vcproj", "{E8CC0D8A-D784-4A6B-B78B-ACEA13F9FB0B}"
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "yamlcpp", "yamlcpp.vcproj", "{3104AB4E-CD31-4F47-95E9-0E8D9374E15D}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test", "test.vcproj", "{D1108F40-6ADF-467E-A95A-236C39A515C5}"
ProjectSection(ProjectDependencies) = postProject
{3104AB4E-CD31-4F47-95E9-0E8D9374E15D} = {3104AB4E-CD31-4F47-95E9-0E8D9374E15D}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "yamlcpp", "yamlcpp.vcproj", "{3104AB4E-CD31-4F47-95E9-0E8D9374E15D}"
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "parse", "parse.vcproj", "{CD007B57-7812-4930-A5E2-6E5E56338814}"
ProjectSection(ProjectDependencies) = postProject
{3104AB4E-CD31-4F47-95E9-0E8D9374E15D} = {3104AB4E-CD31-4F47-95E9-0E8D9374E15D}
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -14,14 +19,18 @@ Global
Release|Win32 = Release|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{E8CC0D8A-D784-4A6B-B78B-ACEA13F9FB0B}.Debug|Win32.ActiveCfg = Debug|Win32
{E8CC0D8A-D784-4A6B-B78B-ACEA13F9FB0B}.Debug|Win32.Build.0 = Debug|Win32
{E8CC0D8A-D784-4A6B-B78B-ACEA13F9FB0B}.Release|Win32.ActiveCfg = Release|Win32
{E8CC0D8A-D784-4A6B-B78B-ACEA13F9FB0B}.Release|Win32.Build.0 = Release|Win32
{3104AB4E-CD31-4F47-95E9-0E8D9374E15D}.Debug|Win32.ActiveCfg = Debug|Win32
{3104AB4E-CD31-4F47-95E9-0E8D9374E15D}.Debug|Win32.Build.0 = Debug|Win32
{3104AB4E-CD31-4F47-95E9-0E8D9374E15D}.Release|Win32.ActiveCfg = Release|Win32
{3104AB4E-CD31-4F47-95E9-0E8D9374E15D}.Release|Win32.Build.0 = Release|Win32
{D1108F40-6ADF-467E-A95A-236C39A515C5}.Debug|Win32.ActiveCfg = Debug|Win32
{D1108F40-6ADF-467E-A95A-236C39A515C5}.Debug|Win32.Build.0 = Debug|Win32
{D1108F40-6ADF-467E-A95A-236C39A515C5}.Release|Win32.ActiveCfg = Release|Win32
{D1108F40-6ADF-467E-A95A-236C39A515C5}.Release|Win32.Build.0 = Release|Win32
{CD007B57-7812-4930-A5E2-6E5E56338814}.Debug|Win32.ActiveCfg = Debug|Win32
{CD007B57-7812-4930-A5E2-6E5E56338814}.Debug|Win32.Build.0 = Debug|Win32
{CD007B57-7812-4930-A5E2-6E5E56338814}.Release|Win32.ActiveCfg = Release|Win32
{CD007B57-7812-4930-A5E2-6E5E56338814}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
+20 -4
View File
@@ -40,6 +40,7 @@
/>
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/D_SCL_SECURE_NO_WARNINGS"
Optimization="0"
AdditionalIncludeDirectories="include"
PreprocessorDefinitions="WIN32;_DEBUG;_LIB"
@@ -49,6 +50,7 @@
UsePrecompiledHeader="0"
WarningLevel="4"
DebugInformationFormat="3"
DisableSpecificWarnings="4127;4355"
/>
<Tool
Name="VCManagedResourceCompilerTool"
@@ -104,6 +106,7 @@
/>
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/D_SCL_SECURE_NO_WARNINGS"
Optimization="2"
EnableIntrinsicFunctions="true"
AdditionalIncludeDirectories="include"
@@ -113,6 +116,7 @@
UsePrecompiledHeader="0"
WarningLevel="4"
DebugInformationFormat="3"
DisableSpecificWarnings="4127;4355"
/>
<Tool
Name="VCManagedResourceCompilerTool"
@@ -171,10 +175,6 @@
RelativePath=".\src\aliascontent.cpp"
>
</File>
<File
RelativePath=".\src\content.cpp"
>
</File>
<File
RelativePath=".\src\conversion.cpp"
>
@@ -203,6 +203,10 @@
RelativePath=".\src\sequence.cpp"
>
</File>
<File
RelativePath=".\src\tag.cpp"
>
</File>
</Filter>
<Filter
Name="Scanner"
@@ -223,6 +227,10 @@
RelativePath=".\src\scanscalar.cpp"
>
</File>
<File
RelativePath=".\src\scantag.cpp"
>
</File>
<File
RelativePath=".\src\scantoken.cpp"
>
@@ -337,6 +345,10 @@
RelativePath=".\src\sequence.h"
>
</File>
<File
RelativePath=".\src\tag.h"
>
</File>
</Filter>
<Filter
Name="Scanner"
@@ -361,6 +373,10 @@
RelativePath=".\src\scanscalar.h"
>
</File>
<File
RelativePath=".\src\scantag.h"
>
</File>
<File
RelativePath=".\src\stream.h"
>