├── .gitignore ├── .travis.yml ├── Makefile ├── bower.json ├── package.json ├── CHANGELOG.md ├── README.md ├── hipack.min.js ├── test └── test.js ├── hipack.min.map └── hipack.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: "node_js" 2 | node_js: 3 | - "node" 4 | - "iojs" 5 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | UGLIFY_FLAGS = -c -m 3 | 4 | all: 5 | 6 | node_modules/uglify-hs/bin/uglifyjs node_modules/mocha/bin/mocha: 7 | @npm install 8 | 9 | %.min.js %.min.map: %.js | node_modules/uglify-js/bin/uglifyjs 10 | ./node_modules/uglify-js/bin/uglifyjs $(UGLIFY_FLAGS) \ 11 | --source-map $(patsubst %.js,%.map,$@) \ 12 | -o $@ $< 13 | 14 | all: hipack.min.js hipack.min.map 15 | 16 | test: node_modules/mocha/bin/mocha 17 | @./node_modules/mocha/bin/mocha 18 | 19 | .PHONY: test 20 | 21 | # vim:ft=make 22 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hipack-js", 3 | "version": "0.1.5", 4 | "description": "HiPack (de)serialization module", 5 | "keywords": ["hipack", "serialization", "parser"], 6 | "authors": "Adrián Pérez de Castro ", 7 | "license": "MIT", 8 | "main": "hipack.js", 9 | "moduleType": ["node", "globals"], 10 | "homepage": "https://github.com/aperezdc/hipack-js", 11 | "repository": { 12 | "type": "git", 13 | "url": "git://github.com/aperezdc/hipack-js.git" 14 | }, 15 | "ignore": [ 16 | "**/.*", 17 | "node_modules", 18 | "bower_components", 19 | "test" 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hipack-js", 3 | "version": "0.1.5", 4 | "description": "HiPack (de)serialization module", 5 | "main": "hipack.js", 6 | "scripts": { 7 | "test": "./node_modules/mocha/bin/mocha" 8 | }, 9 | "devDependencies": { 10 | "should": ">=7.0.0", 11 | "mocha": ">=2.2.0", 12 | "uglify-js": "*" 13 | }, 14 | "repository": { 15 | "type": "git", 16 | "url": "git+https://github.com/aperezdc/hipack-js.git" 17 | }, 18 | "keywords": [ 19 | "hipack", 20 | "serialization", 21 | "parser" 22 | ], 23 | "author": "Adrián Pérez de Castro ", 24 | "license": "MIT", 25 | "bugs": { 26 | "url": "https://github.com/aperezdc/hipack-js/issues" 27 | }, 28 | "homepage": "https://github.com/aperezdc/hipack-js#readme" 29 | } 30 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | All notable changes to this project will be documented in this file. 3 | 4 | ## [Unreleased] 5 | 6 | ## [v0.1.5] - 2016-12-07 7 | ### Fixed 8 | - Cast function is now called also for hexadecimal numbers. 9 | 10 | ## [v0.1.4] - 2015-12-03 11 | ### Fixed 12 | - Correct handling of multiple framed messages, which are now correctly 13 | returned by repeated calls to `Parser.parseMessage()`. 14 | 15 | ## [v0.1.3] - 2015-12-02 16 | ### Added 17 | - Support for HEP-1 Value Annotations. 18 | - Added this change log. 19 | 20 | ### Fixed 21 | - Fixed a couple of situations in which a `ReferenceError` would have been 22 | thrown; now a `hipack.ParseError` are correctly thrown. 23 | 24 | [Unreleased]: https://github.com/aperezdc/hipack-js/compare/v0.1.5...HEAD 25 | [v0.1.5]: https://github.com/aperezdc/hipack-js/compare/v0.1.4...v0.1.5 26 | [v0.1.4]: https://github.com/aperezdc/hipack-js/compare/v0.1.3...v0.1.4 27 | [v0.1.3]: https://github.com/aperezdc/hipack-js/compare/v0.1.2...v0.1.3 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | HiPack (de)serialization library in JavaScript 2 | ============================================== 3 | 4 | [![Builld status](https://img.shields.io/travis/aperezdc/hipack-js.svg?style=flat-square)](https://travis-ci.org/aperezdc/hipack-js) 5 | 6 | JavaScript module to work with the [HiPack](http://hipack.org) serialization 7 | format. The implementation and API are intentionally simple. 8 | 9 | Features: 10 | 11 | * Reading and writing HiPack formatted messages. 12 | * Works in NodeJS and browsers. 13 | * Small, self contained JavaScript implementation. 14 | * Less than 8kB when minified using [UglifyJS2](http://lisperator.net/uglifyjs/)! 15 | 16 | 17 | Installation 18 | ------------ 19 | 20 | For [Node](http://nodejs.org), `npm` can be used to install the module: 21 | 22 | ```sh 23 | npm install hipack-js 24 | ``` 25 | 26 | A `hipack-js` package is also available to be used with 27 | [Bower](http://bower.io): 28 | 29 | ```sh 30 | bower install hipack-js 31 | ``` 32 | 33 | 34 | Usage 35 | ----- 36 | 37 | (The following examples use [Node](http://nodejs.org).) 38 | 39 | First, import the module: 40 | 41 | ```javascript 42 | var hipack = require("hipack") 43 | ``` 44 | 45 | To serialize an object containing data, use `hipack.dump()`: 46 | 47 | ```javascript 48 | var hiPackText = hipack.dump({ 49 | authors: [ 50 | { name: "Adrián Pérez", email: "aperez@igalia.com" }, 51 | { name: "John Doe", email: "j@doe.org" }, 52 | ] 53 | }); 54 | console.info(hiPackText); 55 | ``` 56 | 57 | The call to `console.info()` will output the following 58 | 59 | ``` 60 | authors [ 61 | { 62 | email: "aperez@igalia.com" 63 | name: "Adrián Pérez" 64 | } 65 | { 66 | email: "j@doe.org" 67 | name: "John Doe" 68 | } 69 | ] 70 | ``` 71 | 72 | Optionally, pass `true` as a second parameter to `hipack.dump()` in order to 73 | generate a “compact” representation of the data with indentation and 74 | whitespace removed, all in a single line. 75 | 76 | Parsing is done using the `hipack.load()` function: 77 | 78 | ```javascript 79 | var data = hipack.load(hiPackText); 80 | ``` 81 | 82 | 83 | Browser Usage 84 | ------------- 85 | 86 | The [hipack.js](hipack.js) script can be directly used with a ` 92 | ``` 93 | 94 | If the `hipack` global name needs to be used for other purposes, 95 | a `hipack.noConflict()` function is provided, which will restore its previous 96 | value and return the `hipack` object: 97 | 98 | ```html 99 | 104 | ``` 105 | -------------------------------------------------------------------------------- /hipack.min.js: -------------------------------------------------------------------------------- 1 | "use strict";(function(){function t(t){switch(t){case 9:case 10:case 13:case 32:return!0;default:return!1}}function e(t){switch(t){case 9:case 10:case 13:case 32:case 91:case 93:case 123:case 125:case 58:case 44:return!1;default:return!0}}function s(t){switch(t){case 48:case 49:case 50:case 51:case 52:case 53:case 54:case 55:case 56:case 57:case 97:case 65:case 98:case 66:case 99:case 67:case 100:case 68:case 101:case 69:case 102:case 70:return!0;default:return!1}}function r(t){switch(t){case 46:case 43:case 61:return!0;default:return s(t)}}function o(t){return t>48&&56>t}function i(t){switch(t){case 48:return 0;case 49:return 1;case 50:return 2;case 51:return 3;case 52:return 4;case 53:return 5;case 54:return 6;case 55:return 7;case 56:return 8;case 57:return 9;case 97:case 65:return 10;case 98:case 66:return 11;case 99:case 67:return 12;case 100:case 68:return 13;case 101:case 69:return 14;case 102:case 70:return 15}}var h=this,a=h.hipack,n={};if(n.noConflict=function(){return h.hipack=a,n},void 0===u){var u=function(){this._set=Object.create(null)};u.prototype.add=function(t){this._set[t]=!0},u.prototype.remove=function(t){delete this._set[t]},u.prototype.contains=function(t){return!!this._set[t]},u.prototype.clear=function(){this._set=Object.create(null)},u.prototype.empty=function(){return 0==Object.keys(this._set).length},u.prototype.size=function(){return Object.keys(this._set).length},u.prototype.get=function(){return Object.keys(this._set)}}n.ANNOT_INT=".int",n.ANNOT_FLOAT=".float",n.ANNOT_BOOL=".bool",n.ANNOT_STRING=".string",n.ANNOT_LIST=".list",n.ANNOT_DICT=".dict";var c=Object.keys,p=Array.isArray;n.DumpError=function(t){this.message=t,Error.captureStackTrace?Error.captureStackTrace(this,this.constructor):this.stack=Error().stack},n.value=function(t,e){return t},n.Dumper=function(t,e){void 0===e&&(e=n.value),this.indent=t?-1:0,this.value=e,this.output=""},n.Dumper.prototype.moreIndent=function(){this.indent>=0&&this.indent++},n.Dumper.prototype.lessIndent=function(){this.indent>0&&this.indent--},n.Dumper.prototype.dumpIndent=function(){for(var t=this.indent>=0?this.indent:0;t--;)this.output+=" "},n.Dumper.prototype.dumpString=function(t){this.output+='"';for(var e=0;es?(this.output+="\\",16>s&&(this.output+="0"),this.output+=s.toString(16).toUpperCase()):this.output+=t.charAt(e)}}this.output+='"'},n.Dumper.prototype.dumpBoolean=function(t){this.output+=t?"True":"False"},n.Dumper.prototype.dumpNumber=function(t){this.output+=t.toString()},n.Dumper.prototype.dumpKeyVal=function(t,e){for(var s=0;s=0&&(this.output+=" "),this.dumpValue(r),this.indent>=0?this.output+="\n":s=0&&(this.output+="\n");for(var e=0;e=0?this.output+="\n":e=0&&(this.output+="\n"),this.dumpKeyVal(t,e.sort()),this.lessIndent(),this.dumpIndent(),void(this.output+="}"))},n.Dumper.prototype.dumpValue=function(t){var e=new u;if(t=this.value(t,e),!e.empty()){this.indent<0&&":"!=this.output[this.output.length-1]&&(this.output+=":"),e=e.get();for(var s=0;s=this.input.length)return l;var t=this.input.charCodeAt(this.pos++);return 10==t&&(this.column=0,this.line++),this.column++,t},n.Parser.prototype.nextCharCode=function(){do if(this.look=this.nextCharCodeRaw(),35==this.look)for(;10!=this.look&&this.look!=l;)this.look=this.nextCharCodeRaw();while(this.look!=l&&35==this.look)},n.Parser.prototype.skipWhite=function(){for(;this.look!=l&&t(this.look);)this.nextCharCode()},n.Parser.prototype.matchCharCode=function(t,e){if(this.look!=t)throw void 0===e&&(e="Expected '"+f(t)+"', but '"+f(this.look)+"' was found instead"),new n.ParseError(this,e);this.nextCharCode()},n.Parser.prototype.parseKey=function(){for(var t=null;this.look!=l&&e(this.look);)null===t&&(t=""),t+=f(this.look),this.nextCharCode();if(null===t)throw new n.ParseError(this,"key expected");return t},n.Parser.prototype.parseString=function(t){this.matchCharCode(34);for(var e='"',r="";34!=this.look&&this.look!=l;){if(e+=f(this.look),92==this.look)switch(this.look=this.nextCharCodeRaw()){case 34:this.look=34;break;case 110:this.look=10;break;case 114:this.look=13;break;case 116:this.look=9;break;case 92:this.look=92;break;default:var o=this.nextCharCodeRaw();if(!s(o)||!s(this.look))throw new n.ParseError(this,"invalid escape sequence");this.look=16*i(this.look)+i(o)}r+=f(this.look),this.look=this.nextCharCodeRaw()}return this.matchCharCode(34),e+='"',t.add(n.ANNOT_STRING),this.cast(t,e,r)},n.Parser.prototype.parseList=function(e){this.matchCharCode(91),this.skipWhite();for(var s=[];93!=this.look;){s.push(this.parseValue());var r=t(this.look);if(this.skipWhite(),44==this.look)this.nextCharCode();else if(!r&&!t(this.look))break;this.skipWhite()}return this.matchCharCode(93),e.add(n.ANNOT_LIST),this.cast(e,null,s)},n.Parser.prototype.parseDict=function(t){this.matchCharCode(123),this.skipWhite();var e=this.parseKeyValItems(125);return this.matchCharCode(125),t.add(n.ANNOT_DICT),this.cast(t,null,e)},n.Parser.prototype.parseBoolean=function(t){t.add(n.ANNOT_BOOL);var e=f(this.look);if(84==this.look||116==this.look)return this.nextCharCode(),this.matchCharCode(114),this.matchCharCode(117),this.matchCharCode(101),this.cast(t,e+"rue",!0);if(70==this.look||102==this.look)return this.nextCharCode(),this.matchCharCode(97),this.matchCharCode(108),this.matchCharCode(115),this.matchCharCode(101),this.cast(t,e+"alse",!1);throw new n.ParseError(this,"boolean value expected")},n.Parser.prototype.parseNumber=function(t){var e="",s=!1;(43==this.look||45==this.look)&&(e+=f(this.look),this.nextCharCode(),s=!0);var i=!1,h=!1;48==this.look&&(e+="0",this.nextCharCode(),88==this.look||120==this.look?(e+=f(this.look),this.nextCharCode(),h=!0):o(this.look)&&(i=!0));for(var a=!1,u=!1;this.look!=l&&r(this.look);)if(h||69!=this.look&&101!=this.look){if(46==this.look){if(a||h||i)throw new n.ParseError(this,"invalid number");a=!0}if(43==this.look||45==this.look)throw new n.ParseError(this,"invalid number");e+=f(this.look),this.nextCharCode()}else{if(u)throw new n.ParseError(this,"invalid number");e+="e",u=!0,this.nextCharCode(),(43==this.look||45==this.look)&&(e+=f(this.look),this.nextCharCode())}if(0==e.length)throw new n.ParseError(this,"number expected");if(h){if(u||a)throw new n.ParseError(this,"invalid hex number");return t.add(n.ANNOT_INT),this.cast(t,e,d(e,16))}if(i){if(u||a)throw new n.ParseError(this,"invalid octal number");return t.add(n.ANNOT_INT),this.cast(t,e,d(e,8))}return a||u?(t.add(n.ANNOT_FLOAT),this.cast(t,e,k(e))):(t.add(n.ANNOT_INT),this.cast(t,e,d(e,10)))},n.Parser.prototype.parseAnnotations=function(){for(var t=new u;58==this.look;){this.nextCharCode();var e=this.parseKey();if(t.contains(e))throw new ParseError(this,"duplicate annotation: "+e);t.add(e),this.skipWhite()}return t},n.Parser.prototype.parseValue=function(){var t=this.parseAnnotations();switch(this.look){case 34:return this.parseString(t);case 91:return this.parseList(t);case 123:return this.parseDict(t);case 84:case 116:case 70:case 102:return this.parseBoolean(t);default:return this.parseNumber(t)}},n.Parser.prototype.parseKeyValItems=function(e){for(var s={};this.look!=e&&this.look!=l;){var r=this.parseKey(),o=!1;if(t(this.look)?(o=!0,this.skipWhite()):58==this.look?(o=!0,this.nextCharCode(),this.skipWhite()):(123==this.look||91==this.look)&&(o=!0),!o)throw new n.ParseError(this,"missing separator");if(s[r]=this.parseValue(),44==this.look)this.nextCharCode();else if(this.look!=e&&!t(this.look))break;this.skipWhite()}return s},n.Parser.prototype.parseMessage=function(){var t=null;return this.framed?this.look!=l&&(this.matchCharCode(123),this.nextCharCode(),this.skipWhite(),t=this.parseKeyValItems(125),this.matchCharCode(125,"unterminated message, '}' expected"),this.skipWhite()):t=this.parseKeyValItems(l),t},n.load=function(t,e){return new n.Parser(String(t),e).parseMessage()},"undefined"!=typeof exports?("undefined"!=typeof module&&module.exports&&(exports=module.exports=n),exports.hipack=n):h.hipack=n}).call(this); 2 | //# sourceMappingURL=hipack.min.map -------------------------------------------------------------------------------- /test/test.js: -------------------------------------------------------------------------------- 1 | /* 2 | * test.js 3 | * Copyright (C) 2015 Adrian Perez 4 | * 5 | * Distributed under terms of the MIT license. 6 | */ 7 | 8 | var hipack = require("../hipack"); 9 | var should = require("should"); 10 | 11 | describe("hipack", function () { 12 | it("has a .dump() function", function () { 13 | hipack.should.have.property("dump").which.is.a.Function(); 14 | }); 15 | it("has a .load() function", function () { 16 | hipack.should.have.property("load").which.is.a.Function(); 17 | }); 18 | it("has a Dumper() function", function () { 19 | hipack.should.have.property("Dumper").which.is.a.Function(); 20 | }); 21 | if("has a Parser() function", function () { 22 | hipack.should.have.property("Parser").which.is.a.Function(); 23 | }); 24 | it("has a DumpError() function", function () { 25 | hipack.should.have.property("DumpError").which.is.a.Function(); 26 | }); 27 | it("has a ParseError() function", function () { 28 | hipack.should.have.property("ParseError").which.is.a.Function(); 29 | }); 30 | it("has a noConflict() function", function () { 31 | hipack.should.have.property("noConflict").which.is.a.Function(); 32 | }); 33 | it("has an ANNOT_INT property", function () { 34 | hipack.should.have.property("ANNOT_INT").which.is.a.String(); 35 | }); 36 | it("has an ANNOT_FLOAT property", function () { 37 | hipack.should.have.property("ANNOT_FLOAT").which.is.a.String(); 38 | }); 39 | it("has an ANNOT_BOOL property", function () { 40 | hipack.should.have.property("ANNOT_BOOL").which.is.a.String(); 41 | }); 42 | it("has an ANNOT_STRING property", function () { 43 | hipack.should.have.property("ANNOT_STRING").which.is.a.String(); 44 | }); 45 | it("has an ANNOT_LIST property", function () { 46 | hipack.should.have.property("ANNOT_LIST").which.is.a.String(); 47 | }); 48 | it("has an ANNOT_DICT property", function () { 49 | hipack.should.have.property("ANNOT_DICT").which.is.a.String(); 50 | }); 51 | 52 | describe(".dump()", function () { 53 | 54 | it("encodes empty objects", function () { 55 | hipack.dump({}).should.equal(""); 56 | }); 57 | it("encodes integer numbers", function () { 58 | hipack.dump({ value: 42 }).should.equal("value: 42\n"); 59 | }); 60 | it("encodes floating point numbers", function () { 61 | hipack.dump({ value: 1.5 }).should.equal("value: 1.5\n"); 62 | }); 63 | it("encodes string values", function () { 64 | hipack.dump({ value: "a string" }).should.equal( 65 | "value: \"a string\"\n"); 66 | }); 67 | it("encodes boolean values", function () { 68 | hipack.dump({ value: false }).should.equal("value: False\n"); 69 | hipack.dump({ value: true }).should.equal("value: True\n"); 70 | }); 71 | it("encodes empty arrays", function () { 72 | hipack.dump({ value: [] }).should.equal("value []\n"); 73 | }); 74 | it("encodes empty objects recursively", function () { 75 | hipack.dump({ value: {} }).should.equal("value {}\n"); 76 | }); 77 | it("encodes objects recursively", function () { 78 | hipack.dump({ value: { value: 42 } }).should.equal( 79 | "value {\n" + 80 | " value: 42\n" + 81 | "}\n"); 82 | }); 83 | it("encodes values with annotations", function () { 84 | hipack.dump({ value: 1 }, false, function (obj, ann) { 85 | ann.add("annot"); return obj; 86 | }).should.equal("value: :annot 1\n"); 87 | }); 88 | it("encodes values with annotations compactly", function () { 89 | hipack.dump({ value: 1 }, true, function (obj, ann) { 90 | ann.add("annot"); return obj; 91 | }).should.equal("value::annot 1"); 92 | }); 93 | it("encodes compound values with annotations", function () { 94 | hipack.dump({ value: [] }, false, function (obj, ann) { 95 | ann.add("annot"); return obj; 96 | }).should.equal("value :annot []\n"); 97 | }); 98 | it("encodes compund values with annotations compactly", function () { 99 | hipack.dump({ value: [] }, true, function (obj, ann) { 100 | ann.add("annot"); return obj; 101 | }).should.equal("value::annot []"); 102 | }); 103 | 104 | it("sorts dictionary keys", function () { 105 | hipack.dump({ c:1, b:2, a:3 }).should.equal("a: 3\nb: 2\nc: 1\n"); 106 | }); 107 | 108 | it("supports compact output mode", function () { 109 | hipack.dump({ value: [1, 2, 3, 4, 5] }, true) 110 | .should.equal("value[1,2,3,4,5]"); 111 | hipack.dump({ value: { a: 1, b: [2, 3] } }, true) 112 | .should.equal("value{a:1,b[2,3]}"); 113 | }); 114 | 115 | it("cannot encode nulls", function () { 116 | (function () { 117 | hipack.dump({ value: null }); 118 | }).should.throw(hipack.DumpError); 119 | }); 120 | it("cannot encode undefineds", function () { 121 | (function () { 122 | hipack.dump({ value: undefined }); 123 | }).should.throw(hipack.DumpError); 124 | }); 125 | it("cannot encode functions", function () { 126 | (function () { 127 | hipack.dump({ value: function (){} }); 128 | }).should.throw(hipack.DumpError); 129 | }); 130 | 131 | if (typeof Symbol !== "undefined") { 132 | it("cannot encode symbols", function () { 133 | (function () { 134 | hipack.dump({ value: Symbol("aSymbol") }); 135 | }).should.throw(hipack.DumpError); 136 | }); 137 | } 138 | 139 | }); 140 | 141 | 142 | describe(".load()", function () { 143 | 144 | it("decodes boolean values", function () { 145 | hipack.load("value: True").should.have.property("value") 146 | .which.is.a.Boolean().and.is.True(); 147 | hipack.load("value: true").should.have.property("value") 148 | .which.is.a.Boolean().and.is.True(); 149 | hipack.load("value: False").should.have.property("value") 150 | .which.is.a.Boolean().and.is.False(); 151 | hipack.load("value: false").should.have.property("value") 152 | .which.is.a.Boolean().and.is.False(); 153 | }); 154 | it("decodes integer values", function () { 155 | hipack.load("value: 42").should.have.property("value") 156 | .which.is.a.Number().and.is.equal(42); 157 | }); 158 | it("decodes negative integer values", function () { 159 | hipack.load("value: -42").should.have.property("value") 160 | .which.is.a.Number().and.is.equal(-42); 161 | }); 162 | it("decodes hex integer values", function () { 163 | hipack.load("value: 0xCAFE").should.have.property("value") 164 | .which.is.a.Number().and.is.equal(0xCAFE); 165 | }); 166 | it("decodes negative hex integer values", function () { 167 | hipack.load("value: -0xCAFE").should.have.property("value") 168 | .which.is.a.Number().and.is.equal(-0xCAFE); 169 | }); 170 | it("decodes octal integer values", function () { 171 | hipack.load("value: 01755").should.have.property("value") 172 | .which.is.a.Number().and.is.equal(01755); 173 | }); 174 | it("decodes negative octal integer values", function () { 175 | hipack.load("value: -01755").should.have.property("value") 176 | .which.is.a.Number().and.is.equal(-01755); 177 | }); 178 | it("decodes floating point values", function () { 179 | hipack.load("value: 3.14").should.have.property("value") 180 | .which.is.a.Number().and.is.equal(3.14); 181 | hipack.load("value: -3.14").should.have.property("value") 182 | .which.is.a.Number().and.is.equal(-3.14); 183 | hipack.load("value: -3.14e4").should.have.property("value") 184 | .which.is.a.Number().and.is.equal(-3.14e4); 185 | hipack.load("value: 3.14e-4").should.have.property("value") 186 | .which.is.a.Number().and.is.equal(3.14e-4); 187 | hipack.load("value: -3.14e-4").should.have.property("value") 188 | .which.is.a.Number().and.is.equal(-3.14e-4); 189 | hipack.load("value: 3e4").should.have.property("value") 190 | .which.is.a.Number().and.is.equal(3e4); 191 | hipack.load("value: -3e4").should.have.property("value") 192 | .which.is.a.Number().and.is.equal(-3e4); 193 | }); 194 | it("decodes string values", function () { 195 | hipack.load("value: \"Spam\"").should.have.property("value") 196 | .which.is.a.String().and.is.equal("Spam"); 197 | }); 198 | it("decodes empty list values", function () { 199 | hipack.load("value: []").should.have.property("value") 200 | .which.is.an.Array().and.is.empty(); 201 | }); 202 | it("decodes list values", function () { 203 | hipack.load("value: [True, False, True]") 204 | .should.have.property("value") 205 | .which.is.an.Array().and.is.eql([true, false, true]); 206 | }); 207 | it("decodes empty dictionary values", function () { 208 | hipack.load("value: {}").should.have.property("value") 209 | .which.is.an.Object().and.is.eql({}); 210 | }); 211 | it("decodes dictionary values", function () { 212 | hipack.load("value: { value: True }") 213 | .should.have.property("value") 214 | .which.is.an.Object().eql({ value: true }); 215 | }); 216 | it("decodes space-separated list items", function () { 217 | hipack.load("value: [1 2 3]").should.have.property("value") 218 | .which.is.an.Array().and.is.eql([1, 2, 3]); 219 | }); 220 | it("decodes comma-separated list items", function () { 221 | hipack.load("value: [1,2, 3]").should.have.property("value") 222 | .which.is.an.Array().and.is.eql([1, 2, 3]); 223 | }); 224 | it("decodes mixed-separated list items", function () { 225 | hipack.load("value: [1,2 3]").should.have.property("value") 226 | .which.is.an.Array().and.is.eql([1, 2, 3]); 227 | }); 228 | it("decodes space-separated dict items", function () { 229 | hipack.load("value { a:1 b:2 }").should.have.property("value") 230 | .which.is.an.Object().and.is.eql({ a:1, b:2 }); 231 | }); 232 | it("decodes comma-separated dict items", function () { 233 | hipack.load("value { a:1,b:2 }").should.have.property("value") 234 | .which.is.an.Object().and.is.eql({ a:1, b:2 }); 235 | }); 236 | it("decodes mixed-separated dict items", function () { 237 | hipack.load("value { a:1,b:2 c:3 }").should.have.property("value") 238 | .which.is.an.Object().and.is.eql({ a:1, b:2, c:3 }); 239 | }); 240 | it("decodes dict items which omit colon-after-key", function () { 241 | hipack.load("value { a 1, b 2 }").should.have.property("value") 242 | .which.is.an.Object().and.is.eql({ a:1, b:2 }); 243 | }); 244 | it("decodes space-separated dict items which omit colon-after-key", function () { 245 | hipack.load("value { a 1 b 2 }").should.have.property("value") 246 | .which.is.an.Object().and.is.eql({ a:1, b:2 }); 247 | }); 248 | it("parses a single annotation", function () { 249 | hipack.load("value :annot { a 1 }", function (annotations, _, value) { 250 | if (typeof value === "object") { 251 | annotations.contains("annot").should.equal(true); 252 | annotations.contains("other").should.equal(false); 253 | } 254 | return value; 255 | }).should.have.property("value").which.is.an.Object().and.is.eql({ a:1 }); 256 | }); 257 | it("parses multiple annotations", function () { 258 | hipack.load("value :ann1 :ann2 :ann3 { a 1 }", function (annotations, _, value) { 259 | if (typeof value === "object") { 260 | annotations.contains("ann1").should.equal(true); 261 | annotations.contains("ann2").should.equal(true); 262 | annotations.contains("ann3").should.equal(true); 263 | annotations.contains("other").should.equal(false); 264 | } 265 | return value; 266 | }).should.have.property("value").which.is.an.Object().and.is.eql({ a:1 }); 267 | }); 268 | }); 269 | 270 | describe("Parser", function () { 271 | it("parses framed subsequent messages", function () { 272 | var input = "{ value: 1 }\n" + 273 | "{ value: 2 }\n" + 274 | "{ value: 3 }\n"; 275 | var parser = new hipack.Parser(input); 276 | for (var i = 1; i <= 3; i++) { 277 | var msg = parser.parseMessage(); 278 | msg.should.have.property("value").which.is.eql(i); 279 | } 280 | }); 281 | it("returns null after the last framed message", function () { 282 | var parser = new hipack.Parser("{ value: 42 }\n"); 283 | parser.parseMessage().should.have.property("value").which.is.eql(42); 284 | should(parser.parseMessage()).equal(null); 285 | }); 286 | }); 287 | }); 288 | -------------------------------------------------------------------------------- /hipack.min.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["hipack.js"],"names":["isHiPackWhitespace","ch","isHiPackKeyCharacter","isHexDigit","isNumberCharacter","isOctalNonZeroDigit","hexDigitToInt","xdigit","root","this","previousModule","hipack","noConflict","undefined","Set","_set","Object","create","prototype","add","item","remove","contains","clear","empty","keys","length","size","get","ANNOT_INT","ANNOT_FLOAT","ANNOT_BOOL","ANNOT_STRING","ANNOT_LIST","ANNOT_DICT","_objectKeys","_isArray","Array","isArray","DumpError","message","Error","captureStackTrace","constructor","stack","value","obj","annotations","Dumper","compact","indent","output","moreIndent","lessIndent","dumpIndent","dumpString","i","charCodeAt","toString","toUpperCase","charAt","dumpBoolean","dumpNumber","dumpKeyVal","dumpValue","dumpList","list","dumpDict","dict","sort","valueType","dump","data","dumper","Boolean","EOF","_parseInt","Number","parseInt","_parseFloat","parseFloat","_fromCharCode","String","fromCharCode","ParseError","parser","position","pos","line","column","cast","input","Parser","look","nextCharCode","skipWhite","framed","nextCharCodeRaw","matchCharCode","errmsg","parseKey","key","parseString","s","str","extra","parseList","push","parseValue","gotWhitespace","parseDict","parseKeyValItems","parseBoolean","parseNumber","number","hasSign","isOctal","isHex","dotSeen","expSeen","parseAnnotations","eos","gotSeparator","parseMessage","result","load","exports","module","call"],"mappings":"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","file":"hipack.min.js"} -------------------------------------------------------------------------------- /hipack.js: -------------------------------------------------------------------------------- 1 | /* 2 | * hipack.js 3 | * Copyright (C) 2015-2016 Adrian Perez 4 | * 5 | * Distributed under terms of the MIT license. 6 | */ 7 | 8 | "use strict"; 9 | (function () { 10 | var root = this; 11 | var previousModule = root.hipack; 12 | 13 | var hipack = {}; 14 | hipack.noConflict = function () { 15 | root.hipack = previousModule; 16 | return hipack; 17 | } 18 | 19 | /* Minimal implementation of ES6 Set, used as fall-back. */ 20 | if (Set === undefined) { 21 | var Set = function () { this._set = Object.create(null) } 22 | Set.prototype.add = function (item) { this._set[item] = true } 23 | Set.prototype.remove = function (item) { delete this._set[item] } 24 | Set.prototype.contains = function (item) { return !!this._set[item] } 25 | Set.prototype.clear = function () { this._set = Object.create(null) } 26 | Set.prototype.empty = function () { return Object.keys(this._set).length == 0 } 27 | Set.prototype.size = function () { return Object.keys(this._set).length } 28 | Set.prototype.get = function () { return Object.keys(this._set) } 29 | } 30 | 31 | hipack.ANNOT_INT = ".int"; 32 | hipack.ANNOT_FLOAT = ".float"; 33 | hipack.ANNOT_BOOL = ".bool"; 34 | hipack.ANNOT_STRING = ".string"; 35 | hipack.ANNOT_LIST = ".list"; 36 | hipack.ANNOT_DICT = ".dict"; 37 | 38 | 39 | function isHiPackWhitespace(ch) { 40 | switch (ch) { 41 | case 0x09: /* Horizontal tab. */ 42 | case 0x0A: /* New line. */ 43 | case 0x0D: /* Carriage return. */ 44 | case 0x20: /* Space. */ 45 | return true; 46 | default: 47 | return false; 48 | } 49 | } 50 | 51 | 52 | function isHiPackKeyCharacter(ch) { 53 | switch (ch) { 54 | /* Keys do not contain whitespace. */ 55 | case 0x09: /* Horizontal tab. */ 56 | case 0x0A: /* New line. */ 57 | case 0x0D: /* Carriage return. */ 58 | case 0x20: /* Space. */ 59 | /* Characters forbidden in keys by the spec. */ 60 | case 0x5B: /* '[' */ 61 | case 0x5D: /* ']' */ 62 | case 0x7B: /* '{' */ 63 | case 0x7D: /* '}' */ 64 | case 0x3A: /* ':' */ 65 | case 0x2C: /* ',' */ 66 | return false; 67 | default: 68 | return true; 69 | } 70 | } 71 | 72 | 73 | function isHexDigit(ch) { 74 | switch (ch) { 75 | case 0x30: /* '0' */ 76 | case 0x31: /* '1' */ 77 | case 0x32: /* '2' */ 78 | case 0x33: /* '3' */ 79 | case 0x34: /* '4' */ 80 | case 0x35: /* '5' */ 81 | case 0x36: /* '6' */ 82 | case 0x37: /* '7' */ 83 | case 0x38: /* '8' */ 84 | case 0x39: /* '9' */ 85 | case 0x61: /* 'a' */ case 0x41: /* 'A' */ 86 | case 0x62: /* 'b' */ case 0x42: /* 'B' */ 87 | case 0x63: /* 'c' */ case 0x43: /* 'C' */ 88 | case 0x64: /* 'd' */ case 0x44: /* 'D' */ 89 | case 0x65: /* 'e' */ case 0x45: /* 'E' */ 90 | case 0x66: /* 'f' */ case 0x46: /* 'F' */ 91 | return true; 92 | default: 93 | return false; 94 | } 95 | } 96 | 97 | 98 | function isNumberCharacter(ch) { 99 | switch (ch) { 100 | case 0x2E: /* '.' */ 101 | case 0x2B: /* '+' */ 102 | case 0x3D: /* '-' */ 103 | return true; 104 | default: 105 | return isHexDigit(ch); 106 | } 107 | } 108 | 109 | 110 | function isOctalNonZeroDigit(ch) { 111 | return (ch > 0x30 /* '0' */) && (ch < 0x38 /* '8' */); 112 | } 113 | 114 | 115 | function hexDigitToInt(xdigit) { 116 | // TODO: Check that the digit is in range. 117 | 118 | switch (xdigit) { 119 | case 0x30: /* '0' */ return 0; 120 | case 0x31: /* '1' */ return 1; 121 | case 0x32: /* '2' */ return 2; 122 | case 0x33: /* '3' */ return 3; 123 | case 0x34: /* '4' */ return 4; 124 | case 0x35: /* '5' */ return 5; 125 | case 0x36: /* '6' */ return 6; 126 | case 0x37: /* '7' */ return 7; 127 | case 0x38: /* '8' */ return 8; 128 | case 0x39: /* '9' */ return 9; 129 | case 0x61: /* 'a' */ case 0x41: /* 'A' */ return 0xA; 130 | case 0x62: /* 'b' */ case 0x42: /* 'B' */ return 0xB; 131 | case 0x63: /* 'c' */ case 0x43: /* 'C' */ return 0xC; 132 | case 0x64: /* 'd' */ case 0x44: /* 'D' */ return 0xD; 133 | case 0x65: /* 'e' */ case 0x45: /* 'E' */ return 0xE; 134 | case 0x66: /* 'f' */ case 0x46: /* 'F' */ return 0xF; 135 | default: // TODO: What to do in this case? assert? throw? 136 | } 137 | } 138 | 139 | 140 | var _objectKeys = Object.keys; 141 | var _isArray = Array.isArray; 142 | 143 | 144 | hipack.DumpError = function (message) { 145 | this.message = message; 146 | if (Error.captureStackTrace) { 147 | Error.captureStackTrace(this, this.constructor); 148 | } else { 149 | this.stack = Error().stack; 150 | } 151 | } 152 | 153 | 154 | hipack.value = function (obj, annotations) { return obj } 155 | 156 | hipack.Dumper = function (compact, value) { 157 | if (value === undefined) 158 | value = hipack.value; 159 | this.indent = compact ? -1 : 0; 160 | this.value = value; 161 | this.output = ""; 162 | } 163 | hipack.Dumper.prototype.moreIndent = function () { 164 | if (this.indent >= 0) this.indent++; 165 | } 166 | hipack.Dumper.prototype.lessIndent = function () { 167 | if (this.indent > 0) this.indent--; 168 | } 169 | hipack.Dumper.prototype.dumpIndent = function () { 170 | var indent = (this.indent >= 0) ? this.indent : 0; 171 | while (indent--) this.output += " "; 172 | } 173 | hipack.Dumper.prototype.dumpString = function (value) { 174 | // assert(typeof value === "string") 175 | this.output += "\""; 176 | for (var i = 0; i < value.length; i++) { 177 | var ch = value.charCodeAt(i); 178 | switch (ch) { 179 | case 0x09: /* Horizontal tab. */ 180 | this.output += "\\t"; 181 | break; 182 | case 0x0A: /* New line. */ 183 | this.output += "\\n"; 184 | break; 185 | case 0x0D: /* Carriage return. */ 186 | this.output += "\\r"; 187 | break; 188 | case 0x22: /* Double quote. */ 189 | this.output += "\\\""; 190 | break; 191 | case 0x5C: /* Backslash. */ 192 | this.output += "\\\\"; 193 | break; 194 | default: 195 | if (ch < 0x20) { 196 | /* ASCII non-printable character. */ 197 | this.output += "\\"; 198 | if (ch < 16) { 199 | /* Add a leading zero. */ 200 | this.output += "0"; 201 | } 202 | this.output += ch.toString(16).toUpperCase(); 203 | } else { 204 | this.output += value.charAt(i); 205 | } 206 | } 207 | } 208 | this.output += "\""; 209 | } 210 | hipack.Dumper.prototype.dumpBoolean = function (value) { 211 | // assert(typeof value === "boolean") 212 | this.output += value ? "True" : "False"; 213 | } 214 | hipack.Dumper.prototype.dumpNumber = function (value) { 215 | // assert(typeof value === "number") 216 | this.output += value.toString(); 217 | } 218 | hipack.Dumper.prototype.dumpKeyVal = function (obj, keys) { 219 | for (var i = 0; i < keys.length; i++) { 220 | this.dumpIndent(); 221 | this.output += keys[i]; 222 | var value = obj[keys[i]]; 223 | 224 | /* Only write colon for simple (non-compound) objects. */ 225 | if (typeof value !== "object") 226 | this.output += ":"; 227 | 228 | /* Do not write the extra space in compact mode. */ 229 | if (this.indent >= 0) 230 | this.output += " "; 231 | 232 | this.dumpValue(value); 233 | 234 | if (this.indent >= 0) { 235 | this.output += "\n"; 236 | } else if (i < keys.length-1) { 237 | this.output += ","; 238 | } 239 | } 240 | } 241 | hipack.Dumper.prototype.dumpList = function (list) { 242 | if (list.length == 0) { 243 | this.output += "[]"; 244 | return; 245 | } 246 | 247 | this.output += "["; 248 | this.moreIndent(); 249 | 250 | /* Do not write the newline in compact mode. */ 251 | if (this.indent >= 0) 252 | this.output += "\n"; 253 | 254 | for (var i = 0; i < list.length; i++) { 255 | this.dumpIndent(); 256 | this.dumpValue(list[i]); 257 | if (this.indent >= 0) { 258 | this.output += "\n"; 259 | } else if (i < list.length-1) { 260 | this.output += ","; 261 | } 262 | } 263 | this.lessIndent(); 264 | this.output += "]"; 265 | } 266 | hipack.Dumper.prototype.dumpDict = function (dict) { 267 | var keys = _objectKeys(dict); 268 | if (keys.length == 0) { 269 | this.output += "{}"; 270 | return; 271 | } 272 | 273 | this.output += "{"; 274 | this.moreIndent(); 275 | 276 | /* Do not write the newline in compact mode. */ 277 | if (this.indent >= 0) 278 | this.output += "\n"; 279 | 280 | this.dumpKeyVal(dict, keys.sort()); 281 | 282 | this.lessIndent(); 283 | this.dumpIndent(); 284 | this.output += "}"; 285 | } 286 | hipack.Dumper.prototype.dumpValue = function (value) { 287 | var annotations = new Set(); 288 | value = this.value(value, annotations); 289 | if (!annotations.empty()) { 290 | if (this.indent < 0 && this.output[this.output.length-1] != ":") { 291 | this.output += ":"; 292 | } 293 | annotations = annotations.get(); 294 | for (var i = 0; i < annotations.length; i++) { 295 | this.output += ":"; 296 | this.output += annotations[i]; 297 | } 298 | this.output += " "; 299 | } 300 | var valueType = typeof value; 301 | switch (valueType) { 302 | case "number": 303 | this.dumpNumber(value); 304 | break; 305 | case "boolean": 306 | this.dumpBoolean(value); 307 | break; 308 | case "string": 309 | this.dumpString(value); 310 | break; 311 | case "object": 312 | if (value === null) { 313 | valueType = "null"; 314 | } else { 315 | if (_isArray(value)) { 316 | this.dumpList(value); 317 | } else { 318 | this.dumpDict(value); 319 | } 320 | break; 321 | } 322 | /* fall-through */ 323 | default: 324 | throw new hipack.DumpError("Values of type '" + 325 | valueType + "' cannot be dumped"); 326 | } 327 | } 328 | 329 | 330 | hipack.dump = function (data, compact, value) { 331 | var dumper = new hipack.Dumper(Boolean(compact), value); 332 | var keys = _objectKeys(data); 333 | dumper.dumpKeyVal(data, keys.sort()); 334 | return dumper.output; 335 | } 336 | 337 | 338 | var EOF = -1; 339 | var _parseInt = Number.parseInt; 340 | var _parseFloat = Number.parseFloat; 341 | var _fromCharCode = String.fromCharCode; 342 | 343 | hipack.ParseError = function (parser, message) { 344 | this.message = message; 345 | this.position = parser.pos; 346 | this.line = parser.line; 347 | this.column = parser.column; 348 | if (Error.captureStackTrace) { 349 | Error.captureStackTrace(this, this.constructor); 350 | } else { 351 | this.stack = Error().stack; 352 | } 353 | } 354 | 355 | hipack.cast = function (annotations, input, value) { return value } 356 | 357 | hipack.Parser = function (input, cast) { 358 | if (cast === undefined) 359 | cast = hipack.cast; 360 | this.input = input; 361 | this.cast = cast; 362 | this.look = 0; 363 | this.line = 1; 364 | this.column = 0; 365 | this.pos = 0; 366 | this.nextCharCode(); 367 | this.skipWhite(); 368 | this.framed = (this.look == 0x7B /* '{' */); 369 | } 370 | hipack.Parser.prototype.nextCharCodeRaw = function () { 371 | if (this.pos >= this.input.length) 372 | return EOF; 373 | 374 | var ch = this.input.charCodeAt(this.pos++); 375 | if (ch == 0x0A /* '\n' */) { 376 | this.column = 0; 377 | this.line++; 378 | } 379 | this.column++; 380 | return ch; 381 | } 382 | hipack.Parser.prototype.nextCharCode = function () { 383 | do { 384 | this.look = this.nextCharCodeRaw(); 385 | if (this.look == 0x23 /* '#' */) { 386 | while (this.look != 0x0A /* '\n' */ && this.look != EOF) { 387 | this.look = this.nextCharCodeRaw(); 388 | } 389 | } 390 | } while (this.look != EOF && this.look == 0x23 /* '#' */); 391 | } 392 | hipack.Parser.prototype.skipWhite = function () { 393 | while (this.look != EOF && isHiPackWhitespace(this.look)) 394 | this.nextCharCode(); 395 | } 396 | hipack.Parser.prototype.matchCharCode = function (ch, errmsg) { 397 | if (this.look != ch) { 398 | if (errmsg === undefined) { 399 | errmsg = "Expected '" + _fromCharCode(ch) + "', but '" + 400 | _fromCharCode(this.look) + "' was found instead"; 401 | } 402 | throw new hipack.ParseError(this, errmsg); 403 | } 404 | this.nextCharCode(); 405 | } 406 | hipack.Parser.prototype.parseKey = function () { 407 | var key = null; 408 | while (this.look != EOF && isHiPackKeyCharacter(this.look)) { 409 | if (key === null) key = ""; 410 | key += _fromCharCode(this.look); 411 | this.nextCharCode(); 412 | } 413 | if (key === null) 414 | throw new hipack.ParseError(this, "key expected"); 415 | return key; 416 | } 417 | hipack.Parser.prototype.parseString = function (annotations) { 418 | this.matchCharCode(0x22 /* '"' */); 419 | var s = '"'; // Original input string literal 420 | var str = ""; // String with escapes converted 421 | while (this.look != 0x22 /* '"' */ && this.look != EOF) { 422 | s += _fromCharCode(this.look); 423 | /* Handle escapes. */ 424 | if (this.look == 0x5C /* '\\' */) { 425 | switch (this.look = this.nextCharCodeRaw()) { 426 | case 0x22 /* '"' */: this.look = 0x22 /* '"' */; break; 427 | case 0x6E /* 'n' */: this.look = 0x0A /* '\n' */; break; 428 | case 0x72 /* 'r' */: this.look = 0x0D /* '\r' */; break; 429 | case 0x74 /* 't' */: this.look = 0x09 /* '\t' */; break; 430 | case 0x5C /* '\\' */: this.look = 0x5C /* '\\' */; break; 431 | default: 432 | /* Hex number. */ 433 | var extra = this.nextCharCodeRaw(); 434 | if (!isHexDigit(extra) || !isHexDigit(this.look)) { 435 | throw new hipack.ParseError(this, "invalid escape sequence"); 436 | } 437 | this.look = (hexDigitToInt(this.look) * 16) + hexDigitToInt(extra); 438 | } 439 | } 440 | str += _fromCharCode(this.look); 441 | this.look = this.nextCharCodeRaw(); 442 | } 443 | this.matchCharCode(0x22 /* '"'" */); 444 | s += '"'; 445 | annotations.add(hipack.ANNOT_STRING); 446 | return this.cast(annotations, s, str); 447 | } 448 | hipack.Parser.prototype.parseList = function (annotations) { 449 | this.matchCharCode(0x5B /* '[' */); 450 | this.skipWhite(); 451 | 452 | var list = []; 453 | while (this.look != 0x5D /* ']' */) { 454 | list.push(this.parseValue()); 455 | var gotWhitespace = isHiPackWhitespace(this.look); 456 | this.skipWhite(); 457 | 458 | /* There must be either a comma or whitespace after the value. */ 459 | if (this.look == 0x2C /* ',' */) { 460 | this.nextCharCode(); 461 | } else if (!gotWhitespace && !isHiPackWhitespace(this.look)) { 462 | break; 463 | } 464 | this.skipWhite(); 465 | } 466 | 467 | this.matchCharCode(0x5D /* ']' */); 468 | annotations.add(hipack.ANNOT_LIST); 469 | return this.cast(annotations, null, list); 470 | } 471 | hipack.Parser.prototype.parseDict = function (annotations) { 472 | this.matchCharCode(0x7B /* '{' */); 473 | this.skipWhite(); 474 | var dict = this.parseKeyValItems(0x7D /* '}' */); 475 | this.matchCharCode(0x7D /* '}' */); 476 | annotations.add(hipack.ANNOT_DICT); 477 | return this.cast(annotations, null, dict); 478 | } 479 | hipack.Parser.prototype.parseBoolean = function (annotations) { 480 | annotations.add(hipack.ANNOT_BOOL); 481 | var s = _fromCharCode(this.look); 482 | if (this.look == 0x54 /* 'T' */ || this.look == 0x74 /* 't' */) { 483 | this.nextCharCode(); 484 | this.matchCharCode(0x72 /* 'r' */); 485 | this.matchCharCode(0x75 /* 'u' */); 486 | this.matchCharCode(0x65 /* 'e' */); 487 | return this.cast(annotations, s + "rue", true); 488 | } else if (this.look == 0x46 /* 'F' */ || this.look == 0x66 /* 'f' */) { 489 | this.nextCharCode(); 490 | this.matchCharCode(0x61 /* 'a' */); 491 | this.matchCharCode(0x6C /* 'l' */); 492 | this.matchCharCode(0x73 /* 's' */); 493 | this.matchCharCode(0x65 /* 'e' */); 494 | return this.cast(annotations, s + "alse", false); 495 | } else { 496 | throw new hipack.ParseError(this, "boolean value expected"); 497 | } 498 | } 499 | hipack.Parser.prototype.parseNumber = function (annotations) { 500 | var number = ""; 501 | var hasSign = false; 502 | if (this.look == 0x2B /* '+' */ || this.look == 0x2D /* '-' */) { 503 | number += _fromCharCode(this.look); 504 | this.nextCharCode(); 505 | hasSign = true; 506 | } 507 | 508 | var isOctal = false; 509 | var isHex = false; 510 | if (this.look == 0x30 /* '0' */) { 511 | number += "0"; 512 | this.nextCharCode(); 513 | if (this.look == 0x58 /* 'X' */ || this.look == 0x78 /* 'x' */) { 514 | number += _fromCharCode(this.look); 515 | this.nextCharCode(); 516 | isHex = true; 517 | } else if (isOctalNonZeroDigit(this.look)) { 518 | isOctal = true; 519 | } 520 | } 521 | 522 | var dotSeen = false; 523 | var expSeen = false; 524 | while (this.look != EOF && isNumberCharacter(this.look)) { 525 | if (!isHex && (this.look == 0x45 /* 'E' */ || 526 | this.look == 0x65 /* 'e' */)) { 527 | if (expSeen) { 528 | throw new hipack.ParseError(this, "invalid number"); 529 | } 530 | number += "e"; 531 | expSeen = true; 532 | this.nextCharCode(); 533 | /* Optional exponent sign. */ 534 | if (this.look == 0x2B /* '+' */ || this.look == 0x2D /* '-' */) { 535 | number += _fromCharCode(this.look); 536 | this.nextCharCode(); 537 | } 538 | } else { 539 | if (this.look == 0x2E /* '.' */) { 540 | if (dotSeen || isHex || isOctal) { 541 | throw new hipack.ParseError(this, "invalid number"); 542 | } 543 | dotSeen = true; 544 | } 545 | if (this.look == 0x2B /* '+' */ || this.look == 0x2D /* '-' */) { 546 | throw new hipack.ParseError(this, "invalid number"); 547 | } 548 | number += _fromCharCode(this.look); 549 | this.nextCharCode(); 550 | } 551 | } 552 | 553 | if (number.length == 0) { 554 | throw new hipack.ParseError(this, "number expected"); 555 | } 556 | 557 | if (isHex) { 558 | // TODO: assert(!isOctal); 559 | if (expSeen || dotSeen) { 560 | throw new hipack.ParseError(this, "invalid hex number"); 561 | } 562 | annotations.add(hipack.ANNOT_INT) 563 | return this.cast(annotations, number, _parseInt(number, 16)); 564 | } else if (isOctal) { 565 | // TODO: assert(!isHex); 566 | if (expSeen || dotSeen) { 567 | throw new hipack.ParseError(this, "invalid octal number"); 568 | } 569 | annotations.add(hipack.ANNOT_INT); 570 | return this.cast(annotations, number, _parseInt(number, 8)); 571 | } else if (dotSeen || expSeen) { 572 | // TODO: assert(!isHex); 573 | // TODO: assert(!isOctal); 574 | annotations.add(hipack.ANNOT_FLOAT); 575 | return this.cast(annotations, number, _parseFloat(number)); 576 | } else { 577 | // TODO: assert(!isHex); 578 | // TODO: assert(!isOctal); 579 | // TODO: assert(!expSeen); 580 | // TODO: assert(!dotSeen); 581 | annotations.add(hipack.ANNOT_INT); 582 | return this.cast(annotations, number, _parseInt(number, 10)); 583 | } 584 | } 585 | hipack.Parser.prototype.parseAnnotations = function () { 586 | var annotations = new Set(); 587 | while (this.look == 0x3A /* ':' */) { 588 | this.nextCharCode(); 589 | var key = this.parseKey(); 590 | if (annotations.contains(key)) { 591 | throw new ParseError(this, "duplicate annotation: " + key); 592 | } 593 | annotations.add(key); 594 | this.skipWhite(); 595 | } 596 | return annotations; 597 | } 598 | hipack.Parser.prototype.parseValue = function () { 599 | var annotations = this.parseAnnotations(); 600 | switch (this.look) { 601 | case 0x22 /* '"' */: return this.parseString(annotations); 602 | case 0x5B /* '[' */: return this.parseList(annotations); 603 | case 0x7B /* '{' */: return this.parseDict(annotations); 604 | case 0x54 /* 'T' */: 605 | case 0x74 /* 't' */: 606 | case 0x46 /* 'F' */: 607 | case 0x66 /* 'f' */: return this.parseBoolean(annotations); 608 | default: return this.parseNumber(annotations); 609 | } 610 | } 611 | hipack.Parser.prototype.parseKeyValItems = function (eos) { 612 | var dict = {}; 613 | while (this.look != eos && this.look != EOF) { 614 | var key = this.parseKey(); 615 | var gotSeparator = false; 616 | if (isHiPackWhitespace(this.look)) { 617 | gotSeparator = true; 618 | this.skipWhite(); 619 | } else if (this.look == 0x3A /* ':' */) { 620 | gotSeparator = true; 621 | this.nextCharCode(); 622 | this.skipWhite(); 623 | } else if (this.look == 0x7B /* '{' */ || this.look == 0x5B /* '[' */) { 624 | gotSeparator = true; 625 | } 626 | 627 | if (!gotSeparator) { 628 | throw new hipack.ParseError(this, "missing separator"); 629 | } 630 | 631 | dict[key] = this.parseValue(); 632 | 633 | /* 634 | * There must be either a comma or a whitespace after the value, or 635 | * the end-of-sequence character. 636 | */ 637 | if (this.look == 0x2C /* ',' */) { 638 | this.nextCharCode(); 639 | } else if (this.look != eos && !isHiPackWhitespace(this.look)) { 640 | break; 641 | } 642 | this.skipWhite(); 643 | } 644 | return dict; 645 | } 646 | hipack.Parser.prototype.parseMessage = function () { 647 | var result = null; 648 | if (this.framed) { 649 | if (this.look != EOF) { 650 | this.matchCharCode(0x7B /* '{' */); 651 | this.nextCharCode(); 652 | this.skipWhite(); 653 | result = this.parseKeyValItems(0x7D /* '}' */); 654 | this.matchCharCode(0x7D /* '}' */, "unterminated message, '}' expected"); 655 | this.skipWhite(); 656 | } 657 | } else { 658 | result = this.parseKeyValItems(EOF); 659 | } 660 | return result; 661 | } 662 | 663 | 664 | hipack.load = function (input, cast) { 665 | return (new hipack.Parser(String(input), cast)).parseMessage(); 666 | } 667 | 668 | 669 | if (typeof exports !== "undefined") { 670 | if (typeof module !== "undefined" && module.exports) { 671 | exports = module.exports = hipack; 672 | } 673 | exports.hipack = hipack; 674 | } else { 675 | root.hipack = hipack; 676 | } 677 | }).call(this) 678 | --------------------------------------------------------------------------------